aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/tools/lld
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/lld')
-rw-r--r--contrib/llvm/tools/lld/COFF/CMakeLists.txt1
-rw-r--r--contrib/llvm/tools/lld/COFF/Chunks.cpp175
-rw-r--r--contrib/llvm/tools/lld/COFF/Chunks.h92
-rw-r--r--contrib/llvm/tools/lld/COFF/Config.h29
-rw-r--r--contrib/llvm/tools/lld/COFF/DLL.cpp2
-rw-r--r--contrib/llvm/tools/lld/COFF/DLL.h5
-rw-r--r--contrib/llvm/tools/lld/COFF/Driver.cpp425
-rw-r--r--contrib/llvm/tools/lld/COFF/Driver.h21
-rw-r--r--contrib/llvm/tools/lld/COFF/DriverUtils.cpp115
-rw-r--r--contrib/llvm/tools/lld/COFF/ICF.cpp96
-rw-r--r--contrib/llvm/tools/lld/COFF/ICF.h (renamed from contrib/llvm/tools/lld/COFF/Strings.h)21
-rw-r--r--contrib/llvm/tools/lld/COFF/InputFiles.cpp92
-rw-r--r--contrib/llvm/tools/lld/COFF/InputFiles.h51
-rw-r--r--contrib/llvm/tools/lld/COFF/LTO.cpp70
-rw-r--r--contrib/llvm/tools/lld/COFF/LTO.h2
-rw-r--r--contrib/llvm/tools/lld/COFF/MapFile.cpp12
-rw-r--r--contrib/llvm/tools/lld/COFF/MarkLive.cpp7
-rw-r--r--contrib/llvm/tools/lld/COFF/MarkLive.h24
-rw-r--r--contrib/llvm/tools/lld/COFF/MinGW.cpp2
-rw-r--r--contrib/llvm/tools/lld/COFF/Options.td29
-rw-r--r--contrib/llvm/tools/lld/COFF/PDB.cpp522
-rw-r--r--contrib/llvm/tools/lld/COFF/PDB.h4
-rw-r--r--contrib/llvm/tools/lld/COFF/Strings.cpp35
-rw-r--r--contrib/llvm/tools/lld/COFF/SymbolTable.cpp96
-rw-r--r--contrib/llvm/tools/lld/COFF/SymbolTable.h6
-rw-r--r--contrib/llvm/tools/lld/COFF/Symbols.cpp8
-rw-r--r--contrib/llvm/tools/lld/COFF/Symbols.h11
-rw-r--r--contrib/llvm/tools/lld/COFF/Writer.cpp825
-rw-r--r--contrib/llvm/tools/lld/COFF/Writer.h16
-rw-r--r--contrib/llvm/tools/lld/Common/Args.cpp18
-rw-r--r--contrib/llvm/tools/lld/Common/CMakeLists.txt1
-rw-r--r--contrib/llvm/tools/lld/Common/ErrorHandler.cpp27
-rw-r--r--contrib/llvm/tools/lld/Common/Strings.cpp77
-rw-r--r--contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp8
-rw-r--r--contrib/llvm/tools/lld/Common/Timer.cpp80
-rw-r--r--contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp14
-rw-r--r--contrib/llvm/tools/lld/ELF/AArch64ErrataFix.h1
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp57
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp2
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/ARM.cpp30
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/Hexagon.cpp103
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/Mips.cpp167
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp37
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/PPC.cpp7
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp423
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp12
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/X86.cpp64
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp110
-rw-r--r--contrib/llvm/tools/lld/ELF/CMakeLists.txt4
-rw-r--r--contrib/llvm/tools/lld/ELF/CallGraphSort.cpp249
-rw-r--r--contrib/llvm/tools/lld/ELF/CallGraphSort.h23
-rw-r--r--contrib/llvm/tools/lld/ELF/Config.h54
-rw-r--r--contrib/llvm/tools/lld/ELF/Driver.cpp616
-rw-r--r--contrib/llvm/tools/lld/ELF/Driver.h6
-rw-r--r--contrib/llvm/tools/lld/ELF/DriverUtils.cpp55
-rw-r--r--contrib/llvm/tools/lld/ELF/EhFrame.cpp8
-rw-r--r--contrib/llvm/tools/lld/ELF/Filesystem.cpp2
-rw-r--r--contrib/llvm/tools/lld/ELF/GdbIndex.cpp2
-rw-r--r--contrib/llvm/tools/lld/ELF/GdbIndex.h1
-rw-r--r--contrib/llvm/tools/lld/ELF/ICF.cpp125
-rw-r--r--contrib/llvm/tools/lld/ELF/ICF.h4
-rw-r--r--contrib/llvm/tools/lld/ELF/InputFiles.cpp614
-rw-r--r--contrib/llvm/tools/lld/ELF/InputFiles.h82
-rw-r--r--contrib/llvm/tools/lld/ELF/InputSection.cpp457
-rw-r--r--contrib/llvm/tools/lld/ELF/InputSection.h65
-rw-r--r--contrib/llvm/tools/lld/ELF/LTO.cpp214
-rw-r--r--contrib/llvm/tools/lld/ELF/LTO.h6
-rw-r--r--contrib/llvm/tools/lld/ELF/LinkerScript.cpp373
-rw-r--r--contrib/llvm/tools/lld/ELF/LinkerScript.h53
-rw-r--r--contrib/llvm/tools/lld/ELF/MapFile.cpp213
-rw-r--r--contrib/llvm/tools/lld/ELF/MapFile.h1
-rw-r--r--contrib/llvm/tools/lld/ELF/MarkLive.cpp38
-rw-r--r--contrib/llvm/tools/lld/ELF/MarkLive.h21
-rw-r--r--contrib/llvm/tools/lld/ELF/Options.td524
-rw-r--r--contrib/llvm/tools/lld/ELF/OutputSections.cpp81
-rw-r--r--contrib/llvm/tools/lld/ELF/OutputSections.h14
-rw-r--r--contrib/llvm/tools/lld/ELF/Relocations.cpp808
-rw-r--r--contrib/llvm/tools/lld/ELF/Relocations.h21
-rw-r--r--contrib/llvm/tools/lld/ELF/ScriptLexer.cpp10
-rw-r--r--contrib/llvm/tools/lld/ELF/ScriptParser.cpp291
-rw-r--r--contrib/llvm/tools/lld/ELF/Strings.cpp62
-rw-r--r--contrib/llvm/tools/lld/ELF/Strings.h75
-rw-r--r--contrib/llvm/tools/lld/ELF/SymbolTable.cpp292
-rw-r--r--contrib/llvm/tools/lld/ELF/SymbolTable.h11
-rw-r--r--contrib/llvm/tools/lld/ELF/Symbols.cpp95
-rw-r--r--contrib/llvm/tools/lld/ELF/Symbols.h159
-rw-r--r--contrib/llvm/tools/lld/ELF/SyntheticSections.cpp1531
-rw-r--r--contrib/llvm/tools/lld/ELF/SyntheticSections.h346
-rw-r--r--contrib/llvm/tools/lld/ELF/Target.cpp28
-rw-r--r--contrib/llvm/tools/lld/ELF/Target.h113
-rw-r--r--contrib/llvm/tools/lld/ELF/Thunks.cpp390
-rw-r--r--contrib/llvm/tools/lld/ELF/Thunks.h20
-rw-r--r--contrib/llvm/tools/lld/ELF/Writer.cpp735
-rw-r--r--contrib/llvm/tools/lld/ELF/Writer.h8
-rw-r--r--contrib/llvm/tools/lld/LICENSE.TXT2
-rw-r--r--contrib/llvm/tools/lld/docs/AtomLLD.rst62
-rw-r--r--contrib/llvm/tools/lld/docs/CMakeLists.txt8
-rw-r--r--contrib/llvm/tools/lld/docs/Driver.rst82
-rw-r--r--contrib/llvm/tools/lld/docs/NewLLD.rst309
-rw-r--r--contrib/llvm/tools/lld/docs/README.txt12
-rw-r--r--contrib/llvm/tools/lld/docs/Readers.rst174
-rw-r--r--contrib/llvm/tools/lld/docs/ReleaseNotes.rst37
-rw-r--r--contrib/llvm/tools/lld/docs/WebAssembly.rst36
-rw-r--r--contrib/llvm/tools/lld/docs/_static/favicon.icobin0 -> 1150 bytes
-rw-r--r--contrib/llvm/tools/lld/docs/_templates/indexsidebar.html4
-rw-r--r--contrib/llvm/tools/lld/docs/_templates/layout.html12
-rw-r--r--contrib/llvm/tools/lld/docs/conf.py255
-rw-r--r--contrib/llvm/tools/lld/docs/design.rst421
-rw-r--r--contrib/llvm/tools/lld/docs/development.rst45
-rw-r--r--contrib/llvm/tools/lld/docs/getting_started.rst106
-rw-r--r--contrib/llvm/tools/lld/docs/hello.pngbin0 -> 27616 bytes
-rw-r--r--contrib/llvm/tools/lld/docs/index.rst178
-rw-r--r--contrib/llvm/tools/lld/docs/ld.lld.1570
-rw-r--r--contrib/llvm/tools/lld/docs/llvm-theme/layout.html22
-rw-r--r--contrib/llvm/tools/lld/docs/llvm-theme/static/contents.pngbin0 -> 202 bytes
-rw-r--r--contrib/llvm/tools/lld/docs/llvm-theme/static/llvm.css345
-rw-r--r--contrib/llvm/tools/lld/docs/llvm-theme/static/logo.pngbin0 -> 9865 bytes
-rw-r--r--contrib/llvm/tools/lld/docs/llvm-theme/static/navigation.pngbin0 -> 218 bytes
-rw-r--r--contrib/llvm/tools/lld/docs/llvm-theme/theme.conf4
-rw-r--r--contrib/llvm/tools/lld/docs/make.bat190
-rw-r--r--contrib/llvm/tools/lld/docs/open_projects.rst11
-rw-r--r--contrib/llvm/tools/lld/docs/sphinx_intro.rst127
-rw-r--r--contrib/llvm/tools/lld/docs/windows_support.rst97
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/Driver.h2
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/ErrorHandler.h70
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/Strings.h26
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/TargetOptionsCommandFlags.h1
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/Timer.h59
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/Version.h2
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/DefinedAtom.h44
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/File.h24
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Instrumentation.h14
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/LinkingContext.h9
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/PassManager.h4
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Reader.h6
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Resolver.h6
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Simple.h2
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/SymbolTable.h22
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/TODO.txt3
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Writer.h6
-rw-r--r--contrib/llvm/tools/lld/include/lld/ReaderWriter/MachOLinkingContext.h28
-rw-r--r--contrib/llvm/tools/lld/lib/Core/LinkingContext.cpp4
-rw-r--r--contrib/llvm/tools/lld/lib/Driver/CMakeLists.txt1
-rw-r--r--contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp312
-rw-r--r--contrib/llvm/tools/lld/lib/Driver/DarwinLdOptions.td8
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp6
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp4
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CMakeLists.txt1
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp43
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.cpp31
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp14
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp6
-rw-r--r--contrib/llvm/tools/lld/tools/lld/lld.cpp49
153 files changed, 12372 insertions, 4476 deletions
diff --git a/contrib/llvm/tools/lld/COFF/CMakeLists.txt b/contrib/llvm/tools/lld/COFF/CMakeLists.txt
index 4610ccc880fd..bb241e788c19 100644
--- a/contrib/llvm/tools/lld/COFF/CMakeLists.txt
+++ b/contrib/llvm/tools/lld/COFF/CMakeLists.txt
@@ -18,7 +18,6 @@ add_lld_library(lldCOFF
MarkLive.cpp
MinGW.cpp
PDB.cpp
- Strings.cpp
SymbolTable.cpp
Symbols.cpp
Writer.cpp
diff --git a/contrib/llvm/tools/lld/COFF/Chunks.cpp b/contrib/llvm/tools/lld/COFF/Chunks.cpp
index 557b02654426..412ff783222b 100644
--- a/contrib/llvm/tools/lld/COFF/Chunks.cpp
+++ b/contrib/llvm/tools/lld/COFF/Chunks.cpp
@@ -31,8 +31,7 @@ namespace coff {
SectionChunk::SectionChunk(ObjFile *F, const coff_section *H)
: Chunk(SectionKind), Repl(this), Header(H), File(F),
- Relocs(File->getCOFFObj()->getRelocations(Header)),
- NumRelocs(std::distance(Relocs.begin(), Relocs.end())) {
+ Relocs(File->getCOFFObj()->getRelocations(Header)) {
// Initialize SectionName.
File->getCOFFObj()->getSectionName(Header, SectionName);
@@ -51,13 +50,21 @@ static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); }
static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); }
static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); }
+// Verify that given sections are appropriate targets for SECREL
+// relocations. This check is relaxed because unfortunately debug
+// sections have section-relative relocations against absolute symbols.
+static bool checkSecRel(const SectionChunk *Sec, OutputSection *OS) {
+ if (OS)
+ return true;
+ if (Sec->isCodeView())
+ return false;
+ fatal("SECREL relocation cannot be applied to absolute symbols");
+}
+
static void applySecRel(const SectionChunk *Sec, uint8_t *Off,
OutputSection *OS, uint64_t S) {
- if (!OS) {
- if (Sec->isCodeView())
- return;
- fatal("SECREL relocation cannot be applied to absolute symbols");
- }
+ if (!checkSecRel(Sec, OS))
+ return;
uint64_t SecRel = S - OS->getRVA();
if (SecRel > UINT32_MAX) {
error("overflow in SECREL relocation in section: " + Sec->getSectionName());
@@ -67,10 +74,13 @@ static void applySecRel(const SectionChunk *Sec, uint8_t *Off,
}
static void applySecIdx(uint8_t *Off, OutputSection *OS) {
- // If we have no output section, this must be an absolute symbol. Use the
- // sentinel absolute symbol section index.
- uint16_t SecIdx = OS ? OS->SectionIndex : DefinedAbsolute::OutputSectionIndex;
- add16(Off, SecIdx);
+ // Absolute symbol doesn't have section index, but section index relocation
+ // against absolute symbol should be resolved to one plus the last output
+ // section index. This is required for compatibility with MSVC.
+ if (OS)
+ add16(Off, OS->SectionIndex);
+ else
+ add16(Off, DefinedAbsolute::NumOutputSections + 1);
}
void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS,
@@ -88,7 +98,8 @@ void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS,
case IMAGE_REL_AMD64_SECTION: applySecIdx(Off, OS); break;
case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, OS, S); break;
default:
- fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
+ fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
+ toString(File));
}
}
@@ -102,7 +113,8 @@ void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS,
case IMAGE_REL_I386_SECTION: applySecIdx(Off, OS); break;
case IMAGE_REL_I386_SECREL: applySecRel(this, Off, OS, S); break;
default:
- fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
+ fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
+ toString(File));
}
}
@@ -112,11 +124,10 @@ static void applyMOV(uint8_t *Off, uint16_t V) {
}
static uint16_t readMOV(uint8_t *Off) {
- uint16_t Opcode1 = read16le(Off);
- uint16_t Opcode2 = read16le(Off + 2);
- uint16_t Imm = (Opcode2 & 0x00ff) | ((Opcode2 >> 4) & 0x0700);
- Imm |= ((Opcode1 << 1) & 0x0800) | ((Opcode1 & 0x000f) << 12);
- return Imm;
+ uint16_t Op1 = read16le(Off);
+ uint16_t Op2 = read16le(Off + 2);
+ return (Op2 & 0x00ff) | ((Op2 >> 4) & 0x0700) | ((Op1 << 1) & 0x0800) |
+ ((Op1 & 0x000f) << 12);
}
void applyMOV32T(uint8_t *Off, uint32_t V) {
@@ -153,7 +164,7 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS,
uint64_t S, uint64_t P) const {
// Pointer to thumb code must have the LSB set.
uint64_t SX = S;
- if (OS && (OS->getPermissions() & IMAGE_SCN_MEM_EXECUTE))
+ if (OS && (OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE))
SX |= 1;
switch (Type) {
case IMAGE_REL_ARM_ADDR32: add32(Off, SX + Config->ImageBase); break;
@@ -165,18 +176,19 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS,
case IMAGE_REL_ARM_SECTION: applySecIdx(Off, OS); break;
case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, OS, S); break;
default:
- fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
+ fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
+ toString(File));
}
}
// Interpret the existing immediate value as a byte offset to the
// target symbol, then update the instruction with the immediate as
// the page offset from the current instruction to the target.
-static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P) {
+static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift) {
uint32_t Orig = read32le(Off);
uint64_t Imm = ((Orig >> 29) & 0x3) | ((Orig >> 3) & 0x1FFFFC);
S += Imm;
- Imm = (S >> 12) - (P >> 12);
+ Imm = (S >> Shift) - (P >> Shift);
uint32_t ImmLo = (Imm & 0x3) << 29;
uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
@@ -213,19 +225,70 @@ static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) {
applyArm64Imm(Off, Imm >> Size, Size);
}
+static void applySecRelLow12A(const SectionChunk *Sec, uint8_t *Off,
+ OutputSection *OS, uint64_t S) {
+ if (checkSecRel(Sec, OS))
+ applyArm64Imm(Off, (S - OS->getRVA()) & 0xfff, 0);
+}
+
+static void applySecRelHigh12A(const SectionChunk *Sec, uint8_t *Off,
+ OutputSection *OS, uint64_t S) {
+ if (!checkSecRel(Sec, OS))
+ return;
+ uint64_t SecRel = (S - OS->getRVA()) >> 12;
+ if (0xfff < SecRel) {
+ error("overflow in SECREL_HIGH12A relocation in section: " +
+ Sec->getSectionName());
+ return;
+ }
+ applyArm64Imm(Off, SecRel & 0xfff, 0);
+}
+
+static void applySecRelLdr(const SectionChunk *Sec, uint8_t *Off,
+ OutputSection *OS, uint64_t S) {
+ if (checkSecRel(Sec, OS))
+ applyArm64Ldr(Off, (S - OS->getRVA()) & 0xfff);
+}
+
+static void applyArm64Branch26(uint8_t *Off, int64_t V) {
+ if (!isInt<28>(V))
+ fatal("relocation out of range");
+ or32(Off, (V & 0x0FFFFFFC) >> 2);
+}
+
+static void applyArm64Branch19(uint8_t *Off, int64_t V) {
+ if (!isInt<21>(V))
+ fatal("relocation out of range");
+ or32(Off, (V & 0x001FFFFC) << 3);
+}
+
+static void applyArm64Branch14(uint8_t *Off, int64_t V) {
+ if (!isInt<16>(V))
+ fatal("relocation out of range");
+ or32(Off, (V & 0x0000FFFC) << 3);
+}
+
void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS,
uint64_t S, uint64_t P) const {
switch (Type) {
- case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P); break;
+ case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P, 12); break;
+ case IMAGE_REL_ARM64_REL21: applyArm64Addr(Off, S, P, 0); break;
case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff, 0); break;
case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break;
- case IMAGE_REL_ARM64_BRANCH26: or32(Off, ((S - P) & 0x0FFFFFFC) >> 2); break;
+ case IMAGE_REL_ARM64_BRANCH26: applyArm64Branch26(Off, S - P); break;
+ case IMAGE_REL_ARM64_BRANCH19: applyArm64Branch19(Off, S - P); break;
+ case IMAGE_REL_ARM64_BRANCH14: applyArm64Branch14(Off, S - P); break;
case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break;
case IMAGE_REL_ARM64_ADDR32NB: add32(Off, S); break;
case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break;
case IMAGE_REL_ARM64_SECREL: applySecRel(this, Off, OS, S); break;
+ case IMAGE_REL_ARM64_SECREL_LOW12A: applySecRelLow12A(this, Off, OS, S); break;
+ case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, Off, OS, S); break;
+ case IMAGE_REL_ARM64_SECREL_LOW12L: applySecRelLdr(this, Off, OS, S); break;
+ case IMAGE_REL_ARM64_SECTION: applySecIdx(Off, OS); break;
default:
- fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
+ fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
+ toString(File));
}
}
@@ -234,7 +297,8 @@ void SectionChunk::writeTo(uint8_t *Buf) const {
return;
// Copy section contents from source object file to output file.
ArrayRef<uint8_t> A = getContents();
- memcpy(Buf + OutputSectionOff, A.data(), A.size());
+ if (!A.empty())
+ memcpy(Buf + OutputSectionOff, A.data(), A.size());
// Apply relocations.
size_t InputSize = getSize();
@@ -350,8 +414,8 @@ bool SectionChunk::hasData() const {
return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA);
}
-uint32_t SectionChunk::getPermissions() const {
- return Header->Characteristics & PermMask;
+uint32_t SectionChunk::getOutputCharacteristics() const {
+ return Header->Characteristics & (PermMask | TypeMask);
}
bool SectionChunk::isCOMDAT() const {
@@ -378,6 +442,7 @@ ArrayRef<uint8_t> SectionChunk::getContents() const {
}
void SectionChunk::replace(SectionChunk *Other) {
+ Alignment = std::max(Alignment, Other->Alignment);
Other->Repl = Repl;
Other->Live = false;
}
@@ -388,7 +453,7 @@ CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) {
Alignment = std::min(uint64_t(32), PowerOf2Ceil(Sym.getValue()));
}
-uint32_t CommonChunk::getPermissions() const {
+uint32_t CommonChunk::getOutputCharacteristics() const {
return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ |
IMAGE_SCN_MEM_WRITE;
}
@@ -433,7 +498,7 @@ void ImportThunkChunkARM::writeTo(uint8_t *Buf) const {
void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const {
int64_t Off = ImpSymbol->getRVA() & 0xfff;
memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64));
- applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA);
+ applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA, 12);
applyArm64Ldr(Buf + OutputSectionOff + 4, Off);
}
@@ -453,12 +518,14 @@ void LocalImportChunk::writeTo(uint8_t *Buf) const {
}
}
-void SEHTableChunk::writeTo(uint8_t *Buf) const {
+void RVATableChunk::writeTo(uint8_t *Buf) const {
ulittle32_t *Begin = reinterpret_cast<ulittle32_t *>(Buf + OutputSectionOff);
size_t Cnt = 0;
- for (Defined *D : Syms)
- Begin[Cnt++] = D->getRVA();
+ for (const ChunkAndOffset &CO : Syms)
+ Begin[Cnt++] = CO.InputChunk->getRVA() + CO.Offset;
std::sort(Begin, Begin + Cnt);
+ assert(std::unique(Begin, Begin + Cnt) == Begin + Cnt &&
+ "RVA tables should be de-duplicated");
}
// Windows-specific. This class represents a block in .reloc section.
@@ -531,5 +598,47 @@ uint8_t Baserel::getDefaultType() {
}
}
+std::map<uint32_t, MergeChunk *> MergeChunk::Instances;
+
+MergeChunk::MergeChunk(uint32_t Alignment)
+ : Builder(StringTableBuilder::RAW, Alignment) {
+ this->Alignment = Alignment;
+}
+
+void MergeChunk::addSection(SectionChunk *C) {
+ auto *&MC = Instances[C->Alignment];
+ if (!MC)
+ MC = make<MergeChunk>(C->Alignment);
+ MC->Sections.push_back(C);
+}
+
+void MergeChunk::finalizeContents() {
+ for (SectionChunk *C : Sections)
+ if (C->isLive())
+ Builder.add(toStringRef(C->getContents()));
+ Builder.finalize();
+
+ for (SectionChunk *C : Sections) {
+ if (!C->isLive())
+ continue;
+ size_t Off = Builder.getOffset(toStringRef(C->getContents()));
+ C->setOutputSection(Out);
+ C->setRVA(RVA + Off);
+ C->OutputSectionOff = OutputSectionOff + Off;
+ }
+}
+
+uint32_t MergeChunk::getOutputCharacteristics() const {
+ return IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA;
+}
+
+size_t MergeChunk::getSize() const {
+ return Builder.getSize();
+}
+
+void MergeChunk::writeTo(uint8_t *Buf) const {
+ Builder.write(Buf + OutputSectionOff);
+}
+
} // namespace coff
} // namespace lld
diff --git a/contrib/llvm/tools/lld/COFF/Chunks.h b/contrib/llvm/tools/lld/COFF/Chunks.h
index 381527ee6ef2..9e896531bd9a 100644
--- a/contrib/llvm/tools/lld/COFF/Chunks.h
+++ b/contrib/llvm/tools/lld/COFF/Chunks.h
@@ -16,6 +16,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/iterator_range.h"
+#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/COFF.h"
#include <utility>
#include <vector>
@@ -37,9 +38,11 @@ class ObjFile;
class OutputSection;
class Symbol;
-// Mask for section types (code, data, bss, disacardable, etc.)
-// and permissions (writable, readable or executable).
-const uint32_t PermMask = 0xFF0000F0;
+// Mask for permissions (discardable, writable, readable, executable, etc).
+const uint32_t PermMask = 0xFE000000;
+
+// Mask for section types (code, data, bss).
+const uint32_t TypeMask = 0x000000E0;
// A Chunk represents a chunk of data that will occupy space in the
// output (if the resolver chose that). It may or may not be backed by
@@ -60,6 +63,10 @@ public:
// before calling this function.
virtual void writeTo(uint8_t *Buf) const {}
+ // Called by the writer after an RVA is assigned, but before calling
+ // getSize().
+ virtual void finalizeContents() {}
+
// The writer sets and uses the addresses.
uint64_t getRVA() const { return RVA; }
void setRVA(uint64_t V) { RVA = V; }
@@ -70,7 +77,7 @@ public:
virtual bool hasData() const { return true; }
// Returns readable/writable/executable bits.
- virtual uint32_t getPermissions() const { return 0; }
+ virtual uint32_t getOutputCharacteristics() const { return 0; }
// Returns the section name if this is a section chunk.
// It is illegal to call this function on non-section chunks.
@@ -137,7 +144,7 @@ public:
ArrayRef<uint8_t> getContents() const;
void writeTo(uint8_t *Buf) const override;
bool hasData() const override;
- uint32_t getPermissions() const override;
+ uint32_t getOutputCharacteristics() const override;
StringRef getSectionName() const override { return SectionName; }
void getBaserels(std::vector<Baserel> *Res) override;
bool isCOMDAT() const;
@@ -208,11 +215,11 @@ public:
// The COMDAT leader symbol if this is a COMDAT chunk.
DefinedRegular *Sym = nullptr;
+ ArrayRef<coff_relocation> Relocs;
+
private:
StringRef SectionName;
std::vector<SectionChunk *> AssocChildren;
- llvm::iterator_range<const coff_relocation *> Relocs;
- size_t NumRelocs;
// Used by the garbage collector.
bool Live;
@@ -222,13 +229,40 @@ private:
uint32_t Class[2] = {0, 0};
};
+// This class is used to implement an lld-specific feature (not implemented in
+// MSVC) that minimizes the output size by finding string literals sharing tail
+// parts and merging them.
+//
+// If string tail merging is enabled and a section is identified as containing a
+// string literal, it is added to a MergeChunk with an appropriate alignment.
+// The MergeChunk then tail merges the strings using the StringTableBuilder
+// class and assigns RVAs and section offsets to each of the member chunks based
+// on the offsets assigned by the StringTableBuilder.
+class MergeChunk : public Chunk {
+public:
+ MergeChunk(uint32_t Alignment);
+ static void addSection(SectionChunk *C);
+ void finalizeContents() override;
+
+ uint32_t getOutputCharacteristics() const override;
+ StringRef getSectionName() const override { return ".rdata"; }
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) const override;
+
+ static std::map<uint32_t, MergeChunk *> Instances;
+ std::vector<SectionChunk *> Sections;
+
+private:
+ llvm::StringTableBuilder Builder;
+};
+
// A chunk for common symbols. Common chunks don't have actual data.
class CommonChunk : public Chunk {
public:
CommonChunk(const COFFSymbolRef Sym);
size_t getSize() const override { return Sym.getValue(); }
bool hasData() const override { return false; }
- uint32_t getPermissions() const override;
+ uint32_t getOutputCharacteristics() const override;
StringRef getSectionName() const override { return ".bss"; }
private:
@@ -320,17 +354,41 @@ private:
Defined *Sym;
};
-// Windows-specific.
-// A chunk for SEH table which contains RVAs of safe exception handler
-// functions. x86-only.
-class SEHTableChunk : public Chunk {
+// Duplicate RVAs are not allowed in RVA tables, so unique symbols by chunk and
+// offset into the chunk. Order does not matter as the RVA table will be sorted
+// later.
+struct ChunkAndOffset {
+ Chunk *InputChunk;
+ uint32_t Offset;
+
+ struct DenseMapInfo {
+ static ChunkAndOffset getEmptyKey() {
+ return {llvm::DenseMapInfo<Chunk *>::getEmptyKey(), 0};
+ }
+ static ChunkAndOffset getTombstoneKey() {
+ return {llvm::DenseMapInfo<Chunk *>::getTombstoneKey(), 0};
+ }
+ static unsigned getHashValue(const ChunkAndOffset &CO) {
+ return llvm::DenseMapInfo<std::pair<Chunk *, uint32_t>>::getHashValue(
+ {CO.InputChunk, CO.Offset});
+ }
+ static bool isEqual(const ChunkAndOffset &LHS, const ChunkAndOffset &RHS) {
+ return LHS.InputChunk == RHS.InputChunk && LHS.Offset == RHS.Offset;
+ }
+ };
+};
+
+using SymbolRVASet = llvm::DenseSet<ChunkAndOffset>;
+
+// Table which contains symbol RVAs. Used for /safeseh and /guard:cf.
+class RVATableChunk : public Chunk {
public:
- explicit SEHTableChunk(std::set<Defined *> S) : Syms(std::move(S)) {}
+ explicit RVATableChunk(SymbolRVASet S) : Syms(std::move(S)) {}
size_t getSize() const override { return Syms.size() * 4; }
void writeTo(uint8_t *Buf) const override;
private:
- std::set<Defined *> Syms;
+ SymbolRVASet Syms;
};
// Windows-specific.
@@ -362,4 +420,10 @@ void applyBranch24T(uint8_t *Off, int32_t V);
} // namespace coff
} // namespace lld
+namespace llvm {
+template <>
+struct DenseMapInfo<lld::coff::ChunkAndOffset>
+ : lld::coff::ChunkAndOffset::DenseMapInfo {};
+}
+
#endif
diff --git a/contrib/llvm/tools/lld/COFF/Config.h b/contrib/llvm/tools/lld/COFF/Config.h
index b01689930fac..3ae50b868333 100644
--- a/contrib/llvm/tools/lld/COFF/Config.h
+++ b/contrib/llvm/tools/lld/COFF/Config.h
@@ -10,6 +10,7 @@
#ifndef LLD_COFF_CONFIG_H
#define LLD_COFF_CONFIG_H
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/CachePruning.h"
@@ -71,6 +72,12 @@ enum class DebugType {
Fixup = 0x4, /// Relocation Table
};
+enum class GuardCFLevel {
+ Off,
+ NoLongJmp, // Emit gfids but no longjmp tables
+ Full, // Enable all protections.
+};
+
// Global configuration.
struct Configuration {
enum ManifestKind { SideBySide, Embed, No };
@@ -85,13 +92,19 @@ struct Configuration {
std::string ImportName;
bool DoGC = true;
bool DoICF = true;
+ bool TailMerge;
bool Relocatable = true;
bool Force = false;
bool Debug = false;
bool DebugDwarf = false;
bool DebugGHashes = false;
+ bool DebugSymtab = false;
+ bool ShowTiming = false;
unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
+ std::vector<std::string> NatvisFiles;
+ llvm::SmallString<128> PDBAltPath;
llvm::SmallString<128> PDBPath;
+ llvm::SmallString<128> PDBSourcePath;
std::vector<llvm::StringRef> Argv;
// Symbols in this set are considered as live by the garbage collector.
@@ -110,15 +123,18 @@ struct Configuration {
bool SaveTemps = false;
+ // /guard:cf
+ GuardCFLevel GuardCF = GuardCFLevel::Off;
+
// Used for SafeSEH.
Symbol *SEHTable = nullptr;
Symbol *SEHCount = nullptr;
// Used for /opt:lldlto=N
- unsigned LTOOptLevel = 2;
+ unsigned LTOO = 2;
// Used for /opt:lldltojobs=N
- unsigned LTOJobs = 0;
+ unsigned ThinLTOJobs = 0;
// Used for /opt:lldltopartitions=N
unsigned LTOPartitions = 1;
@@ -152,6 +168,9 @@ struct Configuration {
// Used for /alternatename.
std::map<StringRef, StringRef> AlternateNames;
+ // Used for /order.
+ llvm::StringMap<int> Order;
+
// Used for /lldmap.
std::string MapFile;
@@ -164,7 +183,7 @@ struct Configuration {
uint32_t MinorImageVersion = 0;
uint32_t MajorOSVersion = 6;
uint32_t MinorOSVersion = 0;
- bool CanExitEarly = false;
+ uint32_t Timestamp = 0;
bool DynamicBase = true;
bool AllowBind = true;
bool NxCompat = true;
@@ -174,8 +193,12 @@ struct Configuration {
bool HighEntropyVA = false;
bool AppContainer = false;
bool MinGW = false;
+ bool WarnMissingOrderSymbol = true;
bool WarnLocallyDefinedImported = true;
+ bool Incremental = true;
+ bool IntegrityCheck = false;
bool KillAt = false;
+ bool Repro = false;
};
extern Configuration *Config;
diff --git a/contrib/llvm/tools/lld/COFF/DLL.cpp b/contrib/llvm/tools/lld/COFF/DLL.cpp
index 195839139670..464abe8e0894 100644
--- a/contrib/llvm/tools/lld/COFF/DLL.cpp
+++ b/contrib/llvm/tools/lld/COFF/DLL.cpp
@@ -18,8 +18,8 @@
//
//===----------------------------------------------------------------------===//
-#include "Chunks.h"
#include "DLL.h"
+#include "Chunks.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Path.h"
diff --git a/contrib/llvm/tools/lld/COFF/DLL.h b/contrib/llvm/tools/lld/COFF/DLL.h
index ad312789edf1..c5d6e7c93abf 100644
--- a/contrib/llvm/tools/lld/COFF/DLL.h
+++ b/contrib/llvm/tools/lld/COFF/DLL.h
@@ -76,6 +76,11 @@ class EdataContents {
public:
EdataContents();
std::vector<Chunk *> Chunks;
+
+ uint64_t getRVA() { return Chunks[0]->getRVA(); }
+ uint64_t getSize() {
+ return Chunks.back()->getRVA() + Chunks.back()->getSize() - getRVA();
+ }
};
} // namespace coff
diff --git a/contrib/llvm/tools/lld/COFF/Driver.cpp b/contrib/llvm/tools/lld/COFF/Driver.cpp
index d4030588e211..eefdb48beadd 100644
--- a/contrib/llvm/tools/lld/COFF/Driver.cpp
+++ b/contrib/llvm/tools/lld/COFF/Driver.cpp
@@ -9,14 +9,18 @@
#include "Driver.h"
#include "Config.h"
+#include "ICF.h"
#include "InputFiles.h"
+#include "MarkLive.h"
#include "MinGW.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "Writer.h"
+#include "lld/Common/Args.h"
#include "lld/Common/Driver.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Timer.h"
#include "lld/Common/Version.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
@@ -35,9 +39,8 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
#include <algorithm>
-#include <memory>
-
#include <future>
+#include <memory>
using namespace llvm;
using namespace llvm::object;
@@ -47,20 +50,20 @@ using llvm::sys::Process;
namespace lld {
namespace coff {
+static Timer InputFileTimer("Input File Reading", Timer::root());
+
Configuration *Config;
LinkerDriver *Driver;
bool link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Diag) {
- errorHandler().LogName = Args[0];
+ errorHandler().LogName = sys::path::filename(Args[0]);
errorHandler().ErrorOS = &Diag;
errorHandler().ColorDiagnostics = Diag.has_colors();
errorHandler().ErrorLimitExceededMsg =
"too many errors emitted, stopping now"
- " (use /ERRORLIMIT:0 to see all errors)";
+ " (use /errorlimit:0 to see all errors)";
errorHandler().ExitEarly = CanExitEarly;
Config = make<Configuration>();
- Config->Argv = {Args.begin(), Args.end()};
- Config->CanExitEarly = CanExitEarly;
Symtab = make<SymbolTable>();
@@ -72,6 +75,9 @@ bool link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Diag) {
exitLld(errorCount() ? 1 : 0);
freeArena();
+ ObjFile::Instances.clear();
+ ImportFile::Instances.clear();
+ BitcodeFile::Instances.clear();
return !errorCount();
}
@@ -93,7 +99,7 @@ typedef std::pair<std::unique_ptr<MemoryBuffer>, std::error_code> MBErrPair;
// Create a std::future that opens and maps a file using the best strategy for
// the host platform.
static std::future<MBErrPair> createFutureForFile(std::string Path) {
-#if LLVM_ON_WIN32
+#if _WIN32
// On Windows, file I/O is relatively slow so it is best to do this
// asynchronously.
auto Strategy = std::launch::async;
@@ -101,7 +107,9 @@ static std::future<MBErrPair> createFutureForFile(std::string Path) {
auto Strategy = std::launch::deferred;
#endif
return std::async(Strategy, [=]() {
- auto MBOrErr = MemoryBuffer::getFile(Path);
+ auto MBOrErr = MemoryBuffer::getFile(Path,
+ /*FileSize*/ -1,
+ /*RequiresNullTerminator*/ false);
if (!MBOrErr)
return MBErrPair{nullptr, MBOrErr.getError()};
return MBErrPair{std::move(*MBOrErr), std::error_code()};
@@ -120,39 +128,46 @@ MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> MB) {
void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> MB,
bool WholeArchive) {
+ StringRef Filename = MB->getBufferIdentifier();
+
MemoryBufferRef MBRef = takeBuffer(std::move(MB));
- FilePaths.push_back(MBRef.getBufferIdentifier());
+ FilePaths.push_back(Filename);
// File type is detected by contents, not by file extension.
switch (identify_magic(MBRef.getBuffer())) {
case file_magic::windows_resource:
Resources.push_back(MBRef);
break;
-
case file_magic::archive:
if (WholeArchive) {
std::unique_ptr<Archive> File =
- CHECK(Archive::create(MBRef),
- MBRef.getBufferIdentifier() + ": failed to parse archive");
+ CHECK(Archive::create(MBRef), Filename + ": failed to parse archive");
for (MemoryBufferRef M : getArchiveMembers(File.get()))
- addArchiveBuffer(M, "<whole-archive>", MBRef.getBufferIdentifier());
+ addArchiveBuffer(M, "<whole-archive>", Filename);
return;
}
Symtab->addFile(make<ArchiveFile>(MBRef));
break;
-
case file_magic::bitcode:
Symtab->addFile(make<BitcodeFile>(MBRef));
break;
-
+ case file_magic::coff_object:
+ case file_magic::coff_import_library:
+ Symtab->addFile(make<ObjFile>(MBRef));
+ break;
case file_magic::coff_cl_gl_object:
- error(MBRef.getBufferIdentifier() + ": is not a native COFF file. "
- "Recompile without /GL");
+ error(Filename + ": is not a native COFF file. Recompile without /GL");
break;
-
+ case file_magic::pecoff_executable:
+ if (Filename.endswith_lower(".dll")) {
+ error(Filename + ": bad file type. Did you specify a DLL instead of an "
+ "import library?");
+ break;
+ }
+ LLVM_FALLTHROUGH;
default:
- Symtab->addFile(make<ObjFile>(MBRef));
+ error(MBRef.getBufferIdentifier() + ": unknown file type");
break;
}
}
@@ -228,7 +243,29 @@ static bool isDecorated(StringRef Sym) {
void LinkerDriver::parseDirectives(StringRef S) {
ArgParser Parser;
// .drectve is always tokenized using Windows shell rules.
- opt::InputArgList Args = Parser.parseDirectives(S);
+ // /EXPORT: option can appear too many times, processing in fastpath.
+ opt::InputArgList Args;
+ std::vector<StringRef> Exports;
+ std::tie(Args, Exports) = Parser.parseDirectives(S);
+
+ for (StringRef E : Exports) {
+ // If a common header file contains dllexported function
+ // declarations, many object files may end up with having the
+ // same /EXPORT options. In order to save cost of parsing them,
+ // we dedup them first.
+ if (!DirectivesExports.insert(E).second)
+ continue;
+
+ Export Exp = parseExport(E);
+ if (Config->Machine == I386 && Config->MinGW) {
+ if (!isDecorated(Exp.Name))
+ Exp.Name = Saver.save("_" + Exp.Name);
+ if (!Exp.ExtName.empty() && !isDecorated(Exp.ExtName))
+ Exp.ExtName = Saver.save("_" + Exp.ExtName);
+ }
+ Exp.Directives = true;
+ Config->Exports.push_back(Exp);
+ }
for (auto *Arg : Args) {
switch (Arg->getOption().getUnaliasedOption().getID()) {
@@ -245,25 +282,6 @@ void LinkerDriver::parseDirectives(StringRef S) {
case OPT_entry:
Config->Entry = addUndefined(mangle(Arg->getValue()));
break;
- case OPT_export: {
- // If a common header file contains dllexported function
- // declarations, many object files may end up with having the
- // same /EXPORT options. In order to save cost of parsing them,
- // we dedup them first.
- if (!DirectivesExports.insert(Arg->getValue()).second)
- break;
-
- Export E = parseExport(Arg->getValue());
- if (Config->Machine == I386 && Config->MinGW) {
- if (!isDecorated(E.Name))
- E.Name = Saver.save("_" + E.Name);
- if (!E.ExtName.empty() && !isDecorated(E.ExtName))
- E.ExtName = Saver.save("_" + E.ExtName);
- }
- E.Directives = true;
- Config->Exports.push_back(E);
- break;
- }
case OPT_failifmismatch:
checkFailIfMismatch(Arg->getValue());
break;
@@ -316,13 +334,24 @@ StringRef LinkerDriver::doFindFile(StringRef Filename) {
return Filename;
}
+static Optional<sys::fs::UniqueID> getUniqueID(StringRef Path) {
+ sys::fs::UniqueID Ret;
+ if (sys::fs::getUniqueID(Path, Ret))
+ return None;
+ return Ret;
+}
+
// Resolves a file path. This never returns the same path
// (in that case, it returns None).
Optional<StringRef> LinkerDriver::findFile(StringRef Filename) {
StringRef Path = doFindFile(Filename);
- bool Seen = !VisitedFiles.insert(Path.lower()).second;
- if (Seen)
- return None;
+
+ if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path)) {
+ bool Seen = !VisitedFiles.insert(*ID).second;
+ if (Seen)
+ return None;
+ }
+
if (Path.endswith_lower(".lib"))
VisitedLibs.insert(sys::path::filename(Path));
return Path;
@@ -345,11 +374,14 @@ Optional<StringRef> LinkerDriver::findLib(StringRef Filename) {
return None;
if (!VisitedLibs.insert(Filename.lower()).second)
return None;
+
StringRef Path = doFindLib(Filename);
if (Config->NoDefaultLibs.count(Path))
return None;
- if (!VisitedFiles.insert(Path.lower()).second)
- return None;
+
+ if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path))
+ if (!VisitedFiles.insert(*ID).second)
+ return None;
return Path;
}
@@ -384,7 +416,24 @@ StringRef LinkerDriver::mangle(StringRef Sym) {
}
// Windows specific -- find default entry point name.
+//
+// There are four different entry point functions for Windows executables,
+// each of which corresponds to a user-defined "main" function. This function
+// infers an entry point from a user-defined "main" function.
StringRef LinkerDriver::findDefaultEntry() {
+ // As a special case, if /nodefaultlib is given, we directly look for an
+ // entry point. This is because, if no default library is linked, users
+ // need to define an entry point instead of a "main".
+ if (Config->NoDefaultLibAll) {
+ for (StringRef S : {"mainCRTStartup", "wmainCRTStartup",
+ "WinMainCRTStartup", "wWinMainCRTStartup"}) {
+ StringRef Entry = Symtab->findMangle(S);
+ if (!Entry.empty() && !isa<Undefined>(Symtab->find(Entry)))
+ return mangle(S);
+ }
+ return "";
+ }
+
// User-defined main functions and their corresponding entry points.
static const char *Entries[][2] = {
{"main", "mainCRTStartup"},
@@ -534,10 +583,49 @@ static void createImportLibrary(bool AsLib) {
Exports.push_back(E2);
}
- auto E = writeImportLibrary(getImportName(AsLib), getImplibPath(), Exports,
- Config->Machine, false);
- handleAllErrors(std::move(E),
- [&](ErrorInfoBase &EIB) { error(EIB.message()); });
+ auto HandleError = [](Error &&E) {
+ handleAllErrors(std::move(E),
+ [](ErrorInfoBase &EIB) { error(EIB.message()); });
+ };
+ std::string LibName = getImportName(AsLib);
+ std::string Path = getImplibPath();
+
+ if (!Config->Incremental) {
+ HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine,
+ Config->MinGW));
+ return;
+ }
+
+ // If the import library already exists, replace it only if the contents
+ // have changed.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> OldBuf = MemoryBuffer::getFile(
+ Path, /*FileSize*/ -1, /*RequiresNullTerminator*/ false);
+ if (!OldBuf) {
+ HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine,
+ Config->MinGW));
+ return;
+ }
+
+ SmallString<128> TmpName;
+ if (std::error_code EC =
+ sys::fs::createUniqueFile(Path + ".tmp-%%%%%%%%.lib", TmpName))
+ fatal("cannot create temporary file for import library " + Path + ": " +
+ EC.message());
+
+ if (Error E = writeImportLibrary(LibName, TmpName, Exports, Config->Machine,
+ Config->MinGW)) {
+ HandleError(std::move(E));
+ return;
+ }
+
+ std::unique_ptr<MemoryBuffer> NewBuf = check(MemoryBuffer::getFile(
+ TmpName, /*FileSize*/ -1, /*RequiresNullTerminator*/ false));
+ if ((*OldBuf)->getBuffer() != NewBuf->getBuffer()) {
+ OldBuf->reset();
+ HandleError(errorCodeToError(sys::fs::rename(TmpName, Path)));
+ } else {
+ sys::fs::remove(TmpName);
+ }
}
static void parseModuleDefs(StringRef Path) {
@@ -570,9 +658,18 @@ static void parseModuleDefs(StringRef Path) {
for (COFFShortExport E1 : M.Exports) {
Export E2;
+ // In simple cases, only Name is set. Renamed exports are parsed
+ // and set as "ExtName = Name". If Name has the form "OtherDll.Func",
+ // it shouldn't be a normal exported function but a forward to another
+ // DLL instead. This is supported by both MS and GNU linkers.
+ if (E1.ExtName != E1.Name && StringRef(E1.Name).contains('.')) {
+ E2.Name = Saver.save(E1.ExtName);
+ E2.ForwardTo = Saver.save(E1.Name);
+ Config->Exports.push_back(E2);
+ continue;
+ }
E2.Name = Saver.save(E1.Name);
- if (E1.isWeak())
- E2.ExtName = Saver.save(E1.ExtName);
+ E2.ExtName = Saver.save(E1.ExtName);
E2.Ordinal = E1.Ordinal;
E2.Noname = E1.Noname;
E2.Data = E1.Data;
@@ -635,8 +732,8 @@ filterBitcodeFiles(StringRef Path, std::vector<std::string> &TemporaryFiles) {
log("Creating a temporary archive for " + Path + " to remove bitcode files");
SmallString<128> S;
- if (auto EC = sys::fs::createTemporaryFile("lld-" + sys::path::stem(Path),
- ".lib", S))
+ if (std::error_code EC = sys::fs::createTemporaryFile(
+ "lld-" + sys::path::stem(Path), ".lib", S))
fatal("cannot create a temporary file: " + EC.message());
std::string Temp = S.str();
TemporaryFiles.push_back(Temp);
@@ -712,6 +809,8 @@ void LinkerDriver::enqueueTask(std::function<void()> Task) {
}
bool LinkerDriver::run() {
+ ScopedTimer T(InputFileTimer);
+
bool DidWork = !TaskQueue.empty();
while (!TaskQueue.empty()) {
TaskQueue.front()();
@@ -720,6 +819,46 @@ bool LinkerDriver::run() {
return DidWork;
}
+// Parse an /order file. If an option is given, the linker places
+// COMDAT sections in the same order as their names appear in the
+// given file.
+static void parseOrderFile(StringRef Arg) {
+ // For some reason, the MSVC linker requires a filename to be
+ // preceded by "@".
+ if (!Arg.startswith("@")) {
+ error("malformed /order option: '@' missing");
+ return;
+ }
+
+ // Get a list of all comdat sections for error checking.
+ DenseSet<StringRef> Set;
+ for (Chunk *C : Symtab->getChunks())
+ if (auto *Sec = dyn_cast<SectionChunk>(C))
+ if (Sec->Sym)
+ Set.insert(Sec->Sym->getName());
+
+ // Open a file.
+ StringRef Path = Arg.substr(1);
+ std::unique_ptr<MemoryBuffer> MB = CHECK(
+ MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
+
+ // Parse a file. An order file contains one symbol per line.
+ // All symbols that were not present in a given order file are
+ // considered to have the lowest priority 0 and are placed at
+ // end of an output section.
+ for (std::string S : args::getLines(MB->getMemBufferRef())) {
+ if (Config->Machine == I386 && !isDecorated(S))
+ S = "_" + S;
+
+ if (Set.count(S) == 0) {
+ if (Config->WarnMissingOrderSymbol)
+ warn("/order:" + Arg + ": missing symbol: " + S + " [LNK4037]");
+ }
+ else
+ Config->Order[S] = INT_MIN + Config->Order.size();
+ }
+}
+
void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// If the first command line argument is "/lib", link.exe acts like lib.exe.
// We call our own implementation of lib.exe that understands bitcode files.
@@ -735,11 +874,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
InitializeAllTargetMCs();
InitializeAllAsmParsers();
InitializeAllAsmPrinters();
- InitializeAllDisassemblers();
// Parse command line options.
ArgParser Parser;
- opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1));
+ opt::InputArgList Args = Parser.parseLINK(ArgsArr);
// Parse and evaluate -mllvm options.
std::vector<const char *> V;
@@ -763,6 +901,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
return;
}
+ if (Args.hasArg(OPT_show_timing))
+ Config->ShowTiming = true;
+
+ ScopedTimer T(Timer::root());
// Handle --version, which is an lld extension. This option is a bit odd
// because it doesn't start with "/", but we deliberately chose "--" to
// avoid conflict with /version and for compatibility with clang-cl.
@@ -805,7 +947,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /ignore
for (auto *Arg : Args.filtered(OPT_ignore)) {
- if (StringRef(Arg->getValue()) == "4217")
+ if (StringRef(Arg->getValue()) == "4037")
+ Config->WarnMissingOrderSymbol = false;
+ else if (StringRef(Arg->getValue()) == "4217")
Config->WarnLocallyDefinedImported = false;
// Other warning numbers are ignored.
}
@@ -826,6 +970,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /debug
if (Args.hasArg(OPT_debug, OPT_debug_dwarf, OPT_debug_ghash)) {
Config->Debug = true;
+ Config->Incremental = true;
if (auto *Arg = Args.getLastArg(OPT_debugtype))
Config->DebugTypes = parseDebugType(Arg->getValue());
else
@@ -834,9 +979,17 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /pdb
bool ShouldCreatePDB = Args.hasArg(OPT_debug, OPT_debug_ghash);
- if (ShouldCreatePDB)
+ if (ShouldCreatePDB) {
if (auto *Arg = Args.getLastArg(OPT_pdb))
Config->PDBPath = Arg->getValue();
+ if (auto *Arg = Args.getLastArg(OPT_pdbaltpath))
+ Config->PDBAltPath = Arg->getValue();
+ if (Args.hasArg(OPT_natvis))
+ Config->NatvisFiles = Args.getAllArgValues(OPT_natvis);
+
+ if (auto *Arg = Args.getLastArg(OPT_pdb_source_path))
+ Config->PDBSourcePath = Arg->getValue();
+ }
// Handle /noentry
if (Args.hasArg(OPT_noentry)) {
@@ -860,6 +1013,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
DynamicBaseArg->getOption().getID() == OPT_dynamicbase_no)
Config->DynamicBase = false;
+ // MSDN claims "/FIXED:NO is the default setting for a DLL, and /FIXED is the
+ // default setting for any other project type.", but link.exe defaults to
+ // /FIXED:NO for exe outputs as well. Match behavior, not docs.
bool Fixed = Args.hasFlag(OPT_fixed, OPT_fixed_no, false);
if (Fixed) {
if (DynamicBaseArg &&
@@ -895,6 +1051,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (auto *Arg = Args.getLastArg(OPT_stack))
parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit);
+ // Handle /guard:cf
+ if (auto *Arg = Args.getLastArg(OPT_guard))
+ parseGuard(Arg->getValue());
+
// Handle /heap
if (auto *Arg = Args.getLastArg(OPT_heap))
parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit);
@@ -909,6 +1069,23 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion,
&Config->MinorOSVersion);
+ // Handle /timestamp
+ if (llvm::opt::Arg *Arg = Args.getLastArg(OPT_timestamp, OPT_repro)) {
+ if (Arg->getOption().getID() == OPT_repro) {
+ Config->Timestamp = 0;
+ Config->Repro = true;
+ } else {
+ Config->Repro = false;
+ StringRef Value(Arg->getValue());
+ if (Value.getAsInteger(0, Config->Timestamp))
+ fatal(Twine("invalid timestamp: ") + Value +
+ ". Expected 32-bit integer");
+ }
+ } else {
+ Config->Repro = false;
+ Config->Timestamp = time(nullptr);
+ }
+
// Handle /alternatename
for (auto *Arg : Args.filtered(OPT_alternatename))
parseAlternateName(Arg->getValue());
@@ -922,8 +1099,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Config->Implib = Arg->getValue();
// Handle /opt.
- bool DoGC = !Args.hasArg(OPT_debug);
- unsigned ICFLevel = 1; // 0: off, 1: limited, 2: on
+ bool DoGC = !Args.hasArg(OPT_debug) || Args.hasArg(OPT_profile);
+ unsigned ICFLevel =
+ Args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on
+ unsigned TailMerge = 1;
for (auto *Arg : Args.filtered(OPT_opt)) {
std::string Str = StringRef(Arg->getValue()).lower();
SmallVector<StringRef, 1> Vec;
@@ -937,14 +1116,18 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
ICFLevel = 2;
} else if (S == "noicf") {
ICFLevel = 0;
+ } else if (S == "lldtailmerge") {
+ TailMerge = 2;
+ } else if (S == "nolldtailmerge") {
+ TailMerge = 0;
} else if (S.startswith("lldlto=")) {
StringRef OptLevel = S.substr(7);
- if (OptLevel.getAsInteger(10, Config->LTOOptLevel) ||
- Config->LTOOptLevel > 3)
+ if (OptLevel.getAsInteger(10, Config->LTOO) || Config->LTOO > 3)
error("/opt:lldlto: invalid optimization level: " + OptLevel);
} else if (S.startswith("lldltojobs=")) {
StringRef Jobs = S.substr(11);
- if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0)
+ if (Jobs.getAsInteger(10, Config->ThinLTOJobs) ||
+ Config->ThinLTOJobs == 0)
error("/opt:lldltojobs: invalid job count: " + Jobs);
} else if (S.startswith("lldltopartitions=")) {
StringRef N = S.substr(17);
@@ -965,6 +1148,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
ICFLevel = 0;
Config->DoGC = DoGC;
Config->DoICF = ICFLevel > 0;
+ Config->TailMerge = (TailMerge == 1 && Config->DoICF) || TailMerge == 2;
// Handle /lldsavetemps
if (Args.hasArg(OPT_lldsavetemps))
@@ -992,6 +1176,14 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
for (auto *Arg : Args.filtered(OPT_merge))
parseMerge(Arg->getValue());
+ // Add default section merging rules after user rules. User rules take
+ // precedence, but we will emit a warning if there is a conflict.
+ parseMerge(".idata=.rdata");
+ parseMerge(".didat=.rdata");
+ parseMerge(".edata=.rdata");
+ parseMerge(".xdata=.rdata");
+ parseMerge(".bss=.data");
+
// Handle /section
for (auto *Arg : Args.filtered(OPT_section))
parseSection(Arg->getValue());
@@ -1029,39 +1221,77 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (!Config->ManifestInput.empty() &&
Config->Manifest != Configuration::Embed) {
- fatal("/MANIFESTINPUT: requires /MANIFEST:EMBED");
+ fatal("/manifestinput: requires /manifest:embed");
}
// Handle miscellaneous boolean flags.
Config->AllowBind = Args.hasFlag(OPT_allowbind, OPT_allowbind_no, true);
Config->AllowIsolation =
Args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true);
+ Config->Incremental =
+ Args.hasFlag(OPT_incremental, OPT_incremental_no,
+ !Config->DoGC && !Config->DoICF && !Args.hasArg(OPT_order) &&
+ !Args.hasArg(OPT_profile));
+ Config->IntegrityCheck =
+ Args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false);
Config->NxCompat = Args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true);
- Config->TerminalServerAware = Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true);
+ Config->TerminalServerAware =
+ !Config->DLL && Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true);
Config->DebugDwarf = Args.hasArg(OPT_debug_dwarf);
Config->DebugGHashes = Args.hasArg(OPT_debug_ghash);
+ Config->DebugSymtab = Args.hasArg(OPT_debug_symtab);
Config->MapFile = getMapFile(Args);
+ if (Config->Incremental && Args.hasArg(OPT_profile)) {
+ warn("ignoring '/incremental' due to '/profile' specification");
+ Config->Incremental = false;
+ }
+
+ if (Config->Incremental && Args.hasArg(OPT_order)) {
+ warn("ignoring '/incremental' due to '/order' specification");
+ Config->Incremental = false;
+ }
+
+ if (Config->Incremental && Config->DoGC) {
+ warn("ignoring '/incremental' because REF is enabled; use '/opt:noref' to "
+ "disable");
+ Config->Incremental = false;
+ }
+
+ if (Config->Incremental && Config->DoICF) {
+ warn("ignoring '/incremental' because ICF is enabled; use '/opt:noicf' to "
+ "disable");
+ Config->Incremental = false;
+ }
+
if (errorCount())
return;
- bool WholeArchiveFlag = Args.hasArg(OPT_wholearchive_flag);
+ std::set<sys::fs::UniqueID> WholeArchives;
+ for (auto *Arg : Args.filtered(OPT_wholearchive_file))
+ if (Optional<StringRef> Path = doFindFile(Arg->getValue()))
+ if (Optional<sys::fs::UniqueID> ID = getUniqueID(*Path))
+ WholeArchives.insert(*ID);
+
+ // A predicate returning true if a given path is an argument for
+ // /wholearchive:, or /wholearchive is enabled globally.
+ // This function is a bit tricky because "foo.obj /wholearchive:././foo.obj"
+ // needs to be handled as "/wholearchive:foo.obj foo.obj".
+ auto IsWholeArchive = [&](StringRef Path) -> bool {
+ if (Args.hasArg(OPT_wholearchive_flag))
+ return true;
+ if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path))
+ return WholeArchives.count(*ID);
+ return false;
+ };
+
// Create a list of input files. Files can be given as arguments
// for /defaultlib option.
- std::vector<MemoryBufferRef> MBs;
- for (auto *Arg : Args.filtered(OPT_INPUT, OPT_wholearchive_file)) {
- switch (Arg->getOption().getID()) {
- case OPT_INPUT:
- if (Optional<StringRef> Path = findFile(Arg->getValue()))
- enqueuePath(*Path, WholeArchiveFlag);
- break;
- case OPT_wholearchive_file:
- if (Optional<StringRef> Path = findFile(Arg->getValue()))
- enqueuePath(*Path, true);
- break;
- }
- }
+ for (auto *Arg : Args.filtered(OPT_INPUT, OPT_wholearchive_file))
+ if (Optional<StringRef> Path = findFile(Arg->getValue()))
+ enqueuePath(*Path, IsWholeArchive(*Path));
+
for (auto *Arg : Args.filtered(OPT_defaultlib))
if (Optional<StringRef> Path = findLib(Arg->getValue()))
enqueuePath(*Path, false);
@@ -1165,10 +1395,24 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue());
}
- // Put the PDB next to the image if no /pdb flag was passed.
- if (ShouldCreatePDB && Config->PDBPath.empty()) {
- Config->PDBPath = Config->OutputFile;
- sys::path::replace_extension(Config->PDBPath, ".pdb");
+ if (ShouldCreatePDB) {
+ // Put the PDB next to the image if no /pdb flag was passed.
+ if (Config->PDBPath.empty()) {
+ Config->PDBPath = Config->OutputFile;
+ sys::path::replace_extension(Config->PDBPath, ".pdb");
+ }
+
+ // The embedded PDB path should be the absolute path to the PDB if no
+ // /pdbaltpath flag was passed.
+ if (Config->PDBAltPath.empty()) {
+ Config->PDBAltPath = Config->PDBPath;
+
+ // It's important to make the path absolute and remove dots. This path
+ // will eventually be written into the PE header, and certain Microsoft
+ // tools won't work correctly if these assumptions are not held.
+ sys::fs::make_absolute(Config->PDBAltPath);
+ sys::path::remove_dots(Config->PDBAltPath);
+ }
}
// Set default image base if /base is not given.
@@ -1181,11 +1425,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Symtab->addAbsolute("___safe_se_handler_count", 0);
}
- // We do not support /guard:cf (control flow protection) yet.
- // Define CFG symbols anyway so that we can link MSVC 2015 CRT.
Symtab->addAbsolute(mangle("__guard_fids_count"), 0);
Symtab->addAbsolute(mangle("__guard_fids_table"), 0);
- Symtab->addAbsolute(mangle("__guard_flags"), 0x100);
+ Symtab->addAbsolute(mangle("__guard_flags"), 0);
Symtab->addAbsolute(mangle("__guard_iat_count"), 0);
Symtab->addAbsolute(mangle("__guard_iat_table"), 0);
Symtab->addAbsolute(mangle("__guard_longjmp_count"), 0);
@@ -1260,7 +1502,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /safeseh.
if (Args.hasFlag(OPT_safeseh, OPT_safeseh_no, false)) {
for (ObjFile *File : ObjFile::Instances)
- if (!File->SEHCompat)
+ if (!File->hasSafeSEH())
error("/safeseh: " + File->getName() + " is not compatible with SEH");
if (errorCount())
return;
@@ -1280,7 +1522,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
E.Name = Def->getName();
E.Sym = Def;
if (Def->getChunk() &&
- !(Def->getChunk()->getPermissions() & IMAGE_SCN_MEM_EXECUTE))
+ !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
E.Data = true;
Config->Exports.push_back(E);
});
@@ -1323,6 +1565,12 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (Config->Manifest == Configuration::SideBySide)
createSideBySideManifest();
+ // Handle /order. We want to do this at this moment because we
+ // need a complete list of comdat sections to warn on nonexistent
+ // functions.
+ if (auto *Arg = Args.getLastArg(OPT_order))
+ parseOrderFile(Arg->getValue());
+
// Identify unreferenced COMDAT sections.
if (Config->DoGC)
markLive(Symtab->getChunks());
@@ -1333,6 +1581,11 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Write the result.
writeResult();
+
+ // Stop early so we can print the results.
+ Timer::root().stop();
+ if (Config->ShowTiming)
+ Timer::root().print();
}
} // namespace coff
diff --git a/contrib/llvm/tools/lld/COFF/Driver.h b/contrib/llvm/tools/lld/COFF/Driver.h
index 3f7fad1038f3..627e991a9028 100644
--- a/contrib/llvm/tools/lld/COFF/Driver.h
+++ b/contrib/llvm/tools/lld/COFF/Driver.h
@@ -21,6 +21,7 @@
#include "llvm/Object/COFF.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/TarWriter.h"
#include <memory>
#include <set>
@@ -36,12 +37,6 @@ using llvm::COFF::MachineTypes;
using llvm::COFF::WindowsSubsystem;
using llvm::Optional;
-// Implemented in MarkLive.cpp.
-void markLive(ArrayRef<Chunk *> Chunks);
-
-// Implemented in ICF.cpp.
-void doICF(ArrayRef<Chunk *> Chunks);
-
class COFFOptTable : public llvm::opt::OptTable {
public:
COFFOptTable();
@@ -56,8 +51,10 @@ public:
llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); }
// Tokenizes a given string and then parses as command line options in
- // .drectve section.
- llvm::opt::InputArgList parseDirectives(StringRef S);
+ // .drectve section. /EXPORT options are returned in second element
+ // to be processed in fastpath.
+ std::pair<llvm::opt::InputArgList, std::vector<StringRef>>
+ parseDirectives(StringRef S);
private:
// Parses command line options.
@@ -98,7 +95,11 @@ private:
// Library search path. The first element is always "" (current directory).
std::vector<StringRef> SearchPaths;
- std::set<std::string> VisitedFiles;
+
+ // We don't want to add the same file more than once.
+ // Files are uniquified by their filesystem and file number.
+ std::set<llvm::sys::fs::UniqueID> VisitedFiles;
+
std::set<std::string> VisitedLibs;
Symbol *addUndefined(StringRef Sym);
@@ -143,6 +144,8 @@ StringRef machineToStr(MachineTypes MT);
// Parses a string in the form of "<integer>[,<integer>]".
void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr);
+void parseGuard(StringRef Arg);
+
// Parses a string in the form of "<integer>[.<integer>]".
// Minor's default value is 0.
void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor);
diff --git a/contrib/llvm/tools/lld/COFF/DriverUtils.cpp b/contrib/llvm/tools/lld/COFF/DriverUtils.cpp
index 4b3b6d5e09d6..c12e791f9507 100644
--- a/contrib/llvm/tools/lld/COFF/DriverUtils.cpp
+++ b/contrib/llvm/tools/lld/COFF/DriverUtils.cpp
@@ -61,12 +61,7 @@ public:
StringRef Exe = Saver.save(*ExeOrErr);
Args.insert(Args.begin(), Exe);
- std::vector<const char *> Vec;
- for (StringRef S : Args)
- Vec.push_back(S.data());
- Vec.push_back(nullptr);
-
- if (sys::ExecuteAndWait(Args[0], Vec.data()) != 0)
+ if (sys::ExecuteAndWait(Args[0], Args) != 0)
fatal("ExecuteAndWait failed: " +
llvm::join(Args.begin(), Args.end(), " "));
}
@@ -128,6 +123,21 @@ void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) {
fatal("invalid number: " + S2);
}
+void parseGuard(StringRef FullArg) {
+ SmallVector<StringRef, 1> SplitArgs;
+ FullArg.split(SplitArgs, ",");
+ for (StringRef Arg : SplitArgs) {
+ if (Arg.equals_lower("no"))
+ Config->GuardCF = GuardCFLevel::Off;
+ else if (Arg.equals_lower("nolongjmp"))
+ Config->GuardCF = GuardCFLevel::NoLongJmp;
+ else if (Arg.equals_lower("cf") || Arg.equals_lower("longjmp"))
+ Config->GuardCF = GuardCFLevel::Full;
+ else
+ fatal("invalid argument to /guard: " + Arg);
+ }
+}
+
// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
uint32_t *Minor) {
@@ -170,6 +180,10 @@ void parseMerge(StringRef S) {
std::tie(From, To) = S.split('=');
if (From.empty() || To.empty())
fatal("/merge: invalid argument: " + S);
+ if (From == ".rsrc" || To == ".rsrc")
+ fatal("/merge: cannot merge '.rsrc' with any section");
+ if (From == ".reloc" || To == ".reloc")
+ fatal("/merge: cannot merge '.reloc' with any section");
auto Pair = Config->Merge.insert(std::make_pair(From, To));
bool Inserted = Pair.second;
if (!Inserted) {
@@ -418,15 +432,15 @@ static std::string createManifestXml() {
return createManifestXmlWithExternalMt(DefaultXml);
}
-static std::unique_ptr<MemoryBuffer>
+static std::unique_ptr<WritableMemoryBuffer>
createMemoryBufferForManifestRes(size_t ManifestSize) {
size_t ResSize = alignTo(
object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE +
sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) +
sizeof(object::WinResHeaderSuffix) + ManifestSize,
object::WIN_RES_DATA_ALIGNMENT);
- return MemoryBuffer::getNewMemBuffer(ResSize,
- Config->OutputFile + ".manifest.res");
+ return WritableMemoryBuffer::getNewMemBuffer(ResSize, Config->OutputFile +
+ ".manifest.res");
}
static void writeResFileHeader(char *&Buf) {
@@ -465,16 +479,16 @@ static void writeResEntryHeader(char *&Buf, size_t ManifestSize) {
std::unique_ptr<MemoryBuffer> createManifestRes() {
std::string Manifest = createManifestXml();
- std::unique_ptr<MemoryBuffer> Res =
+ std::unique_ptr<WritableMemoryBuffer> Res =
createMemoryBufferForManifestRes(Manifest.size());
- char *Buf = const_cast<char *>(Res->getBufferStart());
+ char *Buf = Res->getBufferStart();
writeResFileHeader(Buf);
writeResEntryHeader(Buf, Manifest.size());
// Copy the manifest data into the .res file.
std::copy(Manifest.begin(), Manifest.end(), Buf);
- return Res;
+ return std::move(Res);
}
void createSideBySideManifest() {
@@ -558,6 +572,12 @@ err:
static StringRef undecorate(StringRef Sym) {
if (Config->Machine != I386)
return Sym;
+ // In MSVC mode, a fully decorated stdcall function is exported
+ // as-is with the leading underscore (with type IMPORT_NAME).
+ // In MinGW mode, a decorated stdcall function gets the underscore
+ // removed, just like normal cdecl functions.
+ if (Sym.startswith("_") && Sym.contains('@') && !Config->MinGW)
+ return Sym;
return Sym.startswith("_") ? Sym.substr(1) : Sym;
}
@@ -731,6 +751,28 @@ static const llvm::opt::OptTable::Info InfoTable[] = {
COFFOptTable::COFFOptTable() : OptTable(InfoTable, true) {}
+// Set color diagnostics according to --color-diagnostics={auto,always,never}
+// or --no-color-diagnostics flags.
+static void handleColorDiagnostics(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
+ OPT_no_color_diagnostics);
+ if (!Arg)
+ return;
+ if (Arg->getOption().getID() == OPT_color_diagnostics) {
+ errorHandler().ColorDiagnostics = true;
+ } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) {
+ errorHandler().ColorDiagnostics = false;
+ } else {
+ StringRef S = Arg->getValue();
+ if (S == "always")
+ errorHandler().ColorDiagnostics = true;
+ else if (S == "never")
+ errorHandler().ColorDiagnostics = false;
+ else if (S != "auto")
+ error("unknown option: --color-diagnostics=" + S);
+ }
+}
+
static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) {
StringRef S = Arg->getValue();
@@ -749,50 +791,73 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> Argv) {
// Make InputArgList from string vectors.
unsigned MissingIndex;
unsigned MissingCount;
- SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
// We need to get the quoting style for response files before parsing all
// options so we parse here before and ignore all the options but
// --rsp-quoting.
- opt::InputArgList Args = Table.ParseArgs(Vec, MissingIndex, MissingCount);
+ opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount);
// Expand response files (arguments in the form of @<filename>)
// and then parse the argument again.
- cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
- Args = Table.ParseArgs(Vec, MissingIndex, MissingCount);
+ SmallVector<const char *, 256> ExpandedArgv(Argv.data(), Argv.data() + Argv.size());
+ cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), ExpandedArgv);
+ Args = Table.ParseArgs(makeArrayRef(ExpandedArgv).drop_front(), MissingIndex,
+ MissingCount);
// Print the real command line if response files are expanded.
- if (Args.hasArg(OPT_verbose) && Argv.size() != Vec.size()) {
+ if (Args.hasArg(OPT_verbose) && Argv.size() != ExpandedArgv.size()) {
std::string Msg = "Command line:";
- for (const char *S : Vec)
+ for (const char *S : ExpandedArgv)
Msg += " " + std::string(S);
message(Msg);
}
+ // Save the command line after response file expansion so we can write it to
+ // the PDB if necessary.
+ Config->Argv = {ExpandedArgv.begin(), ExpandedArgv.end()};
+
// Handle /WX early since it converts missing argument warnings to errors.
errorHandler().FatalWarnings = Args.hasFlag(OPT_WX, OPT_WX_no, false);
if (MissingCount)
fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
+
+ handleColorDiagnostics(Args);
+
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
warn("ignoring unknown argument: " + Arg->getSpelling());
+
+ if (Args.hasArg(OPT_lib))
+ warn("ignoring /lib since it's not the first argument");
+
return Args;
}
// Tokenizes and parses a given string as command line in .drective section.
-opt::InputArgList ArgParser::parseDirectives(StringRef S) {
- // Make InputArgList from string vectors.
+// /EXPORT options are processed in fastpath.
+std::pair<opt::InputArgList, std::vector<StringRef>>
+ArgParser::parseDirectives(StringRef S) {
+ std::vector<StringRef> Exports;
+ SmallVector<const char *, 16> Rest;
+
+ for (StringRef Tok : tokenize(S)) {
+ if (Tok.startswith_lower("/export:") || Tok.startswith_lower("-export:"))
+ Exports.push_back(Tok.substr(strlen("/export:")));
+ else
+ Rest.push_back(Tok.data());
+ }
+
+ // Make InputArgList from unparsed string vectors.
unsigned MissingIndex;
unsigned MissingCount;
- opt::InputArgList Args =
- Table.ParseArgs(tokenize(S), MissingIndex, MissingCount);
+ opt::InputArgList Args = Table.ParseArgs(Rest, MissingIndex, MissingCount);
if (MissingCount)
fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
warn("ignoring unknown argument: " + Arg->getSpelling());
- return Args;
+ return {std::move(Args), std::move(Exports)};
}
// link.exe has an interesting feature. If LINK or _LINK_ environment
@@ -802,11 +867,11 @@ opt::InputArgList ArgParser::parseLINK(std::vector<const char *> Argv) {
// Concatenate LINK env and command line arguments, and then parse them.
if (Optional<std::string> S = Process::GetEnv("LINK")) {
std::vector<const char *> V = tokenize(*S);
- Argv.insert(Argv.begin(), V.begin(), V.end());
+ Argv.insert(std::next(Argv.begin()), V.begin(), V.end());
}
if (Optional<std::string> S = Process::GetEnv("_LINK_")) {
std::vector<const char *> V = tokenize(*S);
- Argv.insert(Argv.begin(), V.begin(), V.end());
+ Argv.insert(std::next(Argv.begin()), V.begin(), V.end());
}
return parse(Argv);
}
diff --git a/contrib/llvm/tools/lld/COFF/ICF.cpp b/contrib/llvm/tools/lld/COFF/ICF.cpp
index 48895c34886c..7feb3c4e0b0c 100644
--- a/contrib/llvm/tools/lld/COFF/ICF.cpp
+++ b/contrib/llvm/tools/lld/COFF/ICF.cpp
@@ -18,13 +18,16 @@
//
//===----------------------------------------------------------------------===//
+#include "ICF.h"
#include "Chunks.h"
#include "Symbols.h"
#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Timer.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Parallel.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/xxhash.h"
#include <algorithm>
#include <atomic>
#include <vector>
@@ -34,6 +37,8 @@ using namespace llvm;
namespace lld {
namespace coff {
+static Timer ICFTimer("ICF", Timer::root());
+
class ICF {
public:
void run(ArrayRef<Chunk *> V);
@@ -41,6 +46,8 @@ public:
private:
void segregate(size_t Begin, size_t End, bool Constant);
+ bool assocEquals(const SectionChunk *A, const SectionChunk *B);
+
bool equalsConstant(const SectionChunk *A, const SectionChunk *B);
bool equalsVariable(const SectionChunk *A, const SectionChunk *B);
@@ -59,13 +66,6 @@ private:
std::atomic<bool> Repeat = {false};
};
-// Returns a hash value for S.
-uint32_t ICF::getHash(SectionChunk *C) {
- return hash_combine(C->getPermissions(), C->SectionName, C->NumRelocs,
- C->Alignment, uint32_t(C->Header->SizeOfRawData),
- C->Checksum, C->getContents());
-}
-
// Returns true if section S is subject of ICF.
//
// Microsoft's documentation
@@ -73,21 +73,27 @@ uint32_t ICF::getHash(SectionChunk *C) {
// 2017) says that /opt:icf folds both functions and read-only data.
// Despite that, the MSVC linker folds only functions. We found
// a few instances of programs that are not safe for data merging.
-// Therefore, we merge only functions just like the MSVC tool. However, we merge
-// identical .xdata sections, because the address of unwind information is
-// insignificant to the user program and the Visual C++ linker does this.
+// Therefore, we merge only functions just like the MSVC tool. However, we also
+// merge read-only sections in a couple of cases where the address of the
+// section is insignificant to the user program and the behaviour matches that
+// of the Visual C++ linker.
bool ICF::isEligible(SectionChunk *C) {
// Non-comdat chunks, dead chunks, and writable chunks are not elegible.
- bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
+ bool Writable = C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
if (!C->isCOMDAT() || !C->isLive() || Writable)
return false;
// Code sections are eligible.
- if (C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
+ if (C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
return true;
- // .xdata unwind info sections are eligble.
- return C->getSectionName().split('$').first == ".xdata";
+ // .pdata and .xdata unwind info sections are eligible.
+ StringRef OutSecName = C->getSectionName().split('$').first;
+ if (OutSecName == ".pdata" || OutSecName == ".xdata")
+ return true;
+
+ // So are vtables.
+ return C->Sym && C->Sym->getName().startswith("??_7");
}
// Split an equivalence class into smaller classes.
@@ -116,10 +122,23 @@ void ICF::segregate(size_t Begin, size_t End, bool Constant) {
}
}
+// Returns true if two sections' associative children are equal.
+bool ICF::assocEquals(const SectionChunk *A, const SectionChunk *B) {
+ auto ChildClasses = [&](const SectionChunk *SC) {
+ std::vector<uint32_t> Classes;
+ for (const SectionChunk *C : SC->children())
+ if (!C->SectionName.startswith(".debug") &&
+ C->SectionName != ".gfids$y" && C->SectionName != ".gljmp$y")
+ Classes.push_back(C->Class[Cnt % 2]);
+ return Classes;
+ };
+ return ChildClasses(A) == ChildClasses(B);
+}
+
// Compare "non-moving" part of two sections, namely everything
// except relocation targets.
bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
- if (A->NumRelocs != B->NumRelocs)
+ if (A->Relocs.size() != B->Relocs.size())
return false;
// Compare relocations.
@@ -142,10 +161,11 @@ bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
return false;
// Compare section attributes and contents.
- return A->getPermissions() == B->getPermissions() &&
- A->SectionName == B->SectionName && A->Alignment == B->Alignment &&
+ return A->getOutputCharacteristics() == B->getOutputCharacteristics() &&
+ A->SectionName == B->SectionName &&
A->Header->SizeOfRawData == B->Header->SizeOfRawData &&
- A->Checksum == B->Checksum && A->getContents() == B->getContents();
+ A->Checksum == B->Checksum && A->getContents() == B->getContents() &&
+ assocEquals(A, B);
}
// Compare "moving" part of two sections, namely relocation targets.
@@ -161,9 +181,12 @@ bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) {
return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
return false;
};
- return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq);
+ return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(),
+ Eq) &&
+ assocEquals(A, B);
}
+// Find the first Chunk after Begin that has a different class from Begin.
size_t ICF::findBoundary(size_t Begin, size_t End) {
for (size_t I = Begin + 1; I < End; ++I)
if (Chunks[Begin]->Class[Cnt % 2] != Chunks[I]->Class[Cnt % 2])
@@ -173,11 +196,8 @@ size_t ICF::findBoundary(size_t Begin, size_t End) {
void ICF::forEachClassRange(size_t Begin, size_t End,
std::function<void(size_t, size_t)> Fn) {
- if (Begin > 0)
- Begin = findBoundary(Begin - 1, End);
-
while (Begin < End) {
- size_t Mid = findBoundary(Begin, Chunks.size());
+ size_t Mid = findBoundary(Begin, End);
Fn(Begin, Mid);
Begin = Mid;
}
@@ -193,12 +213,22 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {
return;
}
- // Split sections into 256 shards and call Fn in parallel.
- size_t NumShards = 256;
+ // Shard into non-overlapping intervals, and call Fn in parallel.
+ // The sharding must be completed before any calls to Fn are made
+ // so that Fn can modify the Chunks in its shard without causing data
+ // races.
+ const size_t NumShards = 256;
size_t Step = Chunks.size() / NumShards;
- for_each_n(parallel::par, size_t(0), NumShards, [&](size_t I) {
- size_t End = (I == NumShards - 1) ? Chunks.size() : (I + 1) * Step;
- forEachClassRange(I * Step, End, Fn);
+ size_t Boundaries[NumShards + 1];
+ Boundaries[0] = 0;
+ Boundaries[NumShards] = Chunks.size();
+ for_each_n(parallel::par, size_t(1), NumShards, [&](size_t I) {
+ Boundaries[I] = findBoundary((I - 1) * Step, Chunks.size());
+ });
+ for_each_n(parallel::par, size_t(1), NumShards + 1, [&](size_t I) {
+ if (Boundaries[I - 1] < Boundaries[I]) {
+ forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn);
+ }
});
++Cnt;
}
@@ -207,6 +237,8 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {
// Two sections are considered the same if their section headers,
// contents and relocations are all the same.
void ICF::run(ArrayRef<Chunk *> Vec) {
+ ScopedTimer T(ICFTimer);
+
// Collect only mergeable sections and group by hash value.
uint32_t NextId = 1;
for (Chunk *C : Vec) {
@@ -218,10 +250,16 @@ void ICF::run(ArrayRef<Chunk *> Vec) {
}
}
+ // Make sure that ICF doesn't merge sections that are being handled by string
+ // tail merging.
+ for (auto &P : MergeChunk::Instances)
+ for (SectionChunk *SC : P.second->Sections)
+ SC->Class[0] = NextId++;
+
// Initially, we use hash values to partition sections.
for_each(parallel::par, Chunks.begin(), Chunks.end(), [&](SectionChunk *SC) {
// Set MSB to 1 to avoid collisions with non-hash classs.
- SC->Class[0] = getHash(SC) | (1 << 31);
+ SC->Class[0] = xxHash64(SC->getContents()) | (1 << 31);
});
// From now on, sections in Chunks are ordered so that sections in
diff --git a/contrib/llvm/tools/lld/COFF/Strings.h b/contrib/llvm/tools/lld/COFF/ICF.h
index 67fc1c773c66..9c54e0c9ec2d 100644
--- a/contrib/llvm/tools/lld/COFF/Strings.h
+++ b/contrib/llvm/tools/lld/COFF/ICF.h
@@ -1,4 +1,4 @@
-//===- Strings.h ------------------------------------------------*- C++ -*-===//
+//===- ICF.h --------------------------------------------------------------===//
//
// The LLVM Linker
//
@@ -7,17 +7,20 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLD_COFF_STRINGS_H
-#define LLD_COFF_STRINGS_H
+#ifndef LLD_COFF_ICF_H
+#define LLD_COFF_ICF_H
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringRef.h"
-#include <string>
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
namespace lld {
namespace coff {
-llvm::Optional<std::string> demangleMSVC(llvm::StringRef S);
-}
-}
+
+class Chunk;
+
+void doICF(ArrayRef<Chunk *> Chunks);
+
+} // namespace coff
+} // namespace lld
#endif
diff --git a/contrib/llvm/tools/lld/COFF/InputFiles.cpp b/contrib/llvm/tools/lld/COFF/InputFiles.cpp
index a8f52e0391f7..2b3e65fae04b 100644
--- a/contrib/llvm/tools/lld/COFF/InputFiles.cpp
+++ b/contrib/llvm/tools/lld/COFF/InputFiles.cpp
@@ -27,6 +27,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
#include "llvm/Target/TargetOptions.h"
#include <cstring>
#include <system_error>
@@ -138,12 +139,13 @@ void ObjFile::initializeChunks() {
if (Sec->Characteristics & IMAGE_SCN_LNK_COMDAT)
SparseChunks[I] = PendingComdat;
else
- SparseChunks[I] = readSection(I, nullptr);
+ SparseChunks[I] = readSection(I, nullptr, "");
}
}
SectionChunk *ObjFile::readSection(uint32_t SectionNumber,
- const coff_aux_section_definition *Def) {
+ const coff_aux_section_definition *Def,
+ StringRef LeaderName) {
const coff_section *Sec;
StringRef Name;
if (auto EC = COFFObj->getSection(SectionNumber, Sec))
@@ -151,15 +153,7 @@ SectionChunk *ObjFile::readSection(uint32_t SectionNumber,
if (auto EC = COFFObj->getSectionName(Sec, Name))
fatal("getSectionName failed: #" + Twine(SectionNumber) + ": " +
EC.message());
- if (Name == ".sxdata") {
- ArrayRef<uint8_t> Data;
- COFFObj->getSectionContents(Sec, Data);
- if (Data.size() % 4 != 0)
- fatal(".sxdata must be an array of symbol table indices");
- SXData = {reinterpret_cast<const ulittle32_t *>(Data.data()),
- Data.size() / 4};
- return nullptr;
- }
+
if (Name == ".drectve") {
ArrayRef<uint8_t> Data;
COFFObj->getSectionContents(Sec, Data);
@@ -177,8 +171,8 @@ SectionChunk *ObjFile::readSection(uint32_t SectionNumber,
// CodeView needs a linker support. We need to interpret and debug
// info, and then write it to a separate .pdb file.
- // Ignore debug info unless /debug is given.
- if (!Config->Debug && Name.startswith(".debug"))
+ // Ignore DWARF debug info unless /debug is given.
+ if (!Config->Debug && Name.startswith(".debug_"))
return nullptr;
if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
@@ -191,6 +185,18 @@ SectionChunk *ObjFile::readSection(uint32_t SectionNumber,
// linked in the regular manner.
if (C->isCodeView())
DebugChunks.push_back(C);
+ else if (Config->GuardCF != GuardCFLevel::Off && Name == ".gfids$y")
+ GuardFidChunks.push_back(C);
+ else if (Config->GuardCF != GuardCFLevel::Off && Name == ".gljmp$y")
+ GuardLJmpChunks.push_back(C);
+ else if (Name == ".sxdata")
+ SXDataChunks.push_back(C);
+ else if (Config->TailMerge && Sec->NumberOfRelocations == 0 &&
+ Name == ".rdata" && LeaderName.startswith("??_C@"))
+ // COFF sections that look like string literal sections (i.e. no
+ // relocations, in .rdata, leader symbol name matches the MSVC name mangling
+ // for string literals) are subject to string tail merging.
+ MergeChunk::addSection(C);
else
Chunks.push_back(C);
@@ -211,7 +217,7 @@ void ObjFile::readAssociativeDefinition(
// the section; otherwise mark it as discarded.
int32_t SectionNumber = Sym.getSectionNumber();
if (Parent) {
- SparseChunks[SectionNumber] = readSection(SectionNumber, Def);
+ SparseChunks[SectionNumber] = readSection(SectionNumber, Def, "");
if (SparseChunks[SectionNumber])
Parent->addAssociative(SparseChunks[SectionNumber]);
} else {
@@ -275,6 +281,13 @@ void ObjFile::initializeSymbols() {
if (auto *Def = Sym.getSectionDefinition())
if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
readAssociativeDefinition(Sym, Def);
+ if (SparseChunks[Sym.getSectionNumber()] == PendingComdat) {
+ StringRef Name;
+ COFFObj->getSymbolName(Sym, Name);
+ log("comdat section " + Name +
+ " without leader and unassociated, discarding");
+ continue;
+ }
Symbols[I] = createRegular(Sym);
}
@@ -294,43 +307,46 @@ Symbol *ObjFile::createUndefined(COFFSymbolRef Sym) {
Optional<Symbol *> ObjFile::createDefined(
COFFSymbolRef Sym,
std::vector<const coff_aux_section_definition *> &ComdatDefs) {
- StringRef Name;
+ auto GetName = [&]() {
+ StringRef S;
+ COFFObj->getSymbolName(Sym, S);
+ return S;
+ };
+
if (Sym.isCommon()) {
auto *C = make<CommonChunk>(Sym);
Chunks.push_back(C);
- COFFObj->getSymbolName(Sym, Name);
- Symbol *S =
- Symtab->addCommon(this, Name, Sym.getValue(), Sym.getGeneric(), C);
- return S;
+ return Symtab->addCommon(this, GetName(), Sym.getValue(), Sym.getGeneric(),
+ C);
}
+
if (Sym.isAbsolute()) {
- COFFObj->getSymbolName(Sym, Name);
+ StringRef Name = GetName();
+
// Skip special symbols.
if (Name == "@comp.id")
return nullptr;
- // COFF spec 5.10.1. The .sxdata section.
if (Name == "@feat.00") {
- if (Sym.getValue() & 1)
- SEHCompat = true;
+ Feat00Flags = Sym.getValue();
return nullptr;
}
+
if (Sym.isExternal())
return Symtab->addAbsolute(Name, Sym);
- else
- return make<DefinedAbsolute>(Name, Sym);
+ return make<DefinedAbsolute>(Name, Sym);
}
+
int32_t SectionNumber = Sym.getSectionNumber();
if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG)
return nullptr;
- // Reserved sections numbers don't have contents.
if (llvm::COFF::isReservedSectionNumber(SectionNumber))
- fatal("broken object file: " + toString(this));
+ fatal(toString(this) + ": " + GetName() +
+ " should not refer to special section " + Twine(SectionNumber));
- // This symbol references a section which is not present in the section
- // header.
if ((uint32_t)SectionNumber >= SparseChunks.size())
- fatal("broken object file: " + toString(this));
+ fatal(toString(this) + ": " + GetName() +
+ " should not refer to non-existent section " + Twine(SectionNumber));
// Handle comdat leader symbols.
if (const coff_aux_section_definition *Def = ComdatDefs[SectionNumber]) {
@@ -338,16 +354,16 @@ Optional<Symbol *> ObjFile::createDefined(
Symbol *Leader;
bool Prevailing;
if (Sym.isExternal()) {
- COFFObj->getSymbolName(Sym, Name);
std::tie(Leader, Prevailing) =
- Symtab->addComdat(this, Name, Sym.getGeneric());
+ Symtab->addComdat(this, GetName(), Sym.getGeneric());
} else {
Leader = make<DefinedRegular>(this, /*Name*/ "", false,
/*IsExternal*/ false, Sym.getGeneric());
Prevailing = true;
}
+
if (Prevailing) {
- SectionChunk *C = readSection(SectionNumber, Def);
+ SectionChunk *C = readSection(SectionNumber, Def, GetName());
SparseChunks[SectionNumber] = C;
C->Sym = cast<DefinedRegular>(Leader);
cast<DefinedRegular>(Leader)->Data = &C->Repl;
@@ -429,7 +445,8 @@ void ImportFile::parse() {
// address pointed by the __imp_ symbol. (This allows you to call
// DLL functions just like regular non-DLL functions.)
if (Hdr->getType() == llvm::COFF::IMPORT_CODE)
- ThunkSym = Symtab->addImportThunk(Name, ImpSym, Hdr->Machine);
+ ThunkSym = Symtab->addImportThunk(
+ Name, cast_or_null<DefinedImportData>(ImpSym), Hdr->Machine);
}
void BitcodeFile::parse() {
@@ -462,7 +479,7 @@ void BitcodeFile::parse() {
} else {
Sym = Symtab->addRegular(this, SymName);
}
- SymbolBodies.push_back(Sym);
+ Symbols.push_back(Sym);
}
Directives = Obj->getCOFFLinkerOpts();
}
@@ -486,10 +503,7 @@ MachineTypes BitcodeFile::getMachineType() {
// Returns the last element of a path, which is supposed to be a filename.
static StringRef getBasename(StringRef Path) {
- size_t Pos = Path.find_last_of("\\/");
- if (Pos == StringRef::npos)
- return Path;
- return Path.substr(Pos + 1);
+ return sys::path::filename(Path, sys::path::Style::windows);
}
// Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)".
diff --git a/contrib/llvm/tools/lld/COFF/InputFiles.h b/contrib/llvm/tools/lld/COFF/InputFiles.h
index adedbc2ad7a8..4ee4b363886f 100644
--- a/contrib/llvm/tools/lld/COFF/InputFiles.h
+++ b/contrib/llvm/tools/lld/COFF/InputFiles.h
@@ -110,6 +110,9 @@ public:
MachineTypes getMachineType() override;
ArrayRef<Chunk *> getChunks() { return Chunks; }
ArrayRef<SectionChunk *> getDebugChunks() { return DebugChunks; }
+ ArrayRef<SectionChunk *> getSXDataChunks() { return SXDataChunks; }
+ ArrayRef<SectionChunk *> getGuardFidChunks() { return GuardFidChunks; }
+ ArrayRef<SectionChunk *> getGuardLJmpChunks() { return GuardLJmpChunks; }
ArrayRef<Symbol *> getSymbols() { return Symbols; }
// Returns a Symbol object for the SymbolIndex'th symbol in the
@@ -123,13 +126,17 @@ public:
static std::vector<ObjFile *> Instances;
- // True if this object file is compatible with SEH.
- // COFF-specific and x86-only.
- bool SEHCompat = false;
+ // Flags in the absolute @feat.00 symbol if it is present. These usually
+ // indicate if an object was compiled with certain security features enabled
+ // like stack guard, safeseh, /guard:cf, or other things.
+ uint32_t Feat00Flags = 0;
- // The symbol table indexes of the safe exception handlers.
- // COFF-specific and x86-only.
- ArrayRef<llvm::support::ulittle32_t> SXData;
+ // True if this object file is compatible with SEH. COFF-specific and
+ // x86-only. COFF spec 5.10.1. The .sxdata section.
+ bool hasSafeSEH() { return Feat00Flags & 0x1; }
+
+ // True if this file was compiled with /guard:cf.
+ bool hasGuardCF() { return Feat00Flags & 0x800; }
// Pointer to the PDB module descriptor builder. Various debug info records
// will reference object files by "module index", which is here. Things like
@@ -143,7 +150,8 @@ private:
SectionChunk *
readSection(uint32_t SectionNumber,
- const llvm::object::coff_aux_section_definition *Def);
+ const llvm::object::coff_aux_section_definition *Def,
+ StringRef LeaderName);
void readAssociativeDefinition(
COFFSymbolRef COFFSym,
@@ -165,6 +173,15 @@ private:
// CodeView debug info sections.
std::vector<SectionChunk *> DebugChunks;
+ // Chunks containing symbol table indices of exception handlers. Only used for
+ // 32-bit x86.
+ std::vector<SectionChunk *> SXDataChunks;
+
+ // Chunks containing symbol table indices of address taken symbols and longjmp
+ // targets. These are not linked into the final binary when /guard:cf is set.
+ std::vector<SectionChunk *> GuardFidChunks;
+ std::vector<SectionChunk *> GuardLJmpChunks;
+
// This vector contains the same chunks as Chunks, but they are
// indexed such that you can get a SectionChunk by section index.
// Nonexistent section indices are filled with null pointers.
@@ -184,15 +201,14 @@ private:
// for details about the format.
class ImportFile : public InputFile {
public:
- explicit ImportFile(MemoryBufferRef M)
- : InputFile(ImportKind, M), Live(!Config->DoGC) {}
+ explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == ImportKind; }
static std::vector<ImportFile *> Instances;
- DefinedImportData *ImpSym = nullptr;
- DefinedImportThunk *ThunkSym = nullptr;
+ Symbol *ImpSym = nullptr;
+ Symbol *ThunkSym = nullptr;
std::string DLLName;
private:
@@ -204,12 +220,15 @@ public:
Chunk *Location = nullptr;
// We want to eliminate dllimported symbols if no one actually refers them.
- // This "Live" bit is used to keep track of which import library members
+ // These "Live" bits are used to keep track of which import library members
// are actually in use.
//
// If the Live bit is turned off by MarkLive, Writer will ignore dllimported
- // symbols provided by this import library member.
- bool Live;
+ // symbols provided by this import library member. We also track whether the
+ // imported symbol is used separately from whether the thunk is used in order
+ // to avoid creating unnecessary thunks.
+ bool Live = !Config->DoGC;
+ bool ThunkLive = !Config->DoGC;
};
// Used for LTO.
@@ -217,7 +236,7 @@ class BitcodeFile : public InputFile {
public:
explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
- ArrayRef<Symbol *> getSymbols() { return SymbolBodies; }
+ ArrayRef<Symbol *> getSymbols() { return Symbols; }
MachineTypes getMachineType() override;
static std::vector<BitcodeFile *> Instances;
std::unique_ptr<llvm::lto::InputFile> Obj;
@@ -225,7 +244,7 @@ public:
private:
void parse() override;
- std::vector<Symbol *> SymbolBodies;
+ std::vector<Symbol *> Symbols;
};
} // namespace coff
diff --git a/contrib/llvm/tools/lld/COFF/LTO.cpp b/contrib/llvm/tools/lld/COFF/LTO.cpp
index fa2a54b61841..93f7ba3f9e4c 100644
--- a/contrib/llvm/tools/lld/COFF/LTO.cpp
+++ b/contrib/llvm/tools/lld/COFF/LTO.cpp
@@ -12,6 +12,7 @@
#include "InputFiles.h"
#include "Symbols.h"
#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/TargetOptionsCommandFlags.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
@@ -40,47 +41,32 @@ using namespace llvm::object;
using namespace lld;
using namespace lld::coff;
-static void diagnosticHandler(const DiagnosticInfo &DI) {
- SmallString<128> ErrStorage;
- raw_svector_ostream OS(ErrStorage);
- DiagnosticPrinterRawOStream DP(OS);
- DI.print(DP);
- warn(ErrStorage);
-}
-
-static void checkError(Error E) {
- handleAllErrors(std::move(E),
- [&](ErrorInfoBase &EIB) { error(EIB.message()); });
-}
+static std::unique_ptr<lto::LTO> createLTO() {
+ lto::Config C;
+ C.Options = InitTargetOptionsFromCodeGenFlags();
-static void saveBuffer(StringRef Buffer, const Twine &Path) {
- std::error_code EC;
- raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
- if (EC)
- error("cannot create " + Path + ": " + EC.message());
- OS << Buffer;
-}
+ // Always emit a section per function/datum with LTO. LLVM LTO should get most
+ // of the benefit of linker GC, but there are still opportunities for ICF.
+ C.Options.FunctionSections = true;
+ C.Options.DataSections = true;
-static std::unique_ptr<lto::LTO> createLTO() {
- lto::Config Conf;
- Conf.Options = InitTargetOptionsFromCodeGenFlags();
// Use static reloc model on 32-bit x86 because it usually results in more
// compact code, and because there are also known code generation bugs when
// using the PIC model (see PR34306).
if (Config->Machine == COFF::IMAGE_FILE_MACHINE_I386)
- Conf.RelocModel = Reloc::Static;
+ C.RelocModel = Reloc::Static;
else
- Conf.RelocModel = Reloc::PIC_;
- Conf.DisableVerify = true;
- Conf.DiagHandler = diagnosticHandler;
- Conf.OptLevel = Config->LTOOptLevel;
+ C.RelocModel = Reloc::PIC_;
+ C.DisableVerify = true;
+ C.DiagHandler = diagnosticHandler;
+ C.OptLevel = Config->LTOO;
if (Config->SaveTemps)
- checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
- /*UseInputModulePath*/ true));
+ checkError(C.addSaveTemps(std::string(Config->OutputFile) + ".",
+ /*UseInputModulePath*/ true));
lto::ThinBackend Backend;
- if (Config->LTOJobs != 0)
- Backend = lto::createInProcessThinBackend(Config->LTOJobs);
- return llvm::make_unique<lto::LTO>(std::move(Conf), Backend,
+ if (Config->ThinLTOJobs != 0)
+ Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
+ return llvm::make_unique<lto::LTO>(std::move(C), Backend,
Config->LTOPartitions);
}
@@ -119,7 +105,7 @@ void BitcodeCompiler::add(BitcodeFile &F) {
// and return the resulting objects.
std::vector<StringRef> BitcodeCompiler::compile() {
unsigned MaxTasks = LTOObj->getMaxTasks();
- Buff.resize(MaxTasks);
+ Buf.resize(MaxTasks);
Files.resize(MaxTasks);
// The /lldltocache option specifies the path to a directory in which to cache
@@ -127,15 +113,15 @@ std::vector<StringRef> BitcodeCompiler::compile() {
// specified, configure LTO to use it as the cache directory.
lto::NativeObjectCache Cache;
if (!Config->LTOCache.empty())
- Cache = check(
- lto::localCache(Config->LTOCache,
- [&](size_t Task, std::unique_ptr<MemoryBuffer> MB,
- StringRef Path) { Files[Task] = std::move(MB); }));
+ Cache = check(lto::localCache(
+ Config->LTOCache, [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+ Files[Task] = std::move(MB);
+ }));
checkError(LTOObj->run(
[&](size_t Task) {
return llvm::make_unique<lto::NativeObjectStream>(
- llvm::make_unique<raw_svector_ostream>(Buff[Task]));
+ llvm::make_unique<raw_svector_ostream>(Buf[Task]));
},
Cache));
@@ -144,15 +130,15 @@ std::vector<StringRef> BitcodeCompiler::compile() {
std::vector<StringRef> Ret;
for (unsigned I = 0; I != MaxTasks; ++I) {
- if (Buff[I].empty())
+ if (Buf[I].empty())
continue;
if (Config->SaveTemps) {
if (I == 0)
- saveBuffer(Buff[I], Config->OutputFile + ".lto.obj");
+ saveBuffer(Buf[I], Config->OutputFile + ".lto.obj");
else
- saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.obj");
+ saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.obj");
}
- Ret.emplace_back(Buff[I].data(), Buff[I].size());
+ Ret.emplace_back(Buf[I].data(), Buf[I].size());
}
for (std::unique_ptr<MemoryBuffer> &File : Files)
diff --git a/contrib/llvm/tools/lld/COFF/LTO.h b/contrib/llvm/tools/lld/COFF/LTO.h
index a444aa7ac4fe..f00924654780 100644
--- a/contrib/llvm/tools/lld/COFF/LTO.h
+++ b/contrib/llvm/tools/lld/COFF/LTO.h
@@ -48,7 +48,7 @@ public:
private:
std::unique_ptr<llvm::lto::LTO> LTOObj;
- std::vector<SmallString<0>> Buff;
+ std::vector<SmallString<0>> Buf;
std::vector<std::unique_ptr<MemoryBuffer>> Files;
};
}
diff --git a/contrib/llvm/tools/lld/COFF/MapFile.cpp b/contrib/llvm/tools/lld/COFF/MapFile.cpp
index 717ed3419ea5..6ca1b6647bd7 100644
--- a/contrib/llvm/tools/lld/COFF/MapFile.cpp
+++ b/contrib/llvm/tools/lld/COFF/MapFile.cpp
@@ -23,7 +23,6 @@
#include "SymbolTable.h"
#include "Symbols.h"
#include "Writer.h"
-
#include "lld/Common/ErrorHandler.h"
#include "llvm/Support/Parallel.h"
#include "llvm/Support/raw_ostream.h"
@@ -37,14 +36,15 @@ using namespace lld::coff;
typedef DenseMap<const SectionChunk *, SmallVector<DefinedRegular *, 4>>
SymbolMapTy;
+static const std::string Indent8 = " "; // 8 spaces
+static const std::string Indent16 = " "; // 16 spaces
+
// Print out the first three columns of a line.
static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
uint64_t Align) {
OS << format("%08llx %08llx %5lld ", Addr, Size, Align);
}
-static std::string indent(int Depth) { return std::string(Depth * 8, ' '); }
-
// Returns a list of all symbols that we want to print out.
static std::vector<DefinedRegular *> getSymbols() {
std::vector<DefinedRegular *> V;
@@ -79,7 +79,7 @@ getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
for_each_n(parallel::par, (size_t)0, Syms.size(), [&](size_t I) {
raw_string_ostream OS(Str[I]);
writeHeader(OS, Syms[I]->getRVA(), 0, 0);
- OS << indent(2) << toString(*Syms[I]);
+ OS << Indent16 << toString(*Syms[I]);
});
DenseMap<DefinedRegular *, std::string> Ret;
@@ -108,7 +108,7 @@ void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
// Print out file contents.
for (OutputSection *Sec : OutputSections) {
writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize);
- OS << Sec->getName() << '\n';
+ OS << Sec->Name << '\n';
for (Chunk *C : Sec->getChunks()) {
auto *SC = dyn_cast<SectionChunk>(C);
@@ -116,7 +116,7 @@ void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
continue;
writeHeader(OS, SC->getRVA(), SC->getSize(), SC->Alignment);
- OS << indent(1) << SC->File->getName() << ":(" << SC->getSectionName()
+ OS << Indent8 << SC->File->getName() << ":(" << SC->getSectionName()
<< ")\n";
for (DefinedRegular *Sym : SectionSyms[SC])
OS << SymStr[Sym] << '\n';
diff --git a/contrib/llvm/tools/lld/COFF/MarkLive.cpp b/contrib/llvm/tools/lld/COFF/MarkLive.cpp
index 01be60d12d82..57ae450a9138 100644
--- a/contrib/llvm/tools/lld/COFF/MarkLive.cpp
+++ b/contrib/llvm/tools/lld/COFF/MarkLive.cpp
@@ -9,16 +9,21 @@
#include "Chunks.h"
#include "Symbols.h"
+#include "lld/Common/Timer.h"
#include "llvm/ADT/STLExtras.h"
#include <vector>
namespace lld {
namespace coff {
+static Timer GCTimer("GC", Timer::root());
+
// Set live bit on for each reachable chunk. Unmarked (unreachable)
// COMDAT chunks will be ignored by Writer, so they will be excluded
// from the final output.
void markLive(ArrayRef<Chunk *> Chunks) {
+ ScopedTimer T(GCTimer);
+
// We build up a worklist of sections which have been marked as live. We only
// push into the worklist when we discover an unmarked section, and we mark
// as we push, so sections never appear twice in the list.
@@ -43,7 +48,7 @@ void markLive(ArrayRef<Chunk *> Chunks) {
else if (auto *Sym = dyn_cast<DefinedImportData>(B))
Sym->File->Live = true;
else if (auto *Sym = dyn_cast<DefinedImportThunk>(B))
- Sym->WrappedSym->File->Live = true;
+ Sym->WrappedSym->File->Live = Sym->WrappedSym->File->ThunkLive = true;
};
// Add GC root chunks.
diff --git a/contrib/llvm/tools/lld/COFF/MarkLive.h b/contrib/llvm/tools/lld/COFF/MarkLive.h
new file mode 100644
index 000000000000..5b652dd48196
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/MarkLive.h
@@ -0,0 +1,24 @@
+//===- MarkLive.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_MARKLIVE_H
+#define LLD_COFF_MARKLIVE_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+
+namespace lld {
+namespace coff {
+
+void markLive(ArrayRef<Chunk *> Chunks);
+
+} // namespace coff
+} // namespace lld
+
+#endif // LLD_COFF_MARKLIVE_H
diff --git a/contrib/llvm/tools/lld/COFF/MinGW.cpp b/contrib/llvm/tools/lld/COFF/MinGW.cpp
index b7a47165640d..2ca00587331f 100644
--- a/contrib/llvm/tools/lld/COFF/MinGW.cpp
+++ b/contrib/llvm/tools/lld/COFF/MinGW.cpp
@@ -138,7 +138,7 @@ void coff::writeDefFile(StringRef Name) {
<< "@" << E.Ordinal;
if (auto *Def = dyn_cast_or_null<Defined>(E.Sym)) {
if (Def && Def->getChunk() &&
- !(Def->getChunk()->getPermissions() & IMAGE_SCN_MEM_EXECUTE))
+ !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
OS << " DATA";
}
OS << "\n";
diff --git a/contrib/llvm/tools/lld/COFF/Options.td b/contrib/llvm/tools/lld/COFF/Options.td
index 2a1de14657c1..871bad8bd655 100644
--- a/contrib/llvm/tools/lld/COFF/Options.td
+++ b/contrib/llvm/tools/lld/COFF/Options.td
@@ -20,6 +20,10 @@ def align : P<"align", "Section alignment">;
def aligncomm : P<"aligncomm", "Set common symbol alignment">;
def alternatename : P<"alternatename", "Define weak alias">;
def base : P<"base", "Base address of the program">;
+def color_diagnostics: Flag<["--"], "color-diagnostics">,
+ HelpText<"Use colors in diagnostics">;
+def color_diagnostics_eq: Joined<["--"], "color-diagnostics=">,
+ HelpText<"Use colors in diagnostics; one of 'always', 'never', 'auto'">;
def defaultlib : P<"defaultlib", "Add the library to the list of input files">;
def delayload : P<"delayload", "Delay loaded DLL name">;
def entry : P<"entry", "Name of entry point symbol">;
@@ -28,9 +32,12 @@ def errorlimit : P<"errorlimit",
def export : P<"export", "Export a function">;
// No help text because /failifmismatch is not intended to be used by the user.
def failifmismatch : P<"failifmismatch", "">;
+def guard : P<"guard", "Control flow guard">;
def heap : P<"heap", "Size of the heap">;
def ignore : P<"ignore", "Specify warning codes to ignore">;
def implib : P<"implib", "Import library name">;
+def lib : F<"lib">,
+ HelpText<"Act like lib.exe; must be first argument if present">;
def libpath : P<"libpath", "Additional library search path">;
def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">;
def lldltocache : P<"lldltocache", "Path to ThinLTO cached object file directory">;
@@ -42,12 +49,18 @@ def merge : P<"merge", "Combine sections">;
def mllvm : P<"mllvm", "Options to pass to LLVM">;
def nodefaultlib : P<"nodefaultlib", "Remove a default library">;
def opt : P<"opt", "Control optimizations">;
+def order : P<"order", "Put functions in order">;
def out : P<"out", "Path to file to write output">;
+def natvis : P<"natvis", "Path to natvis file to embed in the PDB">;
+def no_color_diagnostics: F<"no-color-diagnostics">,
+ HelpText<"Do not use colors in diagnostics">;
def pdb : P<"pdb", "PDB file path">;
+def pdbaltpath : P<"pdbaltpath", "PDB file path to embed in the image">;
def section : P<"section", "Specify section attributes">;
def stack : P<"stack", "Size of the stack">;
def stub : P<"stub", "Specify DOS stub file">;
def subsystem : P<"subsystem", "Specify subsystem">;
+def timestamp : P<"timestamp", "Specify the PE header timestamp">;
def version : P<"version", "Specify a version number in the PE header">;
def wholearchive_file : P<"wholearchive", "Include all object files from this archive">;
@@ -72,12 +85,14 @@ def deffile : Joined<["/", "-"], "def:">,
HelpText<"Use module-definition file">;
def debug : F<"debug">, HelpText<"Embed a symbol table in the image">;
+def debug_full : F<"debug:full">, Alias<debug>;
def debugtype : P<"debugtype", "Debug Info Options">;
def dll : F<"dll">, HelpText<"Create a DLL">;
def driver : P<"driver", "Generate a Windows NT Kernel Mode Driver">;
def nodefaultlib_all : F<"nodefaultlib">;
def noentry : F<"noentry">;
def profile : F<"profile">;
+def repro : F<"Brepro">, HelpText<"Use a hash of the executable as the PE header timestamp">;
def swaprun_cd : F<"swaprun:cd">;
def swaprun_net : F<"swaprun:net">;
def verbose : F<"verbose">;
@@ -102,6 +117,12 @@ defm fixed : B<"fixed", "Disable base relocations",
defm highentropyva : B<"highentropyva",
"Enable 64-bit ASLR (default on 64-bit)",
"Disable 64-bit ASLR">;
+defm incremental : B<"incremental",
+ "Keep original import library if contents are unchanged",
+ "Overwrite import library even if contents are unchanged">;
+defm integritycheck : B<"integritycheck",
+ "Set FORCE_INTEGRITY bit in PE header",
+ "No effect (default)">;
defm largeaddressaware : B<"largeaddressaware",
"Enable large addresses (default on 64-bit)",
"Disable large addresses (default on 32-bit)">;
@@ -120,11 +141,14 @@ def help_q : Flag<["/?", "-?"], "">, Alias<help>;
// LLD extensions
def debug_ghash : F<"debug:ghash">;
def debug_dwarf : F<"debug:dwarf">;
+def debug_symtab : F<"debug:symtab">;
def export_all_symbols : F<"export-all-symbols">;
def kill_at : F<"kill-at">;
def lldmingw : F<"lldmingw">;
def msvclto : F<"msvclto">;
def output_def : Joined<["/", "-"], "output-def:">;
+def pdb_source_path : P<"pdbsourcepath",
+ "Base path used to make relative source file path absolute in PDB">;
def rsp_quoting : Joined<["--"], "rsp-quoting=">,
HelpText<"Quoting style for response files, 'windows' (default) or 'posix'">;
def dash_dash_version : Flag<["--"], "version">,
@@ -133,6 +157,7 @@ def dash_dash_version : Flag<["--"], "version">,
// Flags for debugging
def lldmap : F<"lldmap">;
def lldmap_file : Joined<["/", "-"], "lldmap:">;
+def show_timing : F<"time">;
//==============================================================================
// The flags below do nothing. They are defined only for link.exe compatibility.
@@ -147,8 +172,6 @@ multiclass QB<string name> {
def functionpadmin : F<"functionpadmin">;
def ignoreidl : F<"ignoreidl">;
-def incremental : F<"incremental">;
-def no_incremental : F<"incremental:no">;
def nologo : F<"nologo">;
def throwingnew : F<"throwingnew">;
def editandcontinue : F<"editandcontinue">;
@@ -158,8 +181,6 @@ def delay : QF<"delay">;
def errorreport : QF<"errorreport">;
def idlout : QF<"idlout">;
def maxilksize : QF<"maxilksize">;
-def natvis : QF<"natvis">;
-def pdbaltpath : QF<"pdbaltpath">;
def tlbid : QF<"tlbid">;
def tlbout : QF<"tlbout">;
def verbose_all : QF<"verbose">;
diff --git a/contrib/llvm/tools/lld/COFF/PDB.cpp b/contrib/llvm/tools/lld/COFF/PDB.cpp
index 8ca52556ae58..766bf3f6b456 100644
--- a/contrib/llvm/tools/lld/COFF/PDB.cpp
+++ b/contrib/llvm/tools/lld/COFF/PDB.cpp
@@ -15,7 +15,7 @@
#include "Symbols.h"
#include "Writer.h"
#include "lld/Common/ErrorHandler.h"
-#include "llvm/DebugInfo/CodeView/CVDebugRecord.h"
+#include "lld/Common/Timer.h"
#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
@@ -45,8 +45,10 @@
#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
#include "llvm/DebugInfo/PDB/PDB.h"
#include "llvm/Object/COFF.h"
+#include "llvm/Object/CVDebugRecord.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/JamCRC.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
@@ -61,6 +63,15 @@ using llvm::object::coff_section;
static ExitOnError ExitOnErr;
+static Timer TotalPdbLinkTimer("PDB Emission (Cumulative)", Timer::root());
+
+static Timer AddObjectsTimer("Add Objects", TotalPdbLinkTimer);
+static Timer TypeMergingTimer("Type Merging", AddObjectsTimer);
+static Timer SymbolMergingTimer("Symbol Merging", AddObjectsTimer);
+static Timer GlobalsLayoutTimer("Globals Stream Layout", TotalPdbLinkTimer);
+static Timer TpiStreamLayoutTimer("TPI Stream Layout", TotalPdbLinkTimer);
+static Timer DiskCommitTimer("Commit to Disk", TotalPdbLinkTimer);
+
namespace {
/// Map from type index and item index in a type server PDB to the
/// corresponding index in the destination PDB.
@@ -74,11 +85,19 @@ class PDBLinker {
public:
PDBLinker(SymbolTable *Symtab)
: Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(Alloc),
- IDTable(Alloc), GlobalTypeTable(Alloc), GlobalIDTable(Alloc) {}
+ IDTable(Alloc), GlobalTypeTable(Alloc), GlobalIDTable(Alloc) {
+ // This isn't strictly necessary, but link.exe usually puts an empty string
+ // as the first "valid" string in the string table, so we do the same in
+ // order to maintain as much byte-for-byte compatibility as possible.
+ PDBStrTab.insert("");
+ }
/// Emit the basic PDB structure: initial streams, headers, etc.
void initialize(const llvm::codeview::DebugInfo &BuildId);
+ /// Add natvis files specified on the command line.
+ void addNatvisFiles();
+
/// Link CodeView from each object file in the symbol table into the PDB.
void addObjectsToPDB();
@@ -106,9 +125,6 @@ public:
void addSections(ArrayRef<OutputSection *> OutputSections,
ArrayRef<uint8_t> SectionTable);
- void addSectionContrib(pdb::DbiModuleDescriptorBuilder &LinkerModule,
- OutputSection *OS, Chunk *C);
-
/// Write the PDB to disk.
void commit();
@@ -137,6 +153,11 @@ private:
llvm::SmallString<128> NativePath;
+ /// A list of other PDBs which are loaded during the linking process and which
+ /// we need to keep around since the linking operation may reference pointers
+ /// inside of these PDBs.
+ llvm::SmallVector<std::unique_ptr<pdb::NativeSession>, 2> LoadedPDBs;
+
std::vector<pdb::SecMapEntry> SectionMap;
/// Type index mappings of type server PDBs that we've loaded so far.
@@ -184,8 +205,8 @@ static bool canUseDebugH(ArrayRef<uint8_t> DebugH) {
DebugH = DebugH.drop_front(sizeof(object::debug_h_header));
return Header->Magic == COFF::DEBUG_HASHES_SECTION_MAGIC &&
Header->Version == 0 &&
- Header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1) &&
- (DebugH.size() % 20 == 0);
+ Header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1_8) &&
+ (DebugH.size() % 8 == 0);
}
static Optional<ArrayRef<uint8_t>> getDebugH(ObjFile *File) {
@@ -237,6 +258,8 @@ maybeReadTypeServerRecord(CVTypeArray &Types) {
Expected<const CVIndexMap&> PDBLinker::mergeDebugT(ObjFile *File,
CVIndexMap &ObjectIndexMap) {
+ ScopedTimer T(TypeMergingTimer);
+
ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
if (Data.empty())
return ObjectIndexMap;
@@ -348,10 +371,16 @@ Expected<const CVIndexMap&> PDBLinker::maybeMergeTypeServerPDB(ObjFile *File,
return std::move(E);
}
- auto ExpectedTpi = (*ExpectedSession)->getPDBFile().getPDBTpiStream();
+ pdb::NativeSession *Session = ExpectedSession->get();
+
+ // Keep a strong reference to this PDB, so that it's safe to hold pointers
+ // into the file.
+ LoadedPDBs.push_back(std::move(*ExpectedSession));
+
+ auto ExpectedTpi = Session->getPDBFile().getPDBTpiStream();
if (auto E = ExpectedTpi.takeError())
fatal("Type server does not have TPI stream: " + toString(std::move(E)));
- auto ExpectedIpi = (*ExpectedSession)->getPDBFile().getPDBIpiStream();
+ auto ExpectedIpi = Session->getPDBFile().getPDBIpiStream();
if (auto E = ExpectedIpi.takeError())
fatal("Type server does not have TPI stream: " + toString(std::move(E)));
@@ -428,6 +457,38 @@ static void remapTypesInSymbolRecord(ObjFile *File, SymbolKind SymKind,
}
}
+static void
+recordStringTableReferenceAtOffset(MutableArrayRef<uint8_t> Contents,
+ uint32_t Offset,
+ std::vector<ulittle32_t *> &StrTableRefs) {
+ Contents =
+ Contents.drop_front(Offset).take_front(sizeof(support::ulittle32_t));
+ ulittle32_t *Index = reinterpret_cast<ulittle32_t *>(Contents.data());
+ StrTableRefs.push_back(Index);
+}
+
+static void
+recordStringTableReferences(SymbolKind Kind, MutableArrayRef<uint8_t> Contents,
+ std::vector<ulittle32_t *> &StrTableRefs) {
+ // For now we only handle S_FILESTATIC, but we may need the same logic for
+ // S_DEFRANGE and S_DEFRANGE_SUBFIELD. However, I cannot seem to generate any
+ // PDBs that contain these types of records, so because of the uncertainty
+ // they are omitted here until we can prove that it's necessary.
+ switch (Kind) {
+ case SymbolKind::S_FILESTATIC:
+ // FileStaticSym::ModFileOffset
+ recordStringTableReferenceAtOffset(Contents, 4, StrTableRefs);
+ break;
+ case SymbolKind::S_DEFRANGE:
+ case SymbolKind::S_DEFRANGE_SUBFIELD:
+ log("Not fixing up string table reference in S_DEFRANGE / "
+ "S_DEFRANGE_SUBFIELD record");
+ break;
+ default:
+ break;
+ }
+}
+
static SymbolKind symbolKind(ArrayRef<uint8_t> RecordData) {
const RecordPrefix *Prefix =
reinterpret_cast<const RecordPrefix *>(RecordData.data());
@@ -644,53 +705,65 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjFile *File,
pdb::GSIStreamBuilder &GsiBuilder,
const CVIndexMap &IndexMap,
TypeCollection &IDTable,
+ std::vector<ulittle32_t *> &StringTableRefs,
BinaryStreamRef SymData) {
// FIXME: Improve error recovery by warning and skipping records when
// possible.
- CVSymbolArray Syms;
- BinaryStreamReader Reader(SymData);
- ExitOnErr(Reader.readArray(Syms, Reader.getLength()));
+ ArrayRef<uint8_t> SymsBuffer;
+ cantFail(SymData.readBytes(0, SymData.getLength(), SymsBuffer));
SmallVector<SymbolScope, 4> Scopes;
- for (CVSymbol Sym : Syms) {
- // Discover type index references in the record. Skip it if we don't know
- // where they are.
- SmallVector<TiReference, 32> TypeRefs;
- if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) {
- log("ignoring unknown symbol record with kind 0x" + utohexstr(Sym.kind()));
- continue;
- }
-
- // Copy the symbol record so we can mutate it.
- MutableArrayRef<uint8_t> NewData = copySymbolForPdb(Sym, Alloc);
-
- // Re-map all the type index references.
- MutableArrayRef<uint8_t> Contents =
- NewData.drop_front(sizeof(RecordPrefix));
- remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap, TypeRefs);
- // An object file may have S_xxx_ID symbols, but these get converted to
- // "real" symbols in a PDB.
- translateIdSymbols(NewData, IDTable);
-
- SymbolKind NewKind = symbolKind(NewData);
-
- // Fill in "Parent" and "End" fields by maintaining a stack of scopes.
- CVSymbol NewSym(NewKind, NewData);
- if (symbolOpensScope(NewKind))
- scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym);
- else if (symbolEndsScope(NewKind))
- scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File);
-
- // Add the symbol to the globals stream if necessary. Do this before adding
- // the symbol to the module since we may need to get the next symbol offset,
- // and writing to the module's symbol stream will update that offset.
- if (symbolGoesInGlobalsStream(NewSym))
- addGlobalSymbol(GsiBuilder, *File, NewSym);
+ auto EC = forEachCodeViewRecord<CVSymbol>(
+ SymsBuffer, [&](const CVSymbol &Sym) -> llvm::Error {
+ // Discover type index references in the record. Skip it if we don't
+ // know where they are.
+ SmallVector<TiReference, 32> TypeRefs;
+ if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) {
+ log("ignoring unknown symbol record with kind 0x" +
+ utohexstr(Sym.kind()));
+ return Error::success();
+ }
- // Add the symbol to the module.
- if (symbolGoesInModuleStream(NewSym))
- File->ModuleDBI->addSymbol(NewSym);
- }
+ // Copy the symbol record so we can mutate it.
+ MutableArrayRef<uint8_t> NewData = copySymbolForPdb(Sym, Alloc);
+
+ // Re-map all the type index references.
+ MutableArrayRef<uint8_t> Contents =
+ NewData.drop_front(sizeof(RecordPrefix));
+ remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap,
+ TypeRefs);
+
+ // An object file may have S_xxx_ID symbols, but these get converted to
+ // "real" symbols in a PDB.
+ translateIdSymbols(NewData, IDTable);
+
+ // If this record refers to an offset in the object file's string table,
+ // add that item to the global PDB string table and re-write the index.
+ recordStringTableReferences(Sym.kind(), Contents, StringTableRefs);
+
+ SymbolKind NewKind = symbolKind(NewData);
+
+ // Fill in "Parent" and "End" fields by maintaining a stack of scopes.
+ CVSymbol NewSym(NewKind, NewData);
+ if (symbolOpensScope(NewKind))
+ scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(),
+ NewSym);
+ else if (symbolEndsScope(NewKind))
+ scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File);
+
+ // Add the symbol to the globals stream if necessary. Do this before
+ // adding the symbol to the module since we may need to get the next
+ // symbol offset, and writing to the module's symbol stream will update
+ // that offset.
+ if (symbolGoesInGlobalsStream(NewSym))
+ addGlobalSymbol(GsiBuilder, *File, NewSym);
+
+ // Add the symbol to the module.
+ if (symbolGoesInModuleStream(NewSym))
+ File->ModuleDBI->addSymbol(NewSym);
+ return Error::success();
+ });
+ cantFail(std::move(EC));
}
// Allocate memory for a .debug$S section and relocate it.
@@ -704,6 +777,32 @@ static ArrayRef<uint8_t> relocateDebugChunk(BumpPtrAllocator &Alloc,
".debug$S");
}
+static pdb::SectionContrib createSectionContrib(const Chunk *C, uint32_t Modi) {
+ OutputSection *OS = C->getOutputSection();
+ pdb::SectionContrib SC;
+ memset(&SC, 0, sizeof(SC));
+ SC.ISect = OS->SectionIndex;
+ SC.Off = C->getRVA() - OS->getRVA();
+ SC.Size = C->getSize();
+ if (auto *SecChunk = dyn_cast<SectionChunk>(C)) {
+ SC.Characteristics = SecChunk->Header->Characteristics;
+ SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex();
+ ArrayRef<uint8_t> Contents = SecChunk->getContents();
+ JamCRC CRC(0);
+ ArrayRef<char> CharContents = makeArrayRef(
+ reinterpret_cast<const char *>(Contents.data()), Contents.size());
+ CRC.update(CharContents);
+ SC.DataCrc = CRC.getCRC();
+ } else {
+ SC.Characteristics = OS->Header.Characteristics;
+ // FIXME: When we start creating DBI for import libraries, use those here.
+ SC.Imod = Modi;
+ }
+ SC.RelocCrc = 0; // FIXME
+
+ return SC;
+}
+
void PDBLinker::addObjFile(ObjFile *File) {
// Add a module descriptor for every object file. We need to put an absolute
// path to the object into the PDB. If this is a plain object, we make its
@@ -718,6 +817,17 @@ void PDBLinker::addObjFile(ObjFile *File) {
File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name));
File->ModuleDBI->setObjFileName(Path);
+ auto Chunks = File->getChunks();
+ uint32_t Modi = File->ModuleDBI->getModuleIndex();
+ for (Chunk *C : Chunks) {
+ auto *SecChunk = dyn_cast<SectionChunk>(C);
+ if (!SecChunk || !SecChunk->isLive())
+ continue;
+ pdb::SectionContrib SC = createSectionContrib(SecChunk, Modi);
+ File->ModuleDBI->setFirstSectionContrib(SC);
+ break;
+ }
+
// Before we can process symbol substreams from .debug$S, we need to process
// type information, file checksums, and the string table. Add type info to
// the PDB first, so that we can get the map from object file type and item
@@ -734,7 +844,12 @@ void PDBLinker::addObjFile(ObjFile *File) {
const CVIndexMap &IndexMap = *IndexMapResult;
+ ScopedTimer T(SymbolMergingTimer);
+
// Now do all live .debug$S sections.
+ DebugStringTableSubsectionRef CVStrTab;
+ DebugChecksumsSubsectionRef Checksums;
+ std::vector<ulittle32_t *> StringTableReferences;
for (SectionChunk *DebugChunk : File->getDebugChunks()) {
if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S")
continue;
@@ -748,14 +863,17 @@ void PDBLinker::addObjFile(ObjFile *File) {
BinaryStreamReader Reader(RelocatedDebugContents, support::little);
ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size()));
- DebugStringTableSubsectionRef CVStrTab;
- DebugChecksumsSubsectionRef Checksums;
for (const DebugSubsectionRecord &SS : Subsections) {
switch (SS.kind()) {
- case DebugSubsectionKind::StringTable:
+ case DebugSubsectionKind::StringTable: {
+ assert(!CVStrTab.valid() &&
+ "Encountered multiple string table subsections!");
ExitOnErr(CVStrTab.initialize(SS.getRecordData()));
break;
+ }
case DebugSubsectionKind::FileChecksums:
+ assert(!Checksums.valid() &&
+ "Encountered multiple checksum subsections!");
ExitOnErr(Checksums.initialize(SS.getRecordData()));
break;
case DebugSubsectionKind::Lines:
@@ -766,10 +884,12 @@ void PDBLinker::addObjFile(ObjFile *File) {
case DebugSubsectionKind::Symbols:
if (Config->DebugGHashes) {
mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap,
- GlobalIDTable, SS.getRecordData());
+ GlobalIDTable, StringTableReferences,
+ SS.getRecordData());
} else {
mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap,
- IDTable, SS.getRecordData());
+ IDTable, StringTableReferences,
+ SS.getRecordData());
}
break;
default:
@@ -777,25 +897,55 @@ void PDBLinker::addObjFile(ObjFile *File) {
break;
}
}
+ }
- if (Checksums.valid()) {
- // Make a new file checksum table that refers to offsets in the PDB-wide
- // string table. Generally the string table subsection appears after the
- // checksum table, so we have to do this after looping over all the
- // subsections.
- if (!CVStrTab.valid())
- fatal(".debug$S sections must have both a string table subsection "
- "and a checksum subsection table or neither");
- auto NewChecksums = make_unique<DebugChecksumsSubsection>(PDBStrTab);
- for (FileChecksumEntry &FC : Checksums) {
- StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset));
- ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(*File->ModuleDBI,
- FileName));
- NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum);
- }
- File->ModuleDBI->addDebugSubsection(std::move(NewChecksums));
+ // We should have seen all debug subsections across the entire object file now
+ // which means that if a StringTable subsection and Checksums subsection were
+ // present, now is the time to handle them.
+ if (!CVStrTab.valid()) {
+ if (Checksums.valid())
+ fatal(".debug$S sections with a checksums subsection must also contain a "
+ "string table subsection");
+
+ if (!StringTableReferences.empty())
+ warn("No StringTable subsection was encountered, but there are string "
+ "table references");
+ return;
+ }
+
+ // Rewrite each string table reference based on the value that the string
+ // assumes in the final PDB.
+ for (ulittle32_t *Ref : StringTableReferences) {
+ auto ExpectedString = CVStrTab.getString(*Ref);
+ if (!ExpectedString) {
+ warn("Invalid string table reference");
+ consumeError(ExpectedString.takeError());
+ continue;
}
+
+ *Ref = PDBStrTab.insert(*ExpectedString);
}
+
+ // Make a new file checksum table that refers to offsets in the PDB-wide
+ // string table. Generally the string table subsection appears after the
+ // checksum table, so we have to do this after looping over all the
+ // subsections.
+ auto NewChecksums = make_unique<DebugChecksumsSubsection>(PDBStrTab);
+ for (FileChecksumEntry &FC : Checksums) {
+ SmallString<128> FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset));
+ if (!sys::path::is_absolute(FileName) &&
+ !Config->PDBSourcePath.empty()) {
+ SmallString<128> AbsoluteFileName = Config->PDBSourcePath;
+ sys::path::append(AbsoluteFileName, FileName);
+ sys::path::native(AbsoluteFileName);
+ sys::path::remove_dots(AbsoluteFileName, /*remove_dot_dots=*/true);
+ FileName = std::move(AbsoluteFileName);
+ }
+ ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(*File->ModuleDBI,
+ FileName));
+ NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum);
+ }
+ File->ModuleDBI->addDebugSubsection(std::move(NewChecksums));
}
static PublicSym32 createPublic(Defined *Def) {
@@ -818,12 +968,15 @@ static PublicSym32 createPublic(Defined *Def) {
// Add all object files to the PDB. Merge .debug$T sections into IpiData and
// TpiData.
void PDBLinker::addObjectsToPDB() {
+ ScopedTimer T1(AddObjectsTimer);
for (ObjFile *File : ObjFile::Instances)
addObjFile(File);
Builder.getStringTableBuilder().setStrings(PDBStrTab);
+ T1.stop();
// Construct TPI and IPI stream contents.
+ ScopedTimer T2(TpiStreamLayoutTimer);
if (Config->DebugGHashes) {
addTypeInfo(Builder.getTpiBuilder(), GlobalTypeTable);
addTypeInfo(Builder.getIpiBuilder(), GlobalIDTable);
@@ -831,7 +984,9 @@ void PDBLinker::addObjectsToPDB() {
addTypeInfo(Builder.getTpiBuilder(), TypeTable);
addTypeInfo(Builder.getIpiBuilder(), IDTable);
}
+ T2.stop();
+ ScopedTimer T3(GlobalsLayoutTimer);
// Compute the public and global symbols.
auto &GsiBuilder = Builder.getGsiBuilder();
std::vector<PublicSym32> Publics;
@@ -853,6 +1008,35 @@ void PDBLinker::addObjectsToPDB() {
}
}
+void PDBLinker::addNatvisFiles() {
+ for (StringRef File : Config->NatvisFiles) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> DataOrErr =
+ MemoryBuffer::getFile(File);
+ if (!DataOrErr) {
+ warn("Cannot open input file: " + File);
+ continue;
+ }
+ Builder.addInjectedSource(File, std::move(*DataOrErr));
+ }
+}
+
+static codeview::CPUType toCodeViewMachine(COFF::MachineTypes Machine) {
+ switch (Machine) {
+ case COFF::IMAGE_FILE_MACHINE_AMD64:
+ return codeview::CPUType::X64;
+ case COFF::IMAGE_FILE_MACHINE_ARM:
+ return codeview::CPUType::ARM7;
+ case COFF::IMAGE_FILE_MACHINE_ARM64:
+ return codeview::CPUType::ARM64;
+ case COFF::IMAGE_FILE_MACHINE_ARMNT:
+ return codeview::CPUType::ARMNT;
+ case COFF::IMAGE_FILE_MACHINE_I386:
+ return codeview::CPUType::Intel80386;
+ default:
+ llvm_unreachable("Unsupported CPU Type");
+ }
+}
+
static void addCommonLinkerModuleSymbols(StringRef Path,
pdb::DbiModuleDescriptorBuilder &Mod,
BumpPtrAllocator &Allocator) {
@@ -863,7 +1047,7 @@ static void addCommonLinkerModuleSymbols(StringRef Path,
ONS.Name = "* Linker *";
ONS.Signature = 0;
- CS.Machine = Config->is64() ? CPUType::X64 : CPUType::Intel80386;
+ CS.Machine = toCodeViewMachine(Config->Machine);
// Interestingly, if we set the string to 0.0.0.0, then when trying to view
// local variables WinDbg emits an error that private symbols are not present.
// By setting this to a valid MSVC linker version string, local variables are
@@ -914,9 +1098,9 @@ static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &Mod,
BumpPtrAllocator &Allocator) {
SectionSym Sym(SymbolRecordKind::SectionSym);
Sym.Alignment = 12; // 2^12 = 4KB
- Sym.Characteristics = OS.getCharacteristics();
+ Sym.Characteristics = OS.Header.Characteristics;
Sym.Length = OS.getVirtualSize();
- Sym.Name = OS.getName();
+ Sym.Name = OS.Name;
Sym.Rva = OS.getRVA();
Sym.SectionNumber = OS.SectionIndex;
Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
@@ -928,10 +1112,15 @@ void coff::createPDB(SymbolTable *Symtab,
ArrayRef<OutputSection *> OutputSections,
ArrayRef<uint8_t> SectionTable,
const llvm::codeview::DebugInfo &BuildId) {
+ ScopedTimer T1(TotalPdbLinkTimer);
PDBLinker PDB(Symtab);
+
PDB.initialize(BuildId);
PDB.addObjectsToPDB();
PDB.addSections(OutputSections, SectionTable);
+ PDB.addNatvisFiles();
+
+ ScopedTimer T2(DiskCommitTimer);
PDB.commit();
}
@@ -945,44 +1134,22 @@ void PDBLinker::initialize(const llvm::codeview::DebugInfo &BuildId) {
// Add an Info stream.
auto &InfoBuilder = Builder.getInfoBuilder();
- InfoBuilder.setAge(BuildId.PDB70.Age);
-
GUID uuid;
memcpy(&uuid, &BuildId.PDB70.Signature, sizeof(uuid));
+ InfoBuilder.setAge(BuildId.PDB70.Age);
InfoBuilder.setGuid(uuid);
- InfoBuilder.setSignature(time(nullptr));
InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);
// Add an empty DBI stream.
pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
DbiBuilder.setAge(BuildId.PDB70.Age);
DbiBuilder.setVersionHeader(pdb::PdbDbiV70);
- ExitOnErr(DbiBuilder.addDbgStream(pdb::DbgHeaderType::NewFPO, {}));
-}
-
-void PDBLinker::addSectionContrib(pdb::DbiModuleDescriptorBuilder &LinkerModule,
- OutputSection *OS, Chunk *C) {
- pdb::SectionContrib SC;
- memset(&SC, 0, sizeof(SC));
- SC.ISect = OS->SectionIndex;
- SC.Off = C->getRVA() - OS->getRVA();
- SC.Size = C->getSize();
- if (auto *SecChunk = dyn_cast<SectionChunk>(C)) {
- SC.Characteristics = SecChunk->Header->Characteristics;
- SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex();
- ArrayRef<uint8_t> Contents = SecChunk->getContents();
- JamCRC CRC(0);
- ArrayRef<char> CharContents = makeArrayRef(
- reinterpret_cast<const char *>(Contents.data()), Contents.size());
- CRC.update(CharContents);
- SC.DataCrc = CRC.getCRC();
- } else {
- SC.Characteristics = OS->getCharacteristics();
- // FIXME: When we start creating DBI for import libraries, use those here.
- SC.Imod = LinkerModule.getModuleIndex();
- }
- SC.RelocCrc = 0; // FIXME
- Builder.getDbiBuilder().addSectionContrib(SC);
+ DbiBuilder.setMachineType(Config->Machine);
+ // Technically we are not link.exe 14.11, but there are known cases where
+ // debugging tools on Windows expect Microsoft-specific version numbers or
+ // they fail to work at all. Since we know we produce PDBs that are
+ // compatible with LINK 14.11, we set that version number here.
+ DbiBuilder.setBuildNumber(14, 11);
}
void PDBLinker::addSections(ArrayRef<OutputSection *> OutputSections,
@@ -1000,8 +1167,11 @@ void PDBLinker::addSections(ArrayRef<OutputSection *> OutputSections,
// Add section contributions. They must be ordered by ascending RVA.
for (OutputSection *OS : OutputSections) {
addLinkerModuleSectionSymbol(LinkerModule, *OS, Alloc);
- for (Chunk *C : OS->getChunks())
- addSectionContrib(LinkerModule, OS, C);
+ for (Chunk *C : OS->getChunks()) {
+ pdb::SectionContrib SC =
+ createSectionContrib(C, LinkerModule.getModuleIndex());
+ Builder.getDbiBuilder().addSectionContrib(SC);
+ }
}
// Add Section Map stream.
@@ -1020,3 +1190,145 @@ void PDBLinker::commit() {
// Write to a file.
ExitOnErr(Builder.commit(Config->PDBPath));
}
+
+static Expected<StringRef>
+getFileName(const DebugStringTableSubsectionRef &Strings,
+ const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) {
+ auto Iter = Checksums.getArray().at(FileID);
+ if (Iter == Checksums.getArray().end())
+ return make_error<CodeViewError>(cv_error_code::no_records);
+ uint32_t Offset = Iter->FileNameOffset;
+ return Strings.getString(Offset);
+}
+
+static uint32_t getSecrelReloc() {
+ switch (Config->Machine) {
+ case AMD64:
+ return COFF::IMAGE_REL_AMD64_SECREL;
+ case I386:
+ return COFF::IMAGE_REL_I386_SECREL;
+ case ARMNT:
+ return COFF::IMAGE_REL_ARM_SECREL;
+ case ARM64:
+ return COFF::IMAGE_REL_ARM64_SECREL;
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+}
+
+// Try to find a line table for the given offset Addr into the given chunk C.
+// If a line table was found, the line table, the string and checksum tables
+// that are used to interpret the line table, and the offset of Addr in the line
+// table are stored in the output arguments. Returns whether a line table was
+// found.
+static bool findLineTable(const SectionChunk *C, uint32_t Addr,
+ DebugStringTableSubsectionRef &CVStrTab,
+ DebugChecksumsSubsectionRef &Checksums,
+ DebugLinesSubsectionRef &Lines,
+ uint32_t &OffsetInLinetable) {
+ ExitOnError ExitOnErr;
+ uint32_t SecrelReloc = getSecrelReloc();
+
+ for (SectionChunk *DbgC : C->File->getDebugChunks()) {
+ if (DbgC->getSectionName() != ".debug$S")
+ continue;
+
+ // Build a mapping of SECREL relocations in DbgC that refer to C.
+ DenseMap<uint32_t, uint32_t> Secrels;
+ for (const coff_relocation &R : DbgC->Relocs) {
+ if (R.Type != SecrelReloc)
+ continue;
+
+ if (auto *S = dyn_cast_or_null<DefinedRegular>(
+ C->File->getSymbols()[R.SymbolTableIndex]))
+ if (S->getChunk() == C)
+ Secrels[R.VirtualAddress] = S->getValue();
+ }
+
+ ArrayRef<uint8_t> Contents =
+ consumeDebugMagic(DbgC->getContents(), ".debug$S");
+ DebugSubsectionArray Subsections;
+ BinaryStreamReader Reader(Contents, support::little);
+ ExitOnErr(Reader.readArray(Subsections, Contents.size()));
+
+ for (const DebugSubsectionRecord &SS : Subsections) {
+ switch (SS.kind()) {
+ case DebugSubsectionKind::StringTable: {
+ assert(!CVStrTab.valid() &&
+ "Encountered multiple string table subsections!");
+ ExitOnErr(CVStrTab.initialize(SS.getRecordData()));
+ break;
+ }
+ case DebugSubsectionKind::FileChecksums:
+ assert(!Checksums.valid() &&
+ "Encountered multiple checksum subsections!");
+ ExitOnErr(Checksums.initialize(SS.getRecordData()));
+ break;
+ case DebugSubsectionKind::Lines: {
+ ArrayRef<uint8_t> Bytes;
+ auto Ref = SS.getRecordData();
+ ExitOnErr(Ref.readLongestContiguousChunk(0, Bytes));
+ size_t OffsetInDbgC = Bytes.data() - DbgC->getContents().data();
+
+ // Check whether this line table refers to C.
+ auto I = Secrels.find(OffsetInDbgC);
+ if (I == Secrels.end())
+ break;
+
+ // Check whether this line table covers Addr in C.
+ DebugLinesSubsectionRef LinesTmp;
+ ExitOnErr(LinesTmp.initialize(BinaryStreamReader(Ref)));
+ uint32_t OffsetInC = I->second + LinesTmp.header()->RelocOffset;
+ if (Addr < OffsetInC || Addr >= OffsetInC + LinesTmp.header()->CodeSize)
+ break;
+
+ assert(!Lines.header() &&
+ "Encountered multiple line tables for function!");
+ ExitOnErr(Lines.initialize(BinaryStreamReader(Ref)));
+ OffsetInLinetable = Addr - OffsetInC;
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (CVStrTab.valid() && Checksums.valid() && Lines.header())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Use CodeView line tables to resolve a file and line number for the given
+// offset into the given chunk and return them, or {"", 0} if a line table was
+// not found.
+std::pair<StringRef, uint32_t> coff::getFileLine(const SectionChunk *C,
+ uint32_t Addr) {
+ ExitOnError ExitOnErr;
+
+ DebugStringTableSubsectionRef CVStrTab;
+ DebugChecksumsSubsectionRef Checksums;
+ DebugLinesSubsectionRef Lines;
+ uint32_t OffsetInLinetable;
+
+ if (!findLineTable(C, Addr, CVStrTab, Checksums, Lines, OffsetInLinetable))
+ return {"", 0};
+
+ uint32_t NameIndex;
+ uint32_t LineNumber;
+ for (LineColumnEntry &Entry : Lines) {
+ for (const LineNumberEntry &LN : Entry.LineNumbers) {
+ if (LN.Offset > OffsetInLinetable) {
+ StringRef Filename =
+ ExitOnErr(getFileName(CVStrTab, Checksums, NameIndex));
+ return {Filename, LineNumber};
+ }
+ LineInfo LI(LN.Flags);
+ NameIndex = Entry.NameIndex;
+ LineNumber = LI.getStartLine();
+ }
+ }
+ StringRef Filename = ExitOnErr(getFileName(CVStrTab, Checksums, NameIndex));
+ return {Filename, LineNumber};
+}
diff --git a/contrib/llvm/tools/lld/COFF/PDB.h b/contrib/llvm/tools/lld/COFF/PDB.h
index defd7d236790..a98d129a633b 100644
--- a/contrib/llvm/tools/lld/COFF/PDB.h
+++ b/contrib/llvm/tools/lld/COFF/PDB.h
@@ -22,12 +22,16 @@ union DebugInfo;
namespace lld {
namespace coff {
class OutputSection;
+class SectionChunk;
class SymbolTable;
void createPDB(SymbolTable *Symtab,
llvm::ArrayRef<OutputSection *> OutputSections,
llvm::ArrayRef<uint8_t> SectionTable,
const llvm::codeview::DebugInfo &BuildId);
+
+std::pair<llvm::StringRef, uint32_t> getFileLine(const SectionChunk *C,
+ uint32_t Addr);
}
}
diff --git a/contrib/llvm/tools/lld/COFF/Strings.cpp b/contrib/llvm/tools/lld/COFF/Strings.cpp
deleted file mode 100644
index 89b9c5186fd1..000000000000
--- a/contrib/llvm/tools/lld/COFF/Strings.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-//===- Strings.cpp -------------------------------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "Strings.h"
-#include <mutex>
-
-#if defined(_MSC_VER)
-#include <Windows.h>
-#include <DbgHelp.h>
-#pragma comment(lib, "dbghelp.lib")
-#endif
-
-using namespace lld;
-using namespace lld::coff;
-using namespace llvm;
-
-Optional<std::string> coff::demangleMSVC(StringRef S) {
-#if defined(_MSC_VER)
- // UnDecorateSymbolName is not thread-safe, so we need a mutex.
- static std::mutex Mu;
- std::lock_guard<std::mutex> Lock(Mu);
-
- char Buf[4096];
- if (S.startswith("?"))
- if (size_t Len = UnDecorateSymbolName(S.str().c_str(), Buf, sizeof(Buf), 0))
- return std::string(Buf, Len);
-#endif
- return None;
-}
diff --git a/contrib/llvm/tools/lld/COFF/SymbolTable.cpp b/contrib/llvm/tools/lld/COFF/SymbolTable.cpp
index df76679535cb..b286d865caaf 100644
--- a/contrib/llvm/tools/lld/COFF/SymbolTable.cpp
+++ b/contrib/llvm/tools/lld/COFF/SymbolTable.cpp
@@ -11,9 +11,11 @@
#include "Config.h"
#include "Driver.h"
#include "LTO.h"
+#include "PDB.h"
#include "Symbols.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Timer.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -24,6 +26,8 @@ using namespace llvm;
namespace lld {
namespace coff {
+static Timer LTOTimer("LTO", Timer::root());
+
SymbolTable *Symtab;
void SymbolTable::addFile(InputFile *File) {
@@ -34,8 +38,9 @@ void SymbolTable::addFile(InputFile *File) {
if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
Config->Machine = MT;
} else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Machine != MT) {
- fatal(toString(File) + ": machine type " + machineToStr(MT) +
+ error(toString(File) + ": machine type " + machineToStr(MT) +
" conflicts with " + machineToStr(Config->Machine));
+ return;
}
if (auto *F = dyn_cast<ObjFile>(File)) {
@@ -61,6 +66,66 @@ static void errorOrWarn(const Twine &S) {
error(S);
}
+// Returns the name of the symbol in SC whose value is <= Addr that is closest
+// to Addr. This is generally the name of the global variable or function whose
+// definition contains Addr.
+static StringRef getSymbolName(SectionChunk *SC, uint32_t Addr) {
+ DefinedRegular *Candidate = nullptr;
+
+ for (Symbol *S : SC->File->getSymbols()) {
+ auto *D = dyn_cast_or_null<DefinedRegular>(S);
+ if (!D || D->getChunk() != SC || D->getValue() > Addr ||
+ (Candidate && D->getValue() < Candidate->getValue()))
+ continue;
+
+ Candidate = D;
+ }
+
+ if (!Candidate)
+ return "";
+ return Candidate->getName();
+}
+
+static std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
+ struct Location {
+ StringRef SymName;
+ std::pair<StringRef, uint32_t> FileLine;
+ };
+ std::vector<Location> Locations;
+
+ for (Chunk *C : File->getChunks()) {
+ auto *SC = dyn_cast<SectionChunk>(C);
+ if (!SC)
+ continue;
+ for (const coff_relocation &R : SC->Relocs) {
+ if (R.SymbolTableIndex != SymIndex)
+ continue;
+ std::pair<StringRef, uint32_t> FileLine =
+ getFileLine(SC, R.VirtualAddress);
+ StringRef SymName = getSymbolName(SC, R.VirtualAddress);
+ if (!FileLine.first.empty() || !SymName.empty())
+ Locations.push_back({SymName, FileLine});
+ }
+ }
+
+ if (Locations.empty())
+ return "\n>>> referenced by " + toString(File) + "\n";
+
+ std::string Out;
+ llvm::raw_string_ostream OS(Out);
+ for (Location Loc : Locations) {
+ OS << "\n>>> referenced by ";
+ if (!Loc.FileLine.first.empty())
+ OS << Loc.FileLine.first << ":" << Loc.FileLine.second
+ << "\n>>> ";
+ OS << toString(File);
+ if (!Loc.SymName.empty())
+ OS << ":(" << Loc.SymName << ')';
+ }
+ OS << '\n';
+ return OS.str();
+}
+
void SymbolTable::reportRemainingUndefines() {
SmallPtrSet<Symbol *, 8> Undefs;
DenseMap<Symbol *, Symbol *> LocalImports;
@@ -120,20 +185,23 @@ void SymbolTable::reportRemainingUndefines() {
if (Config->WarnLocallyDefinedImported)
if (Symbol *Imp = LocalImports.lookup(B))
warn("<root>: locally defined symbol imported: " + Imp->getName() +
- " (defined in " + toString(Imp->getFile()) + ")");
+ " (defined in " + toString(Imp->getFile()) + ") [LNK4217]");
}
for (ObjFile *File : ObjFile::Instances) {
+ size_t SymIndex = (size_t)-1;
for (Symbol *Sym : File->getSymbols()) {
+ ++SymIndex;
if (!Sym)
continue;
if (Undefs.count(Sym))
- errorOrWarn(toString(File) + ": undefined symbol: " + Sym->getName());
+ errorOrWarn("undefined symbol: " + Sym->getName() +
+ getSymbolLocations(File, SymIndex));
if (Config->WarnLocallyDefinedImported)
if (Symbol *Imp = LocalImports.lookup(Sym))
warn(toString(File) + ": locally defined symbol imported: " +
Imp->getName() + " (defined in " + toString(Imp->getFile()) +
- ")");
+ ") [LNK4217]");
}
}
}
@@ -142,7 +210,7 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
if (Sym)
return {Sym, false};
- Sym = (Symbol *)make<SymbolUnion>();
+ Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
Sym->IsUsedInRegularObj = false;
Sym->PendingArchiveLoad = false;
return {Sym, true};
@@ -274,30 +342,29 @@ Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size,
return S;
}
-DefinedImportData *SymbolTable::addImportData(StringRef N, ImportFile *F) {
+Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {
replaceSymbol<DefinedImportData>(S, N, F);
- return cast<DefinedImportData>(S);
+ return S;
}
reportDuplicate(S, F);
return nullptr;
}
-DefinedImportThunk *SymbolTable::addImportThunk(StringRef Name,
- DefinedImportData *ID,
- uint16_t Machine) {
+Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID,
+ uint16_t Machine) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {
replaceSymbol<DefinedImportThunk>(S, Name, ID, Machine);
- return cast<DefinedImportThunk>(S);
+ return S;
}
reportDuplicate(S, ID->File);
@@ -314,10 +381,7 @@ std::vector<Chunk *> SymbolTable::getChunks() {
}
Symbol *SymbolTable::find(StringRef Name) {
- auto It = SymMap.find(CachedHashStringRef(Name));
- if (It == SymMap.end())
- return nullptr;
- return It->second;
+ return SymMap.lookup(CachedHashStringRef(Name));
}
Symbol *SymbolTable::findUnderscore(StringRef Name) {
@@ -384,6 +448,8 @@ std::vector<StringRef> SymbolTable::compileBitcodeFiles() {
void SymbolTable::addCombinedLTOObjects() {
if (BitcodeFile::Instances.empty())
return;
+
+ ScopedTimer T(LTOTimer);
for (StringRef Object : compileBitcodeFiles()) {
auto *Obj = make<ObjFile>(MemoryBufferRef(Object, "lto.tmp"));
Obj->parse();
diff --git a/contrib/llvm/tools/lld/COFF/SymbolTable.h b/contrib/llvm/tools/lld/COFF/SymbolTable.h
index 55481e6475bb..30cb1a5410c3 100644
--- a/contrib/llvm/tools/lld/COFF/SymbolTable.h
+++ b/contrib/llvm/tools/lld/COFF/SymbolTable.h
@@ -92,9 +92,9 @@ public:
Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size,
const llvm::object::coff_symbol_generic *S = nullptr,
CommonChunk *C = nullptr);
- DefinedImportData *addImportData(StringRef N, ImportFile *F);
- DefinedImportThunk *addImportThunk(StringRef Name, DefinedImportData *S,
- uint16_t Machine);
+ Symbol *addImportData(StringRef N, ImportFile *F);
+ Symbol *addImportThunk(StringRef Name, DefinedImportData *S,
+ uint16_t Machine);
void reportDuplicate(Symbol *Existing, InputFile *NewFile);
diff --git a/contrib/llvm/tools/lld/COFF/Symbols.cpp b/contrib/llvm/tools/lld/COFF/Symbols.cpp
index 4c5ab48c7565..7c8b7d5e8fc5 100644
--- a/contrib/llvm/tools/lld/COFF/Symbols.cpp
+++ b/contrib/llvm/tools/lld/COFF/Symbols.cpp
@@ -9,9 +9,9 @@
#include "Symbols.h"
#include "InputFiles.h"
-#include "Strings.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -21,7 +21,7 @@ using namespace llvm::object;
// Returns a symbol name for an error message.
std::string lld::toString(coff::Symbol &B) {
- if (Optional<std::string> S = coff::demangleMSVC(B.getName()))
+ if (Optional<std::string> S = lld::demangleMSVC(B.getName()))
return ("\"" + *S + "\" (" + B.getName() + ")").str();
return B.getName();
}
@@ -58,7 +58,7 @@ bool Symbol::isLive() const {
if (auto *Imp = dyn_cast<DefinedImportData>(this))
return Imp->File->Live;
if (auto *Imp = dyn_cast<DefinedImportThunk>(this))
- return Imp->WrappedSym->File->Live;
+ return Imp->WrappedSym->File->ThunkLive;
// Assume any other kind of symbol is live.
return true;
}
@@ -71,7 +71,7 @@ COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(Sym));
}
-uint16_t DefinedAbsolute::OutputSectionIndex = 0;
+uint16_t DefinedAbsolute::NumOutputSections;
static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) {
if (Machine == AMD64)
diff --git a/contrib/llvm/tools/lld/COFF/Symbols.h b/contrib/llvm/tools/lld/COFF/Symbols.h
index d8a030705e27..783965adbd9a 100644
--- a/contrib/llvm/tools/lld/COFF/Symbols.h
+++ b/contrib/llvm/tools/lld/COFF/Symbols.h
@@ -213,11 +213,10 @@ public:
uint64_t getRVA() { return VA - Config->ImageBase; }
void setVA(uint64_t V) { VA = V; }
- // The sentinel absolute symbol section index. Section index relocations
- // against absolute symbols resolve to this 16 bit number, and it is the
- // largest valid section index plus one. This is written by the Writer.
- static uint16_t OutputSectionIndex;
- uint16_t getSecIdx() { return OutputSectionIndex; }
+ // Section index relocations against absolute symbols resolve to
+ // this 16 bit number, and it is the largest valid section index
+ // plus one. This variable keeps it.
+ static uint16_t NumOutputSections;
private:
uint64_t VA;
@@ -416,6 +415,8 @@ union SymbolUnion {
template <typename T, typename... ArgT>
void replaceSymbol(Symbol *S, ArgT &&... Arg) {
+ static_assert(std::is_trivially_destructible<T>(),
+ "Symbol types must be trivially destructible");
static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small");
static_assert(alignof(T) <= alignof(SymbolUnion),
"SymbolUnion not aligned enough");
diff --git a/contrib/llvm/tools/lld/COFF/Writer.cpp b/contrib/llvm/tools/lld/COFF/Writer.cpp
index 584f0621bea3..d17405ec26ab 100644
--- a/contrib/llvm/tools/lld/COFF/Writer.cpp
+++ b/contrib/llvm/tools/lld/COFF/Writer.cpp
@@ -17,6 +17,7 @@
#include "Symbols.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Timer.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
@@ -25,7 +26,9 @@
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Parallel.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/RandomNumberGenerator.h"
+#include "llvm/Support/xxhash.h"
#include <algorithm>
#include <cstdio>
#include <map>
@@ -40,8 +43,40 @@ using namespace llvm::support::endian;
using namespace lld;
using namespace lld::coff;
+/* To re-generate DOSProgram:
+$ cat > /tmp/DOSProgram.asm
+org 0
+ ; Copy cs to ds.
+ push cs
+ pop ds
+ ; Point ds:dx at the $-terminated string.
+ mov dx, str
+ ; Int 21/AH=09h: Write string to standard output.
+ mov ah, 0x9
+ int 0x21
+ ; Int 21/AH=4Ch: Exit with return code (in AL).
+ mov ax, 0x4C01
+ int 0x21
+str:
+ db 'This program cannot be run in DOS mode.$'
+align 8, db 0
+$ nasm -fbin /tmp/DOSProgram.asm -o /tmp/DOSProgram.bin
+$ xxd -i /tmp/DOSProgram.bin
+*/
+static unsigned char DOSProgram[] = {
+ 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c,
+ 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
+ 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65,
+ 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
+ 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x24, 0x00, 0x00
+};
+static_assert(sizeof(DOSProgram) % 8 == 0,
+ "DOSProgram size must be multiple of 8");
+
static const int SectorSize = 512;
-static const int DOSStubSize = 64;
+static const int DOSStubSize = sizeof(dos_header) + sizeof(DOSProgram);
+static_assert(DOSStubSize % 8 == 0, "DOSStub size must be multiple of 8");
+
static const int NumberfOfDataDirectory = 16;
namespace {
@@ -69,24 +104,25 @@ public:
uint64_t Offs = OS->getFileOff() + (Record->getRVA() - OS->getRVA());
D->PointerToRawData = Offs;
+ TimeDateStamps.push_back(&D->TimeDateStamp);
++D;
}
}
+ void setTimeDateStamp(uint32_t TimeDateStamp) {
+ for (support::ulittle32_t *TDS : TimeDateStamps)
+ *TDS = TimeDateStamp;
+ }
+
private:
+ mutable std::vector<support::ulittle32_t *> TimeDateStamps;
const std::vector<Chunk *> &Records;
};
class CVDebugRecordChunk : public Chunk {
public:
- CVDebugRecordChunk() {
- PDBAbsPath = Config->PDBPath;
- if (!PDBAbsPath.empty())
- llvm::sys::fs::make_absolute(PDBAbsPath);
- }
-
size_t getSize() const override {
- return sizeof(codeview::DebugInfo) + PDBAbsPath.size() + 1;
+ return sizeof(codeview::DebugInfo) + Config->PDBAltPath.size() + 1;
}
void writeTo(uint8_t *B) const override {
@@ -96,12 +132,11 @@ public:
// variable sized field (PDB Path)
char *P = reinterpret_cast<char *>(B + OutputSectionOff + sizeof(*BuildId));
- if (!PDBAbsPath.empty())
- memcpy(P, PDBAbsPath.data(), PDBAbsPath.size());
- P[PDBAbsPath.size()] = '\0';
+ if (!Config->PDBAltPath.empty())
+ memcpy(P, Config->PDBAltPath.data(), Config->PDBAltPath.size());
+ P[Config->PDBAltPath.size()] = '\0';
}
- SmallString<128> PDBAbsPath;
mutable codeview::DebugInfo *BuildId = nullptr;
};
@@ -116,12 +151,19 @@ private:
void createMiscChunks();
void createImportTables();
void createExportTable();
+ void mergeSections();
void assignAddresses();
void removeEmptySections();
void createSymbolAndStringTable();
void openFile(StringRef OutputPath);
template <typename PEHeaderTy> void writeHeader();
- void createSEHTable(OutputSection *RData);
+ void createSEHTable();
+ void createGuardCFTables();
+ void markSymbolsForRVATable(ObjFile *File,
+ ArrayRef<SectionChunk *> SymIdxChunks,
+ SymbolRVASet &TableSymbols);
+ void maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
+ StringRef CountSym);
void setSectionPermissions();
void writeSections();
void writeBuildId();
@@ -131,9 +173,8 @@ private:
size_t addEntryToStringTable(StringRef Str);
OutputSection *findSection(StringRef Name);
- OutputSection *createSection(StringRef Name);
- void addBaserels(OutputSection *Dest);
- void addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V);
+ void addBaserels();
+ void addBaserelBlocks(std::vector<Baserel> &V);
uint32_t getSizeOfInitializedData();
std::map<StringRef, std::vector<DefinedImportData *>> binImports();
@@ -145,9 +186,9 @@ private:
IdataContents Idata;
DelayLoadContents DelayIdata;
EdataContents Edata;
- SEHTableChunk *SEHTable = nullptr;
+ bool SetNoSEHCharacteristic = false;
- Chunk *DebugDirectory = nullptr;
+ DebugDirectoryChunk *DebugDirectory = nullptr;
std::vector<Chunk *> DebugRecords;
CVDebugRecordChunk *BuildId = nullptr;
Optional<codeview::DebugInfo> PreviousBuildId;
@@ -157,50 +198,55 @@ private:
uint32_t PointerToSymbolTable = 0;
uint64_t SizeOfImage;
uint64_t SizeOfHeaders;
+
+ OutputSection *TextSec;
+ OutputSection *RdataSec;
+ OutputSection *BuildidSec;
+ OutputSection *DataSec;
+ OutputSection *PdataSec;
+ OutputSection *IdataSec;
+ OutputSection *EdataSec;
+ OutputSection *DidatSec;
+ OutputSection *RsrcSec;
+ OutputSection *RelocSec;
+
+ // The first and last .pdata sections in the output file.
+ //
+ // We need to keep track of the location of .pdata in whichever section it
+ // gets merged into so that we can sort its contents and emit a correct data
+ // directory entry for the exception table. This is also the case for some
+ // other sections (such as .edata) but because the contents of those sections
+ // are entirely linker-generated we can keep track of their locations using
+ // the chunks that the linker creates. All .pdata chunks come from input
+ // files, so we need to keep track of them separately.
+ Chunk *FirstPdata = nullptr;
+ Chunk *LastPdata;
};
} // anonymous namespace
namespace lld {
namespace coff {
-void writeResult() { Writer().run(); }
-
-void OutputSection::setRVA(uint64_t RVA) {
- Header.VirtualAddress = RVA;
- for (Chunk *C : Chunks)
- C->setRVA(C->getRVA() + RVA);
-}
+static Timer CodeLayoutTimer("Code Layout", Timer::root());
+static Timer DiskCommitTimer("Commit Output File", Timer::root());
-void OutputSection::setFileOffset(uint64_t Off) {
- // If a section has no actual data (i.e. BSS section), we want to
- // set 0 to its PointerToRawData. Otherwise the output is rejected
- // by the loader.
- if (Header.SizeOfRawData == 0)
- return;
- Header.PointerToRawData = Off;
-}
+void writeResult() { Writer().run(); }
void OutputSection::addChunk(Chunk *C) {
Chunks.push_back(C);
C->setOutputSection(this);
- uint64_t Off = Header.VirtualSize;
- Off = alignTo(Off, C->Alignment);
- C->setRVA(Off);
- C->OutputSectionOff = Off;
- Off += C->getSize();
- if (Off > UINT32_MAX)
- error("section larger than 4 GiB: " + Name);
- Header.VirtualSize = Off;
- if (C->hasData())
- Header.SizeOfRawData = alignTo(Off, SectorSize);
}
-void OutputSection::addPermissions(uint32_t C) {
- Header.Characteristics |= C & PermMask;
+void OutputSection::setPermissions(uint32_t C) {
+ Header.Characteristics &= ~PermMask;
+ Header.Characteristics |= C;
}
-void OutputSection::setPermissions(uint32_t C) {
- Header.Characteristics = C & PermMask;
+void OutputSection::merge(OutputSection *Other) {
+ for (Chunk *C : Other->Chunks)
+ C->setOutputSection(this);
+ Chunks.insert(Chunks.end(), Other->Chunks.begin(), Other->Chunks.end());
+ Other->Chunks.clear();
}
// Write the section header to a given buffer.
@@ -284,17 +330,22 @@ static Optional<codeview::DebugInfo> loadExistingBuildId(StringRef Path) {
// The main function of the writer.
void Writer::run() {
+ ScopedTimer T1(CodeLayoutTimer);
+
createSections();
createMiscChunks();
createImportTables();
createExportTable();
- if (Config->Relocatable)
- createSection(".reloc");
+ mergeSections();
assignAddresses();
removeEmptySections();
setSectionPermissions();
createSymbolAndStringTable();
+ if (FileSize > UINT32_MAX)
+ fatal("image size (" + Twine(FileSize) + ") " +
+ "exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")");
+
// We must do this before opening the output file, as it depends on being able
// to read the contents of the existing output file.
PreviousBuildId = loadExistingBuildId(Config->OutputFile);
@@ -308,35 +359,79 @@ void Writer::run() {
sortExceptionTable();
writeBuildId();
- if (!Config->PDBPath.empty() && Config->Debug) {
+ T1.stop();
+ if (!Config->PDBPath.empty() && Config->Debug) {
assert(BuildId);
createPDB(Symtab, OutputSections, SectionTable, *BuildId->BuildId);
}
writeMapFile(OutputSections);
+ ScopedTimer T2(DiskCommitTimer);
if (auto E = Buffer->commit())
fatal("failed to write the output file: " + toString(std::move(E)));
}
-static StringRef getOutputSection(StringRef Name) {
+static StringRef getOutputSectionName(StringRef Name) {
StringRef S = Name.split('$').first;
// Treat a later period as a separator for MinGW, for sections like
// ".ctors.01234".
- S = S.substr(0, S.find('.', 1));
+ return S.substr(0, S.find('.', 1));
+}
- auto It = Config->Merge.find(S);
- if (It == Config->Merge.end())
- return S;
- return It->second;
+// For /order.
+static void sortBySectionOrder(std::vector<Chunk *> &Chunks) {
+ auto GetPriority = [](const Chunk *C) {
+ if (auto *Sec = dyn_cast<SectionChunk>(C))
+ if (Sec->Sym)
+ return Config->Order.lookup(Sec->Sym->getName());
+ return 0;
+ };
+
+ std::stable_sort(Chunks.begin(), Chunks.end(),
+ [=](const Chunk *A, const Chunk *B) {
+ return GetPriority(A) < GetPriority(B);
+ });
}
// Create output section objects and add them to OutputSections.
void Writer::createSections() {
- // First, bin chunks by name.
- std::map<StringRef, std::vector<Chunk *>> Map;
+ // First, create the builtin sections.
+ const uint32_t DATA = IMAGE_SCN_CNT_INITIALIZED_DATA;
+ const uint32_t BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+ const uint32_t CODE = IMAGE_SCN_CNT_CODE;
+ const uint32_t DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE;
+ const uint32_t R = IMAGE_SCN_MEM_READ;
+ const uint32_t W = IMAGE_SCN_MEM_WRITE;
+ const uint32_t X = IMAGE_SCN_MEM_EXECUTE;
+
+ SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> Sections;
+ auto CreateSection = [&](StringRef Name, uint32_t OutChars) {
+ OutputSection *&Sec = Sections[{Name, OutChars}];
+ if (!Sec) {
+ Sec = make<OutputSection>(Name, OutChars);
+ OutputSections.push_back(Sec);
+ }
+ return Sec;
+ };
+
+ // Try to match the section order used by link.exe.
+ TextSec = CreateSection(".text", CODE | R | X);
+ CreateSection(".bss", BSS | R | W);
+ RdataSec = CreateSection(".rdata", DATA | R);
+ BuildidSec = CreateSection(".buildid", DATA | R);
+ DataSec = CreateSection(".data", DATA | R | W);
+ PdataSec = CreateSection(".pdata", DATA | R);
+ IdataSec = CreateSection(".idata", DATA | R);
+ EdataSec = CreateSection(".edata", DATA | R);
+ DidatSec = CreateSection(".didat", DATA | R);
+ RsrcSec = CreateSection(".rsrc", DATA | R);
+ RelocSec = CreateSection(".reloc", DATA | DISCARDABLE | R);
+
+ // Then bin chunks by name and output characteristics.
+ std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> Map;
for (Chunk *C : Symtab->getChunks()) {
auto *SC = dyn_cast<SectionChunk>(C);
if (SC && !SC->isLive()) {
@@ -344,42 +439,71 @@ void Writer::createSections() {
SC->printDiscardedMessage();
continue;
}
- Map[C->getSectionName()].push_back(C);
+ Map[{C->getSectionName(), C->getOutputCharacteristics()}].push_back(C);
}
+ // Process an /order option.
+ if (!Config->Order.empty())
+ for (auto &Pair : Map)
+ sortBySectionOrder(Pair.second);
+
// Then create an OutputSection for each section.
// '$' and all following characters in input section names are
// discarded when determining output section. So, .text$foo
// contributes to .text, for example. See PE/COFF spec 3.2.
- SmallDenseMap<StringRef, OutputSection *> Sections;
for (auto Pair : Map) {
- StringRef Name = getOutputSection(Pair.first);
- OutputSection *&Sec = Sections[Name];
- if (!Sec) {
- Sec = make<OutputSection>(Name);
- OutputSections.push_back(Sec);
- }
+ StringRef Name = getOutputSectionName(Pair.first.first);
+ uint32_t OutChars = Pair.first.second;
+
+ // In link.exe, there is a special case for the I386 target where .CRT
+ // sections are treated as if they have output characteristics DATA | R if
+ // their characteristics are DATA | R | W. This implements the same special
+ // case for all architectures.
+ if (Name == ".CRT")
+ OutChars = DATA | R;
+
+ OutputSection *Sec = CreateSection(Name, OutChars);
std::vector<Chunk *> &Chunks = Pair.second;
- for (Chunk *C : Chunks) {
+ for (Chunk *C : Chunks)
Sec->addChunk(C);
- Sec->addPermissions(C->getPermissions());
- }
}
+
+ // Finally, move some output sections to the end.
+ auto SectionOrder = [&](OutputSection *S) {
+ // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because
+ // the loader cannot handle holes. Stripping can remove other discardable ones
+ // than .reloc, which is first of them (created early).
+ if (S->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
+ return 2;
+ // .rsrc should come at the end of the non-discardable sections because its
+ // size may change by the Win32 UpdateResources() function, causing
+ // subsequent sections to move (see https://crbug.com/827082).
+ if (S == RsrcSec)
+ return 1;
+ return 0;
+ };
+ std::stable_sort(OutputSections.begin(), OutputSections.end(),
+ [&](OutputSection *S, OutputSection *T) {
+ return SectionOrder(S) < SectionOrder(T);
+ });
}
void Writer::createMiscChunks() {
- OutputSection *RData = createSection(".rdata");
+ for (auto &P : MergeChunk::Instances)
+ RdataSec->addChunk(P.second);
// Create thunks for locally-dllimported symbols.
if (!Symtab->LocalImportChunks.empty()) {
for (Chunk *C : Symtab->LocalImportChunks)
- RData->addChunk(C);
+ RdataSec->addChunk(C);
}
// Create Debug Information Chunks
if (Config->Debug) {
DebugDirectory = make<DebugDirectoryChunk>(DebugRecords);
+ OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec;
+
// Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We
// output a PDB no matter what, and this chunk provides the only means of
// allowing a debugger to match a PDB and an executable. So we need it even
@@ -388,12 +512,18 @@ void Writer::createMiscChunks() {
BuildId = CVChunk;
DebugRecords.push_back(CVChunk);
- RData->addChunk(DebugDirectory);
+ DebugInfoSec->addChunk(DebugDirectory);
for (Chunk *C : DebugRecords)
- RData->addChunk(C);
+ DebugInfoSec->addChunk(C);
}
- createSEHTable(RData);
+ // Create SEH table. x86-only.
+ if (Config->Machine == I386)
+ createSEHTable();
+
+ // Create /guard:cf tables if requested.
+ if (Config->GuardCF != GuardCFLevel::Off)
+ createGuardCFTables();
}
// Create .idata section for the DLL-imported symbol table.
@@ -414,53 +544,49 @@ void Writer::createImportTables() {
std::string DLL = StringRef(File->DLLName).lower();
if (Config->DLLOrder.count(DLL) == 0)
Config->DLLOrder[DLL] = Config->DLLOrder.size();
- }
- OutputSection *Text = createSection(".text");
- for (ImportFile *File : ImportFile::Instances) {
- if (!File->Live)
- continue;
-
- if (DefinedImportThunk *Thunk = File->ThunkSym)
- Text->addChunk(Thunk->getChunk());
+ if (File->ThunkSym) {
+ if (!isa<DefinedImportThunk>(File->ThunkSym))
+ fatal(toString(*File->ThunkSym) + " was replaced");
+ DefinedImportThunk *Thunk = cast<DefinedImportThunk>(File->ThunkSym);
+ if (File->ThunkLive)
+ TextSec->addChunk(Thunk->getChunk());
+ }
+ if (File->ImpSym && !isa<DefinedImportData>(File->ImpSym))
+ fatal(toString(*File->ImpSym) + " was replaced");
+ DefinedImportData *ImpSym = cast_or_null<DefinedImportData>(File->ImpSym);
if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) {
if (!File->ThunkSym)
fatal("cannot delay-load " + toString(File) +
- " due to import of data: " + toString(*File->ImpSym));
- DelayIdata.add(File->ImpSym);
+ " due to import of data: " + toString(*ImpSym));
+ DelayIdata.add(ImpSym);
} else {
- Idata.add(File->ImpSym);
+ Idata.add(ImpSym);
}
}
- if (!Idata.empty()) {
- OutputSection *Sec = createSection(".idata");
+ if (!Idata.empty())
for (Chunk *C : Idata.getChunks())
- Sec->addChunk(C);
- }
+ IdataSec->addChunk(C);
if (!DelayIdata.empty()) {
Defined *Helper = cast<Defined>(Config->DelayLoadHelper);
DelayIdata.create(Helper);
- OutputSection *Sec = createSection(".didat");
for (Chunk *C : DelayIdata.getChunks())
- Sec->addChunk(C);
- Sec = createSection(".data");
+ DidatSec->addChunk(C);
for (Chunk *C : DelayIdata.getDataChunks())
- Sec->addChunk(C);
- Sec = createSection(".text");
+ DataSec->addChunk(C);
for (Chunk *C : DelayIdata.getCodeChunks())
- Sec->addChunk(C);
+ TextSec->addChunk(C);
}
}
void Writer::createExportTable() {
if (Config->Exports.empty())
return;
- OutputSection *Sec = createSection(".edata");
for (Chunk *C : Edata.Chunks)
- Sec->addChunk(C);
+ EdataSec->addChunk(C);
}
// The Windows loader doesn't seem to like empty sections,
@@ -484,19 +610,31 @@ size_t Writer::addEntryToStringTable(StringRef Str) {
}
Optional<coff_symbol16> Writer::createSymbol(Defined *Def) {
- // Relative symbols are unrepresentable in a COFF symbol table.
- if (isa<DefinedSynthetic>(Def))
- return None;
-
- // Don't write dead symbols or symbols in codeview sections to the symbol
- // table.
- if (!Def->isLive())
+ coff_symbol16 Sym;
+ switch (Def->kind()) {
+ case Symbol::DefinedAbsoluteKind:
+ Sym.Value = Def->getRVA();
+ Sym.SectionNumber = IMAGE_SYM_ABSOLUTE;
+ break;
+ case Symbol::DefinedSyntheticKind:
+ // Relative symbols are unrepresentable in a COFF symbol table.
return None;
- if (auto *D = dyn_cast<DefinedRegular>(Def))
- if (D->getChunk()->isCodeView())
+ default: {
+ // Don't write symbols that won't be written to the output to the symbol
+ // table.
+ Chunk *C = Def->getChunk();
+ if (!C)
+ return None;
+ OutputSection *OS = C->getOutputSection();
+ if (!OS)
return None;
- coff_symbol16 Sym;
+ Sym.Value = Def->getRVA() - OS->getRVA();
+ Sym.SectionNumber = OS->SectionIndex;
+ break;
+ }
+ }
+
StringRef Name = Def->getName();
if (Name.size() > COFF::NameSize) {
Sym.Name.Offset.Zeroes = 0;
@@ -515,46 +653,27 @@ Optional<coff_symbol16> Writer::createSymbol(Defined *Def) {
Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
}
Sym.NumberOfAuxSymbols = 0;
-
- switch (Def->kind()) {
- case Symbol::DefinedAbsoluteKind:
- Sym.Value = Def->getRVA();
- Sym.SectionNumber = IMAGE_SYM_ABSOLUTE;
- break;
- default: {
- uint64_t RVA = Def->getRVA();
- OutputSection *Sec = nullptr;
- for (OutputSection *S : OutputSections) {
- if (S->getRVA() > RVA)
- break;
- Sec = S;
- }
- Sym.Value = RVA - Sec->getRVA();
- Sym.SectionNumber = Sec->SectionIndex;
- break;
- }
- }
return Sym;
}
void Writer::createSymbolAndStringTable() {
- // Name field in the section table is 8 byte long. Longer names need
- // to be written to the string table. First, construct string table.
+ // PE/COFF images are limited to 8 byte section names. Longer names can be
+ // supported by writing a non-standard string table, but this string table is
+ // not mapped at runtime and the long names will therefore be inaccessible.
+ // link.exe always truncates section names to 8 bytes, whereas binutils always
+ // preserves long section names via the string table. LLD adopts a hybrid
+ // solution where discardable sections have long names preserved and
+ // non-discardable sections have their names truncated, to ensure that any
+ // section which is mapped at runtime also has its name mapped at runtime.
for (OutputSection *Sec : OutputSections) {
- StringRef Name = Sec->getName();
- if (Name.size() <= COFF::NameSize)
+ if (Sec->Name.size() <= COFF::NameSize)
continue;
- // If a section isn't discardable (i.e. will be mapped at runtime),
- // prefer a truncated section name over a long section name in
- // the string table that is unavailable at runtime. This is different from
- // what link.exe does, but finding ".eh_fram" instead of "/4" is useful
- // to libunwind.
- if ((Sec->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0)
+ if ((Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
continue;
- Sec->setStringTableOff(addEntryToStringTable(Name));
+ Sec->setStringTableOff(addEntryToStringTable(Sec->Name));
}
- if (Config->DebugDwarf) {
+ if (Config->DebugDwarf || Config->DebugSymtab) {
for (ObjFile *File : ObjFile::Instances) {
for (Symbol *B : File->getSymbols()) {
auto *D = dyn_cast_or_null<Defined>(B);
@@ -571,16 +690,45 @@ void Writer::createSymbolAndStringTable() {
if (OutputSymtab.empty() && Strtab.empty())
return;
- OutputSection *LastSection = OutputSections.back();
// We position the symbol table to be adjacent to the end of the last section.
- uint64_t FileOff = LastSection->getFileOff() +
- alignTo(LastSection->getRawSize(), SectorSize);
+ uint64_t FileOff = FileSize;
PointerToSymbolTable = FileOff;
FileOff += OutputSymtab.size() * sizeof(coff_symbol16);
FileOff += 4 + Strtab.size();
FileSize = alignTo(FileOff, SectorSize);
}
+void Writer::mergeSections() {
+ if (!PdataSec->getChunks().empty()) {
+ FirstPdata = PdataSec->getChunks().front();
+ LastPdata = PdataSec->getChunks().back();
+ }
+
+ for (auto &P : Config->Merge) {
+ StringRef ToName = P.second;
+ if (P.first == ToName)
+ continue;
+ StringSet<> Names;
+ while (1) {
+ if (!Names.insert(ToName).second)
+ fatal("/merge: cycle found for section '" + P.first + "'");
+ auto I = Config->Merge.find(ToName);
+ if (I == Config->Merge.end())
+ break;
+ ToName = I->second;
+ }
+ OutputSection *From = findSection(P.first);
+ OutputSection *To = findSection(ToName);
+ if (!From)
+ continue;
+ if (!To) {
+ From->Name = ToName;
+ continue;
+ }
+ To->merge(From);
+ }
+}
+
// Visits all sections to assign incremental, non-overlapping RVAs and
// file offsets.
void Writer::assignAddresses() {
@@ -590,35 +738,57 @@ void Writer::assignAddresses() {
SizeOfHeaders +=
Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);
SizeOfHeaders = alignTo(SizeOfHeaders, SectorSize);
- uint64_t RVA = 0x1000; // The first page is kept unmapped.
+ uint64_t RVA = PageSize; // The first page is kept unmapped.
FileSize = SizeOfHeaders;
- // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because
- // the loader cannot handle holes.
- std::stable_partition(
- OutputSections.begin(), OutputSections.end(), [](OutputSection *S) {
- return (S->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0;
- });
+
for (OutputSection *Sec : OutputSections) {
- if (Sec->getName() == ".reloc")
- addBaserels(Sec);
- Sec->setRVA(RVA);
- Sec->setFileOffset(FileSize);
- RVA += alignTo(Sec->getVirtualSize(), PageSize);
- FileSize += alignTo(Sec->getRawSize(), SectorSize);
+ if (Sec == RelocSec)
+ addBaserels();
+ uint64_t RawSize = 0, VirtualSize = 0;
+ Sec->Header.VirtualAddress = RVA;
+ for (Chunk *C : Sec->getChunks()) {
+ VirtualSize = alignTo(VirtualSize, C->Alignment);
+ C->setRVA(RVA + VirtualSize);
+ C->OutputSectionOff = VirtualSize;
+ C->finalizeContents();
+ VirtualSize += C->getSize();
+ if (C->hasData())
+ RawSize = alignTo(VirtualSize, SectorSize);
+ }
+ if (VirtualSize > UINT32_MAX)
+ error("section larger than 4 GiB: " + Sec->Name);
+ Sec->Header.VirtualSize = VirtualSize;
+ Sec->Header.SizeOfRawData = RawSize;
+ if (RawSize != 0)
+ Sec->Header.PointerToRawData = FileSize;
+ RVA += alignTo(VirtualSize, PageSize);
+ FileSize += alignTo(RawSize, SectorSize);
}
SizeOfImage = alignTo(RVA, PageSize);
}
template <typename PEHeaderTy> void Writer::writeHeader() {
- // Write DOS stub
+ // Write DOS header. For backwards compatibility, the first part of a PE/COFF
+ // executable consists of an MS-DOS MZ executable. If the executable is run
+ // under DOS, that program gets run (usually to just print an error message).
+ // When run under Windows, the loader looks at AddressOfNewExeHeader and uses
+ // the PE header instead.
uint8_t *Buf = Buffer->getBufferStart();
auto *DOS = reinterpret_cast<dos_header *>(Buf);
- Buf += DOSStubSize;
+ Buf += sizeof(dos_header);
DOS->Magic[0] = 'M';
DOS->Magic[1] = 'Z';
+ DOS->UsedBytesInTheLastPage = DOSStubSize % 512;
+ DOS->FileSizeInPages = divideCeil(DOSStubSize, 512);
+ DOS->HeaderSizeInParagraphs = sizeof(dos_header) / 16;
+
DOS->AddressOfRelocationTable = sizeof(dos_header);
DOS->AddressOfNewExeHeader = DOSStubSize;
+ // Write DOS program.
+ memcpy(Buf, DOSProgram, sizeof(DOSProgram));
+ Buf += sizeof(DOSProgram);
+
// Write PE magic
memcpy(Buf, PEMagic, sizeof(PEMagic));
Buf += sizeof(PEMagic);
@@ -688,24 +858,27 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
if (!Config->AllowIsolation)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION;
- if (Config->Machine == I386 && !SEHTable &&
- !Symtab->findUnderscore("_load_config_used"))
+ if (Config->GuardCF != GuardCFLevel::Off)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF;
+ if (Config->IntegrityCheck)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY;
+ if (SetNoSEHCharacteristic)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH;
if (Config->TerminalServerAware)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;
PE->NumberOfRvaAndSize = NumberfOfDataDirectory;
- if (OutputSection *Text = findSection(".text")) {
- PE->BaseOfCode = Text->getRVA();
- PE->SizeOfCode = Text->getRawSize();
+ if (TextSec->getVirtualSize()) {
+ PE->BaseOfCode = TextSec->getRVA();
+ PE->SizeOfCode = TextSec->getRawSize();
}
PE->SizeOfInitializedData = getSizeOfInitializedData();
// Write data directory
auto *Dir = reinterpret_cast<data_directory *>(Buf);
Buf += sizeof(*Dir) * NumberfOfDataDirectory;
- if (OutputSection *Sec = findSection(".edata")) {
- Dir[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA();
- Dir[EXPORT_TABLE].Size = Sec->getVirtualSize();
+ if (!Config->Exports.empty()) {
+ Dir[EXPORT_TABLE].RelativeVirtualAddress = Edata.getRVA();
+ Dir[EXPORT_TABLE].Size = Edata.getSize();
}
if (!Idata.empty()) {
Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA();
@@ -713,17 +886,18 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA();
Dir[IAT].Size = Idata.getIATSize();
}
- if (OutputSection *Sec = findSection(".rsrc")) {
- Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA();
- Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize();
+ if (RsrcSec->getVirtualSize()) {
+ Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA();
+ Dir[RESOURCE_TABLE].Size = RsrcSec->getVirtualSize();
}
- if (OutputSection *Sec = findSection(".pdata")) {
- Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA();
- Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize();
+ if (FirstPdata) {
+ Dir[EXCEPTION_TABLE].RelativeVirtualAddress = FirstPdata->getRVA();
+ Dir[EXCEPTION_TABLE].Size =
+ LastPdata->getRVA() + LastPdata->getSize() - FirstPdata->getRVA();
}
- if (OutputSection *Sec = findSection(".reloc")) {
- Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA();
- Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize();
+ if (RelocSec->getVirtualSize()) {
+ Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = RelocSec->getRVA();
+ Dir[BASE_RELOCATION_TABLE].Size = RelocSec->getVirtualSize();
}
if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) {
if (Defined *B = dyn_cast<Defined>(Sym)) {
@@ -792,35 +966,172 @@ void Writer::openFile(StringRef Path) {
"failed to open " + Path);
}
-void Writer::createSEHTable(OutputSection *RData) {
- // Create SEH table. x86-only.
- if (Config->Machine != I386)
- return;
-
- std::set<Defined *> Handlers;
+void Writer::createSEHTable() {
+ // Set the no SEH characteristic on x86 binaries unless we find exception
+ // handlers.
+ SetNoSEHCharacteristic = true;
+ SymbolRVASet Handlers;
for (ObjFile *File : ObjFile::Instances) {
- if (!File->SEHCompat)
+ // FIXME: We should error here instead of earlier unless /safeseh:no was
+ // passed.
+ if (!File->hasSafeSEH())
return;
- for (uint32_t I : File->SXData)
- if (Symbol *B = File->getSymbol(I))
- if (B->isLive())
- Handlers.insert(cast<Defined>(B));
+
+ markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers);
+ }
+
+ // Remove the "no SEH" characteristic if all object files were built with
+ // safeseh, we found some exception handlers, and there is a load config in
+ // the object.
+ SetNoSEHCharacteristic =
+ Handlers.empty() || !Symtab->findUnderscore("_load_config_used");
+
+ maybeAddRVATable(std::move(Handlers), "__safe_se_handler_table",
+ "__safe_se_handler_count");
+}
+
+// Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set
+// cannot contain duplicates. Therefore, the set is uniqued by Chunk and the
+// symbol's offset into that Chunk.
+static void addSymbolToRVASet(SymbolRVASet &RVASet, Defined *S) {
+ Chunk *C = S->getChunk();
+ if (auto *SC = dyn_cast<SectionChunk>(C))
+ C = SC->Repl; // Look through ICF replacement.
+ uint32_t Off = S->getRVA() - (C ? C->getRVA() : 0);
+ RVASet.insert({C, Off});
+}
+
+// Visit all relocations from all section contributions of this object file and
+// mark the relocation target as address-taken.
+static void markSymbolsWithRelocations(ObjFile *File,
+ SymbolRVASet &UsedSymbols) {
+ for (Chunk *C : File->getChunks()) {
+ // We only care about live section chunks. Common chunks and other chunks
+ // don't generally contain relocations.
+ SectionChunk *SC = dyn_cast<SectionChunk>(C);
+ if (!SC || !SC->isLive())
+ continue;
+
+ // Look for relocations in this section against symbols in executable output
+ // sections.
+ for (Symbol *Ref : SC->symbols()) {
+ // FIXME: Do further testing to see if the relocation type matters,
+ // especially for 32-bit where taking the address of something usually
+ // uses an absolute relocation instead of a relative one.
+ if (auto *D = dyn_cast_or_null<Defined>(Ref)) {
+ Chunk *RefChunk = D->getChunk();
+ OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
+ if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)
+ addSymbolToRVASet(UsedSymbols, D);
+ }
+ }
+ }
+}
+
+// Create the guard function id table. This is a table of RVAs of all
+// address-taken functions. It is sorted and uniqued, just like the safe SEH
+// table.
+void Writer::createGuardCFTables() {
+ SymbolRVASet AddressTakenSyms;
+ SymbolRVASet LongJmpTargets;
+ for (ObjFile *File : ObjFile::Instances) {
+ // If the object was compiled with /guard:cf, the address taken symbols
+ // are in .gfids$y sections, and the longjmp targets are in .gljmp$y
+ // sections. If the object was not compiled with /guard:cf, we assume there
+ // were no setjmp targets, and that all code symbols with relocations are
+ // possibly address-taken.
+ if (File->hasGuardCF()) {
+ markSymbolsForRVATable(File, File->getGuardFidChunks(), AddressTakenSyms);
+ markSymbolsForRVATable(File, File->getGuardLJmpChunks(), LongJmpTargets);
+ } else {
+ markSymbolsWithRelocations(File, AddressTakenSyms);
+ }
+ }
+
+ // Mark the image entry as address-taken.
+ if (Config->Entry)
+ addSymbolToRVASet(AddressTakenSyms, cast<Defined>(Config->Entry));
+
+ // Ensure sections referenced in the gfid table are 16-byte aligned.
+ for (const ChunkAndOffset &C : AddressTakenSyms)
+ if (C.InputChunk->Alignment < 16)
+ C.InputChunk->Alignment = 16;
+
+ maybeAddRVATable(std::move(AddressTakenSyms), "__guard_fids_table",
+ "__guard_fids_count");
+
+ // Add the longjmp target table unless the user told us not to.
+ if (Config->GuardCF == GuardCFLevel::Full)
+ maybeAddRVATable(std::move(LongJmpTargets), "__guard_longjmp_table",
+ "__guard_longjmp_count");
+
+ // Set __guard_flags, which will be used in the load config to indicate that
+ // /guard:cf was enabled.
+ uint32_t GuardFlags = uint32_t(coff_guard_flags::CFInstrumented) |
+ uint32_t(coff_guard_flags::HasFidTable);
+ if (Config->GuardCF == GuardCFLevel::Full)
+ GuardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable);
+ Symbol *FlagSym = Symtab->findUnderscore("__guard_flags");
+ cast<DefinedAbsolute>(FlagSym)->setVA(GuardFlags);
+}
+
+// Take a list of input sections containing symbol table indices and add those
+// symbols to an RVA table. The challenge is that symbol RVAs are not known and
+// depend on the table size, so we can't directly build a set of integers.
+void Writer::markSymbolsForRVATable(ObjFile *File,
+ ArrayRef<SectionChunk *> SymIdxChunks,
+ SymbolRVASet &TableSymbols) {
+ for (SectionChunk *C : SymIdxChunks) {
+ // Skip sections discarded by linker GC. This comes up when a .gfids section
+ // is associated with something like a vtable and the vtable is discarded.
+ // In this case, the associated gfids section is discarded, and we don't
+ // mark the virtual member functions as address-taken by the vtable.
+ if (!C->isLive())
+ continue;
+
+ // Validate that the contents look like symbol table indices.
+ ArrayRef<uint8_t> Data = C->getContents();
+ if (Data.size() % 4 != 0) {
+ warn("ignoring " + C->getSectionName() +
+ " symbol table index section in object " + toString(File));
+ continue;
+ }
+
+ // Read each symbol table index and check if that symbol was included in the
+ // final link. If so, add it to the table symbol set.
+ ArrayRef<ulittle32_t> SymIndices(
+ reinterpret_cast<const ulittle32_t *>(Data.data()), Data.size() / 4);
+ ArrayRef<Symbol *> ObjSymbols = File->getSymbols();
+ for (uint32_t SymIndex : SymIndices) {
+ if (SymIndex >= ObjSymbols.size()) {
+ warn("ignoring invalid symbol table index in section " +
+ C->getSectionName() + " in object " + toString(File));
+ continue;
+ }
+ if (Symbol *S = ObjSymbols[SymIndex]) {
+ if (S->isLive())
+ addSymbolToRVASet(TableSymbols, cast<Defined>(S));
+ }
+ }
}
+}
- if (Handlers.empty())
+// Replace the absolute table symbol with a synthetic symbol pointing to
+// TableChunk so that we can emit base relocations for it and resolve section
+// relative relocations.
+void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
+ StringRef CountSym) {
+ if (TableSymbols.empty())
return;
- SEHTable = make<SEHTableChunk>(Handlers);
- RData->addChunk(SEHTable);
+ RVATableChunk *TableChunk = make<RVATableChunk>(std::move(TableSymbols));
+ RdataSec->addChunk(TableChunk);
- // Replace the absolute table symbol with a synthetic symbol pointing to the
- // SEHTable chunk so that we can emit base relocations for it and resolve
- // section relative relocations.
- Symbol *T = Symtab->find("___safe_se_handler_table");
- Symbol *C = Symtab->find("___safe_se_handler_count");
- replaceSymbol<DefinedSynthetic>(T, T->getName(), SEHTable);
- cast<DefinedAbsolute>(C)->setVA(SEHTable->getSize() / 4);
+ Symbol *T = Symtab->findUnderscore(TableSym);
+ Symbol *C = Symtab->findUnderscore(CountSym);
+ replaceSymbol<DefinedSynthetic>(T, T->getName(), TableChunk);
+ cast<DefinedAbsolute>(C)->setVA(TableChunk->getSize() / 4);
}
// Handles /section options to allow users to overwrite
@@ -829,16 +1140,17 @@ void Writer::setSectionPermissions() {
for (auto &P : Config->Section) {
StringRef Name = P.first;
uint32_t Perm = P.second;
- if (auto *Sec = findSection(Name))
- Sec->setPermissions(Perm);
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->Name == Name)
+ Sec->setPermissions(Perm);
}
}
// Write section contents to a mmap'ed file.
void Writer::writeSections() {
- // Record the section index that should be used when resolving a section
- // relocation against an absolute symbol.
- DefinedAbsolute::OutputSectionIndex = OutputSections.size() + 1;
+ // Record the number of sections to apply section index relocations
+ // against absolute symbols. See applySecIdx in Chunks.cpp..
+ DefinedAbsolute::NumOutputSections = OutputSections.size();
uint8_t *Buf = Buffer->getBufferStart();
for (OutputSection *Sec : OutputSections) {
@@ -846,7 +1158,7 @@ void Writer::writeSections() {
// Fill gaps between functions in .text with INT3 instructions
// instead of leaving as NUL bytes (which can be interpreted as
// ADD instructions).
- if (Sec->getPermissions() & IMAGE_SCN_CNT_CODE)
+ if (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE)
memset(SecBuf, 0xCC, Sec->getRawSize());
for_each(parallel::par, Sec->getChunks().begin(), Sec->getChunks().end(),
[&](Chunk *C) { C->writeTo(SecBuf); });
@@ -854,32 +1166,65 @@ void Writer::writeSections() {
}
void Writer::writeBuildId() {
- // If we're not writing a build id (e.g. because /debug is not specified),
- // then just return;
- if (!Config->Debug)
- return;
+ // There are two important parts to the build ID.
+ // 1) If building with debug info, the COFF debug directory contains a
+ // timestamp as well as a Guid and Age of the PDB.
+ // 2) In all cases, the PE COFF file header also contains a timestamp.
+ // For reproducibility, instead of a timestamp we want to use a hash of the
+ // binary, however when building with debug info the hash needs to take into
+ // account the debug info, since it's possible to add blank lines to a file
+ // which causes the debug info to change but not the generated code.
+ //
+ // To handle this, we first set the Guid and Age in the debug directory (but
+ // only if we're doing a debug build). Then, we hash the binary (thus causing
+ // the hash to change if only the debug info changes, since the Age will be
+ // different). Finally, we write that hash into the debug directory (if
+ // present) as well as the COFF file header (always).
+ if (Config->Debug) {
+ assert(BuildId && "BuildId is not set!");
+ if (PreviousBuildId.hasValue()) {
+ *BuildId->BuildId = *PreviousBuildId;
+ BuildId->BuildId->PDB70.Age = BuildId->BuildId->PDB70.Age + 1;
+ } else {
+ BuildId->BuildId->Signature.CVSignature = OMF::Signature::PDB70;
+ BuildId->BuildId->PDB70.Age = 1;
+ llvm::getRandomBytes(BuildId->BuildId->PDB70.Signature, 16);
+ }
+ }
- assert(BuildId && "BuildId is not set!");
+ // At this point the only fields in the COFF file which remain unset are the
+ // "timestamp" in the COFF file header, and the ones in the coff debug
+ // directory. Now we can hash the file and write that hash to the various
+ // timestamp fields in the file.
+ StringRef OutputFileData(
+ reinterpret_cast<const char *>(Buffer->getBufferStart()),
+ Buffer->getBufferSize());
- if (PreviousBuildId.hasValue()) {
- *BuildId->BuildId = *PreviousBuildId;
- BuildId->BuildId->PDB70.Age = BuildId->BuildId->PDB70.Age + 1;
- return;
- }
+ uint32_t Timestamp = Config->Timestamp;
+ if (Config->Repro)
+ Timestamp = static_cast<uint32_t>(xxHash64(OutputFileData));
+
+ if (DebugDirectory)
+ DebugDirectory->setTimeDateStamp(Timestamp);
- BuildId->BuildId->Signature.CVSignature = OMF::Signature::PDB70;
- BuildId->BuildId->PDB70.Age = 1;
- llvm::getRandomBytes(BuildId->BuildId->PDB70.Signature, 16);
+ uint8_t *Buf = Buffer->getBufferStart();
+ Buf += DOSStubSize + sizeof(PEMagic);
+ object::coff_file_header *CoffHeader =
+ reinterpret_cast<coff_file_header *>(Buf);
+ CoffHeader->TimeDateStamp = Timestamp;
}
// Sort .pdata section contents according to PE/COFF spec 5.5.
void Writer::sortExceptionTable() {
- OutputSection *Sec = findSection(".pdata");
- if (!Sec)
+ if (!FirstPdata)
return;
// We assume .pdata contains function table entries only.
- uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff();
- uint8_t *End = Begin + Sec->getVirtualSize();
+ auto BufAddr = [&](Chunk *C) {
+ return Buffer->getBufferStart() + C->getOutputSection()->getFileOff() +
+ C->getRVA() - C->getOutputSection()->getRVA();
+ };
+ uint8_t *Begin = BufAddr(FirstPdata);
+ uint8_t *End = BufAddr(LastPdata) + LastPdata->getSize();
if (Config->Machine == AMD64) {
struct Entry { ulittle32_t Begin, End, Unwind; };
sort(parallel::par, (Entry *)Begin, (Entry *)End,
@@ -897,7 +1242,7 @@ void Writer::sortExceptionTable() {
OutputSection *Writer::findSection(StringRef Name) {
for (OutputSection *Sec : OutputSections)
- if (Sec->getName() == Name)
+ if (Sec->Name == Name)
return Sec;
return nullptr;
}
@@ -905,55 +1250,31 @@ OutputSection *Writer::findSection(StringRef Name) {
uint32_t Writer::getSizeOfInitializedData() {
uint32_t Res = 0;
for (OutputSection *S : OutputSections)
- if (S->getPermissions() & IMAGE_SCN_CNT_INITIALIZED_DATA)
+ if (S->Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
Res += S->getRawSize();
return Res;
}
-// Returns an existing section or create a new one if not found.
-OutputSection *Writer::createSection(StringRef Name) {
- if (auto *Sec = findSection(Name))
- return Sec;
- const auto DATA = IMAGE_SCN_CNT_INITIALIZED_DATA;
- const auto BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
- const auto CODE = IMAGE_SCN_CNT_CODE;
- const auto DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE;
- const auto R = IMAGE_SCN_MEM_READ;
- const auto W = IMAGE_SCN_MEM_WRITE;
- const auto X = IMAGE_SCN_MEM_EXECUTE;
- uint32_t Perms = StringSwitch<uint32_t>(Name)
- .Case(".bss", BSS | R | W)
- .Case(".data", DATA | R | W)
- .Cases(".didat", ".edata", ".idata", ".rdata", DATA | R)
- .Case(".reloc", DATA | DISCARDABLE | R)
- .Case(".text", CODE | R | X)
- .Default(0);
- if (!Perms)
- llvm_unreachable("unknown section name");
- auto Sec = make<OutputSection>(Name);
- Sec->addPermissions(Perms);
- OutputSections.push_back(Sec);
- return Sec;
-}
-
-// Dest is .reloc section. Add contents to that section.
-void Writer::addBaserels(OutputSection *Dest) {
+// Add base relocations to .reloc section.
+void Writer::addBaserels() {
+ if (!Config->Relocatable)
+ return;
std::vector<Baserel> V;
for (OutputSection *Sec : OutputSections) {
- if (Sec == Dest)
+ if (Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
continue;
// Collect all locations for base relocations.
for (Chunk *C : Sec->getChunks())
C->getBaserels(&V);
// Add the addresses to .reloc section.
if (!V.empty())
- addBaserelBlocks(Dest, V);
+ addBaserelBlocks(V);
V.clear();
}
}
// Add addresses to .reloc section. Note that addresses are grouped by page.
-void Writer::addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V) {
+void Writer::addBaserelBlocks(std::vector<Baserel> &V) {
const uint32_t Mask = ~uint32_t(PageSize - 1);
uint32_t Page = V[0].RVA & Mask;
size_t I = 0, J = 1;
@@ -961,11 +1282,11 @@ void Writer::addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V) {
uint32_t P = V[J].RVA & Mask;
if (P == Page)
continue;
- Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
+ RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
I = J;
Page = P;
}
if (I == J)
return;
- Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
+ RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
}
diff --git a/contrib/llvm/tools/lld/COFF/Writer.h b/contrib/llvm/tools/lld/COFF/Writer.h
index 21be1be6e92a..d37276cb6d91 100644
--- a/contrib/llvm/tools/lld/COFF/Writer.h
+++ b/contrib/llvm/tools/lld/COFF/Writer.h
@@ -13,6 +13,7 @@
#include "Chunks.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/COFF.h"
+#include <chrono>
#include <cstdint>
#include <vector>
@@ -29,16 +30,14 @@ void writeResult();
// non-overlapping file offsets and RVAs.
class OutputSection {
public:
- OutputSection(llvm::StringRef N) : Name(N), Header({}) {}
- void setRVA(uint64_t);
- void setFileOffset(uint64_t);
+ OutputSection(llvm::StringRef N, uint32_t Chars) : Name(N) {
+ Header.Characteristics = Chars;
+ }
void addChunk(Chunk *C);
- llvm::StringRef getName() { return Name; }
+ void merge(OutputSection *Other);
ArrayRef<Chunk *> getChunks() { return Chunks; }
void addPermissions(uint32_t C);
void setPermissions(uint32_t C);
- uint32_t getPermissions() { return Header.Characteristics & PermMask; }
- uint32_t getCharacteristics() { return Header.Characteristics; }
uint64_t getRVA() { return Header.VirtualAddress; }
uint64_t getFileOff() { return Header.PointerToRawData; }
void writeHeaderTo(uint8_t *Buf);
@@ -60,9 +59,10 @@ public:
// N.B. The section index is one based.
uint32_t SectionIndex = 0;
-private:
llvm::StringRef Name;
- llvm::object::coff_section Header;
+ llvm::object::coff_section Header = {};
+
+private:
uint32_t StringTableOff = 0;
std::vector<Chunk *> Chunks;
};
diff --git a/contrib/llvm/tools/lld/Common/Args.cpp b/contrib/llvm/tools/lld/Common/Args.cpp
index 680cf5bd0a6e..ff77bfcc3b76 100644
--- a/contrib/llvm/tools/lld/Common/Args.cpp
+++ b/contrib/llvm/tools/lld/Common/Args.cpp
@@ -18,13 +18,17 @@ using namespace llvm;
using namespace lld;
int lld::args::getInteger(opt::InputArgList &Args, unsigned Key, int Default) {
- int V = Default;
- if (auto *Arg = Args.getLastArg(Key)) {
- StringRef S = Arg->getValue();
- if (!to_integer(S, V, 10))
- error(Arg->getSpelling() + ": number expected, but got '" + S + "'");
- }
- return V;
+ auto *A = Args.getLastArg(Key);
+ if (!A)
+ return Default;
+
+ int V;
+ if (to_integer(A->getValue(), V, 10))
+ return V;
+
+ StringRef Spelling = Args.getArgString(A->getIndex());
+ error(Spelling + ": number expected, but got '" + A->getValue() + "'");
+ return 0;
}
std::vector<StringRef> lld::args::getStrings(opt::InputArgList &Args, int Id) {
diff --git a/contrib/llvm/tools/lld/Common/CMakeLists.txt b/contrib/llvm/tools/lld/Common/CMakeLists.txt
index b376893f35a4..a45fe209f06f 100644
--- a/contrib/llvm/tools/lld/Common/CMakeLists.txt
+++ b/contrib/llvm/tools/lld/Common/CMakeLists.txt
@@ -10,6 +10,7 @@ add_lld_library(lldCommon
Strings.cpp
TargetOptionsCommandFlags.cpp
Threads.cpp
+ Timer.cpp
Version.cpp
ADDITIONAL_HEADER_DIRS
diff --git a/contrib/llvm/tools/lld/Common/ErrorHandler.cpp b/contrib/llvm/tools/lld/Common/ErrorHandler.cpp
index 18affce4d5a6..d1cb3dbbe03c 100644
--- a/contrib/llvm/tools/lld/Common/ErrorHandler.cpp
+++ b/contrib/llvm/tools/lld/Common/ErrorHandler.cpp
@@ -12,7 +12,8 @@
#include "lld/Common/Threads.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/Support/Error.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/raw_ostream.h"
#include <mutex>
@@ -59,6 +60,30 @@ void lld::exitLld(int Val) {
_exit(Val);
}
+void lld::diagnosticHandler(const DiagnosticInfo &DI) {
+ SmallString<128> S;
+ raw_svector_ostream OS(S);
+ DiagnosticPrinterRawOStream DP(OS);
+ DI.print(DP);
+ switch (DI.getSeverity()) {
+ case DS_Error:
+ error(S);
+ break;
+ case DS_Warning:
+ warn(S);
+ break;
+ case DS_Remark:
+ case DS_Note:
+ message(S);
+ break;
+ }
+}
+
+void lld::checkError(Error E) {
+ handleAllErrors(std::move(E),
+ [&](ErrorInfoBase &EIB) { error(EIB.message()); });
+}
+
void ErrorHandler::print(StringRef S, raw_ostream::Colors C) {
*ErrorOS << LogName << ": ";
if (ColorDiagnostics) {
diff --git a/contrib/llvm/tools/lld/Common/Strings.cpp b/contrib/llvm/tools/lld/Common/Strings.cpp
index 6cd4ad8d600a..36f4f77d8476 100644
--- a/contrib/llvm/tools/lld/Common/Strings.cpp
+++ b/contrib/llvm/tools/lld/Common/Strings.cpp
@@ -8,7 +8,21 @@
//===----------------------------------------------------------------------===//
#include "lld/Common/Strings.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/LLVM.h"
#include "llvm/Demangle/Demangle.h"
+#include "llvm/Support/GlobPattern.h"
+#include <algorithm>
+#include <mutex>
+#include <vector>
+
+#if defined(_MSC_VER)
+#include <Windows.h>
+
+// DbgHelp.h must be included after Windows.h.
+#include <DbgHelp.h>
+#pragma comment(lib, "dbghelp.lib")
+#endif
using namespace llvm;
using namespace lld;
@@ -30,3 +44,66 @@ Optional<std::string> lld::demangleItanium(StringRef Name) {
free(Buf);
return S;
}
+
+Optional<std::string> lld::demangleMSVC(StringRef S) {
+#if defined(_MSC_VER)
+ // UnDecorateSymbolName is not thread-safe, so we need a mutex.
+ static std::mutex Mu;
+ std::lock_guard<std::mutex> Lock(Mu);
+
+ char Buf[4096];
+ if (S.startswith("?"))
+ if (size_t Len = UnDecorateSymbolName(S.str().c_str(), Buf, sizeof(Buf), 0))
+ return std::string(Buf, Len);
+#endif
+ return None;
+}
+
+StringMatcher::StringMatcher(ArrayRef<StringRef> Pat) {
+ for (StringRef S : Pat) {
+ Expected<GlobPattern> Pat = GlobPattern::create(S);
+ if (!Pat)
+ error(toString(Pat.takeError()));
+ else
+ Patterns.push_back(*Pat);
+ }
+}
+
+bool StringMatcher::match(StringRef S) const {
+ for (const GlobPattern &Pat : Patterns)
+ if (Pat.match(S))
+ return true;
+ return false;
+}
+
+// Converts a hex string (e.g. "deadbeef") to a vector.
+std::vector<uint8_t> lld::parseHex(StringRef S) {
+ std::vector<uint8_t> Hex;
+ while (!S.empty()) {
+ StringRef B = S.substr(0, 2);
+ S = S.substr(2);
+ uint8_t H;
+ if (!to_integer(B, H, 16)) {
+ error("not a hexadecimal value: " + B);
+ return {};
+ }
+ Hex.push_back(H);
+ }
+ return Hex;
+}
+
+// Returns true if S is valid as a C language identifier.
+bool lld::isValidCIdentifier(StringRef S) {
+ return !S.empty() && (isAlpha(S[0]) || S[0] == '_') &&
+ std::all_of(S.begin() + 1, S.end(),
+ [](char C) { return C == '_' || isAlnum(C); });
+}
+
+// Write the contents of the a buffer to a file
+void lld::saveBuffer(StringRef Buffer, const Twine &Path) {
+ std::error_code EC;
+ raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
+ if (EC)
+ error("cannot create " + Path + ": " + EC.message());
+ OS << Buffer;
+}
diff --git a/contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp b/contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp
index e8e582f4c256..b46df363c361 100644
--- a/contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp
+++ b/contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file exists as a place for global variables defined in LLVM's
-// CodeGen/CommandFlags.def. By putting the resulting object file in
+// CodeGen/CommandFlags.inc. By putting the resulting object file in
// an archive and linking with it, the definitions will automatically be
// included when needed and skipped when already present.
//
@@ -16,12 +16,12 @@
#include "lld/Common/TargetOptionsCommandFlags.h"
-#include "llvm/CodeGen/CommandFlags.def"
+#include "llvm/CodeGen/CommandFlags.inc"
#include "llvm/Target/TargetOptions.h"
// Define an externally visible version of
// InitTargetOptionsFromCodeGenFlags, so that its functionality can be
-// used without having to include llvm/CodeGen/CommandFlags.def, which
+// used without having to include llvm/CodeGen/CommandFlags.inc, which
// would lead to multiple definitions of the command line flags.
llvm::TargetOptions lld::InitTargetOptionsFromCodeGenFlags() {
return ::InitTargetOptionsFromCodeGenFlags();
@@ -30,3 +30,5 @@ llvm::TargetOptions lld::InitTargetOptionsFromCodeGenFlags() {
llvm::Optional<llvm::CodeModel::Model> lld::GetCodeModelFromCMModel() {
return getCodeModel();
}
+
+std::string lld::GetCPUStr() { return ::getCPUStr(); }
diff --git a/contrib/llvm/tools/lld/Common/Timer.cpp b/contrib/llvm/tools/lld/Common/Timer.cpp
new file mode 100644
index 000000000000..89f9829b47cf
--- /dev/null
+++ b/contrib/llvm/tools/lld/Common/Timer.cpp
@@ -0,0 +1,80 @@
+//===- Timer.cpp ----------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/Timer.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Support/Format.h"
+
+using namespace lld;
+using namespace llvm;
+
+ScopedTimer::ScopedTimer(Timer &T) : T(&T) { T.start(); }
+
+void ScopedTimer::stop() {
+ if (!T)
+ return;
+ T->stop();
+ T = nullptr;
+}
+
+ScopedTimer::~ScopedTimer() { stop(); }
+
+Timer::Timer(llvm::StringRef Name) : Name(Name), Parent(nullptr) {}
+Timer::Timer(llvm::StringRef Name, Timer &Parent)
+ : Name(Name), Parent(&Parent) {}
+
+void Timer::start() {
+ if (Parent && Total.count() == 0)
+ Parent->Children.push_back(this);
+ StartTime = std::chrono::high_resolution_clock::now();
+}
+
+void Timer::stop() {
+ Total += (std::chrono::high_resolution_clock::now() - StartTime);
+}
+
+Timer &Timer::root() {
+ static Timer RootTimer("Total Link Time");
+ return RootTimer;
+}
+
+void Timer::print() {
+ double TotalDuration = static_cast<double>(root().millis());
+
+ // We want to print the grand total under all the intermediate phases, so we
+ // print all children first, then print the total under that.
+ for (const auto &Child : Children)
+ Child->print(1, TotalDuration);
+
+ message(std::string(49, '-'));
+
+ root().print(0, root().millis(), false);
+}
+
+double Timer::millis() const {
+ return std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(
+ Total)
+ .count();
+}
+
+void Timer::print(int Depth, double TotalDuration, bool Recurse) const {
+ double P = 100.0 * millis() / TotalDuration;
+
+ SmallString<32> Str;
+ llvm::raw_svector_ostream Stream(Str);
+ std::string S = std::string(Depth * 2, ' ') + Name + std::string(":");
+ Stream << format("%-30s%5d ms (%5.1f%%)", S.c_str(), (int)millis(), P);
+
+ message(Str);
+
+ if (Recurse) {
+ for (const auto &Child : Children)
+ Child->print(Depth + 1, TotalDuration);
+ }
+}
diff --git a/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp b/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp
index 48273d0eb398..7551919cf86f 100644
--- a/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp
+++ b/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp
@@ -34,12 +34,11 @@
#include "LinkerScript.h"
#include "OutputSections.h"
#include "Relocations.h"
-#include "Strings.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/Memory.h"
-
+#include "lld/Common/Strings.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -342,7 +341,7 @@ static bool is843419ErratumSequence(uint32_t Instr1, uint32_t Instr2,
// patch or 0 if no patch required.
static uint64_t scanCortexA53Errata843419(InputSection *IS, uint64_t &Off,
uint64_t Limit) {
- uint64_t ISAddr = IS->getParent()->Addr + IS->OutSecOff;
+ uint64_t ISAddr = IS->getVA(0);
// Advance Off so that (ISAddr + Off) modulo 0x1000 is at least 0xff8.
uint64_t InitialPageOff = (ISAddr + Off) & 0xfff;
@@ -406,7 +405,7 @@ lld::elf::Patch843419Section::Patch843419Section(InputSection *P, uint64_t Off)
}
uint64_t lld::elf::Patch843419Section::getLDSTAddr() const {
- return Patchee->getParent()->Addr + Patchee->OutSecOff + PatcheeOffset;
+ return Patchee->getVA(PatcheeOffset);
}
void lld::elf::Patch843419Section::writeTo(uint8_t *Buf) {
@@ -555,9 +554,8 @@ static void implementPatch(uint64_t AdrpAddr, uint64_t PatcheeOffset,
if (RelIt != IS->Relocations.end() && RelIt->Type == R_AARCH64_JUMP26)
return;
- if (Config->Verbose)
- message("detected cortex-a53-843419 erratum sequence starting at " +
- utohexstr(AdrpAddr) + " in unpatched output.");
+ log("detected cortex-a53-843419 erratum sequence starting at " +
+ utohexstr(AdrpAddr) + " in unpatched output.");
auto *PS = make<Patch843419Section>(IS, PatcheeOffset);
Patches.push_back(PS);
@@ -603,7 +601,7 @@ AArch64Err843419Patcher::patchInputSectionDescription(
(DataSym == MapSyms.end()) ? IS->Data.size() : (*DataSym)->Value;
while (Off < Limit) {
- uint64_t StartAddr = IS->getParent()->Addr + IS->OutSecOff + Off;
+ uint64_t StartAddr = IS->getVA(Off);
if (uint64_t PatcheeOffset = scanCortexA53Errata843419(IS, Off, Limit))
implementPatch(StartAddr, PatcheeOffset, IS, Patches);
}
diff --git a/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.h b/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.h
index 6c100f25d8af..edd154d4cab3 100644
--- a/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.h
+++ b/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.h
@@ -11,7 +11,6 @@
#define LLD_ELF_AARCH64ERRATAFIX_H
#include "lld/Common/LLVM.h"
-
#include <map>
#include <vector>
diff --git a/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp b/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp
index a741cd1cb6da..ae072d4adaac 100644
--- a/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp
+++ b/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp
@@ -34,7 +34,7 @@ public:
AArch64();
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
- bool isPicRel(RelType Type) const override;
+ RelType getDynRel(RelType Type) const override;
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
@@ -93,6 +93,11 @@ RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S,
return R_TLSDESC_CALL;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
return R_TLS;
case R_AARCH64_CALL26:
case R_AARCH64_CONDBR19:
@@ -148,8 +153,10 @@ bool AArch64::usesOnlyLowPageBits(RelType Type) const {
}
}
-bool AArch64::isPicRel(RelType Type) const {
- return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64;
+RelType AArch64::getDynRel(RelType Type) const {
+ if (Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64)
+ return Type;
+ return R_AARCH64_NONE;
}
void AArch64::writeGotPlt(uint8_t *Buf, const Symbol &) const {
@@ -244,12 +251,12 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
switch (Type) {
case R_AARCH64_ABS16:
case R_AARCH64_PREL16:
- checkIntUInt<16>(Loc, Val, Type);
+ checkIntUInt(Loc, Val, 16, Type);
write16le(Loc, Val);
break;
case R_AARCH64_ABS32:
case R_AARCH64_PREL32:
- checkIntUInt<32>(Loc, Val, Type);
+ checkIntUInt(Loc, Val, 32, Type);
write32le(Loc, Val);
break;
case R_AARCH64_ABS64:
@@ -264,11 +271,11 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
case R_AARCH64_TLSDESC_ADR_PAGE21:
- checkInt<33>(Loc, Val, Type);
+ checkInt(Loc, Val, 33, Type);
write32AArch64Addr(Loc, Val >> 12);
break;
case R_AARCH64_ADR_PREL_LO21:
- checkInt<21>(Loc, Val, Type);
+ checkInt(Loc, Val, 21, Type);
write32AArch64Addr(Loc, Val);
break;
case R_AARCH64_JUMP26:
@@ -282,38 +289,40 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
write32le(Loc, 0x14000000);
LLVM_FALLTHROUGH;
case R_AARCH64_CALL26:
- checkInt<28>(Loc, Val, Type);
+ checkInt(Loc, Val, 28, Type);
or32le(Loc, (Val & 0x0FFFFFFC) >> 2);
break;
case R_AARCH64_CONDBR19:
case R_AARCH64_LD_PREL_LO19:
- checkAlignment<4>(Loc, Val, Type);
- checkInt<21>(Loc, Val, Type);
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 21, Type);
or32le(Loc, (Val & 0x1FFFFC) << 3);
break;
- case R_AARCH64_LD64_GOT_LO12_NC:
- case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- case R_AARCH64_TLSDESC_LD64_LO12:
- checkAlignment<8>(Loc, Val, Type);
- or32le(Loc, (Val & 0xFF8) << 7);
- break;
case R_AARCH64_LDST8_ABS_LO12_NC:
+ case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
or32AArch64Imm(Loc, getBits(Val, 0, 11));
break;
case R_AARCH64_LDST16_ABS_LO12_NC:
- checkAlignment<2>(Loc, Val, Type);
+ case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
+ checkAlignment(Loc, Val, 2, Type);
or32AArch64Imm(Loc, getBits(Val, 1, 11));
break;
case R_AARCH64_LDST32_ABS_LO12_NC:
- checkAlignment<4>(Loc, Val, Type);
+ case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
+ checkAlignment(Loc, Val, 4, Type);
or32AArch64Imm(Loc, getBits(Val, 2, 11));
break;
case R_AARCH64_LDST64_ABS_LO12_NC:
- checkAlignment<8>(Loc, Val, Type);
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
+ case R_AARCH64_TLSDESC_LD64_LO12:
+ checkAlignment(Loc, Val, 8, Type);
or32AArch64Imm(Loc, getBits(Val, 3, 11));
break;
case R_AARCH64_LDST128_ABS_LO12_NC:
- checkAlignment<16>(Loc, Val, Type);
+ case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
+ checkAlignment(Loc, Val, 16, Type);
or32AArch64Imm(Loc, getBits(Val, 4, 11));
break;
case R_AARCH64_MOVW_UABS_G0_NC:
@@ -329,11 +338,11 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
or32le(Loc, (Val & 0xFFFF000000000000) >> 43);
break;
case R_AARCH64_TSTBR14:
- checkInt<16>(Loc, Val, Type);
+ checkInt(Loc, Val, 16, Type);
or32le(Loc, (Val & 0xFFFC) << 3);
break;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
- checkInt<24>(Loc, Val, Type);
+ checkInt(Loc, Val, 24, Type);
or32AArch64Imm(Loc, Val >> 12);
break;
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
@@ -357,7 +366,7 @@ void AArch64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
// movk x0, #0x10
// nop
// nop
- checkUInt<32>(Loc, Val, Type);
+ checkUInt(Loc, Val, 32, Type);
switch (Type) {
case R_AARCH64_TLSDESC_ADD_LO12:
@@ -407,7 +416,7 @@ void AArch64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
}
void AArch64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
- checkUInt<32>(Loc, Val, Type);
+ checkUInt(Loc, Val, 32, Type);
if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) {
// Generate MOVZ.
diff --git a/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp b/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp
index 505e0e6ad480..48b27f23510c 100644
--- a/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp
+++ b/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp
@@ -66,6 +66,7 @@ void AMDGPU::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
write32le(Loc, Val);
break;
case R_AMDGPU_ABS64:
+ case R_AMDGPU_REL64:
write64le(Loc, Val);
break;
case R_AMDGPU_GOTPCREL32_HI:
@@ -86,6 +87,7 @@ RelExpr AMDGPU::getRelExpr(RelType Type, const Symbol &S,
case R_AMDGPU_REL32:
case R_AMDGPU_REL32_LO:
case R_AMDGPU_REL32_HI:
+ case R_AMDGPU_REL64:
return R_PC;
case R_AMDGPU_GOTPCREL:
case R_AMDGPU_GOTPCREL32_LO:
diff --git a/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp b/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp
index fc2ac9beef9c..acf9a615f20b 100644
--- a/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp
+++ b/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp
@@ -29,7 +29,6 @@ public:
uint32_t calcEFlags() const override;
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
- bool isPicRel(RelType Type) const override;
RelType getDynRel(RelType Type) const override;
int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override;
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
@@ -55,6 +54,7 @@ ARM::ARM() {
TlsGotRel = R_ARM_TLS_TPOFF32;
TlsModuleIndexRel = R_ARM_TLS_DTPMOD32;
TlsOffsetRel = R_ARM_TLS_DTPOFF32;
+ GotBaseSymInGotPlt = false;
GotEntrySize = 4;
GotPltEntrySize = 4;
PltEntrySize = 16;
@@ -170,18 +170,10 @@ RelExpr ARM::getRelExpr(RelType Type, const Symbol &S,
}
}
-bool ARM::isPicRel(RelType Type) const {
- return (Type == R_ARM_TARGET1 && !Config->Target1Rel) ||
- (Type == R_ARM_ABS32);
-}
-
RelType ARM::getDynRel(RelType Type) const {
- if (Type == R_ARM_TARGET1 && !Config->Target1Rel)
+ if ((Type == R_ARM_ABS32) || (Type == R_ARM_TARGET1 && !Config->Target1Rel))
return R_ARM_ABS32;
- if (Type == R_ARM_ABS32)
- return Type;
- // Keep it going with a dummy value so that we can find more reloc errors.
- return R_ARM_ABS32;
+ return R_ARM_NONE;
}
void ARM::writeGotPlt(uint8_t *Buf, const Symbol &) const {
@@ -401,7 +393,7 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
write32le(Loc, 1);
break;
case R_ARM_PREL31:
- checkInt<31>(Loc, Val, Type);
+ checkInt(Loc, Val, 31, Type);
write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000));
break;
case R_ARM_CALL:
@@ -410,7 +402,7 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
if (Val & 1) {
// If bit 0 of Val is 1 the target is Thumb, we must select a BLX.
// The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1'
- checkInt<26>(Loc, Val, Type);
+ checkInt(Loc, Val, 26, Type);
write32le(Loc, 0xfa000000 | // opcode
((Val & 2) << 23) | // H
((Val >> 2) & 0x00ffffff)); // imm24
@@ -425,16 +417,16 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_ARM_JUMP24:
case R_ARM_PC24:
case R_ARM_PLT32:
- checkInt<26>(Loc, Val, Type);
+ checkInt(Loc, Val, 26, Type);
write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff));
break;
case R_ARM_THM_JUMP11:
- checkInt<12>(Loc, Val, Type);
+ checkInt(Loc, Val, 12, Type);
write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff));
break;
case R_ARM_THM_JUMP19:
// Encoding T3: Val = S:J2:J1:imm6:imm11:0
- checkInt<21>(Loc, Val, Type);
+ checkInt(Loc, Val, 21, Type);
write16le(Loc,
(read16le(Loc) & 0xfbc0) | // opcode cond
((Val >> 10) & 0x0400) | // S
@@ -460,7 +452,7 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_ARM_THM_JUMP24:
// Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0
// FIXME: Use of I1 and I2 require v6T2ops
- checkInt<25>(Loc, Val, Type);
+ checkInt(Loc, Val, 25, Type);
write16le(Loc,
0xf000 | // opcode
((Val >> 14) & 0x0400) | // S
@@ -478,14 +470,14 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
break;
case R_ARM_MOVT_ABS:
case R_ARM_MOVT_PREL:
- checkInt<32>(Loc, Val, Type);
+ checkInt(Loc, Val, 32, Type);
write32le(Loc, (read32le(Loc) & ~0x000f0fff) |
(((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff));
break;
case R_ARM_THM_MOVT_ABS:
case R_ARM_THM_MOVT_PREL:
// Encoding T1: A = imm4:i:imm3:imm8
- checkInt<32>(Loc, Val, Type);
+ checkInt(Loc, Val, 32, Type);
write16le(Loc,
0xf2c0 | // opcode
((Val >> 17) & 0x0400) | // i
diff --git a/contrib/llvm/tools/lld/ELF/Arch/Hexagon.cpp b/contrib/llvm/tools/lld/ELF/Arch/Hexagon.cpp
new file mode 100644
index 000000000000..ff5e862bafa2
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/Hexagon.cpp
@@ -0,0 +1,103 @@
+//===-- Hexagon.cpp -------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class Hexagon final : public TargetInfo {
+public:
+ uint32_t calcEFlags() const override;
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+};
+} // namespace
+
+// Support V60 only at the moment.
+uint32_t Hexagon::calcEFlags() const { return 0x60; }
+
+static uint32_t applyMask(uint32_t Mask, uint32_t Data) {
+ uint32_t Result = 0;
+ size_t Off = 0;
+
+ for (size_t Bit = 0; Bit != 32; ++Bit) {
+ uint32_t ValBit = (Data >> Off) & 1;
+ uint32_t MaskBit = (Mask >> Bit) & 1;
+ if (MaskBit) {
+ Result |= (ValBit << Bit);
+ ++Off;
+ }
+ }
+ return Result;
+}
+
+RelExpr Hexagon::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_HEX_B15_PCREL:
+ case R_HEX_B15_PCREL_X:
+ case R_HEX_B22_PCREL:
+ case R_HEX_B22_PCREL_X:
+ case R_HEX_B32_PCREL_X:
+ return R_PC;
+ default:
+ return R_ABS;
+ }
+}
+
+static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
+
+void Hexagon::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_HEX_NONE:
+ break;
+ case R_HEX_12_X:
+ or32le(Loc, applyMask(0x000007e0, Val));
+ break;
+ case R_HEX_32_6_X:
+ or32le(Loc, applyMask(0x0fff3fff, Val >> 6));
+ break;
+ case R_HEX_B15_PCREL:
+ or32le(Loc, applyMask(0x00df20fe, Val >> 2));
+ break;
+ case R_HEX_B15_PCREL_X:
+ or32le(Loc, applyMask(0x00df20fe, Val & 0x3f));
+ break;
+ case R_HEX_B22_PCREL:
+ or32le(Loc, applyMask(0x1ff3ffe, Val >> 2));
+ break;
+ case R_HEX_B22_PCREL_X:
+ or32le(Loc, applyMask(0x1ff3ffe, Val & 0x3f));
+ break;
+ case R_HEX_B32_PCREL_X:
+ or32le(Loc, applyMask(0x0fff3fff, Val >> 6));
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type));
+ break;
+ }
+}
+
+TargetInfo *elf::getHexagonTargetInfo() {
+ static Hexagon Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp b/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp
index e8af36e6d11e..dc70401c0b0e 100644
--- a/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp
+++ b/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp
@@ -32,7 +32,6 @@ public:
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override;
- bool isPicRel(RelType Type) const override;
RelType getDynRel(RelType Type) const override;
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
void writePltHeader(uint8_t *Buf) const override;
@@ -50,6 +49,7 @@ template <class ELFT> MIPS<ELFT>::MIPS() {
DefaultMaxPageSize = 65536;
GotEntrySize = sizeof(typename ELFT::uint);
GotPltEntrySize = sizeof(typename ELFT::uint);
+ GotBaseSymInGotPlt = false;
PltEntrySize = 16;
PltHeaderSize = 32;
CopyRel = R_MIPS_COPY;
@@ -101,8 +101,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
case R_MIPS_HIGHEST:
case R_MICROMIPS_HI16:
case R_MICROMIPS_LO16:
- case R_MICROMIPS_HIGHER:
- case R_MICROMIPS_HIGHEST:
// R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate
// offset between start of function and 'gp' value which by default
// equal to the start of .got section. In that case we consider these
@@ -124,8 +122,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
case R_MIPS_TLS_TPREL_LO16:
case R_MIPS_TLS_TPREL32:
case R_MIPS_TLS_TPREL64:
- case R_MICROMIPS_GOT_OFST:
- case R_MICROMIPS_SUB:
case R_MICROMIPS_TLS_DTPREL_HI16:
case R_MICROMIPS_TLS_DTPREL_LO16:
case R_MICROMIPS_TLS_TPREL_HI16:
@@ -155,7 +151,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
case R_MIPS_GOT_DISP:
case R_MIPS_TLS_GOTTPREL:
case R_MICROMIPS_CALL16:
- case R_MICROMIPS_GOT_DISP:
case R_MICROMIPS_TLS_GOTTPREL:
return R_MIPS_GOT_OFF;
case R_MIPS_CALL_HI16:
@@ -168,7 +163,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
case R_MICROMIPS_GOT_LO16:
return R_MIPS_GOT_OFF32;
case R_MIPS_GOT_PAGE:
- case R_MICROMIPS_GOT_PAGE:
return R_MIPS_GOT_LOCAL_PAGE;
case R_MIPS_TLS_GD:
case R_MICROMIPS_TLS_GD:
@@ -183,12 +177,10 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
}
}
-template <class ELFT> bool MIPS<ELFT>::isPicRel(RelType Type) const {
- return Type == R_MIPS_32 || Type == R_MIPS_64;
-}
-
template <class ELFT> RelType MIPS<ELFT>::getDynRel(RelType Type) const {
- return RelativeRel;
+ if (Type == R_MIPS_32 || Type == R_MIPS_64)
+ return RelativeRel;
+ return R_MIPS_NONE;
}
template <class ELFT>
@@ -213,8 +205,8 @@ template <endianness E> static uint32_t readShuffle(const uint8_t *Loc) {
}
template <endianness E>
-static void writeRelocation(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
- uint8_t Shift) {
+static void writeValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
+ uint8_t Shift) {
uint32_t Instr = read32<E>(Loc);
uint32_t Mask = 0xffffffff >> (32 - BitsSize);
uint32_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask);
@@ -222,14 +214,14 @@ static void writeRelocation(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
}
template <endianness E>
-static void writeMicroRelocation32(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
- uint8_t Shift) {
+static void writeShuffleValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
+ uint8_t Shift) {
// See comments in readShuffle for purpose of this code.
uint16_t *Words = (uint16_t *)Loc;
if (E == support::little)
std::swap(Words[0], Words[1]);
- writeRelocation<E>(Loc, V, BitsSize, Shift);
+ writeValue<E>(Loc, V, BitsSize, Shift);
if (E == support::little)
std::swap(Words[0], Words[1]);
@@ -301,9 +293,9 @@ template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const {
write32<E>(Buf + 28, 0x2718fffe); // subu $24, $24, 2
uint64_t GotPlt = InX::GotPlt->getVA();
- writeRelocation<E>(Buf, GotPlt + 0x8000, 16, 16);
- writeRelocation<E>(Buf + 4, GotPlt, 16, 0);
- writeRelocation<E>(Buf + 8, GotPlt, 16, 0);
+ writeValue<E>(Buf, GotPlt + 0x8000, 16, 16);
+ writeValue<E>(Buf + 4, GotPlt, 16, 0);
+ writeValue<E>(Buf + 8, GotPlt, 16, 0);
}
template <class ELFT>
@@ -338,9 +330,9 @@ void MIPS<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15)
write32<E>(Buf + 8, JrInst); // jr $25 / jr.hb $25
write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry)
- writeRelocation<E>(Buf, GotPltEntryAddr + 0x8000, 16, 16);
- writeRelocation<E>(Buf + 4, GotPltEntryAddr, 16, 0);
- writeRelocation<E>(Buf + 12, GotPltEntryAddr, 16, 0);
+ writeValue<E>(Buf, GotPltEntryAddr + 0x8000, 16, 16);
+ writeValue<E>(Buf + 4, GotPltEntryAddr, 16, 0);
+ writeValue<E>(Buf + 12, GotPltEntryAddr, 16, 0);
}
template <class ELFT>
@@ -459,9 +451,6 @@ calculateMipsRelChain(uint8_t *Loc, RelType Type, uint64_t Val) {
return std::make_pair(Type2, Val);
if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16))
return std::make_pair(Type3, -Val);
- if (Type2 == R_MICROMIPS_SUB &&
- (Type3 == R_MICROMIPS_HI16 || Type3 == R_MICROMIPS_LO16))
- return std::make_pair(Type3, -Val);
error(getErrorLocation(Loc) + "unsupported relocations combination " +
Twine(Type));
return std::make_pair(Type & 0xff, Val);
@@ -471,6 +460,9 @@ template <class ELFT>
void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
const endianness E = ELFT::TargetEndianness;
+ if (ELFT::Is64Bits || Config->MipsN32Abi)
+ std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val);
+
// Thread pointer and DRP offsets from the start of TLS data area.
// https://www.linux-mips.org/wiki/NPTL
if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 ||
@@ -485,9 +477,6 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
Val -= 0x7000;
}
- if (ELFT::Is64Bits || Config->MipsN32Abi)
- std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val);
-
switch (Type) {
case R_MIPS_32:
case R_MIPS_GPREL32:
@@ -501,25 +490,25 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
write64<E>(Loc, Val);
break;
case R_MIPS_26:
- writeRelocation<E>(Loc, Val, 26, 2);
+ writeValue<E>(Loc, Val, 26, 2);
break;
case R_MIPS_GOT16:
// The R_MIPS_GOT16 relocation's value in "relocatable" linking mode
// is updated addend (not a GOT index). In that case write high 16 bits
// to store a correct addend value.
if (Config->Relocatable) {
- writeRelocation<E>(Loc, Val + 0x8000, 16, 16);
+ writeValue<E>(Loc, Val + 0x8000, 16, 16);
} else {
- checkInt<16>(Loc, Val, Type);
- writeRelocation<E>(Loc, Val, 16, 0);
+ checkInt(Loc, Val, 16, Type);
+ writeValue<E>(Loc, Val, 16, 0);
}
break;
case R_MICROMIPS_GOT16:
if (Config->Relocatable) {
- writeMicroRelocation32<E>(Loc, Val + 0x8000, 16, 16);
+ writeShuffleValue<E>(Loc, Val + 0x8000, 16, 16);
} else {
- checkInt<16>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 16, 0);
+ checkInt(Loc, Val, 16, Type);
+ writeShuffleValue<E>(Loc, Val, 16, 0);
}
break;
case R_MIPS_CALL16:
@@ -529,7 +518,7 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_MIPS_TLS_GD:
case R_MIPS_TLS_GOTTPREL:
case R_MIPS_TLS_LDM:
- checkInt<16>(Loc, Val, Type);
+ checkInt(Loc, Val, 16, Type);
LLVM_FALLTHROUGH;
case R_MIPS_CALL_LO16:
case R_MIPS_GOT_LO16:
@@ -538,28 +527,25 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_MIPS_PCLO16:
case R_MIPS_TLS_DTPREL_LO16:
case R_MIPS_TLS_TPREL_LO16:
- writeRelocation<E>(Loc, Val, 16, 0);
+ writeValue<E>(Loc, Val, 16, 0);
break;
- case R_MICROMIPS_GOT_DISP:
- case R_MICROMIPS_GOT_PAGE:
case R_MICROMIPS_GPREL16:
case R_MICROMIPS_TLS_GD:
case R_MICROMIPS_TLS_LDM:
- checkInt<16>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 16, 0);
+ checkInt(Loc, Val, 16, Type);
+ writeShuffleValue<E>(Loc, Val, 16, 0);
break;
case R_MICROMIPS_CALL16:
case R_MICROMIPS_CALL_LO16:
- case R_MICROMIPS_GOT_OFST:
case R_MICROMIPS_LO16:
case R_MICROMIPS_TLS_DTPREL_LO16:
case R_MICROMIPS_TLS_GOTTPREL:
case R_MICROMIPS_TLS_TPREL_LO16:
- writeMicroRelocation32<E>(Loc, Val, 16, 0);
+ writeShuffleValue<E>(Loc, Val, 16, 0);
break;
case R_MICROMIPS_GPREL7_S2:
- checkInt<7>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 7, 2);
+ checkInt(Loc, Val, 7, Type);
+ writeShuffleValue<E>(Loc, Val, 7, 2);
break;
case R_MIPS_CALL_HI16:
case R_MIPS_GOT_HI16:
@@ -567,86 +553,80 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_MIPS_PCHI16:
case R_MIPS_TLS_DTPREL_HI16:
case R_MIPS_TLS_TPREL_HI16:
- writeRelocation<E>(Loc, Val + 0x8000, 16, 16);
+ writeValue<E>(Loc, Val + 0x8000, 16, 16);
break;
case R_MICROMIPS_CALL_HI16:
case R_MICROMIPS_GOT_HI16:
case R_MICROMIPS_HI16:
case R_MICROMIPS_TLS_DTPREL_HI16:
case R_MICROMIPS_TLS_TPREL_HI16:
- writeMicroRelocation32<E>(Loc, Val + 0x8000, 16, 16);
+ writeShuffleValue<E>(Loc, Val + 0x8000, 16, 16);
break;
case R_MIPS_HIGHER:
- writeRelocation<E>(Loc, Val + 0x80008000, 16, 32);
+ writeValue<E>(Loc, Val + 0x80008000, 16, 32);
break;
case R_MIPS_HIGHEST:
- writeRelocation<E>(Loc, Val + 0x800080008000, 16, 48);
- break;
- case R_MICROMIPS_HIGHER:
- writeMicroRelocation32<E>(Loc, Val + 0x80008000, 16, 32);
- break;
- case R_MICROMIPS_HIGHEST:
- writeMicroRelocation32<E>(Loc, Val + 0x800080008000, 16, 48);
+ writeValue<E>(Loc, Val + 0x800080008000, 16, 48);
break;
case R_MIPS_JALR:
case R_MICROMIPS_JALR:
// Ignore this optimization relocation for now
break;
case R_MIPS_PC16:
- checkAlignment<4>(Loc, Val, Type);
- checkInt<18>(Loc, Val, Type);
- writeRelocation<E>(Loc, Val, 16, 2);
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 18, Type);
+ writeValue<E>(Loc, Val, 16, 2);
break;
case R_MIPS_PC19_S2:
- checkAlignment<4>(Loc, Val, Type);
- checkInt<21>(Loc, Val, Type);
- writeRelocation<E>(Loc, Val, 19, 2);
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 21, Type);
+ writeValue<E>(Loc, Val, 19, 2);
break;
case R_MIPS_PC21_S2:
- checkAlignment<4>(Loc, Val, Type);
- checkInt<23>(Loc, Val, Type);
- writeRelocation<E>(Loc, Val, 21, 2);
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 23, Type);
+ writeValue<E>(Loc, Val, 21, 2);
break;
case R_MIPS_PC26_S2:
- checkAlignment<4>(Loc, Val, Type);
- checkInt<28>(Loc, Val, Type);
- writeRelocation<E>(Loc, Val, 26, 2);
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 28, Type);
+ writeValue<E>(Loc, Val, 26, 2);
break;
case R_MIPS_PC32:
- writeRelocation<E>(Loc, Val, 32, 0);
+ writeValue<E>(Loc, Val, 32, 0);
break;
case R_MICROMIPS_26_S1:
case R_MICROMIPS_PC26_S1:
- checkInt<27>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 26, 1);
+ checkInt(Loc, Val, 27, Type);
+ writeShuffleValue<E>(Loc, Val, 26, 1);
break;
case R_MICROMIPS_PC7_S1:
- checkInt<8>(Loc, Val, Type);
+ checkInt(Loc, Val, 8, Type);
writeMicroRelocation16<E>(Loc, Val, 7, 1);
break;
case R_MICROMIPS_PC10_S1:
- checkInt<11>(Loc, Val, Type);
+ checkInt(Loc, Val, 11, Type);
writeMicroRelocation16<E>(Loc, Val, 10, 1);
break;
case R_MICROMIPS_PC16_S1:
- checkInt<17>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 16, 1);
+ checkInt(Loc, Val, 17, Type);
+ writeShuffleValue<E>(Loc, Val, 16, 1);
break;
case R_MICROMIPS_PC18_S3:
- checkInt<21>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 18, 3);
+ checkInt(Loc, Val, 21, Type);
+ writeShuffleValue<E>(Loc, Val, 18, 3);
break;
case R_MICROMIPS_PC19_S2:
- checkInt<21>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 19, 2);
+ checkInt(Loc, Val, 21, Type);
+ writeShuffleValue<E>(Loc, Val, 19, 2);
break;
case R_MICROMIPS_PC21_S1:
- checkInt<22>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 21, 1);
+ checkInt(Loc, Val, 22, Type);
+ writeShuffleValue<E>(Loc, Val, 21, 1);
break;
case R_MICROMIPS_PC23_S2:
- checkInt<25>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 23, 2);
+ checkInt(Loc, Val, 25, Type);
+ writeShuffleValue<E>(Loc, Val, 23, 2);
break;
default:
error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
@@ -655,19 +635,26 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
template <class ELFT> bool MIPS<ELFT>::usesOnlyLowPageBits(RelType Type) const {
return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST ||
- Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_GOT_OFST;
+ Type == R_MICROMIPS_LO16;
}
// Return true if the symbol is a PIC function.
template <class ELFT> bool elf::isMipsPIC(const Defined *Sym) {
- typedef typename ELFT::Ehdr Elf_Ehdr;
- if (!Sym->Section || !Sym->isFunc())
+ if (!Sym->isFunc())
+ return false;
+
+ if (Sym->StOther & STO_MIPS_PIC)
+ return true;
+
+ if (!Sym->Section)
+ return false;
+
+ ObjFile<ELFT> *File =
+ cast<InputSectionBase>(Sym->Section)->template getFile<ELFT>();
+ if (!File)
return false;
- auto *Sec = cast<InputSectionBase>(Sym->Section);
- const Elf_Ehdr *Hdr = Sec->template getFile<ELFT>()->getObj().getHeader();
- return (Sym->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC ||
- (Hdr->e_flags & EF_MIPS_PIC);
+ return File->getObj().getHeader()->e_flags & EF_MIPS_PIC;
}
template <class ELFT> TargetInfo *elf::getMipsTargetInfo() {
diff --git a/contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp b/contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp
index 754a47001579..98ceac3075e0 100644
--- a/contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp
+++ b/contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp
@@ -65,25 +65,30 @@ static StringRef getNanName(bool IsNan2008) {
static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; }
static void checkFlags(ArrayRef<FileFlags> Files) {
+ assert(!Files.empty() && "expected non-empty file list");
+
uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
bool Nan = Files[0].Flags & EF_MIPS_NAN2008;
bool Fp = Files[0].Flags & EF_MIPS_FP64;
- for (const FileFlags &F : Files.slice(1)) {
+ for (const FileFlags &F : Files) {
+ if (Config->Is64 && F.Flags & EF_MIPS_MICROMIPS)
+ error(toString(F.File) + ": microMIPS 64-bit is not supported");
+
uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
if (ABI != ABI2)
- error("target ABI '" + getAbiName(ABI) + "' is incompatible with '" +
- getAbiName(ABI2) + "': " + toString(F.File));
+ error(toString(F.File) + ": ABI '" + getAbiName(ABI2) +
+ "' is incompatible with target ABI '" + getAbiName(ABI) + "'");
bool Nan2 = F.Flags & EF_MIPS_NAN2008;
if (Nan != Nan2)
- error("target -mnan=" + getNanName(Nan) + " is incompatible with -mnan=" +
- getNanName(Nan2) + ": " + toString(F.File));
+ error(toString(F.File) + ": -mnan=" + getNanName(Nan2) +
+ " is incompatible with target -mnan=" + getNanName(Nan));
bool Fp2 = F.Flags & EF_MIPS_FP64;
if (Fp != Fp2)
- error("target -mfp" + getFpName(Fp) + " is incompatible with -mfp" +
- getFpName(Fp2) + ": " + toString(F.File));
+ error(toString(F.File) + ": -mfp" + getFpName(Fp2) +
+ " is incompatible with target -mfp" + getFpName(Fp));
}
}
@@ -102,11 +107,13 @@ static uint32_t getPicFlags(ArrayRef<FileFlags> Files) {
for (const FileFlags &F : Files.slice(1)) {
bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
if (IsPic && !IsPic2)
- warn("linking abicalls code " + toString(Files[0].File) +
- " with non-abicalls file: " + toString(F.File));
+ warn(toString(F.File) +
+ ": linking non-abicalls code with abicalls code " +
+ toString(Files[0].File));
if (!IsPic && IsPic2)
- warn("linking non-abicalls code " + toString(Files[0].File) +
- " with abicalls file: " + toString(F.File));
+ warn(toString(F.File) +
+ ": linking abicalls code with non-abicalls code " +
+ toString(Files[0].File));
}
// Compute the result PIC/non-PIC flag.
@@ -326,7 +333,7 @@ static StringRef getMipsFpAbiName(uint8_t FpAbi) {
case Mips::Val_GNU_MIPS_ABI_FP_SOFT:
return "-msoft-float";
case Mips::Val_GNU_MIPS_ABI_FP_OLD_64:
- return "-mips32r2 -mfp64 (old)";
+ return "-mgp32 -mfp64 (old)";
case Mips::Val_GNU_MIPS_ABI_FP_XX:
return "-mfpxx";
case Mips::Val_GNU_MIPS_ABI_FP_64:
@@ -343,9 +350,9 @@ uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag,
if (compareMipsFpAbi(NewFlag, OldFlag) >= 0)
return NewFlag;
if (compareMipsFpAbi(OldFlag, NewFlag) < 0)
- error("target floating point ABI '" + getMipsFpAbiName(OldFlag) +
- "' is incompatible with '" + getMipsFpAbiName(NewFlag) +
- "': " + FileName);
+ error(FileName + ": floating point ABI '" + getMipsFpAbiName(NewFlag) +
+ "' is incompatible with target floating point ABI '" +
+ getMipsFpAbiName(OldFlag) + "'");
return OldFlag;
}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp b/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp
index 6af0df331df6..20cae0e59cf4 100644
--- a/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp
+++ b/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp
@@ -21,13 +21,18 @@ using namespace lld::elf;
namespace {
class PPC final : public TargetInfo {
public:
- PPC() { GotBaseSymOff = 0x8000; }
+ PPC();
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
};
} // namespace
+PPC::PPC() {
+ GotBaseSymOff = 0x8000;
+ GotBaseSymInGotPlt = false;
+}
+
RelExpr PPC::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
diff --git a/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp b/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp
index ac4021b5918d..fa3bf6c62a0d 100644
--- a/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp
+++ b/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp
@@ -14,12 +14,14 @@
#include "llvm/Support/Endian.h"
using namespace llvm;
+using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
static uint64_t PPC64TocOffset = 0x8000;
+static uint64_t DynamicThreadPointerOffset = 0x8000;
uint64_t elf::getPPC64TocBase() {
// The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The
@@ -39,11 +41,21 @@ namespace {
class PPC64 final : public TargetInfo {
public:
PPC64();
+ uint32_t calcEFlags() const override;
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
+ void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void writeGotHeader(uint8_t *Buf) const override;
+ bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+ uint64_t BranchAddr, const Symbol &S) const override;
+ RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr Expr) const override;
+ void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
};
} // namespace
@@ -51,21 +63,35 @@ public:
// #higher(value), #highera(value), #highest(value), and #highesta(value)
// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi
// document.
-static uint16_t applyPPCLo(uint64_t V) { return V; }
-static uint16_t applyPPCHi(uint64_t V) { return V >> 16; }
-static uint16_t applyPPCHa(uint64_t V) { return (V + 0x8000) >> 16; }
-static uint16_t applyPPCHigher(uint64_t V) { return V >> 32; }
-static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; }
-static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; }
-static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; }
+static uint16_t lo(uint64_t V) { return V; }
+static uint16_t hi(uint64_t V) { return V >> 16; }
+static uint16_t ha(uint64_t V) { return (V + 0x8000) >> 16; }
+static uint16_t higher(uint64_t V) { return V >> 32; }
+static uint16_t highera(uint64_t V) { return (V + 0x8000) >> 32; }
+static uint16_t highest(uint64_t V) { return V >> 48; }
+static uint16_t highesta(uint64_t V) { return (V + 0x8000) >> 48; }
PPC64::PPC64() {
- PltRel = GotRel = R_PPC64_GLOB_DAT;
+ GotRel = R_PPC64_GLOB_DAT;
+ PltRel = R_PPC64_JMP_SLOT;
RelativeRel = R_PPC64_RELATIVE;
+ IRelativeRel = R_PPC64_IRELATIVE;
GotEntrySize = 8;
+ PltEntrySize = 4;
GotPltEntrySize = 8;
- PltEntrySize = 32;
- PltHeaderSize = 0;
+ GotBaseSymInGotPlt = false;
+ GotBaseSymOff = 0x8000;
+ GotHeaderEntriesNum = 1;
+ GotPltHeaderEntriesNum = 2;
+ PltHeaderSize = 60;
+ NeedsThunks = true;
+ TcbSize = 8;
+ TlsTpOffset = 0x7000;
+
+ TlsModuleIndexRel = R_PPC64_DTPMOD64;
+ TlsOffsetRel = R_PPC64_DTPREL64;
+
+ TlsGotRel = R_PPC64_TPREL64;
// We need 64K pages (at least under glibc/Linux, the loader won't
// set different permissions on a finer granularity than that).
@@ -80,6 +106,110 @@ PPC64::PPC64() {
// And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers
// use 0x10000000 as the starting address.
DefaultImageBase = 0x10000000;
+
+ TrapInstr =
+ (Config->IsLE == sys::IsLittleEndianHost) ? 0x7fe00008 : 0x0800e07f;
+}
+
+static uint32_t getEFlags(InputFile *File) {
+ if (Config->EKind == ELF64BEKind)
+ return cast<ObjFile<ELF64BE>>(File)->getObj().getHeader()->e_flags;
+ return cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags;
+}
+
+// This file implements v2 ABI. This function makes sure that all
+// object files have v2 or an unspecified version as an ABI version.
+uint32_t PPC64::calcEFlags() const {
+ for (InputFile *F : ObjectFiles) {
+ uint32_t Flag = getEFlags(F);
+ if (Flag == 1)
+ error(toString(F) + ": ABI version 1 is not supported");
+ else if (Flag > 2)
+ error(toString(F) + ": unrecognized e_flags: " + Twine(Flag));
+ }
+ return 2;
+}
+
+void PPC64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ // Reference: 3.7.4.2 of the 64-bit ELF V2 abi supplement.
+ // The general dynamic code sequence for a global `x` will look like:
+ // Instruction Relocation Symbol
+ // addis r3, r2, x@got@tlsgd@ha R_PPC64_GOT_TLSGD16_HA x
+ // addi r3, r3, x@got@tlsgd@l R_PPC64_GOT_TLSGD16_LO x
+ // bl __tls_get_addr(x@tlsgd) R_PPC64_TLSGD x
+ // R_PPC64_REL24 __tls_get_addr
+ // nop None None
+
+ // Relaxing to local exec entails converting:
+ // addis r3, r2, x@got@tlsgd@ha into nop
+ // addi r3, r3, x@got@tlsgd@l into addis r3, r13, x@tprel@ha
+ // bl __tls_get_addr(x@tlsgd) into nop
+ // nop into addi r3, r3, x@tprel@l
+
+ uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
+
+ switch (Type) {
+ case R_PPC64_GOT_TLSGD16_HA:
+ write32(Loc - EndianOffset, 0x60000000); // nop
+ break;
+ case R_PPC64_GOT_TLSGD16_LO:
+ write32(Loc - EndianOffset, 0x3c6d0000); // addis r3, r13
+ relocateOne(Loc, R_PPC64_TPREL16_HA, Val);
+ break;
+ case R_PPC64_TLSGD:
+ write32(Loc, 0x60000000); // nop
+ write32(Loc + 4, 0x38630000); // addi r3, r3
+ relocateOne(Loc + 4 + EndianOffset, R_PPC64_TPREL16_LO, Val);
+ break;
+ default:
+ llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
+ }
+}
+
+
+void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ // Reference: 3.7.4.3 of the 64-bit ELF V2 abi supplement.
+ // The local dynamic code sequence for a global `x` will look like:
+ // Instruction Relocation Symbol
+ // addis r3, r2, x@got@tlsld@ha R_PPC64_GOT_TLSLD16_HA x
+ // addi r3, r3, x@got@tlsld@l R_PPC64_GOT_TLSLD16_LO x
+ // bl __tls_get_addr(x@tlsgd) R_PPC64_TLSLD x
+ // R_PPC64_REL24 __tls_get_addr
+ // nop None None
+
+ // Relaxing to local exec entails converting:
+ // addis r3, r2, x@got@tlsld@ha into nop
+ // addi r3, r3, x@got@tlsld@l into addis r3, r13, 0
+ // bl __tls_get_addr(x@tlsgd) into nop
+ // nop into addi r3, r3, 4096
+
+ uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
+ switch (Type) {
+ case R_PPC64_GOT_TLSLD16_HA:
+ write32(Loc - EndianOffset, 0x60000000); // nop
+ break;
+ case R_PPC64_GOT_TLSLD16_LO:
+ write32(Loc - EndianOffset, 0x3c6d0000); // addis r3, r13, 0
+ break;
+ case R_PPC64_TLSLD:
+ write32(Loc, 0x60000000); // nop
+ write32(Loc + 4, 0x38631000); // addi r3, r3, 4096
+ break;
+ case R_PPC64_DTPREL16:
+ case R_PPC64_DTPREL16_HA:
+ case R_PPC64_DTPREL16_HI:
+ case R_PPC64_DTPREL16_DS:
+ case R_PPC64_DTPREL16_LO:
+ case R_PPC64_DTPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_GOT_DTPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_DS:
+ case R_PPC64_GOT_DTPREL16_HI:
+ relocateOne(Loc, Type, Val);
+ break;
+ default:
+ llvm_unreachable("unsupported relocation for TLS LD to LE relaxation");
+ }
}
RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
@@ -95,48 +225,162 @@ RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
case R_PPC64_TOC:
return R_PPC_TOC;
case R_PPC64_REL24:
- return R_PPC_PLT_OPD;
+ return R_PPC_CALL_PLT;
+ case R_PPC64_REL16_LO:
+ case R_PPC64_REL16_HA:
+ case R_PPC64_REL32:
+ case R_PPC64_REL64:
+ return R_PC;
+ case R_PPC64_GOT_TLSGD16:
+ case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TLSGD16_HI:
+ case R_PPC64_GOT_TLSGD16_LO:
+ return R_TLSGD_GOT;
+ case R_PPC64_GOT_TLSLD16:
+ case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TLSLD16_HI:
+ case R_PPC64_GOT_TLSLD16_LO:
+ return R_TLSLD_GOT;
+ case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_TPREL16_LO_DS:
+ case R_PPC64_GOT_TPREL16_DS:
+ case R_PPC64_GOT_TPREL16_HI:
+ return R_GOT_OFF;
+ case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_GOT_DTPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_DS:
+ case R_PPC64_GOT_DTPREL16_HI:
+ return R_TLSLD_GOT_OFF;
+ case R_PPC64_TPREL16:
+ case R_PPC64_TPREL16_HA:
+ case R_PPC64_TPREL16_LO:
+ case R_PPC64_TPREL16_HI:
+ case R_PPC64_TPREL16_DS:
+ case R_PPC64_TPREL16_LO_DS:
+ case R_PPC64_TPREL16_HIGHER:
+ case R_PPC64_TPREL16_HIGHERA:
+ case R_PPC64_TPREL16_HIGHEST:
+ case R_PPC64_TPREL16_HIGHESTA:
+ return R_TLS;
+ case R_PPC64_DTPREL16:
+ case R_PPC64_DTPREL16_DS:
+ case R_PPC64_DTPREL16_HA:
+ case R_PPC64_DTPREL16_HI:
+ case R_PPC64_DTPREL16_HIGHER:
+ case R_PPC64_DTPREL16_HIGHERA:
+ case R_PPC64_DTPREL16_HIGHEST:
+ case R_PPC64_DTPREL16_HIGHESTA:
+ case R_PPC64_DTPREL16_LO:
+ case R_PPC64_DTPREL16_LO_DS:
+ case R_PPC64_DTPREL64:
+ return R_ABS;
+ case R_PPC64_TLSGD:
+ return R_TLSDESC_CALL;
+ case R_PPC64_TLSLD:
+ return R_TLSLD_HINT;
+ case R_PPC64_TLS:
+ return R_HINT;
default:
return R_ABS;
}
}
+void PPC64::writeGotHeader(uint8_t *Buf) const {
+ write64(Buf, getPPC64TocBase());
+}
+
+void PPC64::writePltHeader(uint8_t *Buf) const {
+ // The generic resolver stub goes first.
+ write32(Buf + 0, 0x7c0802a6); // mflr r0
+ write32(Buf + 4, 0x429f0005); // bcl 20,4*cr7+so,8 <_glink+0x8>
+ write32(Buf + 8, 0x7d6802a6); // mflr r11
+ write32(Buf + 12, 0x7c0803a6); // mtlr r0
+ write32(Buf + 16, 0x7d8b6050); // subf r12, r11, r12
+ write32(Buf + 20, 0x380cffcc); // subi r0,r12,52
+ write32(Buf + 24, 0x7800f082); // srdi r0,r0,62,2
+ write32(Buf + 28, 0xe98b002c); // ld r12,44(r11)
+ write32(Buf + 32, 0x7d6c5a14); // add r11,r12,r11
+ write32(Buf + 36, 0xe98b0000); // ld r12,0(r11)
+ write32(Buf + 40, 0xe96b0008); // ld r11,8(r11)
+ write32(Buf + 44, 0x7d8903a6); // mtctr r12
+ write32(Buf + 48, 0x4e800420); // bctr
+
+ // The 'bcl' instruction will set the link register to the address of the
+ // following instruction ('mflr r11'). Here we store the offset from that
+ // instruction to the first entry in the GotPlt section.
+ int64_t GotPltOffset = InX::GotPlt->getVA() - (InX::Plt->getVA() + 8);
+ write64(Buf + 52, GotPltOffset);
+}
+
void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
- uint64_t Off = GotPltEntryAddr - getPPC64TocBase();
-
- // FIXME: What we should do, in theory, is get the offset of the function
- // descriptor in the .opd section, and use that as the offset from %r2 (the
- // TOC-base pointer). Instead, we have the GOT-entry offset, and that will
- // be a pointer to the function descriptor in the .opd section. Using
- // this scheme is simpler, but requires an extra indirection per PLT dispatch.
-
- write32be(Buf, 0xf8410028); // std %r2, 40(%r1)
- write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha
- write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11)
- write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12)
- write32be(Buf + 16, 0x7d6903a6); // mtctr %r11
- write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12)
- write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12)
- write32be(Buf + 28, 0x4e800420); // bctr
+ int32_t Offset = PltHeaderSize + Index * PltEntrySize;
+ // bl __glink_PLTresolve
+ write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc));
}
static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
- uint64_t V = Val - PPC64TocOffset;
+ // Relocations relative to the toc-base need to be adjusted by the Toc offset.
+ uint64_t TocBiasedVal = Val - PPC64TocOffset;
+ // Relocations relative to dtv[dtpmod] need to be adjusted by the DTP offset.
+ uint64_t DTPBiasedVal = Val - DynamicThreadPointerOffset;
+
switch (Type) {
+ // TOC biased relocation.
+ case R_PPC64_GOT_TLSGD16:
+ case R_PPC64_GOT_TLSLD16:
case R_PPC64_TOC16:
- return {R_PPC64_ADDR16, V};
+ return {R_PPC64_ADDR16, TocBiasedVal};
case R_PPC64_TOC16_DS:
- return {R_PPC64_ADDR16_DS, V};
+ case R_PPC64_GOT_TPREL16_DS:
+ case R_PPC64_GOT_DTPREL16_DS:
+ return {R_PPC64_ADDR16_DS, TocBiasedVal};
+ case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_DTPREL16_HA:
case R_PPC64_TOC16_HA:
- return {R_PPC64_ADDR16_HA, V};
+ return {R_PPC64_ADDR16_HA, TocBiasedVal};
+ case R_PPC64_GOT_TLSGD16_HI:
+ case R_PPC64_GOT_TLSLD16_HI:
+ case R_PPC64_GOT_TPREL16_HI:
+ case R_PPC64_GOT_DTPREL16_HI:
case R_PPC64_TOC16_HI:
- return {R_PPC64_ADDR16_HI, V};
+ return {R_PPC64_ADDR16_HI, TocBiasedVal};
+ case R_PPC64_GOT_TLSGD16_LO:
+ case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_TOC16_LO:
- return {R_PPC64_ADDR16_LO, V};
+ return {R_PPC64_ADDR16_LO, TocBiasedVal};
case R_PPC64_TOC16_LO_DS:
- return {R_PPC64_ADDR16_LO_DS, V};
+ case R_PPC64_GOT_TPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_LO_DS:
+ return {R_PPC64_ADDR16_LO_DS, TocBiasedVal};
+
+ // Dynamic Thread pointer biased relocation types.
+ case R_PPC64_DTPREL16:
+ return {R_PPC64_ADDR16, DTPBiasedVal};
+ case R_PPC64_DTPREL16_DS:
+ return {R_PPC64_ADDR16_DS, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HA:
+ return {R_PPC64_ADDR16_HA, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HI:
+ return {R_PPC64_ADDR16_HI, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HIGHER:
+ return {R_PPC64_ADDR16_HIGHER, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HIGHERA:
+ return {R_PPC64_ADDR16_HIGHERA, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HIGHEST:
+ return {R_PPC64_ADDR16_HIGHEST, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HIGHESTA:
+ return {R_PPC64_ADDR16_HIGHESTA, DTPBiasedVal};
+ case R_PPC64_DTPREL16_LO:
+ return {R_PPC64_ADDR16_LO, DTPBiasedVal};
+ case R_PPC64_DTPREL16_LO_DS:
+ return {R_PPC64_ADDR16_LO_DS, DTPBiasedVal};
+ case R_PPC64_DTPREL64:
+ return {R_PPC64_ADDR64, DTPBiasedVal};
+
default:
return {Type, Val};
}
@@ -149,68 +393,139 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
switch (Type) {
case R_PPC64_ADDR14: {
- checkAlignment<4>(Loc, Val, Type);
+ checkAlignment(Loc, Val, 4, Type);
// Preserve the AA/LK bits in the branch instruction
uint8_t AALK = Loc[3];
- write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc));
+ write16(Loc + 2, (AALK & 3) | (Val & 0xfffc));
break;
}
case R_PPC64_ADDR16:
- checkInt<16>(Loc, Val, Type);
- write16be(Loc, Val);
+ case R_PPC64_TPREL16:
+ checkInt(Loc, Val, 16, Type);
+ write16(Loc, Val);
break;
case R_PPC64_ADDR16_DS:
- checkInt<16>(Loc, Val, Type);
- write16be(Loc, (read16be(Loc) & 3) | (Val & ~3));
+ case R_PPC64_TPREL16_DS:
+ checkInt(Loc, Val, 16, Type);
+ write16(Loc, (read16(Loc) & 3) | (Val & ~3));
break;
case R_PPC64_ADDR16_HA:
case R_PPC64_REL16_HA:
- write16be(Loc, applyPPCHa(Val));
+ case R_PPC64_TPREL16_HA:
+ write16(Loc, ha(Val));
break;
case R_PPC64_ADDR16_HI:
case R_PPC64_REL16_HI:
- write16be(Loc, applyPPCHi(Val));
+ case R_PPC64_TPREL16_HI:
+ write16(Loc, hi(Val));
break;
case R_PPC64_ADDR16_HIGHER:
- write16be(Loc, applyPPCHigher(Val));
+ case R_PPC64_TPREL16_HIGHER:
+ write16(Loc, higher(Val));
break;
case R_PPC64_ADDR16_HIGHERA:
- write16be(Loc, applyPPCHighera(Val));
+ case R_PPC64_TPREL16_HIGHERA:
+ write16(Loc, highera(Val));
break;
case R_PPC64_ADDR16_HIGHEST:
- write16be(Loc, applyPPCHighest(Val));
+ case R_PPC64_TPREL16_HIGHEST:
+ write16(Loc, highest(Val));
break;
case R_PPC64_ADDR16_HIGHESTA:
- write16be(Loc, applyPPCHighesta(Val));
+ case R_PPC64_TPREL16_HIGHESTA:
+ write16(Loc, highesta(Val));
break;
case R_PPC64_ADDR16_LO:
- write16be(Loc, applyPPCLo(Val));
+ case R_PPC64_REL16_LO:
+ case R_PPC64_TPREL16_LO:
+ write16(Loc, lo(Val));
break;
case R_PPC64_ADDR16_LO_DS:
- case R_PPC64_REL16_LO:
- write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3));
+ case R_PPC64_TPREL16_LO_DS:
+ write16(Loc, (read16(Loc) & 3) | (lo(Val) & ~3));
break;
case R_PPC64_ADDR32:
case R_PPC64_REL32:
- checkInt<32>(Loc, Val, Type);
- write32be(Loc, Val);
+ checkInt(Loc, Val, 32, Type);
+ write32(Loc, Val);
break;
case R_PPC64_ADDR64:
case R_PPC64_REL64:
case R_PPC64_TOC:
- write64be(Loc, Val);
+ write64(Loc, Val);
break;
case R_PPC64_REL24: {
uint32_t Mask = 0x03FFFFFC;
- checkInt<24>(Loc, Val, Type);
- write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask));
+ checkInt(Loc, Val, 24, Type);
+ write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask));
break;
}
+ case R_PPC64_DTPREL64:
+ write64(Loc, Val - DynamicThreadPointerOffset);
+ break;
default:
error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
}
}
+bool PPC64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+ uint64_t BranchAddr, const Symbol &S) const {
+ // If a function is in the plt it needs to be called through
+ // a call stub.
+ return Type == R_PPC64_REL24 && S.isInPlt();
+}
+
+RelExpr PPC64::adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr Expr) const {
+ if (Expr == R_RELAX_TLS_GD_TO_IE)
+ return R_RELAX_TLS_GD_TO_IE_GOT_OFF;
+ if (Expr == R_RELAX_TLS_LD_TO_LE)
+ return R_RELAX_TLS_LD_TO_LE_ABS;
+ return Expr;
+}
+
+// Reference: 3.7.4.1 of the 64-bit ELF V2 abi supplement.
+// The general dynamic code sequence for a global `x` uses 4 instructions.
+// Instruction Relocation Symbol
+// addis r3, r2, x@got@tlsgd@ha R_PPC64_GOT_TLSGD16_HA x
+// addi r3, r3, x@got@tlsgd@l R_PPC64_GOT_TLSGD16_LO x
+// bl __tls_get_addr(x@tlsgd) R_PPC64_TLSGD x
+// R_PPC64_REL24 __tls_get_addr
+// nop None None
+//
+// Relaxing to initial-exec entails:
+// 1) Convert the addis/addi pair that builds the address of the tls_index
+// struct for 'x' to an addis/ld pair that loads an offset from a got-entry.
+// 2) Convert the call to __tls_get_addr to a nop.
+// 3) Convert the nop following the call to an add of the loaded offset to the
+// thread pointer.
+// Since the nop must directly follow the call, the R_PPC64_TLSGD relocation is
+// used as the relaxation hint for both steps 2 and 3.
+void PPC64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_PPC64_GOT_TLSGD16_HA:
+ // This is relaxed from addis rT, r2, sym@got@tlsgd@ha to
+ // addis rT, r2, sym@got@tprel@ha.
+ relocateOne(Loc, R_PPC64_GOT_TPREL16_HA, Val);
+ return;
+ case R_PPC64_GOT_TLSGD16_LO: {
+ // Relax from addi r3, rA, sym@got@tlsgd@l to
+ // ld r3, sym@got@tprel@l(rA)
+ uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
+ uint32_t InputRegister = (read32(Loc - EndianOffset) & (0x1f << 16));
+ write32(Loc - EndianOffset, 0xE8600000 | InputRegister);
+ relocateOne(Loc, R_PPC64_GOT_TPREL16_LO_DS, Val);
+ return;
+ }
+ case R_PPC64_TLSGD:
+ write32(Loc, 0x60000000); // bl __tls_get_addr(sym@tlsgd) --> nop
+ write32(Loc + 4, 0x7c636A14); // nop --> add r3, r3, r13
+ return;
+ default:
+ llvm_unreachable("unsupported relocation for TLS GD to IE relaxation");
+ }
+}
+
TargetInfo *elf::getPPC64TargetInfo() {
static PPC64 Target;
return &Target;
diff --git a/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp b/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp
index d9d6e1390407..36f5c836930e 100644
--- a/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp
+++ b/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp
@@ -77,23 +77,23 @@ void SPARCV9::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_SPARC_32:
case R_SPARC_UA32:
// V-word32
- checkUInt<32>(Loc, Val, Type);
+ checkUInt(Loc, Val, 32, Type);
write32be(Loc, Val);
break;
case R_SPARC_DISP32:
// V-disp32
- checkInt<32>(Loc, Val, Type);
+ checkInt(Loc, Val, 32, Type);
write32be(Loc, Val);
break;
case R_SPARC_WDISP30:
case R_SPARC_WPLT30:
// V-disp30
- checkInt<32>(Loc, Val, Type);
+ checkInt(Loc, Val, 32, Type);
write32be(Loc, (read32be(Loc) & ~0x3fffffff) | ((Val >> 2) & 0x3fffffff));
break;
case R_SPARC_22:
// V-imm22
- checkUInt<22>(Loc, Val, Type);
+ checkUInt(Loc, Val, 22, Type);
write32be(Loc, (read32be(Loc) & ~0x003fffff) | (Val & 0x003fffff));
break;
case R_SPARC_GOT22:
@@ -103,7 +103,7 @@ void SPARCV9::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
break;
case R_SPARC_WDISP19:
// V-disp19
- checkInt<21>(Loc, Val, Type);
+ checkInt(Loc, Val, 21, Type);
write32be(Loc, (read32be(Loc) & ~0x0007ffff) | ((Val >> 2) & 0x0007ffff));
break;
case R_SPARC_GOT10:
@@ -137,7 +137,7 @@ void SPARCV9::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
};
memcpy(Buf, PltData, sizeof(PltData));
- uint64_t Off = PltHeaderSize + Index * PltEntrySize;
+ uint64_t Off = getPltEntryOffset(Index);
relocateOne(Buf, R_SPARC_22, Off);
relocateOne(Buf + 4, R_SPARC_WDISP19, -(Off + 4 - PltEntrySize));
}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/X86.cpp b/contrib/llvm/tools/lld/ELF/Arch/X86.cpp
index 94b46acdd896..0624fe78750c 100644
--- a/contrib/llvm/tools/lld/ELF/Arch/X86.cpp
+++ b/contrib/llvm/tools/lld/ELF/Arch/X86.cpp
@@ -46,7 +46,6 @@ public:
} // namespace
X86::X86() {
- GotBaseSymOff = -1;
CopyRel = R_386_COPY;
GotRel = R_386_GLOB_DAT;
PltRel = R_386_JUMP_SLOT;
@@ -78,9 +77,9 @@ RelExpr X86::getRelExpr(RelType Type, const Symbol &S,
case R_386_TLS_LDO_32:
return R_ABS;
case R_386_TLS_GD:
- return R_TLSGD;
+ return R_TLSGD_GOT_FROM_END;
case R_386_TLS_LDM:
- return R_TLSLD;
+ return R_TLSLD_GOT_FROM_END;
case R_386_PLT32:
return R_PLT_PC;
case R_386_PC8:
@@ -228,7 +227,7 @@ void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
}
write32le(Buf + 7, RelOff);
- write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
+ write32le(Buf + 12, -getPltEntryOffset(Index) - 16);
}
int64_t X86::getImplicitAddend(const uint8_t *Buf, RelType Type) const {
@@ -260,15 +259,15 @@ void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
// R_386_{PC,}{8,16} are not part of the i386 psABI, but they are
// being used for some 16-bit programs such as boot loaders, so
// we want to support them.
- checkUInt<8>(Loc, Val, Type);
+ checkIntUInt(Loc, Val, 8, Type);
*Loc = Val;
break;
case R_386_PC8:
- checkInt<8>(Loc, Val, Type);
+ checkInt(Loc, Val, 8, Type);
*Loc = Val;
break;
case R_386_16:
- checkUInt<16>(Loc, Val, Type);
+ checkIntUInt(Loc, Val, 16, Type);
write16le(Loc, Val);
break;
case R_386_PC16:
@@ -282,7 +281,7 @@ void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
// current location subtracted from it.
// We just check that Val fits in 17 bits. This misses some cases, but
// should have no false positives.
- checkInt<17>(Loc, Val, Type);
+ checkInt(Loc, Val, 17, Type);
write16le(Loc, Val);
break;
case R_386_32:
@@ -305,7 +304,7 @@ void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_386_TLS_LE_32:
case R_386_TLS_TPOFF:
case R_386_TLS_TPOFF32:
- checkInt<32>(Loc, Val, Type);
+ checkInt(Loc, Val, 32, Type);
write32le(Loc, Val);
break;
default:
@@ -448,6 +447,7 @@ void RetpolinePic::writePltHeader(uint8_t *Buf) const {
0x89, 0xc8, // 2b: mov %ecx, %eax
0x59, // 2d: pop %ecx
0xc3, // 2e: ret
+ 0xcc, // 2f: int3; padding
};
memcpy(Buf, Insn, sizeof(Insn));
@@ -461,21 +461,23 @@ void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const uint8_t Insn[] = {
- 0x50, // pushl %eax
- 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax
- 0xe8, 0, 0, 0, 0, // call plt+0x20
- 0xe9, 0, 0, 0, 0, // jmp plt+0x12
- 0x68, 0, 0, 0, 0, // pushl $reloc_offset
- 0xe9, 0, 0, 0, 0, // jmp plt+0
+ 0x50, // pushl %eax
+ 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax
+ 0xe8, 0, 0, 0, 0, // call plt+0x20
+ 0xe9, 0, 0, 0, 0, // jmp plt+0x12
+ 0x68, 0, 0, 0, 0, // pushl $reloc_offset
+ 0xe9, 0, 0, 0, 0, // jmp plt+0
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding
};
memcpy(Buf, Insn, sizeof(Insn));
uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
+ unsigned Off = getPltEntryOffset(Index);
write32le(Buf + 3, GotPltEntryAddr - Ebx);
- write32le(Buf + 8, -Index * PltEntrySize - PltHeaderSize - 12 + 32);
- write32le(Buf + 13, -Index * PltEntrySize - PltHeaderSize - 17 + 18);
+ write32le(Buf + 8, -Off - 12 + 32);
+ write32le(Buf + 13, -Off - 17 + 18);
write32le(Buf + 18, RelOff);
- write32le(Buf + 23, -Index * PltEntrySize - PltHeaderSize - 27);
+ write32le(Buf + 23, -Off - 27);
}
RetpolineNoPic::RetpolineNoPic() {
@@ -488,7 +490,7 @@ void RetpolineNoPic::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
}
void RetpolineNoPic::writePltHeader(uint8_t *Buf) const {
- const uint8_t PltData[] = {
+ const uint8_t Insn[] = {
0xff, 0x35, 0, 0, 0, 0, // 0: pushl GOTPLT+4
0x50, // 6: pushl %eax
0xa1, 0, 0, 0, 0, // 7: mov GOTPLT+8, %eax
@@ -504,8 +506,9 @@ void RetpolineNoPic::writePltHeader(uint8_t *Buf) const {
0x89, 0xc8, // 2b: mov %ecx, %eax
0x59, // 2d: pop %ecx
0xc3, // 2e: ret
+ 0xcc, // 2f: int3; padding
};
- memcpy(Buf, PltData, sizeof(PltData));
+ memcpy(Buf, Insn, sizeof(Insn));
uint32_t GotPlt = InX::GotPlt->getVA();
write32le(Buf + 2, GotPlt + 4);
@@ -516,20 +519,23 @@ void RetpolineNoPic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const uint8_t Insn[] = {
- 0x50, // 0: pushl %eax
- 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax
- 0xe8, 0, 0, 0, 0, // 6: call plt+0x20
- 0xe9, 0, 0, 0, 0, // b: jmp plt+0x11
- 0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset
- 0xe9, 0, 0, 0, 0, // 15: jmp plt+0
+ 0x50, // 0: pushl %eax
+ 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax
+ 0xe8, 0, 0, 0, 0, // 6: call plt+0x20
+ 0xe9, 0, 0, 0, 0, // b: jmp plt+0x11
+ 0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset
+ 0xe9, 0, 0, 0, 0, // 15: jmp plt+0
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding
+ 0xcc, // 1f: int3; padding
};
memcpy(Buf, Insn, sizeof(Insn));
+ unsigned Off = getPltEntryOffset(Index);
write32le(Buf + 2, GotPltEntryAddr);
- write32le(Buf + 7, -Index * PltEntrySize - PltHeaderSize - 11 + 32);
- write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16 + 17);
+ write32le(Buf + 7, -Off - 11 + 32);
+ write32le(Buf + 12, -Off - 16 + 17);
write32le(Buf + 17, RelOff);
- write32le(Buf + 22, -Index * PltEntrySize - PltHeaderSize - 26);
+ write32le(Buf + 22, -Off - 26);
}
TargetInfo *elf::getX86TargetInfo() {
diff --git a/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp b/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp
index 3db391e9f01c..d4bdb3730c58 100644
--- a/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp
+++ b/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp
@@ -28,7 +28,7 @@ public:
X86_64();
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
- bool isPicRel(RelType Type) const override;
+ RelType getDynRel(RelType Type) const override;
void writeGotPltHeader(uint8_t *Buf) const override;
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
void writePltHeader(uint8_t *Buf) const override;
@@ -43,6 +43,8 @@ public:
void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ bool adjustPrologueForCrossSplitStack(uint8_t *Loc,
+ uint8_t *End) const override;
private:
void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op,
@@ -51,7 +53,6 @@ private:
} // namespace
template <class ELFT> X86_64<ELFT>::X86_64() {
- GotBaseSymOff = -1;
CopyRel = R_X86_64_COPY;
GotRel = R_X86_64_GLOB_DAT;
PltRel = R_X86_64_JUMP_SLOT;
@@ -106,6 +107,11 @@ RelExpr X86_64<ELFT>::getRelExpr(RelType Type, const Symbol &S,
case R_X86_64_REX_GOTPCRELX:
case R_X86_64_GOTTPOFF:
return R_GOT_PC;
+ case R_X86_64_GOTOFF64:
+ return R_GOTREL_FROM_END;
+ case R_X86_64_GOTPC32:
+ case R_X86_64_GOTPC64:
+ return R_GOTONLY_PC_FROM_END;
case R_X86_64_NONE:
return R_NONE;
default:
@@ -124,7 +130,7 @@ template <class ELFT> void X86_64<ELFT>::writeGotPltHeader(uint8_t *Buf) const {
template <class ELFT>
void X86_64<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
// See comments in X86::writeGotPlt.
- write32le(Buf, S.getPltVA() + 6);
+ write64le(Buf, S.getPltVA() + 6);
}
template <class ELFT> void X86_64<ELFT>::writePltHeader(uint8_t *Buf) const {
@@ -153,12 +159,14 @@ void X86_64<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6);
write32le(Buf + 7, Index);
- write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
+ write32le(Buf + 12, -getPltEntryOffset(Index) - 16);
}
-template <class ELFT> bool X86_64<ELFT>::isPicRel(RelType Type) const {
- return Type != R_X86_64_PC32 && Type != R_X86_64_32 &&
- Type != R_X86_64_TPOFF32;
+template <class ELFT> RelType X86_64<ELFT>::getDynRel(RelType Type) const {
+ if (Type == R_X86_64_64 || Type == R_X86_64_PC64 || Type == R_X86_64_SIZE32 ||
+ Type == R_X86_64_SIZE64)
+ return Type;
+ return R_X86_64_NONE;
}
template <class ELFT>
@@ -285,20 +293,21 @@ template <class ELFT>
void X86_64<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
switch (Type) {
case R_X86_64_8:
- checkUInt<8>(Loc, Val, Type);
+ checkUInt(Loc, Val, 8, Type);
*Loc = Val;
break;
case R_X86_64_16:
- checkUInt<16>(Loc, Val, Type);
+ checkUInt(Loc, Val, 16, Type);
write16le(Loc, Val);
break;
case R_X86_64_32:
- checkUInt<32>(Loc, Val, Type);
+ checkUInt(Loc, Val, 32, Type);
write32le(Loc, Val);
break;
case R_X86_64_32S:
case R_X86_64_TPOFF32:
case R_X86_64_GOT32:
+ case R_X86_64_GOTPC32:
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
case R_X86_64_REX_GOTPCRELX:
@@ -309,7 +318,7 @@ void X86_64<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_X86_64_TLSLD:
case R_X86_64_DTPOFF32:
case R_X86_64_SIZE32:
- checkInt<32>(Loc, Val, Type);
+ checkInt(Loc, Val, 32, Type);
write32le(Loc, Val);
break;
case R_X86_64_64:
@@ -318,6 +327,8 @@ void X86_64<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_X86_64_PC64:
case R_X86_64_SIZE64:
case R_X86_64_GOT64:
+ case R_X86_64_GOTOFF64:
+ case R_X86_64_GOTPC64:
write64le(Loc, Val);
break;
default:
@@ -460,6 +471,55 @@ void X86_64<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
write32le(Loc - 1, Val + 1);
}
+// This anonymous namespace works around a warning bug in
+// old versions of gcc. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480
+namespace {
+
+// A split-stack prologue starts by checking the amount of stack remaining
+// in one of two ways:
+// A) Comparing of the stack pointer to a field in the tcb.
+// B) Or a load of a stack pointer offset with an lea to r10 or r11.
+template <>
+bool X86_64<ELF64LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc,
+ uint8_t *End) const {
+ // Replace "cmp %fs:0x70,%rsp" and subsequent branch
+ // with "stc, nopl 0x0(%rax,%rax,1)"
+ if (Loc + 8 < End && memcmp(Loc, "\x64\x48\x3b\x24\x25", 4) == 0) {
+ memcpy(Loc, "\xf9\x0f\x1f\x84\x00\x00\x00\x00", 8);
+ return true;
+ }
+
+ // Adjust "lea -0x200(%rsp),%r10" to lea "-0x4200(%rsp),%r10"
+ if (Loc + 7 < End && memcmp(Loc, "\x4c\x8d\x94\x24\x00\xfe\xff", 7) == 0) {
+ memcpy(Loc, "\x4c\x8d\x94\x24\x00\xbe\xff", 7);
+ return true;
+ }
+
+ // Adjust "lea -0x200(%rsp),%r11" to lea "-0x4200(%rsp),%r11"
+ if (Loc + 7 < End && memcmp(Loc, "\x4c\x8d\x9c\x24\x00\xfe\xff", 7) == 0) {
+ memcpy(Loc, "\x4c\x8d\x9c\x24\x00\xbe\xff", 7);
+ return true;
+ }
+ return false;
+}
+
+template <>
+bool X86_64<ELF32LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc,
+ uint8_t *End) const {
+ llvm_unreachable("Target doesn't support split stacks.");
+}
+
+} // namespace
+
+// These nonstandard PLT entries are to migtigate Spectre v2 security
+// vulnerability. In order to mitigate Spectre v2, we want to avoid indirect
+// branch instructions such as `jmp *GOTPLT(%rip)`. So, in the following PLT
+// entries, we use a CALL followed by MOV and RET to do the same thing as an
+// indirect jump. That instruction sequence is so-called "retpoline".
+//
+// We have two types of retpoline PLTs as a size optimization. If `-z now`
+// is specified, all dynamic symbols are resolved at load-time. Thus, when
+// that option is given, we can omit code for symbol lazy resolution.
namespace {
template <class ELFT> class Retpoline : public X86_64<ELFT> {
public:
@@ -487,7 +547,7 @@ template <class ELFT> Retpoline<ELFT>::Retpoline() {
template <class ELFT>
void Retpoline<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
- write32le(Buf, S.getPltVA() + 17);
+ write64le(Buf, S.getPltVA() + 17);
}
template <class ELFT> void Retpoline<ELFT>::writePltHeader(uint8_t *Buf) const {
@@ -501,6 +561,8 @@ template <class ELFT> void Retpoline<ELFT>::writePltHeader(uint8_t *Buf) const {
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16
0x4c, 0x89, 0x1c, 0x24, // 20: next: mov %r11, (%rsp)
0xc3, // 24: ret
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 25: int3; padding
+ 0xcc, 0xcc, 0xcc, 0xcc, // 2c: int3; padding
};
memcpy(Buf, Insn, sizeof(Insn));
@@ -516,14 +578,15 @@ void Retpoline<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
unsigned RelOff) const {
const uint8_t Insn[] = {
0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 0: mov foo@GOTPLT(%rip), %r11
- 0xe8, 0, 0, 0, 0, // 7: callq plt+0x20
- 0xe9, 0, 0, 0, 0, // c: jmp plt+0x12
- 0x68, 0, 0, 0, 0, // 11: pushq <relocation index>
- 0xe9, 0, 0, 0, 0, // 16: jmp plt+0
+ 0xe8, 0, 0, 0, 0, // 7: callq plt+0x20
+ 0xe9, 0, 0, 0, 0, // c: jmp plt+0x12
+ 0x68, 0, 0, 0, 0, // 11: pushq <relocation index>
+ 0xe9, 0, 0, 0, 0, // 16: jmp plt+0
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1b: int3; padding
};
memcpy(Buf, Insn, sizeof(Insn));
- uint64_t Off = TargetInfo::PltHeaderSize + TargetInfo::PltEntrySize * Index;
+ uint64_t Off = TargetInfo::getPltEntryOffset(Index);
write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7);
write32le(Buf + 8, -Off - 12 + 32);
@@ -547,6 +610,9 @@ void RetpolineZNow<ELFT>::writePltHeader(uint8_t *Buf) const {
0xcc, 0xcc, 0xcc, 0xcc, // c: int3; .align 16
0x4c, 0x89, 0x1c, 0x24, // 10: next: mov %r11, (%rsp)
0xc3, // 14: ret
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 15: int3; padding
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding
+ 0xcc, // 1f: int3; padding
};
memcpy(Buf, Insn, sizeof(Insn));
}
@@ -556,17 +622,17 @@ void RetpolineZNow<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const uint8_t Insn[] = {
- 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11
- 0xe9, 0, 0, 0, 0, // jmp plt+0
+ 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11
+ 0xe9, 0, 0, 0, 0, // jmp plt+0
+ 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding
};
memcpy(Buf, Insn, sizeof(Insn));
write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7);
- write32le(Buf + 8,
- -Index * TargetInfo::PltEntrySize - TargetInfo::PltHeaderSize - 12);
+ write32le(Buf + 8, -TargetInfo::getPltEntryOffset(Index) - 12);
}
-template <class ELFT> TargetInfo *getTargetInfo() {
+template <class ELFT> static TargetInfo *getTargetInfo() {
if (Config->ZRetpolineplt) {
if (Config->ZNow) {
static RetpolineZNow<ELFT> T;
diff --git a/contrib/llvm/tools/lld/ELF/CMakeLists.txt b/contrib/llvm/tools/lld/ELF/CMakeLists.txt
index 7ec837841315..fb2f53a72025 100644
--- a/contrib/llvm/tools/lld/ELF/CMakeLists.txt
+++ b/contrib/llvm/tools/lld/ELF/CMakeLists.txt
@@ -12,6 +12,7 @@ add_lld_library(lldELF
Arch/AMDGPU.cpp
Arch/ARM.cpp
Arch/AVR.cpp
+ Arch/Hexagon.cpp
Arch/Mips.cpp
Arch/MipsArchTree.cpp
Arch/PPC.cpp
@@ -19,6 +20,7 @@ add_lld_library(lldELF
Arch/SPARCV9.cpp
Arch/X86.cpp
Arch/X86_64.cpp
+ CallGraphSort.cpp
Driver.cpp
DriverUtils.cpp
EhFrame.cpp
@@ -35,7 +37,6 @@ add_lld_library(lldELF
Relocations.cpp
ScriptLexer.cpp
ScriptParser.cpp
- Strings.cpp
SymbolTable.cpp
Symbols.cpp
SyntheticSections.cpp
@@ -46,6 +47,7 @@ add_lld_library(lldELF
LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
BinaryFormat
+ BitWriter
Core
DebugInfoDWARF
LTO
diff --git a/contrib/llvm/tools/lld/ELF/CallGraphSort.cpp b/contrib/llvm/tools/lld/ELF/CallGraphSort.cpp
new file mode 100644
index 000000000000..33ac159a6e26
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/CallGraphSort.cpp
@@ -0,0 +1,249 @@
+//===- CallGraphSort.cpp --------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// Implementation of Call-Chain Clustering from: Optimizing Function Placement
+/// for Large-Scale Data-Center Applications
+/// https://research.fb.com/wp-content/uploads/2017/01/cgo2017-hfsort-final1.pdf
+///
+/// The goal of this algorithm is to improve runtime performance of the final
+/// executable by arranging code sections such that page table and i-cache
+/// misses are minimized.
+///
+/// Definitions:
+/// * Cluster
+/// * An ordered list of input sections which are layed out as a unit. At the
+/// beginning of the algorithm each input section has its own cluster and
+/// the weight of the cluster is the sum of the weight of all incomming
+/// edges.
+/// * Call-Chain Clustering (C³) Heuristic
+/// * Defines when and how clusters are combined. Pick the highest weighted
+/// input section then add it to its most likely predecessor if it wouldn't
+/// penalize it too much.
+/// * Density
+/// * The weight of the cluster divided by the size of the cluster. This is a
+/// proxy for the ammount of execution time spent per byte of the cluster.
+///
+/// It does so given a call graph profile by the following:
+/// * Build a weighted call graph from the call graph profile
+/// * Sort input sections by weight
+/// * For each input section starting with the highest weight
+/// * Find its most likely predecessor cluster
+/// * Check if the combined cluster would be too large, or would have too low
+/// a density.
+/// * If not, then combine the clusters.
+/// * Sort non-empty clusters by density
+///
+//===----------------------------------------------------------------------===//
+
+#include "CallGraphSort.h"
+#include "OutputSections.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+struct Edge {
+ int From;
+ uint64_t Weight;
+};
+
+struct Cluster {
+ Cluster(int Sec, size_t S) {
+ Sections.push_back(Sec);
+ Size = S;
+ }
+
+ double getDensity() const {
+ if (Size == 0)
+ return 0;
+ return double(Weight) / double(Size);
+ }
+
+ std::vector<int> Sections;
+ size_t Size = 0;
+ uint64_t Weight = 0;
+ uint64_t InitialWeight = 0;
+ std::vector<Edge> Preds;
+};
+
+class CallGraphSort {
+public:
+ CallGraphSort();
+
+ DenseMap<const InputSectionBase *, int> run();
+
+private:
+ std::vector<Cluster> Clusters;
+ std::vector<const InputSectionBase *> Sections;
+
+ void groupClusters();
+};
+
+// Maximum ammount the combined cluster density can be worse than the original
+// cluster to consider merging.
+constexpr int MAX_DENSITY_DEGRADATION = 8;
+
+// Maximum cluster size in bytes.
+constexpr uint64_t MAX_CLUSTER_SIZE = 1024 * 1024;
+} // end anonymous namespace
+
+// Take the edge list in Config->CallGraphProfile, resolve symbol names to
+// Symbols, and generate a graph between InputSections with the provided
+// weights.
+CallGraphSort::CallGraphSort() {
+ llvm::MapVector<std::pair<const InputSectionBase *, const InputSectionBase *>,
+ uint64_t> &Profile = Config->CallGraphProfile;
+ DenseMap<const InputSectionBase *, int> SecToCluster;
+
+ auto GetOrCreateNode = [&](const InputSectionBase *IS) -> int {
+ auto Res = SecToCluster.insert(std::make_pair(IS, Clusters.size()));
+ if (Res.second) {
+ Sections.push_back(IS);
+ Clusters.emplace_back(Clusters.size(), IS->getSize());
+ }
+ return Res.first->second;
+ };
+
+ // Create the graph.
+ for (const auto &C : Profile) {
+ const auto *FromSB = cast<InputSectionBase>(C.first.first->Repl);
+ const auto *ToSB = cast<InputSectionBase>(C.first.second->Repl);
+ uint64_t Weight = C.second;
+
+ // Ignore edges between input sections belonging to different output
+ // sections. This is done because otherwise we would end up with clusters
+ // containing input sections that can't actually be placed adjacently in the
+ // output. This messes with the cluster size and density calculations. We
+ // would also end up moving input sections in other output sections without
+ // moving them closer to what calls them.
+ if (FromSB->getOutputSection() != ToSB->getOutputSection())
+ continue;
+
+ int From = GetOrCreateNode(FromSB);
+ int To = GetOrCreateNode(ToSB);
+
+ Clusters[To].Weight += Weight;
+
+ if (From == To)
+ continue;
+
+ // Add an edge
+ Clusters[To].Preds.push_back({From, Weight});
+ }
+ for (Cluster &C : Clusters)
+ C.InitialWeight = C.Weight;
+}
+
+// It's bad to merge clusters which would degrade the density too much.
+static bool isNewDensityBad(Cluster &A, Cluster &B) {
+ double NewDensity = double(A.Weight + B.Weight) / double(A.Size + B.Size);
+ if (NewDensity < A.getDensity() / MAX_DENSITY_DEGRADATION)
+ return true;
+ return false;
+}
+
+static void mergeClusters(Cluster &Into, Cluster &From) {
+ Into.Sections.insert(Into.Sections.end(), From.Sections.begin(),
+ From.Sections.end());
+ Into.Size += From.Size;
+ Into.Weight += From.Weight;
+ From.Sections.clear();
+ From.Size = 0;
+ From.Weight = 0;
+}
+
+// Group InputSections into clusters using the Call-Chain Clustering heuristic
+// then sort the clusters by density.
+void CallGraphSort::groupClusters() {
+ std::vector<int> SortedSecs(Clusters.size());
+ std::vector<Cluster *> SecToCluster(Clusters.size());
+
+ for (int SI = 0, SE = Clusters.size(); SI != SE; ++SI) {
+ SortedSecs[SI] = SI;
+ SecToCluster[SI] = &Clusters[SI];
+ }
+
+ std::stable_sort(SortedSecs.begin(), SortedSecs.end(), [&](int A, int B) {
+ return Clusters[B].getDensity() < Clusters[A].getDensity();
+ });
+
+ for (int SI : SortedSecs) {
+ // Clusters[SI] is the same as SecToClusters[SI] here because it has not
+ // been merged into another cluster yet.
+ Cluster &C = Clusters[SI];
+
+ int BestPred = -1;
+ uint64_t BestWeight = 0;
+
+ for (Edge &E : C.Preds) {
+ if (BestPred == -1 || E.Weight > BestWeight) {
+ BestPred = E.From;
+ BestWeight = E.Weight;
+ }
+ }
+
+ // don't consider merging if the edge is unlikely.
+ if (BestWeight * 10 <= C.InitialWeight)
+ continue;
+
+ Cluster *PredC = SecToCluster[BestPred];
+ if (PredC == &C)
+ continue;
+
+ if (C.Size + PredC->Size > MAX_CLUSTER_SIZE)
+ continue;
+
+ if (isNewDensityBad(*PredC, C))
+ continue;
+
+ // NOTE: Consider using a disjoint-set to track section -> cluster mapping
+ // if this is ever slow.
+ for (int SI : C.Sections)
+ SecToCluster[SI] = PredC;
+
+ mergeClusters(*PredC, C);
+ }
+
+ // Remove empty or dead nodes. Invalidates all cluster indices.
+ llvm::erase_if(Clusters, [](const Cluster &C) {
+ return C.Size == 0 || C.Sections.empty();
+ });
+
+ // Sort by density.
+ std::stable_sort(Clusters.begin(), Clusters.end(),
+ [](const Cluster &A, const Cluster &B) {
+ return A.getDensity() > B.getDensity();
+ });
+}
+
+DenseMap<const InputSectionBase *, int> CallGraphSort::run() {
+ groupClusters();
+
+ // Generate order.
+ llvm::DenseMap<const InputSectionBase *, int> OrderMap;
+ ssize_t CurOrder = 1;
+
+ for (const Cluster &C : Clusters)
+ for (int SecIndex : C.Sections)
+ OrderMap[Sections[SecIndex]] = CurOrder++;
+
+ return OrderMap;
+}
+
+// Sort sections by the profile data provided by -callgraph-profile-file
+//
+// This first builds a call graph based on the profile data then merges sections
+// according to the C³ huristic. All clusters are then sorted by a density
+// metric to further improve locality.
+DenseMap<const InputSectionBase *, int> elf::computeCallGraphProfileOrder() {
+ return CallGraphSort().run();
+}
diff --git a/contrib/llvm/tools/lld/ELF/CallGraphSort.h b/contrib/llvm/tools/lld/ELF/CallGraphSort.h
new file mode 100644
index 000000000000..3f96dc88f435
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/CallGraphSort.h
@@ -0,0 +1,23 @@
+//===- CallGraphSort.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_CALL_GRAPH_SORT_H
+#define LLD_ELF_CALL_GRAPH_SORT_H
+
+#include "llvm/ADT/DenseMap.h"
+
+namespace lld {
+namespace elf {
+class InputSectionBase;
+
+llvm::DenseMap<const InputSectionBase *, int> computeCallGraphProfileOrder();
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/Config.h b/contrib/llvm/tools/lld/ELF/Config.h
index d705f11bf626..622324c13e2d 100644
--- a/contrib/llvm/tools/lld/ELF/Config.h
+++ b/contrib/llvm/tools/lld/ELF/Config.h
@@ -10,6 +10,7 @@
#ifndef LLD_ELF_CONFIG_H
#define LLD_ELF_CONFIG_H
+#include "lld/Common/ErrorHandler.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
@@ -17,13 +18,13 @@
#include "llvm/Support/CachePruning.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Endian.h"
-
#include <vector>
namespace lld {
namespace elf {
class InputFile;
+class InputSectionBase;
enum ELFKind {
ELFNoneKind,
@@ -39,6 +40,9 @@ enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid };
// For --discard-{all,locals,none}.
enum class DiscardPolicy { Default, All, Locals, None };
+// For --icf={none,safe,all}.
+enum class ICFLevel { None, Safe, All };
+
// For --strip-{all,debug}.
enum class StripPolicy { None, All, Debug };
@@ -82,21 +86,27 @@ struct Configuration {
llvm::StringMap<uint64_t> SectionStartMap;
llvm::StringRef Chroot;
llvm::StringRef DynamicLinker;
+ llvm::StringRef DwoDir;
llvm::StringRef Entry;
llvm::StringRef Emulation;
llvm::StringRef Fini;
llvm::StringRef Init;
llvm::StringRef LTOAAPipeline;
llvm::StringRef LTONewPmPasses;
+ llvm::StringRef LTOObjPath;
+ llvm::StringRef LTOSampleProfile;
llvm::StringRef MapFile;
llvm::StringRef OutputFile;
llvm::StringRef OptRemarksFilename;
+ llvm::StringRef ProgName;
llvm::StringRef SoName;
llvm::StringRef Sysroot;
llvm::StringRef ThinLTOCacheDir;
+ llvm::StringRef ThinLTOIndexOnlyArg;
+ std::pair<llvm::StringRef, llvm::StringRef> ThinLTOObjectSuffixReplace;
+ std::pair<llvm::StringRef, llvm::StringRef> ThinLTOPrefixReplace;
std::string Rpath;
std::vector<VersionDefinition> VersionDefinitions;
- std::vector<llvm::StringRef> Argv;
std::vector<llvm::StringRef> AuxiliaryList;
std::vector<llvm::StringRef> FilterList;
std::vector<llvm::StringRef> SearchPaths;
@@ -106,34 +116,41 @@ struct Configuration {
std::vector<SymbolVersion> VersionScriptGlobals;
std::vector<SymbolVersion> VersionScriptLocals;
std::vector<uint8_t> BuildIdVector;
+ llvm::MapVector<std::pair<const InputSectionBase *, const InputSectionBase *>,
+ uint64_t>
+ CallGraphProfile;
bool AllowMultipleDefinition;
- bool AndroidPackDynRelocs = false;
+ bool AndroidPackDynRelocs;
bool ARMHasBlx = false;
bool ARMHasMovtMovw = false;
bool ARMJ1J2BranchEncoding = false;
bool AsNeeded = false;
bool Bsymbolic;
bool BsymbolicFunctions;
+ bool CheckSections;
bool CompressDebugSections;
+ bool Cref;
bool DefineCommon;
bool Demangle = true;
bool DisableVerify;
bool EhFrameHdr;
bool EmitRelocs;
bool EnableNewDtags;
+ bool ExecuteOnly;
bool ExportDynamic;
bool FixCortexA53Errata843419;
bool GcSections;
bool GdbIndex;
bool GnuHash = false;
+ bool GnuUnique;
bool HasDynamicList = false;
bool HasDynSymTab;
- bool ICF;
- bool ICFData;
+ bool IgnoreDataAddressEquality;
+ bool IgnoreFunctionAddressEquality;
+ bool LTODebugPassManager;
+ bool LTONewPassManager;
bool MergeArmExidx;
bool MipsN32Abi = false;
- bool NoGnuUnique;
- bool NoUndefinedVersion;
bool NoinhibitExec;
bool Nostdlib;
bool OFormatBinary;
@@ -141,7 +158,9 @@ struct Configuration {
bool OptRemarksWithHotness;
bool Pie;
bool PrintGcSections;
+ bool PrintIcfSections;
bool Relocatable;
+ bool RelrPackDynRelocs;
bool SaveTemps;
bool SingleRoRx;
bool Shared;
@@ -149,13 +168,21 @@ struct Configuration {
bool SysvHash = false;
bool Target1Rel;
bool Trace;
- bool Verbose;
+ bool ThinLTOEmitImportsFiles;
+ bool ThinLTOIndexOnly;
+ bool UndefinedVersion;
+ bool UseAndroidRelrTags = false;
+ bool WarnBackrefs;
bool WarnCommon;
bool WarnMissingEntry;
+ bool WarnSymbolOrdering;
+ bool WriteAddends;
bool ZCombreloc;
+ bool ZCopyreloc;
bool ZExecstack;
bool ZHazardplt;
- bool ZNocopyreloc;
+ bool ZInitfirst;
+ bool ZKeepTextSectionPrefix;
bool ZNodelete;
bool ZNodlopen;
bool ZNow;
@@ -164,9 +191,9 @@ struct Configuration {
bool ZRodynamic;
bool ZText;
bool ZRetpolineplt;
- bool ExitEarly;
bool ZWxneeded;
DiscardPolicy Discard;
+ ICFLevel ICF;
OrphanHandlingPolicy OrphanHandling;
SortSectionPolicy SortSection;
StripPolicy Strip;
@@ -179,6 +206,7 @@ struct Configuration {
uint16_t EMachine = llvm::ELF::EM_NONE;
llvm::Optional<uint64_t> ImageBase;
uint64_t MaxPageSize;
+ uint64_t MipsGotSize;
uint64_t ZStackSize;
unsigned LTOPartitions;
unsigned LTOO;
@@ -244,6 +272,12 @@ struct Configuration {
// The only instance of Configuration struct.
extern Configuration *Config;
+static inline void errorOrWarn(const Twine &Msg) {
+ if (!Config->NoinhibitExec)
+ error(Msg);
+ else
+ warn(Msg);
+}
} // namespace elf
} // namespace lld
diff --git a/contrib/llvm/tools/lld/ELF/Driver.cpp b/contrib/llvm/tools/lld/ELF/Driver.cpp
index 44cfa56c94ce..693dba64ab5a 100644
--- a/contrib/llvm/tools/lld/ELF/Driver.cpp
+++ b/contrib/llvm/tools/lld/ELF/Driver.cpp
@@ -30,9 +30,9 @@
#include "InputFiles.h"
#include "InputSection.h"
#include "LinkerScript.h"
+#include "MarkLive.h"
#include "OutputSections.h"
#include "ScriptParser.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
@@ -42,12 +42,16 @@
#include "lld/Common/Driver.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
+#include "lld/Common/TargetOptionsCommandFlags.h"
#include "lld/Common/Threads.h"
#include "lld/Common/Version.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compression.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TarWriter.h"
#include "llvm/Support/TargetSelect.h"
@@ -66,16 +70,18 @@ using namespace lld::elf;
Configuration *elf::Config;
LinkerDriver *elf::Driver;
-static void setConfigs();
+static void setConfigs(opt::InputArgList &Args);
bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
raw_ostream &Error) {
- errorHandler().LogName = Args[0];
+ errorHandler().LogName = sys::path::filename(Args[0]);
errorHandler().ErrorLimitExceededMsg =
"too many errors emitted, stopping now (use "
"-error-limit=0 to see all errors)";
errorHandler().ErrorOS = &Error;
+ errorHandler().ExitEarly = CanExitEarly;
errorHandler().ColorDiagnostics = Error.has_colors();
+
InputSections.clear();
OutputSections.clear();
Tar = nullptr;
@@ -88,14 +94,14 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
Driver = make<LinkerDriver>();
Script = make<LinkerScript>();
Symtab = make<SymbolTable>();
- Config->Argv = {Args.begin(), Args.end()};
+ Config->ProgName = Args[0];
- Driver->main(Args, CanExitEarly);
+ Driver->main(Args);
// Exit immediately if we don't need to return to the caller.
// This saves time because the overhead of calling destructors
// for all globally-allocated objects is not negligible.
- if (Config->ExitEarly)
+ if (CanExitEarly)
exitLld(errorCount() ? 1 : 0);
freeArena();
@@ -113,7 +119,8 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
std::pair<ELFKind, uint16_t> Ret =
StringSwitch<std::pair<ELFKind, uint16_t>>(S)
- .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64})
+ .Cases("aarch64elf", "aarch64linux", "aarch64_elf64_le_vec",
+ {ELF64LEKind, EM_AARCH64})
.Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM})
.Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
.Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS})
@@ -122,6 +129,7 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
.Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
.Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
.Case("elf64ppc", {ELF64BEKind, EM_PPC64})
+ .Case("elf64lppc", {ELF64LEKind, EM_PPC64})
.Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64})
.Case("elf_i386", {ELF32LEKind, EM_386})
.Case("elf_iamcu", {ELF32LEKind, EM_IAMCU})
@@ -228,11 +236,15 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
Files.push_back(
createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path));
return;
- default:
+ case file_magic::bitcode:
+ case file_magic::elf_relocatable:
if (InLib)
Files.push_back(make<LazyObjFile>(MBRef, "", 0));
else
Files.push_back(createObjectFile(MBRef));
+ break;
+ default:
+ error(Path + ": unknown file type");
}
}
@@ -248,18 +260,11 @@ void LinkerDriver::addLibrary(StringRef Name) {
// LTO calls LLVM functions to compile bitcode files to native code.
// Technically this can be delayed until we read bitcode files, but
// we don't bother to do lazily because the initialization is fast.
-static void initLLVM(opt::InputArgList &Args) {
+static void initLLVM() {
InitializeAllTargets();
InitializeAllTargetMCs();
InitializeAllAsmPrinters();
InitializeAllAsmParsers();
-
- // Parse and evaluate -mllvm options.
- std::vector<const char *> V;
- V.push_back("lld (LLVM option parsing)");
- for (auto *Arg : Args.filtered(OPT_mllvm))
- V.push_back(Arg->getValue());
- cl::ParseCommandLineOptions(V.size(), V.data());
}
// Some command line options or some combinations of them are not allowed.
@@ -290,11 +295,21 @@ static void checkOptions(opt::InputArgList &Args) {
error("-r and -shared may not be used together");
if (Config->GcSections)
error("-r and --gc-sections may not be used together");
- if (Config->ICF)
+ if (Config->GdbIndex)
+ error("-r and --gdb-index may not be used together");
+ if (Config->ICF != ICFLevel::None)
error("-r and --icf may not be used together");
if (Config->Pie)
error("-r and -pie may not be used together");
}
+
+ if (Config->ExecuteOnly) {
+ if (Config->EMachine != EM_AARCH64)
+ error("-execute-only is only supported on AArch64 targets");
+
+ if (Config->SingleRoRx && !Script->HasSectionsCommand)
+ error("-execute-only and -no-rosegment cannot be used together");
+ }
}
static const char *getReproduceOption(opt::InputArgList &Args) {
@@ -310,7 +325,37 @@ static bool hasZOption(opt::InputArgList &Args, StringRef Key) {
return false;
}
-void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
+static bool getZFlag(opt::InputArgList &Args, StringRef K1, StringRef K2,
+ bool Default) {
+ for (auto *Arg : Args.filtered_reverse(OPT_z)) {
+ if (K1 == Arg->getValue())
+ return true;
+ if (K2 == Arg->getValue())
+ return false;
+ }
+ return Default;
+}
+
+static bool isKnown(StringRef S) {
+ return S == "combreloc" || S == "copyreloc" || S == "defs" ||
+ S == "execstack" || S == "hazardplt" || S == "initfirst" ||
+ S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" ||
+ S == "nocombreloc" || S == "nocopyreloc" || S == "nodelete" ||
+ S == "nodlopen" || S == "noexecstack" ||
+ S == "nokeep-text-section-prefix" || S == "norelro" || S == "notext" ||
+ S == "now" || S == "origin" || S == "relro" || S == "retpolineplt" ||
+ S == "rodynamic" || S == "text" || S == "wxneeded" ||
+ S.startswith("max-page-size=") || S.startswith("stack-size=");
+}
+
+// Report an error for an unknown -z option.
+static void checkZOptions(opt::InputArgList &Args) {
+ for (auto *Arg : Args.filtered(OPT_z))
+ if (!isKnown(Arg->getValue()))
+ error("unknown -z value: " + StringRef(Arg->getValue()));
+}
+
+void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
ELFOptTable Parser;
opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
@@ -319,7 +364,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
// Handle -help
if (Args.hasArg(OPT_help)) {
- printHelp(ArgsArr[0]);
+ printHelp();
return;
}
@@ -348,9 +393,6 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
if (Args.hasArg(OPT_version))
return;
- Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown);
- errorHandler().ExitEarly = Config->ExitEarly;
-
if (const char *Path = getReproduceOption(Args)) {
// Note that --reproduce is a debug option so you can ignore it
// if you are trying to understand the whole picture of the code.
@@ -368,10 +410,14 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
}
readConfigs(Args);
- initLLVM(Args);
+ checkZOptions(Args);
+ initLLVM();
createFiles(Args);
+ if (errorCount())
+ return;
+
inferMachineType();
- setConfigs();
+ setConfigs(Args);
checkOptions(Args);
if (errorCount())
return;
@@ -455,6 +501,8 @@ static bool isOutputFormatBinary(opt::InputArgList &Args) {
StringRef S = Arg->getValue();
if (S == "binary")
return true;
+ if (S.startswith("elf"))
+ return false;
error("unknown --oformat value: " + S);
}
return false;
@@ -482,6 +530,15 @@ static StringRef getDynamicLinker(opt::InputArgList &Args) {
return Arg->getValue();
}
+static ICFLevel getICF(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_icf_none, OPT_icf_safe, OPT_icf_all);
+ if (!Arg || Arg->getOption().getID() == OPT_icf_none)
+ return ICFLevel::None;
+ if (Arg->getOption().getID() == OPT_icf_safe)
+ return ICFLevel::Safe;
+ return ICFLevel::All;
+}
+
static StripPolicy getStrip(opt::InputArgList &Args) {
if (Args.hasArg(OPT_relocatable))
return StripPolicy::None;
@@ -556,6 +613,8 @@ getBuildId(opt::InputArgList &Args) {
return {BuildIdKind::Fast, {}};
StringRef S = Arg->getValue();
+ if (S == "fast")
+ return {BuildIdKind::Fast, {}};
if (S == "md5")
return {BuildIdKind::Md5, {}};
if (S == "sha1" || S == "tree")
@@ -570,6 +629,57 @@ getBuildId(opt::InputArgList &Args) {
return {BuildIdKind::None, {}};
}
+static std::pair<bool, bool> getPackDynRelocs(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_pack_dyn_relocs, "none");
+ if (S == "android")
+ return {true, false};
+ if (S == "relr")
+ return {false, true};
+ if (S == "android+relr")
+ return {true, true};
+
+ if (S != "none")
+ error("unknown -pack-dyn-relocs format: " + S);
+ return {false, false};
+}
+
+static void readCallGraph(MemoryBufferRef MB) {
+ // Build a map from symbol name to section
+ DenseMap<StringRef, const Symbol *> SymbolNameToSymbol;
+ for (InputFile *File : ObjectFiles)
+ for (Symbol *Sym : File->getSymbols())
+ SymbolNameToSymbol[Sym->getName()] = Sym;
+
+ for (StringRef L : args::getLines(MB)) {
+ SmallVector<StringRef, 3> Fields;
+ L.split(Fields, ' ');
+ uint64_t Count;
+ if (Fields.size() != 3 || !to_integer(Fields[2], Count))
+ fatal(MB.getBufferIdentifier() + ": parse error");
+ const Symbol *FromSym = SymbolNameToSymbol.lookup(Fields[0]);
+ const Symbol *ToSym = SymbolNameToSymbol.lookup(Fields[1]);
+ if (Config->WarnSymbolOrdering) {
+ if (!FromSym)
+ warn(MB.getBufferIdentifier() + ": no such symbol: " + Fields[0]);
+ if (!ToSym)
+ warn(MB.getBufferIdentifier() + ": no such symbol: " + Fields[1]);
+ }
+ if (!FromSym || !ToSym || Count == 0)
+ continue;
+ warnUnorderableSymbol(FromSym);
+ warnUnorderableSymbol(ToSym);
+ const Defined *FromSymD = dyn_cast<Defined>(FromSym);
+ const Defined *ToSymD = dyn_cast<Defined>(ToSym);
+ if (!FromSymD || !ToSymD)
+ continue;
+ const auto *FromSB = dyn_cast_or_null<InputSectionBase>(FromSymD->Section);
+ const auto *ToSB = dyn_cast_or_null<InputSectionBase>(ToSymD->Section);
+ if (!FromSB || !ToSB)
+ continue;
+ Config->CallGraphProfile[std::make_pair(FromSB, ToSB)] += Count;
+ }
+}
+
static bool getCompressDebugSections(opt::InputArgList &Args) {
StringRef S = Args.getLastArgValue(OPT_compress_debug_sections, "none");
if (S == "none")
@@ -581,54 +691,100 @@ static bool getCompressDebugSections(opt::InputArgList &Args) {
return true;
}
-static int parseInt(StringRef S, opt::Arg *Arg) {
- int V = 0;
- if (!to_integer(S, V, 10))
- error(Arg->getSpelling() + ": number expected, but got '" + S + "'");
- return V;
+static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &Args,
+ unsigned Id) {
+ auto *Arg = Args.getLastArg(Id);
+ if (!Arg)
+ return {"", ""};
+
+ StringRef S = Arg->getValue();
+ std::pair<StringRef, StringRef> Ret = S.split(';');
+ if (Ret.second.empty())
+ error(Arg->getSpelling() + " expects 'old;new' format, but got " + S);
+ return Ret;
+}
+
+// Parse the symbol ordering file and warn for any duplicate entries.
+static std::vector<StringRef> getSymbolOrderingFile(MemoryBufferRef MB) {
+ SetVector<StringRef> Names;
+ for (StringRef S : args::getLines(MB))
+ if (!Names.insert(S) && Config->WarnSymbolOrdering)
+ warn(MB.getBufferIdentifier() + ": duplicate ordered symbol: " + S);
+
+ return Names.takeVector();
+}
+
+static void parseClangOption(StringRef Opt, const Twine &Msg) {
+ std::string Err;
+ raw_string_ostream OS(Err);
+
+ const char *Argv[] = {Config->ProgName.data(), Opt.data()};
+ if (cl::ParseCommandLineOptions(2, Argv, "", &OS))
+ return;
+ OS.flush();
+ error(Msg + ": " + StringRef(Err).trim());
}
// Initializes Config members by the command line options.
void LinkerDriver::readConfigs(opt::InputArgList &Args) {
+ errorHandler().Verbose = Args.hasArg(OPT_verbose);
+ errorHandler().FatalWarnings =
+ Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
+ ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);
+
Config->AllowMultipleDefinition =
- Args.hasArg(OPT_allow_multiple_definition) || hasZOption(Args, "muldefs");
+ Args.hasFlag(OPT_allow_multiple_definition,
+ OPT_no_allow_multiple_definition, false) ||
+ hasZOption(Args, "muldefs");
Config->AuxiliaryList = args::getStrings(Args, OPT_auxiliary);
Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
+ Config->CheckSections =
+ Args.hasFlag(OPT_check_sections, OPT_no_check_sections, true);
Config->Chroot = Args.getLastArgValue(OPT_chroot);
Config->CompressDebugSections = getCompressDebugSections(Args);
+ Config->Cref = Args.hasFlag(OPT_cref, OPT_no_cref, false);
Config->DefineCommon = Args.hasFlag(OPT_define_common, OPT_no_define_common,
!Args.hasArg(OPT_relocatable));
Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true);
Config->DisableVerify = Args.hasArg(OPT_disable_verify);
Config->Discard = getDiscard(Args);
+ Config->DwoDir = Args.getLastArgValue(OPT_plugin_opt_dwo_dir_eq);
Config->DynamicLinker = getDynamicLinker(Args);
Config->EhFrameHdr =
Args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false);
Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
- Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);
+ Config->EnableNewDtags =
+ Args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true);
Config->Entry = Args.getLastArgValue(OPT_entry);
+ Config->ExecuteOnly =
+ Args.hasFlag(OPT_execute_only, OPT_no_execute_only, false);
Config->ExportDynamic =
Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false);
- errorHandler().FatalWarnings =
- Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
Config->FilterList = args::getStrings(Args, OPT_filter);
Config->Fini = Args.getLastArgValue(OPT_fini, "_fini");
Config->FixCortexA53Errata843419 = Args.hasArg(OPT_fix_cortex_a53_843419);
Config->GcSections = Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false);
+ Config->GnuUnique = Args.hasFlag(OPT_gnu_unique, OPT_no_gnu_unique, true);
Config->GdbIndex = Args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false);
- Config->ICF = Args.hasFlag(OPT_icf_all, OPT_icf_none, false);
- Config->ICFData = Args.hasArg(OPT_icf_data);
+ Config->ICF = getICF(Args);
+ Config->IgnoreDataAddressEquality =
+ Args.hasArg(OPT_ignore_data_address_equality);
+ Config->IgnoreFunctionAddressEquality =
+ Args.hasArg(OPT_ignore_function_address_equality);
Config->Init = Args.getLastArgValue(OPT_init, "_init");
Config->LTOAAPipeline = Args.getLastArgValue(OPT_lto_aa_pipeline);
+ Config->LTODebugPassManager = Args.hasArg(OPT_lto_debug_pass_manager);
+ Config->LTONewPassManager = Args.hasArg(OPT_lto_new_pass_manager);
Config->LTONewPmPasses = Args.getLastArgValue(OPT_lto_newpm_passes);
Config->LTOO = args::getInteger(Args, OPT_lto_O, 2);
+ Config->LTOObjPath = Args.getLastArgValue(OPT_plugin_opt_obj_path_eq);
Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1);
+ Config->LTOSampleProfile = Args.getLastArgValue(OPT_lto_sample_profile);
Config->MapFile = Args.getLastArgValue(OPT_Map);
- Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique);
+ Config->MipsGotSize = args::getInteger(Args, OPT_mips_got_size, 0xfff0);
Config->MergeArmExidx =
Args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true);
- Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version);
Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec);
Config->Nostdlib = Args.hasArg(OPT_nostdlib);
Config->OFormatBinary = isOutputFormatBinary(Args);
@@ -638,7 +794,9 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->Optimize = args::getInteger(Args, OPT_O, 1);
Config->OrphanHandling = getOrphanHandling(Args);
Config->OutputFile = Args.getLastArgValue(OPT_o);
- Config->Pie = Args.hasFlag(OPT_pie, OPT_nopie, false);
+ Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false);
+ Config->PrintIcfSections =
+ Args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false);
Config->PrintGcSections =
Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
Config->Rpath = getRpath(Args);
@@ -658,48 +816,58 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->ThinLTOCachePolicy = CHECK(
parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)),
"--thinlto-cache-policy: invalid cache policy");
+ Config->ThinLTOEmitImportsFiles =
+ Args.hasArg(OPT_plugin_opt_thinlto_emit_imports_files);
+ Config->ThinLTOIndexOnly = Args.hasArg(OPT_plugin_opt_thinlto_index_only) ||
+ Args.hasArg(OPT_plugin_opt_thinlto_index_only_eq);
+ Config->ThinLTOIndexOnlyArg =
+ Args.getLastArgValue(OPT_plugin_opt_thinlto_index_only_eq);
Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u);
- ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);
+ Config->ThinLTOObjectSuffixReplace =
+ getOldNewOptions(Args, OPT_plugin_opt_thinlto_object_suffix_replace_eq);
+ Config->ThinLTOPrefixReplace =
+ getOldNewOptions(Args, OPT_plugin_opt_thinlto_prefix_replace_eq);
Config->Trace = Args.hasArg(OPT_trace);
Config->Undefined = args::getStrings(Args, OPT_undefined);
+ Config->UndefinedVersion =
+ Args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true);
+ Config->UseAndroidRelrTags = Args.hasFlag(
+ OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false);
Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args);
- Config->Verbose = Args.hasArg(OPT_verbose);
- errorHandler().Verbose = Config->Verbose;
- Config->WarnCommon = Args.hasArg(OPT_warn_common);
- Config->ZCombreloc = !hasZOption(Args, "nocombreloc");
- Config->ZExecstack = hasZOption(Args, "execstack");
+ Config->WarnBackrefs =
+ Args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false);
+ Config->WarnCommon = Args.hasFlag(OPT_warn_common, OPT_no_warn_common, false);
+ Config->WarnSymbolOrdering =
+ Args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true);
+ Config->ZCombreloc = getZFlag(Args, "combreloc", "nocombreloc", true);
+ Config->ZCopyreloc = getZFlag(Args, "copyreloc", "nocopyreloc", true);
+ Config->ZExecstack = getZFlag(Args, "execstack", "noexecstack", false);
Config->ZHazardplt = hasZOption(Args, "hazardplt");
- Config->ZNocopyreloc = hasZOption(Args, "nocopyreloc");
+ Config->ZInitfirst = hasZOption(Args, "initfirst");
+ Config->ZKeepTextSectionPrefix = getZFlag(
+ Args, "keep-text-section-prefix", "nokeep-text-section-prefix", false);
Config->ZNodelete = hasZOption(Args, "nodelete");
Config->ZNodlopen = hasZOption(Args, "nodlopen");
- Config->ZNow = hasZOption(Args, "now");
+ Config->ZNow = getZFlag(Args, "now", "lazy", false);
Config->ZOrigin = hasZOption(Args, "origin");
- Config->ZRelro = !hasZOption(Args, "norelro");
+ Config->ZRelro = getZFlag(Args, "relro", "norelro", true);
Config->ZRetpolineplt = hasZOption(Args, "retpolineplt");
Config->ZRodynamic = hasZOption(Args, "rodynamic");
Config->ZStackSize = args::getZOptionValue(Args, OPT_z, "stack-size", 0);
- Config->ZText = !hasZOption(Args, "notext");
+ Config->ZText = getZFlag(Args, "text", "notext", true);
Config->ZWxneeded = hasZOption(Args, "wxneeded");
- // Parse LTO plugin-related options for compatibility with gold.
- for (auto *Arg : Args.filtered(OPT_plugin_opt, OPT_plugin_opt_eq)) {
- StringRef S = Arg->getValue();
- if (S == "disable-verify")
- Config->DisableVerify = true;
- else if (S == "save-temps")
- Config->SaveTemps = true;
- else if (S.startswith("O"))
- Config->LTOO = parseInt(S.substr(1), Arg);
- else if (S.startswith("lto-partitions="))
- Config->LTOPartitions = parseInt(S.substr(15), Arg);
- else if (S.startswith("jobs="))
- Config->ThinLTOJobs = parseInt(S.substr(5), Arg);
- else if (!S.startswith("/") && !S.startswith("-fresolution=") &&
- !S.startswith("-pass-through=") && !S.startswith("mcpu=") &&
- !S.startswith("thinlto") && S != "-function-sections" &&
- S != "-data-sections")
- error(Arg->getSpelling() + ": unknown option: " + S);
- }
+ // Parse LTO options.
+ if (auto *Arg = Args.getLastArg(OPT_plugin_opt_mcpu_eq))
+ parseClangOption(Saver.save("-mcpu=" + StringRef(Arg->getValue())),
+ Arg->getSpelling());
+
+ for (auto *Arg : Args.filtered(OPT_plugin_opt))
+ parseClangOption(Arg->getValue(), Arg->getSpelling());
+
+ // Parse -mllvm options.
+ for (auto *Arg : Args.filtered(OPT_mllvm))
+ parseClangOption(Arg->getValue(), Arg->getSpelling());
if (Config->LTOO > 3)
error("invalid optimization level for LTO: " + Twine(Config->LTOO));
@@ -742,17 +910,12 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args);
- if (auto *Arg = Args.getLastArg(OPT_pack_dyn_relocs_eq)) {
- StringRef S = Arg->getValue();
- if (S == "android")
- Config->AndroidPackDynRelocs = true;
- else if (S != "none")
- error("unknown -pack-dyn-relocs format: " + S);
- }
+ std::tie(Config->AndroidPackDynRelocs, Config->RelrPackDynRelocs) =
+ getPackDynRelocs(Args);
if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file))
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
- Config->SymbolOrderingFile = args::getLines(*Buffer);
+ Config->SymbolOrderingFile = getSymbolOrderingFile(*Buffer);
// If --retain-symbol-file is used, we'll keep only the symbols listed in
// the file and discard all others.
@@ -780,32 +943,67 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
{Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false});
}
+ // If --export-dynamic-symbol=foo is given and symbol foo is defined in
+ // an object file in an archive file, that object file should be pulled
+ // out and linked. (It doesn't have to behave like that from technical
+ // point of view, but this is needed for compatibility with GNU.)
+ for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
+ Config->Undefined.push_back(Arg->getValue());
+
for (auto *Arg : Args.filtered(OPT_version_script))
- if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
- readVersionScript(*Buffer);
+ if (Optional<std::string> Path = searchScript(Arg->getValue())) {
+ if (Optional<MemoryBufferRef> Buffer = readFile(*Path))
+ readVersionScript(*Buffer);
+ } else {
+ error(Twine("cannot find version script ") + Arg->getValue());
+ }
}
// Some Config members do not directly correspond to any particular
// command line options, but computed based on other Config values.
// This function initialize such members. See Config.h for the details
// of these values.
-static void setConfigs() {
+static void setConfigs(opt::InputArgList &Args) {
ELFKind Kind = Config->EKind;
uint16_t Machine = Config->EMachine;
- // There is an ILP32 ABI for x86-64, although it's not very popular.
- // It is called the x32 ABI.
- bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64);
-
Config->CopyRelocs = (Config->Relocatable || Config->EmitRelocs);
Config->Is64 = (Kind == ELF64LEKind || Kind == ELF64BEKind);
Config->IsLE = (Kind == ELF32LEKind || Kind == ELF64LEKind);
Config->Endianness =
Config->IsLE ? support::endianness::little : support::endianness::big;
Config->IsMips64EL = (Kind == ELF64LEKind && Machine == EM_MIPS);
- Config->IsRela = Config->Is64 || IsX32 || Config->MipsN32Abi;
Config->Pic = Config->Pie || Config->Shared;
Config->Wordsize = Config->Is64 ? 8 : 4;
+
+ // There is an ILP32 ABI for x86-64, although it's not very popular.
+ // It is called the x32 ABI.
+ bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64);
+
+ // ELF defines two different ways to store relocation addends as shown below:
+ //
+ // Rel: Addends are stored to the location where relocations are applied.
+ // Rela: Addends are stored as part of relocation entry.
+ //
+ // In other words, Rela makes it easy to read addends at the price of extra
+ // 4 or 8 byte for each relocation entry. We don't know why ELF defined two
+ // different mechanisms in the first place, but this is how the spec is
+ // defined.
+ //
+ // You cannot choose which one, Rel or Rela, you want to use. Instead each
+ // ABI defines which one you need to use. The following expression expresses
+ // that.
+ Config->IsRela =
+ (Config->Is64 || IsX32 || Machine == EM_PPC) && Machine != EM_MIPS;
+
+ // If the output uses REL relocations we must store the dynamic relocation
+ // addends to the output sections. We also store addends for RELA relocations
+ // if --apply-dynamic-relocs is used.
+ // We default to not writing the addends when using RELA relocations since
+ // any standard conforming tool can find it in r_addend.
+ Config->WriteAddends = Args.hasFlag(OPT_apply_dynamic_relocs,
+ OPT_no_apply_dynamic_relocs, false) ||
+ !Config->IsRela;
}
// Returns a value of "-format" option.
@@ -820,6 +1018,10 @@ static bool getBinaryOption(StringRef S) {
}
void LinkerDriver::createFiles(opt::InputArgList &Args) {
+ // For --{push,pop}-state.
+ std::vector<std::tuple<bool, bool, bool>> Stack;
+
+ // Iterate over argv to process input files and positional arguments.
for (auto *Arg : Args) {
switch (Arg->getOption().getUnaliasedOption().getID()) {
case OPT_library:
@@ -828,8 +1030,15 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
case OPT_INPUT:
addFile(Arg->getValue(), /*WithLOption=*/false);
break;
+ case OPT_defsym: {
+ StringRef From;
+ StringRef To;
+ std::tie(From, To) = StringRef(Arg->getValue()).split('=');
+ readDefsym(From, MemoryBufferRef(To, "-defsym"));
+ break;
+ }
case OPT_script:
- if (Optional<std::string> Path = searchLinkerScript(Arg->getValue())) {
+ if (Optional<std::string> Path = searchScript(Arg->getValue())) {
if (Optional<MemoryBufferRef> MB = readFile(*Path))
readLinkerScript(*MB);
break;
@@ -857,11 +1066,48 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
case OPT_no_whole_archive:
InWholeArchive = false;
break;
+ case OPT_just_symbols:
+ if (Optional<MemoryBufferRef> MB = readFile(Arg->getValue())) {
+ Files.push_back(createObjectFile(*MB));
+ Files.back()->JustSymbols = true;
+ }
+ break;
+ case OPT_start_group:
+ if (InputFile::IsInGroup)
+ error("nested --start-group");
+ InputFile::IsInGroup = true;
+ break;
+ case OPT_end_group:
+ if (!InputFile::IsInGroup)
+ error("stray --end-group");
+ InputFile::IsInGroup = false;
+ ++InputFile::NextGroupId;
+ break;
case OPT_start_lib:
+ if (InLib)
+ error("nested --start-lib");
+ if (InputFile::IsInGroup)
+ error("may not nest --start-lib in --start-group");
InLib = true;
+ InputFile::IsInGroup = true;
break;
case OPT_end_lib:
+ if (!InLib)
+ error("stray --end-lib");
InLib = false;
+ InputFile::IsInGroup = false;
+ ++InputFile::NextGroupId;
+ break;
+ case OPT_push_state:
+ Stack.emplace_back(Config->AsNeeded, Config->Static, InWholeArchive);
+ break;
+ case OPT_pop_state:
+ if (Stack.empty()) {
+ error("unbalanced --push-state/--pop-state");
+ break;
+ }
+ std::tie(Config->AsNeeded, Config->Static, InWholeArchive) = Stack.back();
+ Stack.pop_back();
break;
}
}
@@ -934,14 +1180,6 @@ static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) {
return Ret;
}
-static Optional<StringRef> getArchiveName(InputFile *File) {
- if (isa<ArchiveFile>(File))
- return File->getName();
- if (!File->ArchiveName.empty())
- return File->ArchiveName;
- return None;
-}
-
// Handles the -exclude-libs option. If a static library file is specified
// by the -exclude-libs option, all public symbols from the archive become
// private unless otherwise specified by version scripts or something.
@@ -949,18 +1187,140 @@ static Optional<StringRef> getArchiveName(InputFile *File) {
//
// This is not a popular option, but some programs such as bionic libc use it.
template <class ELFT>
-static void excludeLibs(opt::InputArgList &Args, ArrayRef<InputFile *> Files) {
+static void excludeLibs(opt::InputArgList &Args) {
DenseSet<StringRef> Libs = getExcludeLibs(Args);
bool All = Libs.count("ALL");
- for (InputFile *File : Files)
- if (Optional<StringRef> Archive = getArchiveName(File))
- if (All || Libs.count(path::filename(*Archive)))
+ auto Visit = [&](InputFile *File) {
+ if (!File->ArchiveName.empty())
+ if (All || Libs.count(path::filename(File->ArchiveName)))
for (Symbol *Sym : File->getSymbols())
- if (!Sym->isLocal())
+ if (!Sym->isLocal() && Sym->File == File)
Sym->VersionId = VER_NDX_LOCAL;
+ };
+
+ for (InputFile *File : ObjectFiles)
+ Visit(File);
+
+ for (BitcodeFile *File : BitcodeFiles)
+ Visit(File);
+}
+
+// Force Sym to be entered in the output. Used for -u or equivalent.
+template <class ELFT> static void handleUndefined(StringRef Name) {
+ Symbol *Sym = Symtab->find(Name);
+ if (!Sym)
+ return;
+
+ // Since symbol S may not be used inside the program, LTO may
+ // eliminate it. Mark the symbol as "used" to prevent it.
+ Sym->IsUsedInRegularObj = true;
+
+ if (Sym->isLazy())
+ Symtab->fetchLazy<ELFT>(Sym);
+}
+
+template <class ELFT> static bool shouldDemote(Symbol &Sym) {
+ // If all references to a DSO happen to be weak, the DSO is not added to
+ // DT_NEEDED. If that happens, we need to eliminate shared symbols created
+ // from the DSO. Otherwise, they become dangling references that point to a
+ // non-existent DSO.
+ if (auto *S = dyn_cast<SharedSymbol>(&Sym))
+ return !S->getFile<ELFT>().IsNeeded;
+
+ // We are done processing archives, so lazy symbols that were used but not
+ // found can be converted to undefined. We could also just delete the other
+ // lazy symbols, but that seems to be more work than it is worth.
+ return Sym.isLazy() && Sym.IsUsedInRegularObj;
}
+// Some files, such as .so or files between -{start,end}-lib may be removed
+// after their symbols are added to the symbol table. If that happens, we
+// need to remove symbols that refer files that no longer exist, so that
+// they won't appear in the symbol table of the output file.
+//
+// We remove symbols by demoting them to undefined symbol.
+template <class ELFT> static void demoteSymbols() {
+ for (Symbol *Sym : Symtab->getSymbols()) {
+ if (shouldDemote<ELFT>(*Sym)) {
+ bool Used = Sym->Used;
+ replaceSymbol<Undefined>(Sym, nullptr, Sym->getName(), Sym->Binding,
+ Sym->StOther, Sym->Type);
+ Sym->Used = Used;
+ }
+ }
+}
+
+// The section referred to by S is considered address-significant. Set the
+// KeepUnique flag on the section if appropriate.
+static void markAddrsig(Symbol *S) {
+ if (auto *D = dyn_cast_or_null<Defined>(S))
+ if (D->Section)
+ // We don't need to keep text sections unique under --icf=all even if they
+ // are address-significant.
+ if (Config->ICF == ICFLevel::Safe || !(D->Section->Flags & SHF_EXECINSTR))
+ D->Section->KeepUnique = true;
+}
+
+// Record sections that define symbols mentioned in --keep-unique <symbol>
+// and symbols referred to by address-significance tables. These sections are
+// ineligible for ICF.
+template <class ELFT>
+static void findKeepUniqueSections(opt::InputArgList &Args) {
+ for (auto *Arg : Args.filtered(OPT_keep_unique)) {
+ StringRef Name = Arg->getValue();
+ auto *D = dyn_cast_or_null<Defined>(Symtab->find(Name));
+ if (!D || !D->Section) {
+ warn("could not find symbol " + Name + " to keep unique");
+ continue;
+ }
+ D->Section->KeepUnique = true;
+ }
+
+ // --icf=all --ignore-data-address-equality means that we can ignore
+ // the dynsym and address-significance tables entirely.
+ if (Config->ICF == ICFLevel::All && Config->IgnoreDataAddressEquality)
+ return;
+
+ // Symbols in the dynsym could be address-significant in other executables
+ // or DSOs, so we conservatively mark them as address-significant.
+ for (Symbol *S : Symtab->getSymbols())
+ if (S->includeInDynsym())
+ markAddrsig(S);
+
+ // Visit the address-significance table in each object file and mark each
+ // referenced symbol as address-significant.
+ for (InputFile *F : ObjectFiles) {
+ auto *Obj = cast<ObjFile<ELFT>>(F);
+ ArrayRef<Symbol *> Syms = Obj->getSymbols();
+ if (Obj->AddrsigSec) {
+ ArrayRef<uint8_t> Contents =
+ check(Obj->getObj().getSectionContents(Obj->AddrsigSec));
+ const uint8_t *Cur = Contents.begin();
+ while (Cur != Contents.end()) {
+ unsigned Size;
+ const char *Err;
+ uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err);
+ if (Err)
+ fatal(toString(F) + ": could not decode addrsig section: " + Err);
+ markAddrsig(Syms[SymIndex]);
+ Cur += Size;
+ }
+ } else {
+ // If an object file does not have an address-significance table,
+ // conservatively mark all of its symbols as address-significant.
+ for (Symbol *S : Syms)
+ markAddrsig(S);
+ }
+ }
+}
+
+static const char *LibcallRoutineNames[] = {
+#define HANDLE_LIBCALL(code, name) name,
+#include "llvm/IR/RuntimeLibcalls.def"
+#undef HANDLE_LIBCALL
+};
+
// Do actual linking. Note that when this function is called,
// all linker scripts have already been parsed.
template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
@@ -1009,14 +1369,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
for (InputFile *F : Files)
Symtab->addFile<ELFT>(F);
- // Process -defsym option.
- for (auto *Arg : Args.filtered(OPT_defsym)) {
- StringRef From;
- StringRef To;
- std::tie(From, To) = StringRef(Arg->getValue()).split('=');
- readDefsym(From, MemoryBufferRef(To, "-defsym"));
- }
-
// Now that we have every file, we can decide if we will need a
// dynamic symbol table.
// We need one if we were asked to export dynamic symbols or if we are
@@ -1033,24 +1385,39 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// Handle the `--undefined <sym>` options.
for (StringRef S : Config->Undefined)
- Symtab->fetchIfLazy<ELFT>(S);
+ handleUndefined<ELFT>(S);
- // If an entry symbol is in a static archive, pull out that file now
- // to complete the symbol table. After this, no new names except a
- // few linker-synthesized ones will be added to the symbol table.
- Symtab->fetchIfLazy<ELFT>(Config->Entry);
+ // If an entry symbol is in a static archive, pull out that file now.
+ handleUndefined<ELFT>(Config->Entry);
+
+ // If any of our inputs are bitcode files, the LTO code generator may create
+ // references to certain library functions that might not be explicit in the
+ // bitcode file's symbol table. If any of those library functions are defined
+ // in a bitcode file in an archive member, we need to arrange to use LTO to
+ // compile those archive members by adding them to the link beforehand.
+ //
+ // With this the symbol table should be complete. After this, no new names
+ // except a few linker-synthesized ones will be added to the symbol table.
+ if (!BitcodeFiles.empty())
+ for (const char *S : LibcallRoutineNames)
+ handleUndefined<ELFT>(S);
// Return if there were name resolution errors.
if (errorCount())
return;
- // Handle undefined symbols in DSOs.
- if (!Config->Shared)
- Symtab->scanShlibUndefined<ELFT>();
+ // Now when we read all script files, we want to finalize order of linker
+ // script commands, which can be not yet final because of INSERT commands.
+ Script->processInsertCommands();
+
+ // We want to declare linker script's symbols early,
+ // so that we can version them.
+ // They also might be exported if referenced by DSOs.
+ Script->declareSymbols();
// Handle the -exclude-libs option.
if (Args.hasArg(OPT_exclude_libs))
- excludeLibs<ELFT>(Args, Files);
+ excludeLibs<ELFT>(Args);
// Create ElfHeader early. We need a dummy section in
// addReservedSymbols to mark the created symbols as not absolute.
@@ -1073,10 +1440,18 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
for (auto *Arg : Args.filtered(OPT_wrap))
Symtab->addSymbolWrap<ELFT>(Arg->getValue());
+ // Do link-time optimization if given files are LLVM bitcode files.
+ // This compiles bitcode files into real object files.
Symtab->addCombinedLTOObject<ELFT>();
if (errorCount())
return;
+ // If -thinlto-index-only is given, we should create only "index
+ // files" and not object files. Index file creation is already done
+ // in addCombinedLTOObject, so we are done if that's the case.
+ if (Config->ThinLTOIndexOnly)
+ return;
+
// Apply symbol renames for -wrap.
Symtab->applySymbolWrap();
@@ -1123,11 +1498,20 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// Do size optimizations: garbage collection, merging of SHF_MERGE sections
// and identical code folding.
- markLive<ELFT>();
decompressSections();
+ splitSections<ELFT>();
+ markLive<ELFT>();
+ demoteSymbols<ELFT>();
mergeSections();
- if (Config->ICF)
+ if (Config->ICF != ICFLevel::None) {
+ findKeepUniqueSections<ELFT>(Args);
doIcf<ELFT>();
+ }
+
+ // Read the callgraph now that we know what was gced or icfed
+ if (auto *Arg = Args.getLastArg(OPT_call_graph_ordering_file))
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ readCallGraph(*Buffer);
// Write the result to the file.
writeResult<ELFT>();
diff --git a/contrib/llvm/tools/lld/ELF/Driver.h b/contrib/llvm/tools/lld/ELF/Driver.h
index 7d2ad7b9cfde..3804fa20f2d3 100644
--- a/contrib/llvm/tools/lld/ELF/Driver.h
+++ b/contrib/llvm/tools/lld/ELF/Driver.h
@@ -26,7 +26,7 @@ extern class LinkerDriver *Driver;
class LinkerDriver {
public:
- void main(ArrayRef<const char *> Args, bool CanExitEarly);
+ void main(ArrayRef<const char *> Args);
void addFile(StringRef Path, bool WithLOption);
void addLibrary(StringRef Name);
@@ -63,11 +63,11 @@ enum {
#undef OPTION
};
-void printHelp(const char *Argv0);
+void printHelp();
std::string createResponseFile(const llvm::opt::InputArgList &Args);
llvm::Optional<std::string> findFromSearchPaths(StringRef Path);
-llvm::Optional<std::string> searchLinkerScript(StringRef Path);
+llvm::Optional<std::string> searchScript(StringRef Path);
llvm::Optional<std::string> searchLibrary(StringRef Path);
} // namespace elf
diff --git a/contrib/llvm/tools/lld/ELF/DriverUtils.cpp b/contrib/llvm/tools/lld/ELF/DriverUtils.cpp
index 774de9f1d03c..c8ca622b0628 100644
--- a/contrib/llvm/tools/lld/ELF/DriverUtils.cpp
+++ b/contrib/llvm/tools/lld/ELF/DriverUtils.cpp
@@ -29,6 +29,7 @@
using namespace llvm;
using namespace llvm::sys;
+using namespace llvm::opt;
using namespace lld;
using namespace lld::elf;
@@ -58,18 +59,18 @@ static void handleColorDiagnostics(opt::InputArgList &Args) {
OPT_no_color_diagnostics);
if (!Arg)
return;
- else if (Arg->getOption().getID() == OPT_color_diagnostics)
+ if (Arg->getOption().getID() == OPT_color_diagnostics) {
errorHandler().ColorDiagnostics = true;
- else if (Arg->getOption().getID() == OPT_no_color_diagnostics)
+ } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) {
errorHandler().ColorDiagnostics = false;
- else {
+ } else {
StringRef S = Arg->getValue();
if (S == "always")
errorHandler().ColorDiagnostics = true;
else if (S == "never")
errorHandler().ColorDiagnostics = false;
else if (S != "auto")
- error("unknown option: -color-diagnostics=" + S);
+ error("unknown option: --color-diagnostics=" + S);
}
}
@@ -87,6 +88,29 @@ static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
return cl::TokenizeGNUCommandLine;
}
+// Gold LTO plugin takes a `--plugin-opt foo=bar` option as an alias for
+// `--plugin-opt=foo=bar`. We want to handle `--plugin-opt=foo=` as an
+// option name and `bar` as a value. Unfortunately, OptParser cannot
+// handle an option with a space in it.
+//
+// In this function, we concatenate command line arguments so that
+// `--plugin-opt <foo>` is converted to `--plugin-opt=<foo>`. This is a
+// bit hacky, but looks like it is still better than handling --plugin-opt
+// options by hand.
+static void concatLTOPluginOptions(SmallVectorImpl<const char *> &Args) {
+ SmallVector<const char *, 256> V;
+ for (size_t I = 0, E = Args.size(); I != E; ++I) {
+ StringRef S = Args[I];
+ if ((S == "-plugin-opt" || S == "--plugin-opt") && I + 1 != E) {
+ V.push_back(Saver.save(S + "=" + Args[I + 1]).data());
+ ++I;
+ } else {
+ V.push_back(Args[I]);
+ }
+ }
+ Args = std::move(V);
+}
+
// Parses a given list of options.
opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
// Make InputArgList from string vectors.
@@ -102,6 +126,7 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
// Expand response files (arguments in the form of @<filename>)
// and then parse the argument again.
cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
+ concatLTOPluginOptions(Vec);
Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
handleColorDiagnostics(Args);
@@ -113,9 +138,9 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
return Args;
}
-void elf::printHelp(const char *Argv0) {
- ELFOptTable().PrintHelp(outs(), Argv0, "lld", false /*ShowHidden*/,
- true /*ShowAllAliases*/);
+void elf::printHelp() {
+ ELFOptTable().PrintHelp(outs(), Config->ProgName.data(), "lld",
+ false /*ShowHidden*/, true /*ShowAllAliases*/);
outs() << "\n";
// Scripts generated by Libtool versions up to at least 2.4.6 (the most
@@ -123,13 +148,7 @@ void elf::printHelp(const char *Argv0) {
// in a message for the -help option. If it doesn't match, the scripts
// assume that the linker doesn't support very basic features such as
// shared libraries. Therefore, we need to print out at least "elf".
- // Here, we print out all the targets that we support.
- outs() << Argv0 << ": supported targets: "
- << "elf32-i386 elf32-iamcu elf32-littlearm elf32-ntradbigmips "
- << "elf32-ntradlittlemips elf32-powerpc elf32-tradbigmips "
- << "elf32-tradlittlemips elf32-x86-64 "
- << "elf64-amdgpu elf64-littleaarch64 elf64-powerpc elf64-tradbigmips "
- << "elf64-tradlittlemips elf64-x86-64\n";
+ outs() << Config->ProgName << ": supported targets: elf\n";
}
// Reconstructs command line arguments so that so that you can re-run
@@ -208,10 +227,10 @@ Optional<std::string> elf::searchLibrary(StringRef Name) {
return None;
}
-// If a linker script doesn't exist in the current directory, we also look for
-// the script in the '-L' search paths. This matches the behaviour of both '-T'
-// and linker script INPUT() directives in ld.bfd.
-Optional<std::string> elf::searchLinkerScript(StringRef Name) {
+// If a linker/version script doesn't exist in the current directory, we also
+// look for the script in the '-L' search paths. This matches the behaviour of
+// '-T', --version-script=, and linker script INPUT() command in ld.bfd.
+Optional<std::string> elf::searchScript(StringRef Name) {
if (fs::exists(Name))
return Name.str();
return findFromSearchPaths(Name);
diff --git a/contrib/llvm/tools/lld/ELF/EhFrame.cpp b/contrib/llvm/tools/lld/ELF/EhFrame.cpp
index 62abc3973e7e..20b32c0a96e6 100644
--- a/contrib/llvm/tools/lld/ELF/EhFrame.cpp
+++ b/contrib/llvm/tools/lld/ELF/EhFrame.cpp
@@ -20,18 +20,16 @@
#include "Config.h"
#include "InputSection.h"
#include "Relocations.h"
-#include "Strings.h"
-
+#include "Target.h"
#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Strings.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::dwarf;
using namespace llvm::object;
-using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
@@ -73,7 +71,7 @@ size_t EhReader::readEhRecordSize() {
// First 4 bytes of CIE/FDE is the size of the record.
// If it is 0xFFFFFFFF, the next 8 bytes contain the size instead,
// but we do not support that format yet.
- uint64_t V = read32(D.data(), Config->Endianness);
+ uint64_t V = read32(D.data());
if (V == UINT32_MAX)
failOn(D.data(), "CIE/FDE too large");
uint64_t Size = V + 4;
diff --git a/contrib/llvm/tools/lld/ELF/Filesystem.cpp b/contrib/llvm/tools/lld/ELF/Filesystem.cpp
index 8d0b5d8a2f1c..5cf240eeca56 100644
--- a/contrib/llvm/tools/lld/ELF/Filesystem.cpp
+++ b/contrib/llvm/tools/lld/ELF/Filesystem.cpp
@@ -44,7 +44,7 @@ using namespace lld::elf;
// The calling thread returns almost immediately.
void elf::unlinkAsync(StringRef Path) {
// Removing a file is async on windows.
-#if defined(LLVM_ON_WIN32)
+#if defined(_WIN32)
sys::fs::remove(Path);
#else
if (!ThreadsEnabled || !sys::fs::exists(Path) ||
diff --git a/contrib/llvm/tools/lld/ELF/GdbIndex.cpp b/contrib/llvm/tools/lld/ELF/GdbIndex.cpp
index d27b57f95938..85449a200647 100644
--- a/contrib/llvm/tools/lld/ELF/GdbIndex.cpp
+++ b/contrib/llvm/tools/lld/ELF/GdbIndex.cpp
@@ -34,7 +34,7 @@ template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *Obj) {
.Case(".debug_ranges", &RangeSection)
.Case(".debug_line", &LineSection)
.Default(nullptr)) {
- Sec->maybeUncompress();
+ Sec->maybeDecompress();
M->Data = toStringRef(Sec->Data);
M->Sec = Sec;
continue;
diff --git a/contrib/llvm/tools/lld/ELF/GdbIndex.h b/contrib/llvm/tools/lld/ELF/GdbIndex.h
index 41ae9d793c11..eba1ba22f879 100644
--- a/contrib/llvm/tools/lld/ELF/GdbIndex.h
+++ b/contrib/llvm/tools/lld/ELF/GdbIndex.h
@@ -49,7 +49,6 @@ public:
return LineSection;
}
StringRef getFileName() const override { return ""; }
- StringRef getCUIndexSection() const override { return ""; }
StringRef getAbbrevSection() const override { return AbbrevSection; }
StringRef getStringSection() const override { return StrSection; }
StringRef getGnuPubNamesSection() const override {
diff --git a/contrib/llvm/tools/lld/ELF/ICF.cpp b/contrib/llvm/tools/lld/ELF/ICF.cpp
index b1e12e0590d5..075938bd16b9 100644
--- a/contrib/llvm/tools/lld/ELF/ICF.cpp
+++ b/contrib/llvm/tools/lld/ELF/ICF.cpp
@@ -77,10 +77,13 @@
#include "Config.h"
#include "SymbolTable.h"
#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Writer.h"
#include "lld/Common/Threads.h"
-#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Object/ELF.h"
+#include "llvm/Support/xxhash.h"
#include <algorithm>
#include <atomic>
@@ -112,9 +115,9 @@ private:
size_t findBoundary(size_t Begin, size_t End);
void forEachClassRange(size_t Begin, size_t End,
- std::function<void(size_t, size_t)> Fn);
+ llvm::function_ref<void(size_t, size_t)> Fn);
- void forEachClass(std::function<void(size_t, size_t)> Fn);
+ void forEachClass(llvm::function_ref<void(size_t, size_t)> Fn);
std::vector<InputSection *> Sections;
@@ -153,23 +156,40 @@ private:
};
}
-// Returns a hash value for S. Note that the information about
-// relocation targets is not included in the hash value.
-template <class ELFT> static uint32_t getHash(InputSection *S) {
- return hash_combine(S->Flags, S->getSize(), S->NumRelocations, S->Data);
-}
-
// Returns true if section S is subject of ICF.
static bool isEligible(InputSection *S) {
- // Don't merge read only data sections unless --icf-data was passed.
- if (!(S->Flags & SHF_EXECINSTR) && !Config->ICFData)
+ if (!S->Live || S->KeepUnique || !(S->Flags & SHF_ALLOC))
+ return false;
+
+ // Don't merge writable sections. .data.rel.ro sections are marked as writable
+ // but are semantically read-only.
+ if ((S->Flags & SHF_WRITE) && S->Name != ".data.rel.ro" &&
+ !S->Name.startswith(".data.rel.ro."))
return false;
- // .init and .fini contains instructions that must be executed to
- // initialize and finalize the process. They cannot and should not
- // be merged.
- return S->Live && (S->Flags & SHF_ALLOC) && !(S->Flags & SHF_WRITE) &&
- S->Name != ".init" && S->Name != ".fini";
+ // SHF_LINK_ORDER sections are ICF'd as a unit with their dependent sections,
+ // so we don't consider them for ICF individually.
+ if (S->Flags & SHF_LINK_ORDER)
+ return false;
+
+ // Don't merge synthetic sections as their Data member is not valid and empty.
+ // The Data member needs to be valid for ICF as it is used by ICF to determine
+ // the equality of section contents.
+ if (isa<SyntheticSection>(S))
+ return false;
+
+ // .init and .fini contains instructions that must be executed to initialize
+ // and finalize the process. They cannot and should not be merged.
+ if (S->Name == ".init" || S->Name == ".fini")
+ return false;
+
+ // A user program may enumerate sections named with a C identifier using
+ // __start_* and __stop_* symbols. We cannot ICF any such sections because
+ // that could change program semantics.
+ if (isValidCIdentifier(S->Name))
+ return false;
+
+ return true;
}
// Split an equivalence class into smaller classes.
@@ -214,9 +234,6 @@ template <class ELFT>
template <class RelTy>
bool ICF<ELFT>::constantEq(const InputSection *SecA, ArrayRef<RelTy> RA,
const InputSection *SecB, ArrayRef<RelTy> RB) {
- if (RA.size() != RB.size())
- return false;
-
for (size_t I = 0; I < RA.size(); ++I) {
if (RA[I].r_offset != RB[I].r_offset ||
RA[I].getType(Config->IsMips64EL) != RB[I].getType(Config->IsMips64EL))
@@ -284,6 +301,13 @@ bool ICF<ELFT>::equalsConstant(const InputSection *A, const InputSection *B) {
A->getSize() != B->getSize() || A->Data != B->Data)
return false;
+ // If two sections have different output sections, we cannot merge them.
+ // FIXME: This doesn't do the right thing in the case where there is a linker
+ // script. We probably need to move output section assignment before ICF to
+ // get the correct behaviour here.
+ if (getOutputSectionName(A) != getOutputSectionName(B))
+ return false;
+
if (A->AreRelocsRela)
return constantEq(A, A->template relas<ELFT>(), B,
B->template relas<ELFT>());
@@ -350,17 +374,12 @@ template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t Begin, size_t End) {
// vector. Therefore, Sections vector can be considered as contiguous
// groups of sections, grouped by the class.
//
-// This function calls Fn on every group that starts within [Begin, End).
-// Note that a group must start in that range but doesn't necessarily
-// have to end before End.
+// This function calls Fn on every group within [Begin, End).
template <class ELFT>
void ICF<ELFT>::forEachClassRange(size_t Begin, size_t End,
- std::function<void(size_t, size_t)> Fn) {
- if (Begin > 0)
- Begin = findBoundary(Begin - 1, End);
-
+ llvm::function_ref<void(size_t, size_t)> Fn) {
while (Begin < End) {
- size_t Mid = findBoundary(Begin, Sections.size());
+ size_t Mid = findBoundary(Begin, End);
Fn(Begin, Mid);
Begin = Mid;
}
@@ -368,7 +387,7 @@ void ICF<ELFT>::forEachClassRange(size_t Begin, size_t End,
// Call Fn on each equivalence class.
template <class ELFT>
-void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) {
+void ICF<ELFT>::forEachClass(llvm::function_ref<void(size_t, size_t)> Fn) {
// If threading is disabled or the number of sections are
// too small to use threading, call Fn sequentially.
if (!ThreadsEnabled || Sections.size() < 1024) {
@@ -380,16 +399,32 @@ void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) {
Current = Cnt % 2;
Next = (Cnt + 1) % 2;
- // Split sections into 256 shards and call Fn in parallel.
- size_t NumShards = 256;
+ // Shard into non-overlapping intervals, and call Fn in parallel.
+ // The sharding must be completed before any calls to Fn are made
+ // so that Fn can modify the Chunks in its shard without causing data
+ // races.
+ const size_t NumShards = 256;
size_t Step = Sections.size() / NumShards;
- parallelForEachN(0, NumShards, [&](size_t I) {
- size_t End = (I == NumShards - 1) ? Sections.size() : (I + 1) * Step;
- forEachClassRange(I * Step, End, Fn);
+ size_t Boundaries[NumShards + 1];
+ Boundaries[0] = 0;
+ Boundaries[NumShards] = Sections.size();
+
+ parallelForEachN(1, NumShards, [&](size_t I) {
+ Boundaries[I] = findBoundary((I - 1) * Step, Sections.size());
+ });
+
+ parallelForEachN(1, NumShards + 1, [&](size_t I) {
+ if (Boundaries[I - 1] < Boundaries[I])
+ forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn);
});
++Cnt;
}
+static void print(const Twine &S) {
+ if (Config->PrintIcfSections)
+ message(S);
+}
+
// The main function of ICF.
template <class ELFT> void ICF<ELFT>::run() {
// Collect sections to merge.
@@ -401,7 +436,7 @@ template <class ELFT> void ICF<ELFT>::run() {
// Initially, we use hash values to partition sections.
parallelForEach(Sections, [&](InputSection *S) {
// Set MSB to 1 to avoid collisions with non-hash IDs.
- S->Class[0] = getHash<ELFT>(S) | (1 << 31);
+ S->Class[0] = xxHash64(S->Data) | (1U << 31);
});
// From now on, sections in Sections vector are ordered so that sections
@@ -424,25 +459,21 @@ template <class ELFT> void ICF<ELFT>::run() {
log("ICF needed " + Twine(Cnt) + " iterations");
// Merge sections by the equivalence class.
- forEachClass([&](size_t Begin, size_t End) {
+ forEachClassRange(0, Sections.size(), [&](size_t Begin, size_t End) {
if (End - Begin == 1)
return;
-
- log("selected " + Sections[Begin]->Name);
+ print("selected section " + toString(Sections[Begin]));
for (size_t I = Begin + 1; I < End; ++I) {
- log(" removed " + Sections[I]->Name);
+ print(" removing identical section " + toString(Sections[I]));
Sections[Begin]->replace(Sections[I]);
+
+ // At this point we know sections merged are fully identical and hence
+ // we want to remove duplicate implicit dependencies such as link order
+ // and relocation sections.
+ for (InputSection *IS : Sections[I]->DependentSections)
+ IS->Live = false;
}
});
-
- // Mark ARM Exception Index table sections that refer to folded code
- // sections as not live. These sections have an implict dependency
- // via the link order dependency.
- if (Config->EMachine == EM_ARM)
- for (InputSectionBase *Sec : InputSections)
- if (auto *S = dyn_cast<InputSection>(Sec))
- if (S->Flags & SHF_LINK_ORDER)
- S->Live = S->getLinkOrderDep()->Live;
}
// ICF entry point function.
diff --git a/contrib/llvm/tools/lld/ELF/ICF.h b/contrib/llvm/tools/lld/ELF/ICF.h
index 24219855fc17..a6c8636ead6d 100644
--- a/contrib/llvm/tools/lld/ELF/ICF.h
+++ b/contrib/llvm/tools/lld/ELF/ICF.h
@@ -12,8 +12,10 @@
namespace lld {
namespace elf {
+
template <class ELFT> void doIcf();
-}
+
+} // namespace elf
} // namespace lld
#endif
diff --git a/contrib/llvm/tools/lld/ELF/InputFiles.cpp b/contrib/llvm/tools/lld/ELF/InputFiles.cpp
index dfd5bbf1e0fc..0eb605a556ae 100644
--- a/contrib/llvm/tools/lld/ELF/InputFiles.cpp
+++ b/contrib/llvm/tools/lld/ELF/InputFiles.cpp
@@ -38,14 +38,23 @@ using namespace llvm::sys::fs;
using namespace lld;
using namespace lld::elf;
+bool InputFile::IsInGroup;
+uint32_t InputFile::NextGroupId;
std::vector<BinaryFile *> elf::BinaryFiles;
std::vector<BitcodeFile *> elf::BitcodeFiles;
+std::vector<LazyObjFile *> elf::LazyObjFiles;
std::vector<InputFile *> elf::ObjectFiles;
std::vector<InputFile *> elf::SharedFiles;
TarWriter *elf::Tar;
-InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
+InputFile::InputFile(Kind K, MemoryBufferRef M)
+ : MB(M), GroupId(NextGroupId), FileKind(K) {
+ // All files within the same --{start,end}-group get the same group ID.
+ // Otherwise, a new file will get a new group ID.
+ if (!IsInGroup)
+ ++NextGroupId;
+}
Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
// The --chroot option changes our virtual root directory.
@@ -55,7 +64,7 @@ Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
log(Path);
- auto MBOrErr = MemoryBuffer::getFile(Path);
+ auto MBOrErr = MemoryBuffer::getFile(Path, -1, false);
if (auto EC = MBOrErr.getError()) {
error("cannot open " + Path + ": " + EC.message());
return None;
@@ -115,51 +124,60 @@ std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec,
}
template <class ELFT> void ObjFile<ELFT>::initializeDwarf() {
- DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(this));
- const DWARFObject &Obj = Dwarf.getDWARFObj();
- DwarfLine.reset(new DWARFDebugLine);
+ Dwarf = llvm::make_unique<DWARFContext>(make_unique<LLDDwarfObj<ELFT>>(this));
+ const DWARFObject &Obj = Dwarf->getDWARFObj();
DWARFDataExtractor LineData(Obj, Obj.getLineSection(), Config->IsLE,
Config->Wordsize);
- // The second parameter is offset in .debug_line section
- // for compilation unit (CU) of interest. We have only one
- // CU (object file), so offset is always 0.
- // FIXME: Provide the associated DWARFUnit if there is one. DWARF v5
- // needs it in order to find indirect strings.
- const DWARFDebugLine::LineTable *LT =
- DwarfLine->getOrParseLineTable(LineData, 0, nullptr);
-
- // Return if there is no debug information about CU available.
- if (!Dwarf.getNumCompileUnits())
- return;
-
- // Loop over variable records and insert them to VariableLoc.
- DWARFCompileUnit *CU = Dwarf.getCompileUnitAtIndex(0);
- for (const auto &Entry : CU->dies()) {
- DWARFDie Die(CU, &Entry);
- // Skip all tags that are not variables.
- if (Die.getTag() != dwarf::DW_TAG_variable)
+ for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf->compile_units()) {
+ auto Report = [](Error Err) {
+ handleAllErrors(std::move(Err),
+ [](ErrorInfoBase &Info) { warn(Info.message()); });
+ };
+ Expected<const DWARFDebugLine::LineTable *> ExpectedLT =
+ Dwarf->getLineTableForUnit(CU.get(), Report);
+ const DWARFDebugLine::LineTable *LT = nullptr;
+ if (ExpectedLT)
+ LT = *ExpectedLT;
+ else
+ Report(ExpectedLT.takeError());
+ if (!LT)
continue;
+ LineTables.push_back(LT);
- // Skip if a local variable because we don't need them for generating error
- // messages. In general, only non-local symbols can fail to be linked.
- if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0))
- continue;
+ // Loop over variable records and insert them to VariableLoc.
+ for (const auto &Entry : CU->dies()) {
+ DWARFDie Die(CU.get(), &Entry);
+ // Skip all tags that are not variables.
+ if (Die.getTag() != dwarf::DW_TAG_variable)
+ continue;
- // Get the source filename index for the variable.
- unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0);
- if (!LT->hasFileAtIndex(File))
- continue;
+ // Skip if a local variable because we don't need them for generating
+ // error messages. In general, only non-local symbols can fail to be
+ // linked.
+ if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0))
+ continue;
- // Get the line number on which the variable is declared.
- unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0);
+ // Get the source filename index for the variable.
+ unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0);
+ if (!LT->hasFileAtIndex(File))
+ continue;
- // Get the name of the variable and add the collected information to
- // VariableLoc. Usually Name is non-empty, but it can be empty if the input
- // object file lacks some debug info.
- StringRef Name = dwarf::toString(Die.find(dwarf::DW_AT_name), "");
- if (!Name.empty())
- VariableLoc.insert({Name, {File, Line}});
+ // Get the line number on which the variable is declared.
+ unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0);
+
+ // Here we want to take the variable name to add it into VariableLoc.
+ // Variable can have regular and linkage name associated. At first, we try
+ // to get linkage name as it can be different, for example when we have
+ // two variables in different namespaces of the same object. Use common
+ // name otherwise, but handle the case when it also absent in case if the
+ // input object file lacks some debug info.
+ StringRef Name =
+ dwarf::toString(Die.find(dwarf::DW_AT_linkage_name),
+ dwarf::toString(Die.find(dwarf::DW_AT_name), ""));
+ if (!Name.empty())
+ VariableLoc.insert({Name, {LT, File, Line}});
+ }
}
}
@@ -170,11 +188,6 @@ Optional<std::pair<std::string, unsigned>>
ObjFile<ELFT>::getVariableLoc(StringRef Name) {
llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); });
- // There is always only one CU so it's offset is 0.
- const DWARFDebugLine::LineTable *LT = DwarfLine->getLineTable(0);
- if (!LT)
- return None;
-
// Return if we have no debug information about data object.
auto It = VariableLoc.find(Name);
if (It == VariableLoc.end())
@@ -182,12 +195,12 @@ ObjFile<ELFT>::getVariableLoc(StringRef Name) {
// Take file name string from line table.
std::string FileName;
- if (!LT->getFileNameByIndex(
- It->second.first /* File */, nullptr,
+ if (!It->second.LT->getFileNameByIndex(
+ It->second.File, nullptr,
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName))
return None;
- return std::make_pair(FileName, It->second.second /*Line*/);
+ return std::make_pair(FileName, It->second.Line);
}
// Returns source line information for a given offset
@@ -197,29 +210,15 @@ Optional<DILineInfo> ObjFile<ELFT>::getDILineInfo(InputSectionBase *S,
uint64_t Offset) {
llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); });
- // The offset to CU is 0.
- const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0);
- if (!Tbl)
- return None;
-
// Use fake address calcuated by adding section file offset and offset in
// section. See comments for ObjectInfo class.
DILineInfo Info;
- Tbl->getFileLineInfoForAddress(
- S->getOffsetInFile() + Offset, nullptr,
- DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info);
- if (Info.Line == 0)
- return None;
- return Info;
-}
-
-// Returns source line information for a given offset
-// using DWARF debug info.
-template <class ELFT>
-std::string ObjFile<ELFT>::getLineInfo(InputSectionBase *S, uint64_t Offset) {
- if (Optional<DILineInfo> Info = getDILineInfo(S, Offset))
- return Info->FileName + ":" + std::to_string(Info->Line);
- return "";
+ for (const llvm::DWARFDebugLine::LineTable *LT : LineTables)
+ if (LT->getFileLineInfoForAddress(
+ S->getOffsetInFile() + Offset, nullptr,
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info))
+ return Info;
+ return None;
}
// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
@@ -249,7 +248,7 @@ ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) {
template <class ELFT>
typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalELFSyms() {
- return makeArrayRef(ELFSyms.begin() + FirstNonLocal, ELFSyms.end());
+ return makeArrayRef(ELFSyms.begin() + FirstGlobal, ELFSyms.end());
}
template <class ELFT>
@@ -260,9 +259,9 @@ uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const {
template <class ELFT>
void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr *Symtab) {
- FirstNonLocal = Symtab->sh_info;
+ FirstGlobal = Symtab->sh_info;
ELFSyms = CHECK(getObj().symbols(Symtab), this);
- if (FirstNonLocal == 0 || FirstNonLocal > ELFSyms.size())
+ if (FirstGlobal == 0 || FirstGlobal > ELFSyms.size())
fatal(toString(this) + ": invalid sh_info in symbol table");
StringTable =
@@ -278,17 +277,22 @@ ObjFile<ELFT>::ObjFile(MemoryBufferRef M, StringRef ArchiveName)
template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getLocalSymbols() {
if (this->Symbols.empty())
return {};
- return makeArrayRef(this->Symbols).slice(1, this->FirstNonLocal - 1);
+ return makeArrayRef(this->Symbols).slice(1, this->FirstGlobal - 1);
}
template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getGlobalSymbols() {
- return makeArrayRef(this->Symbols).slice(this->FirstNonLocal);
+ return makeArrayRef(this->Symbols).slice(this->FirstGlobal);
}
template <class ELFT>
void ObjFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
- // Read section and symbol tables.
- initializeSections(ComdatGroups);
+ // Read a section table. JustSymbols is usually false.
+ if (this->JustSymbols)
+ initializeJustSymbols();
+ else
+ initializeSections(ComdatGroups);
+
+ // Read a symbol table.
initializeSymbols();
}
@@ -312,7 +316,7 @@ StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
// we use a section name as a signature.
//
// Such SHT_GROUP sections are invalid from the perspective of the ELF
- // standard, but GNU gold 1.14 (the neweset version as of July 2017) or
+ // standard, but GNU gold 1.14 (the newest version as of July 2017) or
// older produce such sections as outputs for the -r option, so we need
// a bug-compatibility.
if (Signature.empty() && Sym->getType() == STT_SECTION)
@@ -332,9 +336,19 @@ ObjFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
}
template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
- // We don't merge sections if -O0 (default is -O1). This makes sometimes
- // the linker significantly faster, although the output will be bigger.
- if (Config->Optimize == 0)
+ // On a regular link we don't merge sections if -O0 (default is -O1). This
+ // sometimes makes the linker significantly faster, although the output will
+ // be bigger.
+ //
+ // Doing the same for -r would create a problem as it would combine sections
+ // with different sh_entsize. One option would be to just copy every SHF_MERGE
+ // section as is to the output. While this would produce a valid ELF file with
+ // usable SHF_MERGE sections, tools like (llvm-)?dwarfdump get confused when
+ // they see two .debug_str. We could have separate logic for combining
+ // SHF_MERGE sections based both on their name and sh_entsize, but that seems
+ // to be more trouble than it is worth. Instead, we just use the regular (-O1)
+ // logic for -r.
+ if (Config->Optimize == 0 && !Config->Relocatable)
return false;
// A mergeable section with size 0 is useless because they don't have
@@ -365,12 +379,33 @@ template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
return true;
}
+// This is for --just-symbols.
+//
+// --just-symbols is a very minor feature that allows you to link your
+// output against other existing program, so that if you load both your
+// program and the other program into memory, your output can refer the
+// other program's symbols.
+//
+// When the option is given, we link "just symbols". The section table is
+// initialized with null pointers.
+template <class ELFT> void ObjFile<ELFT>::initializeJustSymbols() {
+ ArrayRef<Elf_Shdr> ObjSections = CHECK(this->getObj().sections(), this);
+ this->Sections.resize(ObjSections.size());
+
+ for (const Elf_Shdr &Sec : ObjSections) {
+ if (Sec.sh_type != SHT_SYMTAB)
+ continue;
+ this->initSymtab(ObjSections, &Sec);
+ return;
+ }
+}
+
template <class ELFT>
void ObjFile<ELFT>::initializeSections(
DenseSet<CachedHashStringRef> &ComdatGroups) {
const ELFFile<ELFT> &Obj = this->getObj();
- ArrayRef<Elf_Shdr> ObjSections = CHECK(this->getObj().sections(), this);
+ ArrayRef<Elf_Shdr> ObjSections = CHECK(Obj.sections(), this);
uint64_t Size = ObjSections.size();
this->Sections.resize(Size);
this->SectionStringTable =
@@ -385,6 +420,17 @@ void ObjFile<ELFT>::initializeSections(
// if -r is given, we'll let the final link discard such sections.
// This is compatible with GNU.
if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) {
+ if (Sec.sh_type == SHT_LLVM_ADDRSIG) {
+ // We ignore the address-significance table if we know that the object
+ // file was created by objcopy or ld -r. This is because these tools
+ // will reorder the symbols in the symbol table, invalidating the data
+ // in the address-significance table, which refers to symbols by index.
+ if (Sec.sh_link != 0)
+ this->AddrsigSec = &Sec;
+ else if (Config->ICF == ICFLevel::Safe)
+ warn(toString(this) + ": --icf=safe is incompatible with object "
+ "files created using objcopy or ld -r");
+ }
this->Sections[I] = &InputSection::Discarded;
continue;
}
@@ -435,8 +481,15 @@ void ObjFile<ELFT>::initializeSections(
if (Sec.sh_link >= this->Sections.size())
fatal(toString(this) +
": invalid sh_link index: " + Twine(Sec.sh_link));
- this->Sections[Sec.sh_link]->DependentSections.push_back(
- cast<InputSection>(this->Sections[I]));
+
+ InputSectionBase *LinkSec = this->Sections[Sec.sh_link];
+ InputSection *IS = cast<InputSection>(this->Sections[I]);
+ LinkSec->DependentSections.push_back(IS);
+ if (!isa<InputSection>(LinkSec))
+ error("a section " + IS->Name +
+ " with SHF_LINK_ORDER should not refer a non-regular "
+ "section: " +
+ toString(LinkSec));
}
}
}
@@ -573,10 +626,11 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
}
case SHT_RELA:
case SHT_REL: {
- // Find the relocation target section and associate this
- // section with it. Target can be discarded, for example
- // if it is a duplicated member of SHT_GROUP section, we
- // do not create or proccess relocatable sections then.
+ // Find a relocation target section and associate this section with that.
+ // Target may have been discarded if it is in a different section group
+ // and the group is discarded, even though it's a violation of the
+ // spec. We handle that situation gracefully by discarding dangling
+ // relocation sections.
InputSectionBase *Target = getRelocTarget(Sec);
if (!Target)
return nullptr;
@@ -591,32 +645,28 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
fatal(toString(this) +
": multiple relocation sections to one section are not supported");
- // Mergeable sections with relocations are tricky because relocations
- // need to be taken into account when comparing section contents for
- // merging. It's not worth supporting such mergeable sections because
- // they are rare and it'd complicates the internal design (we usually
- // have to determine if two sections are mergeable early in the link
- // process much before applying relocations). We simply handle mergeable
- // sections with relocations as non-mergeable.
+ // ELF spec allows mergeable sections with relocations, but they are
+ // rare, and it is in practice hard to merge such sections by contents,
+ // because applying relocations at end of linking changes section
+ // contents. So, we simply handle such sections as non-mergeable ones.
+ // Degrading like this is acceptable because section merging is optional.
if (auto *MS = dyn_cast<MergeInputSection>(Target)) {
Target = toRegularSection(MS);
this->Sections[Sec.sh_info] = Target;
}
- size_t NumRelocations;
if (Sec.sh_type == SHT_RELA) {
ArrayRef<Elf_Rela> Rels = CHECK(this->getObj().relas(&Sec), this);
Target->FirstRelocation = Rels.begin();
- NumRelocations = Rels.size();
+ Target->NumRelocations = Rels.size();
Target->AreRelocsRela = true;
} else {
ArrayRef<Elf_Rel> Rels = CHECK(this->getObj().rels(&Sec), this);
Target->FirstRelocation = Rels.begin();
- NumRelocations = Rels.size();
+ Target->NumRelocations = Rels.size();
Target->AreRelocsRela = false;
}
- assert(isUInt<31>(NumRelocations));
- Target->NumRelocations = NumRelocations;
+ assert(isUInt<31>(Target->NumRelocations));
// Relocation sections processed by the linker are usually removed
// from the output, so returning `nullptr` for the normal case.
@@ -648,13 +698,24 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
if (Name == ".note.GNU-stack")
return &InputSection::Discarded;
- // Split stacks is a feature to support a discontiguous stack. At least
- // as of 2017, it seems that the feature is not being used widely.
- // Only GNU gold supports that. We don't. For the details about that,
- // see https://gcc.gnu.org/wiki/SplitStacks
+ // Split stacks is a feature to support a discontiguous stack,
+ // commonly used in the programming language Go. For the details,
+ // see https://gcc.gnu.org/wiki/SplitStacks. An object file compiled
+ // for split stack will include a .note.GNU-split-stack section.
if (Name == ".note.GNU-split-stack") {
- error(toString(this) +
- ": object file compiled with -fsplit-stack is not supported");
+ if (Config->Relocatable) {
+ error("Cannot mix split-stack and non-split-stack in a relocatable link");
+ return &InputSection::Discarded;
+ }
+ this->SplitStack = true;
+ return &InputSection::Discarded;
+ }
+
+ // An object file cmpiled for split stack, but where some of the
+ // functions were compiled with the no_split_stack_attribute will
+ // include a .note.GNU-no-split-stack section.
+ if (Name == ".note.GNU-no-split-stack") {
+ this->SomeNoSplitStack = true;
return &InputSection::Discarded;
}
@@ -666,6 +727,14 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
if (Name.startswith(".gnu.linkonce."))
return &InputSection::Discarded;
+ // If we are creating a new .build-id section, strip existing .build-id
+ // sections so that the output won't have more than one .build-id.
+ // This is not usually a problem because input object files normally don't
+ // have .build-id sections, but you can create such files by
+ // "ld.{bfd,gold,lld} -r --build-id", and we want to guard against it.
+ if (Name == ".note.gnu.build-id" && Config->BuildId != BuildIdKind::None)
+ return &InputSection::Discarded;
+
// The linker merges EH (exception handling) frames and creates a
// .eh_frame_hdr section for runtime. So we handle them with a special
// class. For relocatable outputs, they are just passed through.
@@ -747,33 +816,33 @@ ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File)
File(std::move(File)) {}
template <class ELFT> void ArchiveFile::parse() {
- Symbols.reserve(File->getNumberOfSymbols());
for (const Archive::Symbol &Sym : File->symbols())
- Symbols.push_back(Symtab->addLazyArchive<ELFT>(Sym.getName(), *this, Sym));
+ Symtab->addLazyArchive<ELFT>(Sym.getName(), *this, Sym);
}
// Returns a buffer pointing to a member file containing a given symbol.
-std::pair<MemoryBufferRef, uint64_t>
-ArchiveFile::getMember(const Archive::Symbol *Sym) {
+InputFile *ArchiveFile::fetch(const Archive::Symbol &Sym) {
Archive::Child C =
- CHECK(Sym->getMember(), toString(this) +
- ": could not get the member for symbol " +
- Sym->getName());
+ CHECK(Sym.getMember(), toString(this) +
+ ": could not get the member for symbol " +
+ Sym.getName());
if (!Seen.insert(C.getChildOffset()).second)
- return {MemoryBufferRef(), 0};
+ return nullptr;
- MemoryBufferRef Ret =
+ MemoryBufferRef MB =
CHECK(C.getMemoryBufferRef(),
toString(this) +
": could not get the buffer for the member defining symbol " +
- Sym->getName());
+ Sym.getName());
+
+ if (Tar && C.getParent()->isThin())
+ Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), MB.getBuffer());
- if (C.getParent()->isThin() && Tar)
- Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), Ret.getBuffer());
- if (C.getParent()->isThin())
- return {Ret, 0};
- return {Ret, C.getChildOffset()};
+ InputFile *File = createObjectFile(
+ MB, getName(), C.getParent()->isThin() ? 0 : C.getChildOffset());
+ File->GroupId = GroupId;
+ return File;
}
template <class ELFT>
@@ -830,34 +899,42 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
}
}
+// Parses ".gnu.version" section which is a parallel array for the symbol table.
+// If a given file doesn't have ".gnu.version" section, returns VER_NDX_GLOBAL.
+template <class ELFT> std::vector<uint32_t> SharedFile<ELFT>::parseVersyms() {
+ size_t Size = this->ELFSyms.size() - this->FirstGlobal;
+ if (!VersymSec)
+ return std::vector<uint32_t>(Size, VER_NDX_GLOBAL);
+
+ const char *Base = this->MB.getBuffer().data();
+ const Elf_Versym *Versym =
+ reinterpret_cast<const Elf_Versym *>(Base + VersymSec->sh_offset) +
+ this->FirstGlobal;
+
+ std::vector<uint32_t> Ret(Size);
+ for (size_t I = 0; I < Size; ++I)
+ Ret[I] = Versym[I].vs_index;
+ return Ret;
+}
+
// Parse the version definitions in the object file if present. Returns a vector
// whose nth element contains a pointer to the Elf_Verdef for version identifier
-// n. Version identifiers that are not definitions map to nullptr. The array
-// always has at least length 1.
+// n. Version identifiers that are not definitions map to nullptr.
template <class ELFT>
-std::vector<const typename ELFT::Verdef *>
-SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) {
- std::vector<const Elf_Verdef *> Verdefs(1);
- // We only need to process symbol versions for this DSO if it has both a
- // versym and a verdef section, which indicates that the DSO contains symbol
- // version definitions.
- if (!VersymSec || !VerdefSec)
- return Verdefs;
-
- // The location of the first global versym entry.
- const char *Base = this->MB.getBuffer().data();
- Versym = reinterpret_cast<const Elf_Versym *>(Base + VersymSec->sh_offset) +
- this->FirstNonLocal;
+std::vector<const typename ELFT::Verdef *> SharedFile<ELFT>::parseVerdefs() {
+ if (!VerdefSec)
+ return {};
// We cannot determine the largest verdef identifier without inspecting
// every Elf_Verdef, but both bfd and gold assign verdef identifiers
// sequentially starting from 1, so we predict that the largest identifier
// will be VerdefCount.
unsigned VerdefCount = VerdefSec->sh_info;
- Verdefs.resize(VerdefCount + 1);
+ std::vector<const Elf_Verdef *> Verdefs(VerdefCount + 1);
// Build the Verdefs array by following the chain of Elf_Verdef objects
// from the start of the .gnu.version_d section.
+ const char *Base = this->MB.getBuffer().data();
const char *Verdef = Base + VerdefSec->sh_offset;
for (unsigned I = 0; I != VerdefCount; ++I) {
auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef);
@@ -871,82 +948,99 @@ SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) {
return Verdefs;
}
+// We do not usually care about alignments of data in shared object
+// files because the loader takes care of it. However, if we promote a
+// DSO symbol to point to .bss due to copy relocation, we need to keep
+// the original alignment requirements. We infer it in this function.
+template <class ELFT>
+uint32_t SharedFile<ELFT>::getAlignment(ArrayRef<Elf_Shdr> Sections,
+ const Elf_Sym &Sym) {
+ uint64_t Ret = UINT64_MAX;
+ if (Sym.st_value)
+ Ret = 1ULL << countTrailingZeros((uint64_t)Sym.st_value);
+ if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size())
+ Ret = std::min<uint64_t>(Ret, Sections[Sym.st_shndx].sh_addralign);
+ return (Ret > UINT32_MAX) ? 0 : Ret;
+}
+
// Fully parse the shared object file. This must be called after parseSoName().
+//
+// This function parses symbol versions. If a DSO has version information,
+// the file has a ".gnu.version_d" section which contains symbol version
+// definitions. Each symbol is associated to one version through a table in
+// ".gnu.version" section. That table is a parallel array for the symbol
+// table, and each table entry contains an index in ".gnu.version_d".
+//
+// The special index 0 is reserved for VERF_NDX_LOCAL and 1 is for
+// VER_NDX_GLOBAL. There's no table entry for these special versions in
+// ".gnu.version_d".
+//
+// The file format for symbol versioning is perhaps a bit more complicated
+// than necessary, but you can easily understand the code if you wrap your
+// head around the data structure described above.
template <class ELFT> void SharedFile<ELFT>::parseRest() {
- // Create mapping from version identifiers to Elf_Verdef entries.
- const Elf_Versym *Versym = nullptr;
- Verdefs = parseVerdefs(Versym);
-
+ Verdefs = parseVerdefs(); // parse .gnu.version_d
+ std::vector<uint32_t> Versyms = parseVersyms(); // parse .gnu.version
ArrayRef<Elf_Shdr> Sections = CHECK(this->getObj().sections(), this);
+ // System libraries can have a lot of symbols with versions. Using a
+ // fixed buffer for computing the versions name (foo@ver) can save a
+ // lot of allocations.
+ SmallString<0> VersionedNameBuffer;
+
// Add symbols to the symbol table.
- Elf_Sym_Range Syms = this->getGlobalELFSyms();
- for (const Elf_Sym &Sym : Syms) {
- unsigned VersymIndex = VER_NDX_GLOBAL;
- if (Versym) {
- VersymIndex = Versym->vs_index;
- ++Versym;
- }
- bool Hidden = VersymIndex & VERSYM_HIDDEN;
- VersymIndex = VersymIndex & ~VERSYM_HIDDEN;
+ ArrayRef<Elf_Sym> Syms = this->getGlobalELFSyms();
+ for (size_t I = 0; I < Syms.size(); ++I) {
+ const Elf_Sym &Sym = Syms[I];
StringRef Name = CHECK(Sym.getName(this->StringTable), this);
if (Sym.isUndefined()) {
- Undefs.push_back(Name);
+ Symbol *S = Symtab->addUndefined<ELFT>(Name, Sym.getBinding(),
+ Sym.st_other, Sym.getType(),
+ /*CanOmitFromDynSym=*/false, this);
+ S->ExportDynamic = true;
continue;
}
+ // ELF spec requires that all local symbols precede weak or global
+ // symbols in each symbol table, and the index of first non-local symbol
+ // is stored to sh_info. If a local symbol appears after some non-local
+ // symbol, that's a violation of the spec.
if (Sym.getBinding() == STB_LOCAL) {
warn("found local symbol '" + Name +
"' in global part of symbol table in file " + toString(this));
continue;
}
- if (Config->EMachine == EM_MIPS) {
- // FIXME: MIPS BFD linker puts _gp_disp symbol into DSO files
- // and incorrectly assigns VER_NDX_LOCAL to this section global
- // symbol. Here is a workaround for this bug.
- if (Versym && VersymIndex == VER_NDX_LOCAL && Name == "_gp_disp")
- continue;
- }
-
- const Elf_Verdef *Ver = nullptr;
- if (VersymIndex != VER_NDX_GLOBAL) {
- if (VersymIndex >= Verdefs.size() || VersymIndex == VER_NDX_LOCAL) {
- error("corrupt input file: version definition index " +
- Twine(VersymIndex) + " for symbol " + Name +
- " is out of bounds\n>>> defined in " + toString(this));
- continue;
- }
- Ver = Verdefs[VersymIndex];
- } else {
- VersymIndex = 0;
- }
-
- // We do not usually care about alignments of data in shared object
- // files because the loader takes care of it. However, if we promote a
- // DSO symbol to point to .bss due to copy relocation, we need to keep
- // the original alignment requirements. We infer it here.
- uint64_t Alignment = 1;
- if (Sym.st_value)
- Alignment = 1ULL << countTrailingZeros((uint64_t)Sym.st_value);
- if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size()) {
- uint64_t SecAlign = Sections[Sym.st_shndx].sh_addralign;
- Alignment = std::min(Alignment, SecAlign);
- }
- if (Alignment > UINT32_MAX)
- error(toString(this) + ": alignment too large: " + Name);
+ // MIPS BFD linker puts _gp_disp symbol into DSO files and incorrectly
+ // assigns VER_NDX_LOCAL to this section global symbol. Here is a
+ // workaround for this bug.
+ uint32_t Idx = Versyms[I] & ~VERSYM_HIDDEN;
+ if (Config->EMachine == EM_MIPS && Idx == VER_NDX_LOCAL &&
+ Name == "_gp_disp")
+ continue;
- if (!Hidden)
- Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex);
+ uint64_t Alignment = getAlignment(Sections, Sym);
+ if (!(Versyms[I] & VERSYM_HIDDEN))
+ Symtab->addShared(Name, *this, Sym, Alignment, Idx);
// Also add the symbol with the versioned name to handle undefined symbols
// with explicit versions.
- if (Ver) {
- StringRef VerName = this->StringTable.data() + Ver->getAux()->vda_name;
- Name = Saver.save(Name + "@" + VerName);
- Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex);
+ if (Idx == VER_NDX_GLOBAL)
+ continue;
+
+ if (Idx >= Verdefs.size() || Idx == VER_NDX_LOCAL) {
+ error("corrupt input file: version definition index " + Twine(Idx) +
+ " for symbol " + Name + " is out of bounds\n>>> defined in " +
+ toString(this));
+ continue;
}
+
+ StringRef VerName =
+ this->StringTable.data() + Verdefs[Idx]->getAux()->vda_name;
+ VersionedNameBuffer.clear();
+ Name = (Name + "@" + VerName).toStringRef(VersionedNameBuffer);
+ Symtab->addShared(Saver.save(Name), *this, Sym, Alignment, Idx);
}
}
@@ -979,8 +1073,9 @@ static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) {
case Triple::x86_64:
return EM_X86_64;
default:
- fatal(Path + ": could not infer e_machine from bitcode target triple " +
+ error(Path + ": could not infer e_machine from bitcode target triple " +
T.str());
+ return EM_NONE;
}
}
@@ -989,17 +1084,21 @@ BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName,
: InputFile(BitcodeKind, MB) {
this->ArchiveName = ArchiveName;
- // Here we pass a new MemoryBufferRef which is identified by ArchiveName
- // (the fully resolved path of the archive) + member name + offset of the
- // member in the archive.
- // ThinLTO uses the MemoryBufferRef identifier to access its internal
- // data structures and if two archives define two members with the same name,
- // this causes a collision which result in only one of the objects being
- // taken into consideration at LTO time (which very likely causes undefined
- // symbols later in the link stage).
- MemoryBufferRef MBRef(MB.getBuffer(),
- Saver.save(ArchiveName + MB.getBufferIdentifier() +
- utostr(OffsetInArchive)));
+ std::string Path = MB.getBufferIdentifier().str();
+ if (Config->ThinLTOIndexOnly)
+ Path = replaceThinLTOSuffix(MB.getBufferIdentifier());
+
+ // ThinLTO assumes that all MemoryBufferRefs given to it have a unique
+ // name. If two archives define two members with the same name, this
+ // causes a collision which result in only one of the objects being taken
+ // into consideration at LTO time (which very likely causes undefined
+ // symbols later in the link stage). So we append file offset to make
+ // filename unique.
+ MemoryBufferRef MBRef(
+ MB.getBuffer(),
+ Saver.save(ArchiveName + Path +
+ (ArchiveName.empty() ? "" : utostr(OffsetInArchive))));
+
Obj = CHECK(lto::InputFile::create(MBRef), this);
Triple T(Obj->getTargetTriple());
@@ -1023,7 +1122,7 @@ template <class ELFT>
static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
const lto::InputFile::Symbol &ObjSym,
BitcodeFile &F) {
- StringRef NameRef = Saver.save(ObjSym.getName());
+ StringRef Name = Saver.save(ObjSym.getName());
uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL;
uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE;
@@ -1032,20 +1131,20 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
int C = ObjSym.getComdatIndex();
if (C != -1 && !KeptComdats[C])
- return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type,
+ return Symtab->addUndefined<ELFT>(Name, Binding, Visibility, Type,
CanOmitFromDynSym, &F);
if (ObjSym.isUndefined())
- return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type,
+ return Symtab->addUndefined<ELFT>(Name, Binding, Visibility, Type,
CanOmitFromDynSym, &F);
if (ObjSym.isCommon())
- return Symtab->addCommon(NameRef, ObjSym.getCommonSize(),
+ return Symtab->addCommon(Name, ObjSym.getCommonSize(),
ObjSym.getCommonAlignment(), Binding, Visibility,
STT_OBJECT, F);
- return Symtab->addBitcode(NameRef, Binding, Visibility, Type,
- CanOmitFromDynSym, F);
+ return Symtab->addBitcode(Name, Binding, Visibility, Type, CanOmitFromDynSym,
+ F);
}
template <class ELFT>
@@ -1080,8 +1179,8 @@ static ELFKind getELFKind(MemoryBufferRef MB) {
void BinaryFile::parse() {
ArrayRef<uint8_t> Data = toArrayRef(MB.getBuffer());
- auto *Section = make<InputSection>(nullptr, SHF_ALLOC | SHF_WRITE,
- SHT_PROGBITS, 8, Data, ".data");
+ auto *Section = make<InputSection>(this, SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+ 8, Data, ".data");
Sections.push_back(Section);
// For each input file foo that is embedded to a result as a binary
@@ -1101,11 +1200,6 @@ void BinaryFile::parse() {
Data.size(), 0, STB_GLOBAL, nullptr, nullptr);
}
-static bool isBitcode(MemoryBufferRef MB) {
- using namespace sys::fs;
- return identify_magic(MB.getBuffer()) == file_magic::bitcode;
-}
-
InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName,
uint64_t OffsetInArchive) {
if (isBitcode(MB))
@@ -1141,9 +1235,9 @@ InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) {
}
MemoryBufferRef LazyObjFile::getBuffer() {
- if (Seen)
+ if (AddedToLink)
return MemoryBufferRef();
- Seen = true;
+ AddedToLink = true;
return MB;
}
@@ -1151,66 +1245,72 @@ InputFile *LazyObjFile::fetch() {
MemoryBufferRef MBRef = getBuffer();
if (MBRef.getBuffer().empty())
return nullptr;
- return createObjectFile(MBRef, ArchiveName, OffsetInArchive);
+
+ InputFile *File = createObjectFile(MBRef, ArchiveName, OffsetInArchive);
+ File->GroupId = GroupId;
+ return File;
}
template <class ELFT> void LazyObjFile::parse() {
- for (StringRef Sym : getSymbolNames())
- Symtab->addLazyObject<ELFT>(Sym, *this);
+ // A lazy object file wraps either a bitcode file or an ELF file.
+ if (isBitcode(this->MB)) {
+ std::unique_ptr<lto::InputFile> Obj =
+ CHECK(lto::InputFile::create(this->MB), this);
+ for (const lto::InputFile::Symbol &Sym : Obj->symbols())
+ if (!Sym.isUndefined())
+ Symtab->addLazyObject<ELFT>(Saver.save(Sym.getName()), *this);
+ return;
+ }
+
+ switch (getELFKind(this->MB)) {
+ case ELF32LEKind:
+ addElfSymbols<ELF32LE>();
+ return;
+ case ELF32BEKind:
+ addElfSymbols<ELF32BE>();
+ return;
+ case ELF64LEKind:
+ addElfSymbols<ELF64LE>();
+ return;
+ case ELF64BEKind:
+ addElfSymbols<ELF64BE>();
+ return;
+ default:
+ llvm_unreachable("getELFKind");
+ }
}
-template <class ELFT> std::vector<StringRef> LazyObjFile::getElfSymbols() {
- typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::SymRange Elf_Sym_Range;
+template <class ELFT> void LazyObjFile::addElfSymbols() {
+ ELFFile<ELFT> Obj = check(ELFFile<ELFT>::create(MB.getBuffer()));
+ ArrayRef<typename ELFT::Shdr> Sections = CHECK(Obj.sections(), this);
- ELFFile<ELFT> Obj = check(ELFFile<ELFT>::create(this->MB.getBuffer()));
- ArrayRef<Elf_Shdr> Sections = CHECK(Obj.sections(), this);
- for (const Elf_Shdr &Sec : Sections) {
+ for (const typename ELFT::Shdr &Sec : Sections) {
if (Sec.sh_type != SHT_SYMTAB)
continue;
- Elf_Sym_Range Syms = CHECK(Obj.symbols(&Sec), this);
- uint32_t FirstNonLocal = Sec.sh_info;
+ typename ELFT::SymRange Syms = CHECK(Obj.symbols(&Sec), this);
+ uint32_t FirstGlobal = Sec.sh_info;
StringRef StringTable =
CHECK(Obj.getStringTableForSymtab(Sec, Sections), this);
- std::vector<StringRef> V;
- for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal))
+ for (const typename ELFT::Sym &Sym : Syms.slice(FirstGlobal))
if (Sym.st_shndx != SHN_UNDEF)
- V.push_back(CHECK(Sym.getName(StringTable), this));
- return V;
+ Symtab->addLazyObject<ELFT>(CHECK(Sym.getName(StringTable), this),
+ *this);
+ return;
}
- return {};
}
-std::vector<StringRef> LazyObjFile::getBitcodeSymbols() {
- std::unique_ptr<lto::InputFile> Obj =
- CHECK(lto::InputFile::create(this->MB), this);
- std::vector<StringRef> V;
- for (const lto::InputFile::Symbol &Sym : Obj->symbols())
- if (!Sym.isUndefined())
- V.push_back(Saver.save(Sym.getName()));
- return V;
-}
+std::string elf::replaceThinLTOSuffix(StringRef Path) {
+ StringRef Suffix = Config->ThinLTOObjectSuffixReplace.first;
+ StringRef Repl = Config->ThinLTOObjectSuffixReplace.second;
-// Returns a vector of globally-visible defined symbol names.
-std::vector<StringRef> LazyObjFile::getSymbolNames() {
- if (isBitcode(this->MB))
- return getBitcodeSymbols();
-
- switch (getELFKind(this->MB)) {
- case ELF32LEKind:
- return getElfSymbols<ELF32LE>();
- case ELF32BEKind:
- return getElfSymbols<ELF32BE>();
- case ELF64LEKind:
- return getElfSymbols<ELF64LE>();
- case ELF64BEKind:
- return getElfSymbols<ELF64BE>();
- default:
- llvm_unreachable("getELFKind");
+ if (!Path.endswith(Suffix)) {
+ error("-thinlto-object-suffix-replace=" + Suffix + ";" + Repl +
+ " was given, but " + Path + " does not end with the suffix");
+ return "";
}
+ return (Path.drop_back(Suffix.size()) + Repl).str();
}
template void ArchiveFile::parse<ELF32LE>();
diff --git a/contrib/llvm/tools/lld/ELF/InputFiles.h b/contrib/llvm/tools/lld/ELF/InputFiles.h
index 70109f002e98..0db3203b0ba2 100644
--- a/contrib/llvm/tools/lld/ELF/InputFiles.h
+++ b/contrib/llvm/tools/lld/ELF/InputFiles.h
@@ -12,22 +12,20 @@
#include "Config.h"
#include "lld/Common/ErrorHandler.h"
-
#include "lld/Common/LLVM.h"
#include "lld/Common/Reproduce.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
#include "llvm/IR/Comdat.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/IRObjectFile.h"
#include "llvm/Support/Threading.h"
-
#include <map>
namespace llvm {
-class DWARFDebugLine;
class TarWriter;
struct DILineInfo;
namespace lto {
@@ -48,7 +46,6 @@ namespace elf {
using llvm::object::Archive;
-class Lazy;
class Symbol;
// If -reproduce option is given, all input files are written
@@ -90,15 +87,15 @@ public:
// Returns object file symbols. It is a runtime error to call this
// function on files of other types.
ArrayRef<Symbol *> getSymbols() {
- assert(FileKind == ObjKind || FileKind == BitcodeKind ||
- FileKind == ArchiveKind);
+ assert(FileKind == BinaryKind || FileKind == ObjKind ||
+ FileKind == BitcodeKind);
return Symbols;
}
// Filename of .a which contained this file. If this file was
// not in an archive file, it is the empty string. We use this
// string for creating error messages.
- StringRef ArchiveName;
+ std::string ArchiveName;
// If this is an architecture-specific file, the following members
// have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type.
@@ -112,6 +109,20 @@ public:
std::string getSrcMsg(const Symbol &Sym, InputSectionBase &Sec,
uint64_t Offset);
+ // True if this is an argument for --just-symbols. Usually false.
+ bool JustSymbols = false;
+
+ // GroupId is used for --warn-backrefs which is an optional error
+ // checking feature. All files within the same --{start,end}-group or
+ // --{start,end}-lib get the same group ID. Otherwise, each file gets a new
+ // group ID. For more info, see checkDependency() in SymbolTable.cpp.
+ uint32_t GroupId;
+ static bool IsInGroup;
+ static uint32_t NextGroupId;
+
+ // Index of MIPS GOT built for this file.
+ llvm::Optional<size_t> MipsGotIndex;
+
protected:
InputFile(Kind K, MemoryBufferRef M);
std::vector<InputSectionBase *> Sections;
@@ -144,7 +155,7 @@ public:
protected:
ArrayRef<Elf_Sym> ELFSyms;
- uint32_t FirstNonLocal = 0;
+ uint32_t FirstGlobal = 0;
ArrayRef<Elf_Word> SymtabSHNDX;
StringRef StringTable;
void initSymtab(ArrayRef<Elf_Shdr> Sections, const Elf_Shdr *Symtab);
@@ -183,9 +194,6 @@ public:
return getSymbol(SymIndex);
}
- // Returns source line information for a given offset.
- // If no information is available, returns "".
- std::string getLineInfo(InputSectionBase *S, uint64_t Offset);
llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t);
llvm::Optional<std::pair<std::string, unsigned>> getVariableLoc(StringRef Name);
@@ -199,10 +207,22 @@ public:
// symbol table.
StringRef SourceFile;
+ // True if the file defines functions compiled with
+ // -fsplit-stack. Usually false.
+ bool SplitStack = false;
+
+ // True if the file defines functions compiled with -fsplit-stack,
+ // but had one or more functions with the no_split_stack attribute.
+ bool SomeNoSplitStack = false;
+
+ // Pointer to this input file's .llvm_addrsig section, if it has one.
+ const Elf_Shdr *AddrsigSec = nullptr;
+
private:
void
initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
void initializeSymbols();
+ void initializeJustSymbols();
void initializeDwarf();
InputSectionBase *getRelocTarget(const Elf_Shdr &Sec);
InputSectionBase *createInputSection(const Elf_Shdr &Sec);
@@ -218,8 +238,14 @@ private:
// reporting. Linker may find reasonable number of errors in a
// single object file, so we cache debugging information in order to
// parse it only once for each object file we link.
- std::unique_ptr<llvm::DWARFDebugLine> DwarfLine;
- llvm::DenseMap<StringRef, std::pair<unsigned, unsigned>> VariableLoc;
+ std::unique_ptr<llvm::DWARFContext> Dwarf;
+ std::vector<const llvm::DWARFDebugLine::LineTable *> LineTables;
+ struct VarLoc {
+ const llvm::DWARFDebugLine::LineTable *LT;
+ unsigned File;
+ unsigned Line;
+ };
+ llvm::DenseMap<StringRef, VarLoc> VariableLoc;
llvm::once_flag InitDwarfLine;
};
@@ -243,13 +269,11 @@ public:
template <class ELFT> void parse();
MemoryBufferRef getBuffer();
InputFile *fetch();
+ bool AddedToLink = false;
private:
- std::vector<StringRef> getSymbolNames();
- template <class ELFT> std::vector<StringRef> getElfSymbols();
- std::vector<StringRef> getBitcodeSymbols();
+ template <class ELFT> void addElfSymbols();
- bool Seen = false;
uint64_t OffsetInArchive;
};
@@ -260,11 +284,11 @@ public:
static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
template <class ELFT> void parse();
- // Returns a memory buffer for a given symbol and the offset in the archive
- // for the member. An empty memory buffer and an offset of zero
- // is returned if we have already returned the same memory buffer.
- // (So that we don't instantiate same members more than once.)
- std::pair<MemoryBufferRef, uint64_t> getMember(const Archive::Symbol *Sym);
+ // Pulls out an object file that contains a definition for Sym and
+ // returns it. If the same file was instantiated before, this
+ // function returns a nullptr (so we don't instantiate the same file
+ // more than once.)
+ InputFile *fetch(const Archive::Symbol &Sym);
private:
std::unique_ptr<Archive> File;
@@ -291,7 +315,6 @@ template <class ELFT> class SharedFile : public ELFFileBase<ELFT> {
typedef typename ELFT::Verdef Elf_Verdef;
typedef typename ELFT::Versym Elf_Versym;
- std::vector<StringRef> Undefs;
const Elf_Shdr *VersymSec = nullptr;
const Elf_Shdr *VerdefSec = nullptr;
@@ -299,8 +322,6 @@ public:
std::vector<const Elf_Verdef *> Verdefs;
std::string SoName;
- llvm::ArrayRef<StringRef> getUndefinedSymbols() { return Undefs; }
-
static bool classof(const InputFile *F) {
return F->kind() == Base::SharedKind;
}
@@ -309,7 +330,9 @@ public:
void parseSoName();
void parseRest();
- std::vector<const Elf_Verdef *> parseVerdefs(const Elf_Versym *&Versym);
+ uint32_t getAlignment(ArrayRef<Elf_Shdr> Sections, const Elf_Sym &Sym);
+ std::vector<const Elf_Verdef *> parseVerdefs();
+ std::vector<uint32_t> parseVersyms();
struct NeededVer {
// The string table offset of the version name in the output file.
@@ -338,8 +361,15 @@ InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "",
uint64_t OffsetInArchive = 0);
InputFile *createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName);
+inline bool isBitcode(MemoryBufferRef MB) {
+ return identify_magic(MB.getBuffer()) == llvm::file_magic::bitcode;
+}
+
+std::string replaceThinLTOSuffix(StringRef Path);
+
extern std::vector<BinaryFile *> BinaryFiles;
extern std::vector<BitcodeFile *> BitcodeFiles;
+extern std::vector<LazyObjFile *> LazyObjFiles;
extern std::vector<InputFile *> ObjectFiles;
extern std::vector<InputFile *> SharedFiles;
diff --git a/contrib/llvm/tools/lld/ELF/InputSection.cpp b/contrib/llvm/tools/lld/ELF/InputSection.cpp
index 0b8fe7ba6b59..54fb57cf9888 100644
--- a/contrib/llvm/tools/lld/ELF/InputSection.cpp
+++ b/contrib/llvm/tools/lld/ELF/InputSection.cpp
@@ -14,6 +14,7 @@
#include "LinkerScript.h"
#include "OutputSections.h"
#include "Relocations.h"
+#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
@@ -26,7 +27,10 @@
#include "llvm/Support/Endian.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/xxhash.h"
+#include <algorithm>
#include <mutex>
+#include <set>
+#include <vector>
using namespace llvm;
using namespace llvm::ELF;
@@ -45,32 +49,6 @@ std::string lld::toString(const InputSectionBase *Sec) {
return (toString(Sec->File) + ":(" + Sec->Name + ")").str();
}
-DenseMap<SectionBase *, int> elf::buildSectionOrder() {
- DenseMap<SectionBase *, int> SectionOrder;
- if (Config->SymbolOrderingFile.empty())
- return SectionOrder;
-
- // Build a map from symbols to their priorities. Symbols that didn't
- // appear in the symbol ordering file have the lowest priority 0.
- // All explicitly mentioned symbols have negative (higher) priorities.
- DenseMap<StringRef, int> SymbolOrder;
- int Priority = -Config->SymbolOrderingFile.size();
- for (StringRef S : Config->SymbolOrderingFile)
- SymbolOrder.insert({S, Priority++});
-
- // Build a map from sections to their priorities.
- for (InputFile *File : ObjectFiles) {
- for (Symbol *Sym : File->getSymbols()) {
- auto *D = dyn_cast<Defined>(Sym);
- if (!D || !D->Section)
- continue;
- int &Priority = SectionOrder[D->Section];
- Priority = std::min(Priority, SymbolOrder.lookup(D->getName()));
- }
- }
- return SectionOrder;
-}
-
template <class ELFT>
static ArrayRef<uint8_t> getSectionContents(ObjFile<ELFT> &File,
const typename ELFT::Shdr &Hdr) {
@@ -168,12 +146,8 @@ uint64_t SectionBase::getOffset(uint64_t Offset) const {
return Offset == uint64_t(-1) ? OS->Size : Offset;
}
case Regular:
- return cast<InputSection>(this)->OutSecOff + Offset;
- case Synthetic: {
- auto *IS = cast<InputSection>(this);
- // For synthetic sections we treat offset -1 as the end of the section.
- return IS->OutSecOff + (Offset == uint64_t(-1) ? IS->getSize() : Offset);
- }
+ case Synthetic:
+ return cast<InputSection>(this)->getOffset(Offset);
case EHFrame:
// The file crtbeginT.o has relocations pointing to the start of an empty
// .eh_frame that is known to be the first in the link. It does that to
@@ -182,16 +156,21 @@ uint64_t SectionBase::getOffset(uint64_t Offset) const {
case Merge:
const MergeInputSection *MS = cast<MergeInputSection>(this);
if (InputSection *IS = MS->getParent())
- return IS->OutSecOff + MS->getOffset(Offset);
- return MS->getOffset(Offset);
+ return IS->getOffset(MS->getParentOffset(Offset));
+ return MS->getParentOffset(Offset);
}
llvm_unreachable("invalid section kind");
}
+uint64_t SectionBase::getVA(uint64_t Offset) const {
+ const OutputSection *Out = getOutputSection();
+ return (Out ? Out->Addr : 0) + getOffset(Offset);
+}
+
OutputSection *SectionBase::getOutputSection() {
InputSection *Sec;
if (auto *IS = dyn_cast<InputSection>(this))
- return IS->getParent();
+ Sec = IS;
else if (auto *MS = dyn_cast<MergeInputSection>(this))
Sec = MS->getParent();
else if (auto *EH = dyn_cast<EhInputSection>(this))
@@ -201,34 +180,50 @@ OutputSection *SectionBase::getOutputSection() {
return Sec ? Sec->getParent() : nullptr;
}
-// Uncompress section contents if required. Note that this function
+// Decompress section contents if required. Note that this function
// is called from parallelForEach, so it must be thread-safe.
-void InputSectionBase::maybeUncompress() {
- if (UncompressBuf || !Decompressor::isCompressedELFSection(Flags, Name))
+void InputSectionBase::maybeDecompress() {
+ if (DecompressBuf)
+ return;
+ if (!(Flags & SHF_COMPRESSED) && !Name.startswith(".zdebug"))
return;
+ // Decompress a section.
Decompressor Dec = check(Decompressor::create(Name, toStringRef(Data),
Config->IsLE, Config->Is64));
size_t Size = Dec.getDecompressedSize();
- UncompressBuf.reset(new char[Size]());
- if (Error E = Dec.decompress({UncompressBuf.get(), Size}))
+ DecompressBuf.reset(new char[Size + Name.size()]());
+ if (Error E = Dec.decompress({DecompressBuf.get(), Size}))
fatal(toString(this) +
": decompress failed: " + llvm::toString(std::move(E)));
- Data = makeArrayRef((uint8_t *)UncompressBuf.get(), Size);
+ Data = makeArrayRef((uint8_t *)DecompressBuf.get(), Size);
Flags &= ~(uint64_t)SHF_COMPRESSED;
+
+ // A section name may have been altered if compressed. If that's
+ // the case, restore the original name. (i.e. ".zdebug_" -> ".debug_")
+ if (Name.startswith(".zdebug")) {
+ DecompressBuf[Size] = '.';
+ memcpy(&DecompressBuf[Size + 1], Name.data() + 2, Name.size() - 2);
+ Name = StringRef(&DecompressBuf[Size], Name.size() - 1);
+ }
}
InputSection *InputSectionBase::getLinkOrderDep() const {
- if ((Flags & SHF_LINK_ORDER) && Link != 0) {
- InputSectionBase *L = File->getSections()[Link];
- if (auto *IS = dyn_cast<InputSection>(L))
- return IS;
- error("a section with SHF_LINK_ORDER should not refer a non-regular "
- "section: " +
- toString(L));
- }
+ assert(Link);
+ assert(Flags & SHF_LINK_ORDER);
+ return cast<InputSection>(File->getSections()[Link]);
+}
+
+// Find a function symbol that encloses a given location.
+template <class ELFT>
+Defined *InputSectionBase::getEnclosingFunction(uint64_t Offset) {
+ for (Symbol *B : File->getSymbols())
+ if (Defined *D = dyn_cast<Defined>(B))
+ if (D->Section == this && D->Type == STT_FUNC && D->Value <= Offset &&
+ Offset < D->Value + D->Size)
+ return D;
return nullptr;
}
@@ -241,9 +236,8 @@ std::string InputSectionBase::getLocation(uint64_t Offset) {
.str();
// First check if we can get desired values from debugging information.
- std::string LineInfo = getFile<ELFT>()->getLineInfo(this, Offset);
- if (!LineInfo.empty())
- return LineInfo;
+ if (Optional<DILineInfo> Info = getFile<ELFT>()->getDILineInfo(this, Offset))
+ return Info->FileName + ":" + std::to_string(Info->Line);
// File->SourceFile contains STT_FILE symbol that contains a
// source file name. If it's missing, we use an object file name.
@@ -251,12 +245,8 @@ std::string InputSectionBase::getLocation(uint64_t Offset) {
if (SrcFile.empty())
SrcFile = toString(File);
- // Find a function symbol that encloses a given location.
- for (Symbol *B : File->getSymbols())
- if (auto *D = dyn_cast<Defined>(B))
- if (D->Section == this && D->Type == STT_FUNC)
- if (D->Value <= Offset && Offset < D->Value + D->Size)
- return SrcFile + ":(function " + toString(*D) + ")";
+ if (Defined *D = getEnclosingFunction<ELFT>(Offset))
+ return SrcFile + ":(function " + toString(*D) + ")";
// If there's no symbol, print out the offset in the section.
return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str();
@@ -292,7 +282,7 @@ std::string InputSectionBase::getObjMsg(uint64_t Off) {
std::string Archive;
if (!File->ArchiveName.empty())
- Archive = (" in archive " + File->ArchiveName).str();
+ Archive = " in archive " + File->ArchiveName;
// Find a symbol that encloses a given location.
for (Symbol *B : File->getSymbols())
@@ -345,8 +335,9 @@ template <class ELFT> void InputSection::copyShtGroup(uint8_t *Buf) {
*To++ = Sections[Idx]->getOutputSection()->SectionIndex;
}
-InputSectionBase *InputSection::getRelocatedSection() {
- assert(Type == SHT_RELA || Type == SHT_REL);
+InputSectionBase *InputSection::getRelocatedSection() const {
+ if (!File || (Type != SHT_RELA && Type != SHT_REL))
+ return nullptr;
ArrayRef<InputSectionBase *> Sections = File->getSections();
return Sections[Info];
}
@@ -365,12 +356,12 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
auto *P = reinterpret_cast<typename ELFT::Rela *>(Buf);
Buf += sizeof(RelTy);
- if (Config->IsRela)
+ if (RelTy::IsRela)
P->r_addend = getAddend<ELFT>(Rel);
// Output section VA is zero for -r, so r_offset is an offset within the
// section, but for --emit-relocs it is an virtual address.
- P->r_offset = Sec->getOutputSection()->Addr + Sec->getOffset(Rel.r_offset);
+ P->r_offset = Sec->getVA(Rel.r_offset);
P->setSymbolAndType(InX::SymTab->getSymbolIndex(&Sym), Type,
Config->IsMips64EL);
@@ -395,17 +386,32 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
continue;
}
- if (Config->IsRela) {
- P->r_addend =
- Sym.getVA(getAddend<ELFT>(Rel)) - Section->getOutputSection()->Addr;
- } else if (Config->Relocatable) {
- const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset;
- Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset,
- Target->getImplicitAddend(BufLoc, Type),
- &Sym});
+ int64_t Addend = getAddend<ELFT>(Rel);
+ const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset;
+ if (!RelTy::IsRela)
+ Addend = Target->getImplicitAddend(BufLoc, Type);
+
+ if (Config->EMachine == EM_MIPS && Config->Relocatable &&
+ Target->getRelExpr(Type, Sym, BufLoc) == R_MIPS_GOTREL) {
+ // Some MIPS relocations depend on "gp" value. By default,
+ // this value has 0x7ff0 offset from a .got section. But
+ // relocatable files produced by a complier or a linker
+ // might redefine this default value and we must use it
+ // for a calculation of the relocation result. When we
+ // generate EXE or DSO it's trivial. Generating a relocatable
+ // output is more difficult case because the linker does
+ // not calculate relocations in this mode and loses
+ // individual "gp" values used by each input object file.
+ // As a workaround we add the "gp" value to the relocation
+ // addend and save it back to the file.
+ Addend += Sec->getFile<ELFT>()->MipsGp0;
}
- }
+ if (RelTy::IsRela)
+ P->r_addend = Sym.getVA(Addend) - Section->getOutputSection()->Addr;
+ else if (Config->Relocatable)
+ Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset, Addend, &Sym});
+ }
}
}
@@ -481,14 +487,17 @@ static uint64_t getARMStaticBase(const Symbol &Sym) {
return OS->PtLoad->FirstSec->Addr;
}
-static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
- const Symbol &Sym, RelExpr Expr) {
+static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
+ uint64_t P, const Symbol &Sym, RelExpr Expr) {
switch (Expr) {
case R_INVALID:
return 0;
case R_ABS:
+ case R_RELAX_TLS_LD_TO_LE_ABS:
case R_RELAX_GOT_PC_NOPIC:
return Sym.getVA(A);
+ case R_ADDEND:
+ return A;
case R_ARM_SBREL:
return Sym.getVA(A) - getARMStaticBase(Sym);
case R_GOT:
@@ -505,7 +514,9 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
case R_GOT_FROM_END:
case R_RELAX_TLS_GD_TO_IE_END:
return Sym.getGotOffset() + A - InX::Got->getSize();
+ case R_TLSLD_GOT_OFF:
case R_GOT_OFF:
+ case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
return Sym.getGotOffset() + A;
case R_GOT_PAGE_PC:
case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
@@ -516,11 +527,12 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
case R_HINT:
case R_NONE:
case R_TLSDESC_CALL:
+ case R_TLSLD_HINT:
llvm_unreachable("cannot relocate hint relocs");
case R_MIPS_GOTREL:
- return Sym.getVA(A) - InX::MipsGot->getGp();
+ return Sym.getVA(A) - InX::MipsGot->getGp(File);
case R_MIPS_GOT_GP:
- return InX::MipsGot->getGp() + A;
+ return InX::MipsGot->getGp(File) + A;
case R_MIPS_GOT_GP_PC: {
// R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target
// is _gp_disp symbol. In that case we should use the following
@@ -529,7 +541,7 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
// microMIPS variants of these relocations use slightly different
// expressions: AHL + GP - P + 3 for %lo() and AHL + GP - P - 1 for %hi()
// to correctly handle less-sugnificant bit of the microMIPS symbol.
- uint64_t V = InX::MipsGot->getGp() + A - P;
+ uint64_t V = InX::MipsGot->getGp(File) + A - P;
if (Type == R_MIPS_LO16 || Type == R_MICROMIPS_LO16)
V += 4;
if (Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_HI16)
@@ -540,21 +552,23 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
// If relocation against MIPS local symbol requires GOT entry, this entry
// should be initialized by 'page address'. This address is high 16-bits
// of sum the symbol's value and the addend.
- return InX::MipsGot->getVA() + InX::MipsGot->getPageEntryOffset(Sym, A) -
- InX::MipsGot->getGp();
+ return InX::MipsGot->getVA() +
+ InX::MipsGot->getPageEntryOffset(File, Sym, A) -
+ InX::MipsGot->getGp(File);
case R_MIPS_GOT_OFF:
case R_MIPS_GOT_OFF32:
// In case of MIPS if a GOT relocation has non-zero addend this addend
// should be applied to the GOT entry content not to the GOT entry offset.
// That is why we use separate expression type.
- return InX::MipsGot->getVA() + InX::MipsGot->getSymEntryOffset(Sym, A) -
- InX::MipsGot->getGp();
+ return InX::MipsGot->getVA() +
+ InX::MipsGot->getSymEntryOffset(File, Sym, A) -
+ InX::MipsGot->getGp(File);
case R_MIPS_TLSGD:
- return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() +
- InX::MipsGot->getGlobalDynOffset(Sym) - InX::MipsGot->getGp();
+ return InX::MipsGot->getVA() + InX::MipsGot->getGlobalDynOffset(File, Sym) -
+ InX::MipsGot->getGp(File);
case R_MIPS_TLSLD:
- return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() +
- InX::MipsGot->getTlsIndexOff() - InX::MipsGot->getGp();
+ return InX::MipsGot->getVA() + InX::MipsGot->getTlsIndexOffset(File) -
+ InX::MipsGot->getGp(File);
case R_PAGE_PC:
case R_PLT_PAGE_PC: {
uint64_t Dest;
@@ -583,25 +597,27 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
case R_PLT:
return Sym.getPltVA() + A;
case R_PLT_PC:
- case R_PPC_PLT_OPD:
+ case R_PPC_CALL_PLT:
return Sym.getPltVA() + A - P;
- case R_PPC_OPD: {
+ case R_PPC_CALL: {
uint64_t SymVA = Sym.getVA(A);
// If we have an undefined weak symbol, we might get here with a symbol
// address of zero. That could overflow, but the code must be unreachable,
// so don't bother doing anything at all.
if (!SymVA)
return 0;
- if (Out::Opd) {
- // If this is a local call, and we currently have the address of a
- // function-descriptor, get the underlying code address instead.
- uint64_t OpdStart = Out::Opd->Addr;
- uint64_t OpdEnd = OpdStart + Out::Opd->Size;
- bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd;
- if (InOpd)
- SymVA = read64be(&Out::OpdBuf[SymVA - OpdStart]);
- }
- return SymVA - P;
+
+ // PPC64 V2 ABI describes two entry points to a function. The global entry
+ // point sets up the TOC base pointer. When calling a local function, the
+ // call should branch to the local entry point rather than the global entry
+ // point. Section 3.4.1 describes using the 3 most significant bits of the
+ // st_other field to find out how many instructions there are between the
+ // local and global entry point.
+ uint8_t StOther = (Sym.StOther >> 5) & 7;
+ if (StOther == 0 || StOther == 1)
+ return SymVA - P;
+
+ return SymVA - P + (1LL << StOther);
}
case R_PPC_TOC:
return getPPC64TocBase() + A;
@@ -618,25 +634,44 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
// statically to zero.
if (Sym.isTls() && Sym.isUndefWeak())
return 0;
- if (Target->TcbSize)
+
+ // For TLS variant 1 the TCB is a fixed size, whereas for TLS variant 2 the
+ // TCB is on unspecified size and content. Targets that implement variant 1
+ // should set TcbSize.
+ if (Target->TcbSize) {
+ // PPC64 V2 ABI has the thread pointer offset into the middle of the TLS
+ // storage area by TlsTpOffset for efficient addressing TCB and up to
+ // 4KB – 8 B of other thread library information (placed before the TCB).
+ // Subtracting this offset will get the address of the first TLS block.
+ if (Target->TlsTpOffset)
+ return Sym.getVA(A) - Target->TlsTpOffset;
+
+ // If thread pointer is not offset into the middle, the first thing in the
+ // TLS storage area is the TCB. Add the TcbSize to get the address of the
+ // first TLS block.
return Sym.getVA(A) + alignTo(Target->TcbSize, Out::TlsPhdr->p_align);
+ }
return Sym.getVA(A) - Out::TlsPhdr->p_memsz;
case R_RELAX_TLS_GD_TO_LE_NEG:
case R_NEG_TLS:
return Out::TlsPhdr->p_memsz - Sym.getVA(A);
case R_SIZE:
- return A; // Sym.getSize was already folded into the addend.
+ return Sym.getSize() + A;
case R_TLSDESC:
return InX::Got->getGlobalDynAddr(Sym) + A;
case R_TLSDESC_PAGE:
return getAArch64Page(InX::Got->getGlobalDynAddr(Sym) + A) -
getAArch64Page(P);
- case R_TLSGD:
+ case R_TLSGD_GOT:
+ return InX::Got->getGlobalDynOffset(Sym) + A;
+ case R_TLSGD_GOT_FROM_END:
return InX::Got->getGlobalDynOffset(Sym) + A - InX::Got->getSize();
case R_TLSGD_PC:
return InX::Got->getGlobalDynAddr(Sym) + A - P;
- case R_TLSLD:
+ case R_TLSLD_GOT_FROM_END:
return InX::Got->getTlsIndexOff() + A - InX::Got->getSize();
+ case R_TLSLD_GOT:
+ return InX::Got->getTlsIndexOff() + A;
case R_TLSLD_PC:
return InX::Got->getTlsIndexVA() + A - P;
}
@@ -656,6 +691,14 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
for (const RelTy &Rel : Rels) {
RelType Type = Rel.getType(Config->IsMips64EL);
+
+ // GCC 8.0 or earlier have a bug that they emit R_386_GOTPC relocations
+ // against _GLOBAL_OFFSET_TABLE_ for .debug_info. The bug has been fixed
+ // in 2017 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82630), but we
+ // need to keep this bug-compatible code for a while.
+ if (Config->EMachine == EM_386 && Type == R_386_GOTPC)
+ continue;
+
uint64_t Offset = getOffset(Rel.r_offset);
uint8_t *BufLoc = Buf + Offset;
int64_t Addend = getAddend<ELFT>(Rel);
@@ -666,17 +709,27 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc);
if (Expr == R_NONE)
continue;
+
if (Expr != R_ABS) {
- // GCC 8.0 or earlier have a bug that it emits R_386_GOTPC relocations
- // against _GLOBAL_OFFSET_TABLE for .debug_info. The bug seems to have
- // been fixed in 2017: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82630,
- // but we need to keep this bug-compatible code for a while.
- if (Config->EMachine == EM_386 && Type == R_386_GOTPC)
- continue;
+ std::string Msg = getLocation<ELFT>(Offset) +
+ ": has non-ABS relocation " + toString(Type) +
+ " against symbol '" + toString(Sym) + "'";
+ if (Expr != R_PC) {
+ error(Msg);
+ return;
+ }
- error(getLocation<ELFT>(Offset) + ": has non-ABS relocation " +
- toString(Type) + " against symbol '" + toString(Sym) + "'");
- return;
+ // If the control reaches here, we found a PC-relative relocation in a
+ // non-ALLOC section. Since non-ALLOC section is not loaded into memory
+ // at runtime, the notion of PC-relative doesn't make sense here. So,
+ // this is a usage error. However, GNU linkers historically accept such
+ // relocations without any errors and relocate them as if they were at
+ // address 0. For bug-compatibilty, we accept them with warnings. We
+ // know Steel Bank Common Lisp as of 2018 have this bug.
+ warn(Msg);
+ Target->relocateOne(BufLoc, Type,
+ SignExtend64<Bits>(Sym.getVA(Addend - Offset)));
+ continue;
}
if (Sym.isTls() && !Out::TlsPhdr)
@@ -705,6 +758,9 @@ static void relocateNonAllocForRelocatable(InputSection *Sec, uint8_t *Buf) {
template <class ELFT>
void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) {
+ if (Flags & SHF_EXECINSTR)
+ adjustSplitStackFunctionPrologues<ELFT>(Buf, BufEnd);
+
if (Flags & SHF_ALLOC) {
relocateAlloc(Buf, BufEnd);
return;
@@ -724,14 +780,17 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
const unsigned Bits = Config->Wordsize * 8;
for (const Relocation &Rel : Relocations) {
- uint64_t Offset = getOffset(Rel.Offset);
+ uint64_t Offset = Rel.Offset;
+ if (auto *Sec = dyn_cast<InputSection>(this))
+ Offset += Sec->OutSecOff;
uint8_t *BufLoc = Buf + Offset;
RelType Type = Rel.Type;
uint64_t AddrLoc = getOutputSection()->Addr + Offset;
RelExpr Expr = Rel.Expr;
uint64_t TargetVA = SignExtend64(
- getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits);
+ getRelocTargetVA(File, Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr),
+ Bits);
switch (Expr) {
case R_RELAX_GOT_PC:
@@ -742,6 +801,7 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
Target->relaxTlsIeToLe(BufLoc, Type, TargetVA);
break;
case R_RELAX_TLS_LD_TO_LE:
+ case R_RELAX_TLS_LD_TO_LE_ABS:
Target->relaxTlsLdToLe(BufLoc, Type, TargetVA);
break;
case R_RELAX_TLS_GD_TO_LE:
@@ -750,15 +810,28 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
break;
case R_RELAX_TLS_GD_TO_IE:
case R_RELAX_TLS_GD_TO_IE_ABS:
+ case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
case R_RELAX_TLS_GD_TO_IE_END:
Target->relaxTlsGdToIe(BufLoc, Type, TargetVA);
break;
- case R_PPC_PLT_OPD:
+ case R_PPC_CALL:
+ // If this is a call to __tls_get_addr, it may be part of a TLS
+ // sequence that has been relaxed and turned into a nop. In this
+ // case, we don't want to handle it as a call.
+ if (read32(BufLoc) == 0x60000000) // nop
+ break;
+
// Patch a nop (0x60000000) to a ld.
- if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000)
- write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1)
- LLVM_FALLTHROUGH;
+ if (Rel.Sym->NeedsTocRestore) {
+ if (BufLoc + 8 > BufEnd || read32(BufLoc + 4) != 0x60000000) {
+ error(getErrorLocation(BufLoc) + "call lacks nop, can't restore toc");
+ break;
+ }
+ write32(BufLoc + 4, 0xe8410018); // ld %r2, 24(%r1)
+ }
+ Target->relocateOne(BufLoc, Type, TargetVA);
+ break;
default:
Target->relocateOne(BufLoc, Type, TargetVA);
break;
@@ -766,6 +839,101 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
}
}
+// For each function-defining prologue, find any calls to __morestack,
+// and replace them with calls to __morestack_non_split.
+static void switchMorestackCallsToMorestackNonSplit(
+ DenseSet<Defined *> &Prologues, std::vector<Relocation *> &MorestackCalls) {
+
+ // If the target adjusted a function's prologue, all calls to
+ // __morestack inside that function should be switched to
+ // __morestack_non_split.
+ Symbol *MoreStackNonSplit = Symtab->find("__morestack_non_split");
+
+ // Sort both collections to compare addresses efficiently.
+ llvm::sort(MorestackCalls.begin(), MorestackCalls.end(),
+ [](const Relocation *L, const Relocation *R) {
+ return L->Offset < R->Offset;
+ });
+ std::vector<Defined *> Functions(Prologues.begin(), Prologues.end());
+ llvm::sort(
+ Functions.begin(), Functions.end(),
+ [](const Defined *L, const Defined *R) { return L->Value < R->Value; });
+
+ auto It = MorestackCalls.begin();
+ for (Defined *F : Functions) {
+ // Find the first call to __morestack within the function.
+ while (It != MorestackCalls.end() && (*It)->Offset < F->Value)
+ ++It;
+ // Adjust all calls inside the function.
+ while (It != MorestackCalls.end() && (*It)->Offset < F->Value + F->Size) {
+ (*It)->Sym = MoreStackNonSplit;
+ ++It;
+ }
+ }
+}
+
+static bool enclosingPrologueAdjusted(uint64_t Offset,
+ const DenseSet<Defined *> &Prologues) {
+ for (Defined *F : Prologues)
+ if (F->Value <= Offset && Offset < F->Value + F->Size)
+ return true;
+ return false;
+}
+
+// If a function compiled for split stack calls a function not
+// compiled for split stack, then the caller needs its prologue
+// adjusted to ensure that the called function will have enough stack
+// available. Find those functions, and adjust their prologues.
+template <class ELFT>
+void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf,
+ uint8_t *End) {
+ if (!getFile<ELFT>()->SplitStack)
+ return;
+ DenseSet<Defined *> AdjustedPrologues;
+ std::vector<Relocation *> MorestackCalls;
+
+ for (Relocation &Rel : Relocations) {
+ // Local symbols can't possibly be cross-calls, and should have been
+ // resolved long before this line.
+ if (Rel.Sym->isLocal())
+ continue;
+
+ Defined *D = dyn_cast<Defined>(Rel.Sym);
+ // A reference to an undefined symbol was an error, and should not
+ // have gotten to this point.
+ if (!D)
+ continue;
+
+ // Ignore calls into the split-stack api.
+ if (D->getName().startswith("__morestack")) {
+ if (D->getName().equals("__morestack"))
+ MorestackCalls.push_back(&Rel);
+ continue;
+ }
+
+ // A relocation to non-function isn't relevant. Sometimes
+ // __morestack is not marked as a function, so this check comes
+ // after the name check.
+ if (D->Type != STT_FUNC)
+ continue;
+
+ if (enclosingPrologueAdjusted(Rel.Offset, AdjustedPrologues))
+ continue;
+
+ if (Defined *F = getEnclosingFunction<ELFT>(Rel.Offset)) {
+ if (Target->adjustPrologueForCrossSplitStack(Buf + F->Value, End)) {
+ AdjustedPrologues.insert(F);
+ continue;
+ }
+ }
+ if (!getFile<ELFT>()->SomeNoSplitStack)
+ error("function call at " + getErrorLocation(Buf + Rel.Offset) +
+ "crosses a split-stack boundary, but unable " +
+ "to adjust the enclosing function's prologue");
+ }
+ switchMorestackCallsToMorestackNonSplit(AdjustedPrologues, MorestackCalls);
+}
+
template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {
if (Type == SHT_NOBITS)
return;
@@ -837,10 +1005,6 @@ static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels,
// .eh_frame is a sequence of CIE or FDE records.
// This function splits an input section into records and returns them.
template <class ELFT> void EhInputSection::split() {
- // Early exit if already split.
- if (!Pieces.empty())
- return;
-
if (AreRelocsRela)
split<ELFT>(relas<ELFT>());
else
@@ -905,8 +1069,7 @@ void MergeInputSection::splitNonStrings(ArrayRef<uint8_t> Data,
bool IsAlloc = Flags & SHF_ALLOC;
for (size_t I = 0; I != Size; I += EntSize)
- Pieces.emplace_back(I, xxHash64(toStringRef(Data.slice(I, EntSize))),
- !IsAlloc);
+ Pieces.emplace_back(I, xxHash64(Data.slice(I, EntSize)), !IsAlloc);
}
template <class ELFT>
@@ -935,15 +1098,9 @@ void MergeInputSection::splitIntoPieces() {
else
splitNonStrings(Data, Entsize);
- if (Config->GcSections && (Flags & SHF_ALLOC))
- for (uint64_t Off : LiveOffsets)
- getSectionPiece(Off)->Live = true;
-}
-
-// Do binary search to get a section piece at a given input offset.
-SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) {
- auto *This = static_cast<const MergeInputSection *>(this);
- return const_cast<SectionPiece *>(This->getSectionPiece(Offset));
+ OffsetMap.reserve(Pieces.size());
+ for (size_t I = 0, E = Pieces.size(); I != E; ++I)
+ OffsetMap[Pieces[I].InputOff] = I;
}
template <class It, class T, class Compare>
@@ -959,32 +1116,34 @@ static It fastUpperBound(It First, It Last, const T &Value, Compare Comp) {
return Comp(Value, *First) ? First : First + 1;
}
-const SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) const {
- if (Data.size() <= Offset)
- fatal(toString(this) + ": entry is past the end of the section");
+// Do binary search to get a section piece at a given input offset.
+static SectionPiece *findSectionPiece(MergeInputSection *Sec, uint64_t Offset) {
+ if (Sec->Data.size() <= Offset)
+ fatal(toString(Sec) + ": entry is past the end of the section");
// Find the element this offset points to.
auto I = fastUpperBound(
- Pieces.begin(), Pieces.end(), Offset,
+ Sec->Pieces.begin(), Sec->Pieces.end(), Offset,
[](const uint64_t &A, const SectionPiece &B) { return A < B.InputOff; });
--I;
return &*I;
}
+SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) {
+ // Find a piece starting at a given offset.
+ auto It = OffsetMap.find(Offset);
+ if (It != OffsetMap.end())
+ return &Pieces[It->second];
+
+ // If Offset is not at beginning of a section piece, it is not in the map.
+ // In that case we need to search from the original section piece vector.
+ return findSectionPiece(this, Offset);
+}
+
// Returns the offset in an output section for a given input offset.
// Because contents of a mergeable section is not contiguous in output,
// it is not just an addition to a base output offset.
-uint64_t MergeInputSection::getOffset(uint64_t Offset) const {
- if (!Live)
- return 0;
-
- // Initialize OffsetMap lazily.
- llvm::call_once(InitOffsetMap, [&] {
- OffsetMap.reserve(Pieces.size());
- for (size_t I = 0; I < Pieces.size(); ++I)
- OffsetMap[Pieces[I].InputOff] = I;
- });
-
+uint64_t MergeInputSection::getParentOffset(uint64_t Offset) const {
// Find a string starting at a given offset.
auto It = OffsetMap.find(Offset);
if (It != OffsetMap.end())
@@ -992,10 +1151,8 @@ uint64_t MergeInputSection::getOffset(uint64_t Offset) const {
// If Offset is not at beginning of a section piece, it is not in the map.
// In that case we need to search from the original section piece vector.
- const SectionPiece &Piece = *getSectionPiece(Offset);
- if (!Piece.Live)
- return 0;
-
+ const SectionPiece &Piece =
+ *findSectionPiece(const_cast<MergeInputSection *>(this), Offset);
uint64_t Addend = Offset - Piece.InputOff;
return Piece.OutputOff + Addend;
}
diff --git a/contrib/llvm/tools/lld/ELF/InputSection.h b/contrib/llvm/tools/lld/ELF/InputSection.h
index 8c114ae71948..4db01e035e32 100644
--- a/contrib/llvm/tools/lld/ELF/InputSection.h
+++ b/contrib/llvm/tools/lld/ELF/InputSection.h
@@ -18,8 +18,6 @@
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/Threading.h"
-#include <mutex>
namespace lld {
namespace elf {
@@ -63,6 +61,9 @@ public:
unsigned Bss : 1;
+ // Set for sections that should not be folded by ICF.
+ unsigned KeepUnique : 1;
+
// These corresponds to the fields in Elf_Shdr.
uint32_t Alignment;
uint64_t Flags;
@@ -80,13 +81,15 @@ public:
// section.
uint64_t getOffset(uint64_t Offset) const;
+ uint64_t getVA(uint64_t Offset = 0) const;
+
protected:
SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags,
uint64_t Entsize, uint64_t Alignment, uint32_t Type,
uint32_t Info, uint32_t Link)
: Name(Name), Repl(this), SectionKind(SectionKind), Live(false),
- Bss(false), Alignment(Alignment), Flags(Flags), Entsize(Entsize),
- Type(Type), Link(Link), Info(Info) {}
+ Bss(false), KeepUnique(false), Alignment(Alignment), Flags(Flags),
+ Entsize(Entsize), Type(Type), Link(Link), Info(Info) {}
};
// This corresponds to a section of an input file.
@@ -103,7 +106,7 @@ public:
static bool classof(const SectionBase *S) { return S->kind() != Output; }
- // The file which contains this section. It's dynamic type is always
+ // The file which contains this section. Its dynamic type is always
// ObjFile<ELFT>, but in order to avoid ELFT, we use InputFile as
// its static type.
InputFile *File;
@@ -161,10 +164,15 @@ public:
InputSection *getLinkOrderDep() const;
+ // Get the function symbol that encloses this offset from within the
+ // section.
+ template <class ELFT>
+ Defined *getEnclosingFunction(uint64_t Offset);
+
// Compilers emit zlib-compressed debug sections if the -gz option
// is given. This function checks if this section is compressed, and
// if so, decompress in memory.
- void maybeUncompress();
+ void maybeDecompress();
// Returns a source location string. Used to construct an error message.
template <class ELFT> std::string getLocation(uint64_t Offset);
@@ -182,6 +190,15 @@ public:
// This vector contains such "cooked" relocations.
std::vector<Relocation> Relocations;
+ // A function compiled with -fsplit-stack calling a function
+ // compiled without -fsplit-stack needs its prologue adjusted. Find
+ // such functions and adjust their prologues. This is very similar
+ // to relocation. See https://gcc.gnu.org/wiki/SplitStacks for more
+ // information.
+ template <typename ELFT>
+ void adjustSplitStackFunctionPrologues(uint8_t *Buf, uint8_t *End);
+
+
template <typename T> llvm::ArrayRef<T> getDataAs() const {
size_t S = Data.size();
assert(S % sizeof(T) == 0);
@@ -189,9 +206,9 @@ public:
}
private:
- // A pointer that owns uncompressed data if a section is compressed by zlib.
+ // A pointer that owns decompressed data if a section is compressed by zlib.
// Since the feature is not used often, this is usually a nullptr.
- std::unique_ptr<char[]> UncompressBuf;
+ std::unique_ptr<char[]> DecompressBuf;
};
// SectionPiece represents a piece of splittable section contents.
@@ -200,7 +217,7 @@ private:
// be found by looking at the next one).
struct SectionPiece {
SectionPiece(size_t Off, uint32_t Hash, bool Live)
- : InputOff(Off), Hash(Hash), OutputOff(-1),
+ : InputOff(Off), Hash(Hash), OutputOff(0),
Live(Live || !Config->GcSections) {}
uint32_t InputOff;
@@ -223,19 +240,14 @@ public:
static bool classof(const SectionBase *S) { return S->kind() == Merge; }
void splitIntoPieces();
- // Mark the piece at a given offset live. Used by GC.
- void markLiveAt(uint64_t Offset) {
- if (this->Flags & llvm::ELF::SHF_ALLOC)
- LiveOffsets.insert(Offset);
- }
-
- // Translate an offset in the input section to an offset
- // in the output section.
- uint64_t getOffset(uint64_t Offset) const;
+ // Translate an offset in the input section to an offset in the parent
+ // MergeSyntheticSection.
+ uint64_t getParentOffset(uint64_t Offset) const;
// Splittable sections are handled as a sequence of data
// rather than a single large blob of data.
std::vector<SectionPiece> Pieces;
+ llvm::DenseMap<uint32_t, uint32_t> OffsetMap;
// Returns I'th piece's data. This function is very hot when
// string merging is enabled, so we want to inline.
@@ -249,18 +261,15 @@ public:
// Returns the SectionPiece at a given input section offset.
SectionPiece *getSectionPiece(uint64_t Offset);
- const SectionPiece *getSectionPiece(uint64_t Offset) const;
+ const SectionPiece *getSectionPiece(uint64_t Offset) const {
+ return const_cast<MergeInputSection *>(this)->getSectionPiece(Offset);
+ }
SyntheticSection *getParent() const;
private:
void splitStrings(ArrayRef<uint8_t> A, size_t Size);
void splitNonStrings(ArrayRef<uint8_t> A, size_t Size);
-
- mutable llvm::DenseMap<uint32_t, uint32_t> OffsetMap;
- mutable llvm::once_flag InitOffsetMap;
-
- llvm::DenseSet<uint64_t> LiveOffsets;
};
struct EhSectionPiece {
@@ -310,6 +319,8 @@ public:
// beginning of the output section.
template <class ELFT> void writeTo(uint8_t *Buf);
+ uint64_t getOffset(uint64_t Offset) const { return OutSecOff + Offset; }
+
OutputSection *getParent() const;
// This variable has two usages. Initially, it represents an index in the
@@ -320,7 +331,7 @@ public:
static bool classof(const SectionBase *S);
- InputSectionBase *getRelocatedSection();
+ InputSectionBase *getRelocatedSection() const;
template <class ELFT, class RelTy>
void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
@@ -342,10 +353,6 @@ private:
// The list of all input sections.
extern std::vector<InputSectionBase *> InputSections;
-
-// Builds section order for handling --symbol-ordering-file.
-llvm::DenseMap<SectionBase *, int> buildSectionOrder();
-
} // namespace elf
std::string toString(const elf::InputSectionBase *);
diff --git a/contrib/llvm/tools/lld/ELF/LTO.cpp b/contrib/llvm/tools/lld/ELF/LTO.cpp
index bfd85288d186..ef58932e86cc 100644
--- a/contrib/llvm/tools/lld/ELF/LTO.cpp
+++ b/contrib/llvm/tools/lld/ELF/LTO.cpp
@@ -20,6 +20,8 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/LTO/Caching.h"
#include "llvm/LTO/Config.h"
@@ -29,7 +31,6 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstddef>
#include <memory>
@@ -44,70 +45,92 @@ using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
-// This is for use when debugging LTO.
-static void saveBuffer(StringRef Buffer, const Twine &Path) {
+// Creates an empty file to store a list of object files for final
+// linking of distributed ThinLTO.
+static std::unique_ptr<raw_fd_ostream> openFile(StringRef File) {
std::error_code EC;
- raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
- if (EC)
- error("cannot create " + Path + ": " + EC.message());
- OS << Buffer;
-}
-
-static void diagnosticHandler(const DiagnosticInfo &DI) {
- SmallString<128> ErrStorage;
- raw_svector_ostream OS(ErrStorage);
- DiagnosticPrinterRawOStream DP(OS);
- DI.print(DP);
- warn(ErrStorage);
+ auto Ret =
+ llvm::make_unique<raw_fd_ostream>(File, EC, sys::fs::OpenFlags::F_None);
+ if (EC) {
+ error("cannot open " + File + ": " + EC.message());
+ return nullptr;
+ }
+ return Ret;
}
-static void checkError(Error E) {
- handleAllErrors(std::move(E),
- [&](ErrorInfoBase &EIB) { error(EIB.message()); });
+static std::string getThinLTOOutputFile(StringRef ModulePath) {
+ return lto::getThinLTOOutputFile(ModulePath,
+ Config->ThinLTOPrefixReplace.first,
+ Config->ThinLTOPrefixReplace.second);
}
-static std::unique_ptr<lto::LTO> createLTO() {
- lto::Config Conf;
+static lto::Config createConfig() {
+ lto::Config C;
// LLD supports the new relocations.
- Conf.Options = InitTargetOptionsFromCodeGenFlags();
- Conf.Options.RelaxELFRelocations = true;
+ C.Options = InitTargetOptionsFromCodeGenFlags();
+ C.Options.RelaxELFRelocations = true;
// Always emit a section per function/datum with LTO.
- Conf.Options.FunctionSections = true;
- Conf.Options.DataSections = true;
+ C.Options.FunctionSections = true;
+ C.Options.DataSections = true;
if (Config->Relocatable)
- Conf.RelocModel = None;
+ C.RelocModel = None;
else if (Config->Pic)
- Conf.RelocModel = Reloc::PIC_;
+ C.RelocModel = Reloc::PIC_;
else
- Conf.RelocModel = Reloc::Static;
- Conf.CodeModel = GetCodeModelFromCMModel();
- Conf.DisableVerify = Config->DisableVerify;
- Conf.DiagHandler = diagnosticHandler;
- Conf.OptLevel = Config->LTOO;
+ C.RelocModel = Reloc::Static;
+
+ C.CodeModel = GetCodeModelFromCMModel();
+ C.DisableVerify = Config->DisableVerify;
+ C.DiagHandler = diagnosticHandler;
+ C.OptLevel = Config->LTOO;
+ C.CPU = GetCPUStr();
// Set up a custom pipeline if we've been asked to.
- Conf.OptPipeline = Config->LTONewPmPasses;
- Conf.AAPipeline = Config->LTOAAPipeline;
+ C.OptPipeline = Config->LTONewPmPasses;
+ C.AAPipeline = Config->LTOAAPipeline;
// Set up optimization remarks if we've been asked to.
- Conf.RemarksFilename = Config->OptRemarksFilename;
- Conf.RemarksWithHotness = Config->OptRemarksWithHotness;
+ C.RemarksFilename = Config->OptRemarksFilename;
+ C.RemarksWithHotness = Config->OptRemarksWithHotness;
+
+ C.SampleProfile = Config->LTOSampleProfile;
+ C.UseNewPM = Config->LTONewPassManager;
+ C.DebugPassManager = Config->LTODebugPassManager;
+ C.DwoDir = Config->DwoDir;
if (Config->SaveTemps)
- checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
- /*UseInputModulePath*/ true));
+ checkError(C.addSaveTemps(Config->OutputFile.str() + ".",
+ /*UseInputModulePath*/ true));
+ return C;
+}
+BitcodeCompiler::BitcodeCompiler() {
+ // Initialize LTOObj.
lto::ThinBackend Backend;
- if (Config->ThinLTOJobs != -1u)
+
+ if (Config->ThinLTOIndexOnly) {
+ StringRef Path = Config->ThinLTOIndexOnlyArg;
+ if (!Path.empty())
+ IndexFile = openFile(Path);
+
+ auto OnIndexWrite = [&](const std::string &Identifier) {
+ ObjectToIndexFileState[Identifier] = true;
+ };
+
+ Backend = lto::createWriteIndexesThinBackend(
+ Config->ThinLTOPrefixReplace.first, Config->ThinLTOPrefixReplace.second,
+ Config->ThinLTOEmitImportsFiles, IndexFile.get(), OnIndexWrite);
+ } else if (Config->ThinLTOJobs != -1U) {
Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
- return llvm::make_unique<lto::LTO>(std::move(Conf), Backend,
- Config->LTOPartitions);
-}
+ }
-BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {
+ LTOObj = llvm::make_unique<lto::LTO>(createConfig(), Backend,
+ Config->LTOPartitions);
+
+ // Initialize UsedStartStop.
for (Symbol *Sym : Symtab->getSymbols()) {
StringRef Name = Sym->getName();
for (StringRef Prefix : {"__start_", "__stop_"})
@@ -125,20 +148,20 @@ static void undefine(Symbol *S) {
void BitcodeCompiler::add(BitcodeFile &F) {
lto::InputFile &Obj = *F.Obj;
- unsigned SymNum = 0;
- std::vector<Symbol *> Syms = F.getSymbols();
- std::vector<lto::SymbolResolution> Resols(Syms.size());
+ bool IsExec = !Config->Shared && !Config->Relocatable;
- DenseSet<StringRef> ScriptSymbols;
- for (BaseCommand *Base : Script->SectionCommands)
- if (auto *Cmd = dyn_cast<SymbolAssignment>(Base))
- ScriptSymbols.insert(Cmd->Name);
+ if (Config->ThinLTOIndexOnly)
+ ObjectToIndexFileState.insert({Obj.getName(), false});
+
+ ArrayRef<Symbol *> Syms = F.getSymbols();
+ ArrayRef<lto::InputFile::Symbol> ObjSyms = Obj.symbols();
+ std::vector<lto::SymbolResolution> Resols(Syms.size());
// Provide a resolution to the LTO API for each symbol.
- for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
- Symbol *Sym = Syms[SymNum];
- lto::SymbolResolution &R = Resols[SymNum];
- ++SymNum;
+ for (size_t I = 0, E = Syms.size(); I != E; ++I) {
+ Symbol *Sym = Syms[I];
+ const lto::InputFile::Symbol &ObjSym = ObjSyms[I];
+ lto::SymbolResolution &R = Resols[I];
// Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
// reports two symbols for module ASM defined. Without this check, lld
@@ -156,25 +179,46 @@ void BitcodeCompiler::add(BitcodeFile &F) {
R.VisibleToRegularObj = Config->Relocatable || Sym->IsUsedInRegularObj ||
(R.Prevailing && Sym->includeInDynsym()) ||
UsedStartStop.count(ObjSym.getSectionName());
+ const auto *DR = dyn_cast<Defined>(Sym);
+ R.FinalDefinitionInLinkageUnit =
+ (IsExec || Sym->Visibility != STV_DEFAULT) && DR &&
+ // Skip absolute symbols from ELF objects, otherwise PC-rel relocations
+ // will be generated by for them, triggering linker errors.
+ // Symbol section is always null for bitcode symbols, hence the check
+ // for isElf(). Skip linker script defined symbols as well: they have
+ // no File defined.
+ !(DR->Section == nullptr && (!Sym->File || Sym->File->isElf()));
+
if (R.Prevailing)
undefine(Sym);
- // We tell LTO to not apply interprocedural optimization for following
- // symbols because otherwise LTO would inline them while their values are
- // still not final:
- // 1) Aliased (with --defsym) or wrapped (with --wrap) symbols.
- // 2) Symbols redefined in linker script.
- R.LinkerRedefined = !Sym->CanInline || ScriptSymbols.count(Sym->getName());
+ // We tell LTO to not apply interprocedural optimization for wrapped
+ // (with --wrap) symbols because otherwise LTO would inline them while
+ // their values are still not final.
+ R.LinkerRedefined = !Sym->CanInline;
}
checkError(LTOObj->add(std::move(F.Obj), Resols));
}
+static void createEmptyIndex(StringRef ModulePath) {
+ std::string Path = replaceThinLTOSuffix(getThinLTOOutputFile(ModulePath));
+ std::unique_ptr<raw_fd_ostream> OS = openFile(Path + ".thinlto.bc");
+ if (!OS)
+ return;
+
+ ModuleSummaryIndex M(/*HaveGVs*/ false);
+ M.setSkipModuleByDistributedBackend();
+ WriteIndexToFile(M, *OS);
+
+ if (Config->ThinLTOEmitImportsFiles)
+ openFile(Path + ".imports");
+}
+
// Merge all the bitcode files we have seen, codegen the result
// and return the resulting ObjectFile(s).
std::vector<InputFile *> BitcodeCompiler::compile() {
- std::vector<InputFile *> Ret;
unsigned MaxTasks = LTOObj->getMaxTasks();
- Buff.resize(MaxTasks);
+ Buf.resize(MaxTasks);
Files.resize(MaxTasks);
// The --thinlto-cache-dir option specifies the path to a directory in which
@@ -184,35 +228,67 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
if (!Config->ThinLTOCacheDir.empty())
Cache = check(
lto::localCache(Config->ThinLTOCacheDir,
- [&](size_t Task, std::unique_ptr<MemoryBuffer> MB,
- StringRef Path) { Files[Task] = std::move(MB); }));
+ [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+ Files[Task] = std::move(MB);
+ }));
checkError(LTOObj->run(
[&](size_t Task) {
return llvm::make_unique<lto::NativeObjectStream>(
- llvm::make_unique<raw_svector_ostream>(Buff[Task]));
+ llvm::make_unique<raw_svector_ostream>(Buf[Task]));
},
Cache));
+ // Emit empty index files for non-indexed files
+ if (Config->ThinLTOIndexOnly) {
+ for (auto &Identifier : ObjectToIndexFileState)
+ if (!Identifier.getValue()) {
+ std::string Path = getThinLTOOutputFile(Identifier.getKey());
+ openFile(Path + ".thinlto.bc");
+
+ if (Config->ThinLTOEmitImportsFiles)
+ openFile(Path + ".imports");
+ }
+ }
+
+ // If LazyObjFile has not been added to link, emit empty index files.
+ // This is needed because this is what GNU gold plugin does and we have a
+ // distributed build system that depends on that behavior.
+ if (Config->ThinLTOIndexOnly) {
+ for (LazyObjFile *F : LazyObjFiles)
+ if (!F->AddedToLink && isBitcode(F->MB))
+ createEmptyIndex(F->getName());
+
+ if (!Config->LTOObjPath.empty())
+ saveBuffer(Buf[0], Config->LTOObjPath);
+
+ // ThinLTO with index only option is required to generate only the index
+ // files. After that, we exit from linker and ThinLTO backend runs in a
+ // distributed environment.
+ if (IndexFile)
+ IndexFile->close();
+ return {};
+ }
+
if (!Config->ThinLTOCacheDir.empty())
pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy);
+ std::vector<InputFile *> Ret;
for (unsigned I = 0; I != MaxTasks; ++I) {
- if (Buff[I].empty())
+ if (Buf[I].empty())
continue;
if (Config->SaveTemps) {
if (I == 0)
- saveBuffer(Buff[I], Config->OutputFile + ".lto.o");
+ saveBuffer(Buf[I], Config->OutputFile + ".lto.o");
else
- saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.o");
+ saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.o");
}
- InputFile *Obj = createObjectFile(MemoryBufferRef(Buff[I], "lto.tmp"));
+ InputFile *Obj = createObjectFile(MemoryBufferRef(Buf[I], "lto.tmp"));
Ret.push_back(Obj);
}
for (std::unique_ptr<MemoryBuffer> &File : Files)
if (File)
Ret.push_back(createObjectFile(*File));
-
return Ret;
}
diff --git a/contrib/llvm/tools/lld/ELF/LTO.h b/contrib/llvm/tools/lld/ELF/LTO.h
index 223af507a97d..8803078eb1df 100644
--- a/contrib/llvm/tools/lld/ELF/LTO.h
+++ b/contrib/llvm/tools/lld/ELF/LTO.h
@@ -24,6 +24,7 @@
#include "lld/Common/LLVM.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
#include <memory>
#include <vector>
@@ -38,6 +39,7 @@ namespace elf {
class BitcodeFile;
class InputFile;
+class LazyObjFile;
class BitcodeCompiler {
public:
@@ -49,9 +51,11 @@ public:
private:
std::unique_ptr<llvm::lto::LTO> LTOObj;
- std::vector<SmallString<0>> Buff;
+ std::vector<SmallString<0>> Buf;
std::vector<std::unique_ptr<MemoryBuffer>> Files;
llvm::DenseSet<StringRef> UsedStartStop;
+ std::unique_ptr<llvm::raw_fd_ostream> IndexFile;
+ llvm::StringMap<bool> ObjectToIndexFileState;
};
} // namespace elf
} // namespace lld
diff --git a/contrib/llvm/tools/lld/ELF/LinkerScript.cpp b/contrib/llvm/tools/lld/ELF/LinkerScript.cpp
index 23c3a11a9d1d..abdd899da487 100644
--- a/contrib/llvm/tools/lld/ELF/LinkerScript.cpp
+++ b/contrib/llvm/tools/lld/ELF/LinkerScript.cpp
@@ -15,13 +15,13 @@
#include "Config.h"
#include "InputSection.h"
#include "OutputSections.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "Writer.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
@@ -74,7 +74,7 @@ uint64_t ExprValue::getSectionOffset() const {
// If the alignment is trivial, we don't have to compute the full
// value to know the offset. This allows this function to succeed in
// cases where the output section is not yet known.
- if (Alignment == 1)
+ if (Alignment == 1 && (!Sec || !Sec->getOutputSection()))
return Val;
return getValue() - getSecAddr();
}
@@ -102,28 +102,67 @@ OutputSection *LinkerScript::getOrCreateOutputSection(StringRef Name) {
return CmdRef;
}
+// Expands the memory region by the specified size.
+static void expandMemoryRegion(MemoryRegion *MemRegion, uint64_t Size,
+ StringRef RegionName, StringRef SecName) {
+ MemRegion->CurPos += Size;
+ uint64_t NewSize = MemRegion->CurPos - MemRegion->Origin;
+ if (NewSize > MemRegion->Length)
+ error("section '" + SecName + "' will not fit in region '" + RegionName +
+ "': overflowed by " + Twine(NewSize - MemRegion->Length) + " bytes");
+}
+
+void LinkerScript::expandMemoryRegions(uint64_t Size) {
+ if (Ctx->MemRegion)
+ expandMemoryRegion(Ctx->MemRegion, Size, Ctx->MemRegion->Name,
+ Ctx->OutSec->Name);
+ if (Ctx->LMARegion)
+ expandMemoryRegion(Ctx->LMARegion, Size, Ctx->LMARegion->Name,
+ Ctx->OutSec->Name);
+}
+
+void LinkerScript::expandOutputSection(uint64_t Size) {
+ Ctx->OutSec->Size += Size;
+ expandMemoryRegions(Size);
+}
+
void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) {
uint64_t Val = E().getValue();
if (Val < Dot && InSec)
error(Loc + ": unable to move location counter backward for: " +
Ctx->OutSec->Name);
- Dot = Val;
// Update to location counter means update to section size.
if (InSec)
- Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr;
+ expandOutputSection(Val - Dot);
+ else
+ expandMemoryRegions(Val - Dot);
+
+ Dot = Val;
}
-// This function is called from processSectionCommands,
-// while we are fixing the output section layout.
-void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
+// Used for handling linker symbol assignments, for both finalizing
+// their values and doing early declarations. Returns true if symbol
+// should be defined from linker script.
+static bool shouldDefineSym(SymbolAssignment *Cmd) {
if (Cmd->Name == ".")
- return;
+ return false;
+
+ if (!Cmd->Provide)
+ return true;
- // If a symbol was in PROVIDE(), we need to define it only when
- // it is a referenced undefined symbol.
+ // If a symbol was in PROVIDE(), we need to define it only
+ // when it is a referenced undefined symbol.
Symbol *B = Symtab->find(Cmd->Name);
- if (Cmd->Provide && (!B || B->isDefined()))
+ if (B && !B->isDefined())
+ return true;
+ return false;
+}
+
+// This function is called from processSectionCommands,
+// while we are fixing the output section layout.
+void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
+ if (!shouldDefineSym(Cmd))
return;
// Define a symbol.
@@ -153,6 +192,76 @@ void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
Cmd->Sym = cast<Defined>(Sym);
}
+// This function is called from LinkerScript::declareSymbols.
+// It creates a placeholder symbol if needed.
+static void declareSymbol(SymbolAssignment *Cmd) {
+ if (!shouldDefineSym(Cmd))
+ return;
+
+ // We can't calculate final value right now.
+ Symbol *Sym;
+ uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
+ std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, /*Type*/ 0, Visibility,
+ /*CanOmitFromDynSym*/ false,
+ /*File*/ nullptr);
+ replaceSymbol<Defined>(Sym, nullptr, Cmd->Name, STB_GLOBAL, Visibility,
+ STT_NOTYPE, 0, 0, nullptr);
+ Cmd->Sym = cast<Defined>(Sym);
+ Cmd->Provide = false;
+}
+
+// This method is used to handle INSERT AFTER statement. Here we rebuild
+// the list of script commands to mix sections inserted into.
+void LinkerScript::processInsertCommands() {
+ std::vector<BaseCommand *> V;
+ auto Insert = [&](std::vector<BaseCommand *> &From) {
+ V.insert(V.end(), From.begin(), From.end());
+ From.clear();
+ };
+
+ for (BaseCommand *Base : SectionCommands) {
+ if (auto *OS = dyn_cast<OutputSection>(Base)) {
+ Insert(InsertBeforeCommands[OS->Name]);
+ V.push_back(Base);
+ Insert(InsertAfterCommands[OS->Name]);
+ continue;
+ }
+ V.push_back(Base);
+ }
+
+ for (auto &Cmds : {InsertBeforeCommands, InsertAfterCommands})
+ for (const std::pair<StringRef, std::vector<BaseCommand *>> &P : Cmds)
+ if (!P.second.empty())
+ error("unable to INSERT AFTER/BEFORE " + P.first +
+ ": section not defined");
+
+ SectionCommands = std::move(V);
+}
+
+// Symbols defined in script should not be inlined by LTO. At the same time
+// we don't know their final values until late stages of link. Here we scan
+// over symbol assignment commands and create placeholder symbols if needed.
+void LinkerScript::declareSymbols() {
+ assert(!Ctx);
+ for (BaseCommand *Base : SectionCommands) {
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ declareSymbol(Cmd);
+ continue;
+ }
+
+ // If the output section directive has constraints,
+ // we can't say for sure if it is going to be included or not.
+ // Skip such sections for now. Improve the checks if we ever
+ // need symbols from that sections to be declared early.
+ auto *Sec = cast<OutputSection>(Base);
+ if (Sec->Constraint != ConstraintKind::NoConstraint)
+ continue;
+ for (BaseCommand *Base2 : Sec->SectionCommands)
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base2))
+ declareSymbol(Cmd);
+ }
+}
+
// This function is called from assignAddresses, while we are
// fixing the output section addresses. This function is supposed
// to set the final value for a given symbol assignment.
@@ -249,23 +358,11 @@ static void sortSections(MutableArrayRef<InputSection *> Vec,
// --sort-section is handled as an inner SORT command.
// 3. If one SORT command is given, and if it is SORT_NONE, don't sort.
// 4. If no SORT command is given, sort according to --sort-section.
-// 5. If no SORT commands are given and --sort-section is not specified,
-// apply sorting provided by --symbol-ordering-file if any exist.
-static void sortInputSections(
- MutableArrayRef<InputSection *> Vec, const SectionPattern &Pat,
- const DenseMap<SectionBase *, int> &Order) {
+static void sortInputSections(MutableArrayRef<InputSection *> Vec,
+ const SectionPattern &Pat) {
if (Pat.SortOuter == SortSectionPolicy::None)
return;
- if (Pat.SortOuter == SortSectionPolicy::Default &&
- Config->SortSection == SortSectionPolicy::Default) {
- // If -symbol-ordering-file was given, sort accordingly.
- // Usually, Order is empty.
- if (!Order.empty())
- sortByOrder(Vec, [&](InputSectionBase *S) { return Order.lookup(S); });
- return;
- }
-
if (Pat.SortInner == SortSectionPolicy::Default)
sortSections(Vec, Config->SortSection);
else
@@ -275,8 +372,7 @@ static void sortInputSections(
// Compute and remember which sections the InputSectionDescription matches.
std::vector<InputSection *>
-LinkerScript::computeInputSections(const InputSectionDescription *Cmd,
- const DenseMap<SectionBase *, int> &Order) {
+LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
std::vector<InputSection *> Ret;
// Collects all sections that satisfy constraints of Cmd.
@@ -290,8 +386,11 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd,
// For -emit-relocs we have to ignore entries like
// .rela.dyn : { *(.rela.data) }
// which are common because they are in the default bfd script.
- if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
- continue;
+ // We do not ignore SHT_REL[A] linker-synthesized sections here because
+ // want to support scripts that do custom layout for them.
+ if (auto *IS = dyn_cast<InputSection>(Sec))
+ if (IS->getRelocatedSection())
+ continue;
std::string Filename = getFilename(Sec->File);
if (!Cmd->FilePat.match(Filename) ||
@@ -307,7 +406,7 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd,
}
sortInputSections(MutableArrayRef<InputSection *>(Ret).slice(SizeBefore),
- Pat, Order);
+ Pat);
}
return Ret;
}
@@ -315,22 +414,31 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd,
void LinkerScript::discard(ArrayRef<InputSection *> V) {
for (InputSection *S : V) {
if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab ||
- S == InX::DynStrTab)
+ S == InX::DynStrTab || S == InX::RelaPlt || S == InX::RelaDyn ||
+ S == InX::RelrDyn)
error("discarding " + S->Name + " section is not allowed");
+ // You can discard .hash and .gnu.hash sections by linker scripts. Since
+ // they are synthesized sections, we need to handle them differently than
+ // other regular sections.
+ if (S == InX::GnuHashTab)
+ InX::GnuHashTab = nullptr;
+ if (S == InX::HashTab)
+ InX::HashTab = nullptr;
+
S->Assigned = false;
S->Live = false;
discard(S->DependentSections);
}
}
-std::vector<InputSection *> LinkerScript::createInputSectionList(
- OutputSection &OutCmd, const DenseMap<SectionBase *, int> &Order) {
+std::vector<InputSection *>
+LinkerScript::createInputSectionList(OutputSection &OutCmd) {
std::vector<InputSection *> Ret;
for (BaseCommand *Base : OutCmd.SectionCommands) {
if (auto *Cmd = dyn_cast<InputSectionDescription>(Base)) {
- Cmd->Sections = computeInputSections(Cmd, Order);
+ Cmd->Sections = computeInputSections(Cmd);
Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end());
}
}
@@ -359,7 +467,6 @@ void LinkerScript::processSectionCommands() {
Ctx->OutSec = Aether;
size_t I = 0;
- DenseMap<SectionBase *, int> Order = buildSectionOrder();
// Add input sections to output sections.
for (BaseCommand *Base : SectionCommands) {
// Handle symbol assignments outside of any output section.
@@ -369,12 +476,13 @@ void LinkerScript::processSectionCommands() {
}
if (auto *Sec = dyn_cast<OutputSection>(Base)) {
- std::vector<InputSection *> V = createInputSectionList(*Sec, Order);
+ std::vector<InputSection *> V = createInputSectionList(*Sec);
// The output section name `/DISCARD/' is special.
// Any input section assigned to it is discarded.
if (Sec->Name == "/DISCARD/") {
discard(V);
+ Sec->SectionCommands.clear();
continue;
}
@@ -414,6 +522,8 @@ void LinkerScript::processSectionCommands() {
Sec->SectionIndex = I++;
if (Sec->Noload)
Sec->Type = SHT_NOBITS;
+ if (Sec->NonAlloc)
+ Sec->Flags &= ~(uint64_t)SHF_ALLOC;
}
}
Ctx = nullptr;
@@ -484,7 +594,7 @@ static OutputSection *addInputSec(StringMap<OutputSection *> &Map,
// ignored. We should not have two output .text sections just because one was
// in a group and another was not for example.
//
- // It also seems that that wording was a late addition and didn't get the
+ // It also seems that wording was a late addition and didn't get the
// necessary scrutiny.
//
// Merging sections with different flags is expected by some users. One
@@ -529,11 +639,11 @@ static OutputSection *addInputSec(StringMap<OutputSection *> &Map,
void LinkerScript::addOrphanSections() {
unsigned End = SectionCommands.size();
StringMap<OutputSection *> Map;
-
std::vector<OutputSection *> V;
- for (InputSectionBase *S : InputSections) {
+
+ auto Add = [&](InputSectionBase *S) {
if (!S->Live || S->Parent)
- continue;
+ return;
StringRef Name = getOutputSectionName(S);
@@ -545,12 +655,24 @@ void LinkerScript::addOrphanSections() {
if (OutputSection *Sec =
findByName(makeArrayRef(SectionCommands).slice(0, End), Name)) {
Sec->addSection(cast<InputSection>(S));
- continue;
+ return;
}
if (OutputSection *OS = addInputSec(Map, S, Name))
V.push_back(OS);
- assert(S->getOutputSection()->SectionIndex == INT_MAX);
+ assert(S->getOutputSection()->SectionIndex == UINT32_MAX);
+ };
+
+ // For futher --emit-reloc handling code we need target output section
+ // to be created before we create relocation output section, so we want
+ // to create target sections first. We do not want priority handling
+ // for synthetic sections because them are special.
+ for (InputSectionBase *IS : InputSections) {
+ if (auto *Sec = dyn_cast<InputSection>(IS))
+ if (InputSectionBase *Rel = Sec->getRelocatedSection())
+ if (auto *RelIS = dyn_cast_or_null<InputSectionBase>(Rel->Parent))
+ Add(RelIS);
+ Add(IS);
}
// If no SECTIONS command was given, we should insert sections commands
@@ -585,33 +707,15 @@ void LinkerScript::output(InputSection *S) {
// Update output section size after adding each section. This is so that
// SIZEOF works correctly in the case below:
// .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) }
- Ctx->OutSec->Size = Pos - Ctx->OutSec->Addr;
-
- // If there is a memory region associated with this input section, then
- // place the section in that region and update the region index.
- if (Ctx->LMARegion)
- Ctx->LMARegion->CurPos += Pos - Before;
- // FIXME: should we also produce overflow errors for LMARegion?
-
- if (Ctx->MemRegion) {
- uint64_t &CurOffset = Ctx->MemRegion->CurPos;
- CurOffset += Pos - Before;
- uint64_t CurSize = CurOffset - Ctx->MemRegion->Origin;
- if (CurSize > Ctx->MemRegion->Length) {
- uint64_t OverflowAmt = CurSize - Ctx->MemRegion->Length;
- error("section '" + Ctx->OutSec->Name + "' will not fit in region '" +
- Ctx->MemRegion->Name + "': overflowed by " + Twine(OverflowAmt) +
- " bytes");
- }
- }
+ expandOutputSection(Pos - Before);
}
void LinkerScript::switchTo(OutputSection *Sec) {
- if (Ctx->OutSec == Sec)
- return;
-
Ctx->OutSec = Sec;
+
+ uint64_t Before = advance(0, 1);
Ctx->OutSec->Addr = advance(0, Ctx->OutSec->Alignment);
+ expandMemoryRegions(Ctx->OutSec->Addr - Before);
}
// This function searches for a memory region to place the given output
@@ -674,9 +778,8 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
if (PhdrEntry *L = Ctx->OutSec->PtLoad)
L->LMAOffset = Ctx->LMAOffset;
- // The Size previously denoted how many InputSections had been added to this
- // section, and was used for sorting SHF_LINK_ORDER sections. Reset it to
- // compute the actual size value.
+ // We can call this method multiple times during the creation of
+ // thunks and want to start over calculation each time.
Sec->Size = 0;
// We visited SectionsCommands from processSectionCommands to
@@ -685,7 +788,9 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
for (BaseCommand *Base : Sec->SectionCommands) {
// This handles the assignments to symbol or to the dot.
if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ Cmd->Addr = Dot;
assignSymbol(Cmd, true);
+ Cmd->Size = Dot - Cmd->Addr;
continue;
}
@@ -693,17 +798,7 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
if (auto *Cmd = dyn_cast<ByteCommand>(Base)) {
Cmd->Offset = Dot - Ctx->OutSec->Addr;
Dot += Cmd->Size;
- if (Ctx->MemRegion)
- Ctx->MemRegion->CurPos += Cmd->Size;
- if (Ctx->LMARegion)
- Ctx->LMARegion->CurPos += Cmd->Size;
- Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr;
- continue;
- }
-
- // Handle ASSERT().
- if (auto *Cmd = dyn_cast<AssertCommand>(Base)) {
- Cmd->Expression();
+ expandOutputSection(Cmd->Size);
continue;
}
@@ -728,24 +823,28 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
}
}
-void LinkerScript::removeEmptyCommands() {
- // It is common practice to use very generic linker scripts. So for any
- // given run some of the output sections in the script will be empty.
- // We could create corresponding empty output sections, but that would
- // clutter the output.
- // We instead remove trivially empty sections. The bfd linker seems even
- // more aggressive at removing them.
- llvm::erase_if(SectionCommands, [&](BaseCommand *Base) {
- if (auto *Sec = dyn_cast<OutputSection>(Base))
- return !Sec->Live;
+static bool isDiscardable(OutputSection &Sec) {
+ // We do not remove empty sections that are explicitly
+ // assigned to any segment.
+ if (!Sec.Phdrs.empty())
return false;
- });
-}
-static bool isAllSectionDescription(const OutputSection &Cmd) {
- for (BaseCommand *Base : Cmd.SectionCommands)
+ // We do not want to remove sections that reference symbols in address and
+ // other expressions. We add script symbols as undefined, and want to ensure
+ // all of them are defined in the output, hence have to keep them.
+ if (Sec.ExpressionsUseSymbols)
+ return false;
+
+ for (BaseCommand *Base : Sec.SectionCommands) {
+ if (auto Cmd = dyn_cast<SymbolAssignment>(Base))
+ // Don't create empty output sections just for unreferenced PROVIDE
+ // symbols.
+ if (Cmd->Name != "." && !Cmd->Sym)
+ continue;
+
if (!isa<InputSectionDescription>(*Base))
return false;
+ }
return true;
}
@@ -761,7 +860,7 @@ void LinkerScript::adjustSectionsBeforeSorting() {
// Given that we want to create the section, we have to worry what impact
// it will have on the link. For example, if we just create a section with
// 0 for flags, it would change which PT_LOADs are created.
- // We could remember that that particular section is dummy and ignore it in
+ // We could remember that particular section is dummy and ignore it in
// other parts of the linker, but unfortunately there are quite a few places
// that would need to change:
// * The program header creation.
@@ -772,29 +871,47 @@ void LinkerScript::adjustSectionsBeforeSorting() {
// the previous sections. Only a few flags are needed to keep the impact low.
uint64_t Flags = SHF_ALLOC;
- for (BaseCommand *Cmd : SectionCommands) {
+ for (BaseCommand *&Cmd : SectionCommands) {
auto *Sec = dyn_cast<OutputSection>(Cmd);
if (!Sec)
continue;
- if (Sec->Live) {
- Flags = Sec->Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR);
- continue;
- }
-
- if (isAllSectionDescription(*Sec))
- continue;
- Sec->Live = true;
- Sec->Flags = Flags;
+ // Handle align (e.g. ".foo : ALIGN(16) { ... }").
+ if (Sec->AlignExpr)
+ Sec->Alignment =
+ std::max<uint32_t>(Sec->Alignment, Sec->AlignExpr().getValue());
+
+ // A live output section means that some input section was added to it. It
+ // might have been removed (if it was empty synthetic section), but we at
+ // least know the flags.
+ if (Sec->Live)
+ Flags = Sec->Flags;
+
+ // We do not want to keep any special flags for output section
+ // in case it is empty.
+ bool IsEmpty = getInputSections(Sec).empty();
+ if (IsEmpty)
+ Sec->Flags = Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR);
+
+ if (IsEmpty && isDiscardable(*Sec)) {
+ Sec->Live = false;
+ Cmd = nullptr;
+ }
}
+
+ // It is common practice to use very generic linker scripts. So for any
+ // given run some of the output sections in the script will be empty.
+ // We could create corresponding empty output sections, but that would
+ // clutter the output.
+ // We instead remove trivially empty sections. The bfd linker seems even
+ // more aggressive at removing them.
+ llvm::erase_if(SectionCommands, [&](BaseCommand *Base) { return !Base; });
}
void LinkerScript::adjustSectionsAfterSorting() {
// Try and find an appropriate memory region to assign offsets in.
for (BaseCommand *Base : SectionCommands) {
if (auto *Sec = dyn_cast<OutputSection>(Base)) {
- if (!Sec->Live)
- continue;
if (!Sec->LMARegionName.empty()) {
if (MemoryRegion *M = MemoryRegions.lookup(Sec->LMARegionName))
Sec->LMARegion = M;
@@ -802,10 +919,6 @@ void LinkerScript::adjustSectionsAfterSorting() {
error("memory region '" + Sec->LMARegionName + "' not declared");
}
Sec->MemRegion = findMemoryRegion(Sec);
- // Handle align (e.g. ".foo : ALIGN(16) { ... }").
- if (Sec->AlignExpr)
- Sec->Alignment =
- std::max<uint32_t>(Sec->Alignment, Sec->AlignExpr().getValue());
}
}
@@ -816,9 +929,9 @@ void LinkerScript::adjustSectionsAfterSorting() {
// PHDRS { seg PT_LOAD; }
// SECTIONS { .aaa : { *(.aaa) } }
std::vector<StringRef> DefPhdrs;
- auto FirstPtLoad =
- std::find_if(PhdrsCommands.begin(), PhdrsCommands.end(),
- [](const PhdrsCommand &Cmd) { return Cmd.Type == PT_LOAD; });
+ auto FirstPtLoad = llvm::find_if(PhdrsCommands, [](const PhdrsCommand &Cmd) {
+ return Cmd.Type == PT_LOAD;
+ });
if (FirstPtLoad != PhdrsCommands.end())
DefPhdrs.push_back(FirstPtLoad->Name);
@@ -847,6 +960,15 @@ static OutputSection *findFirstSection(PhdrEntry *Load) {
return nullptr;
}
+static uint64_t computeBase(uint64_t Min, bool AllocateHeaders) {
+ // If there is no SECTIONS or if the linkerscript is explicit about program
+ // headers, do our best to allocate them.
+ if (!Script->HasSectionsCommand || AllocateHeaders)
+ return 0;
+ // Otherwise only allocate program headers if that would not add a page.
+ return alignDown(Min, Config->MaxPageSize);
+}
+
// Try to find an address for the file and program headers output sections,
// which were unconditionally added to the first PT_LOAD segment earlier.
//
@@ -870,17 +992,22 @@ void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &Phdrs) {
return;
PhdrEntry *FirstPTLoad = *It;
+ bool HasExplicitHeaders =
+ llvm::any_of(PhdrsCommands, [](const PhdrsCommand &Cmd) {
+ return Cmd.HasPhdrs || Cmd.HasFilehdr;
+ });
uint64_t HeaderSize = getHeaderSize();
- // When linker script with SECTIONS is being used, don't output headers
- // unless there's a space for them.
- uint64_t Base = HasSectionsCommand ? alignDown(Min, Config->MaxPageSize) : 0;
- if (HeaderSize <= Min - Base || Script->hasPhdrsCommands()) {
+ if (HeaderSize <= Min - computeBase(Min, HasExplicitHeaders)) {
Min = alignDown(Min - HeaderSize, Config->MaxPageSize);
Out::ElfHeader->Addr = Min;
Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size;
return;
}
+ // Error if we were explicitly asked to allocate headers.
+ if (HasExplicitHeaders)
+ error("could not allocate headers");
+
Out::ElfHeader->PtLoad = nullptr;
Out::ProgramHeaders->PtLoad = nullptr;
FirstPTLoad->FirstSec = findFirstSection(FirstPTLoad);
@@ -924,15 +1051,11 @@ void LinkerScript::assignAddresses() {
for (BaseCommand *Base : SectionCommands) {
if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ Cmd->Addr = Dot;
assignSymbol(Cmd, false);
+ Cmd->Size = Dot - Cmd->Addr;
continue;
}
-
- if (auto *Cmd = dyn_cast<AssertCommand>(Base)) {
- Cmd->Expression();
- continue;
- }
-
assignOffsets(cast<OutputSection>(Base));
}
Ctx = nullptr;
@@ -996,9 +1119,9 @@ ExprValue LinkerScript::getSymbolValue(StringRef Name, const Twine &Loc) {
if (Symbol *Sym = Symtab->find(Name)) {
if (auto *DS = dyn_cast<Defined>(Sym))
return {DS->Section, false, DS->Value, Loc};
- if (auto *SS = dyn_cast<SharedSymbol>(Sym))
- if (!ErrorOnMissingSection || SS->CopyRelSec)
- return {SS->CopyRelSec, false, 0, Loc};
+ if (isa<SharedSymbol>(Sym))
+ if (!ErrorOnMissingSection)
+ return {nullptr, false, 0, Loc};
}
error(Loc + ": symbol not found: " + Name);
diff --git a/contrib/llvm/tools/lld/ELF/LinkerScript.h b/contrib/llvm/tools/lld/ELF/LinkerScript.h
index 0d7578cd2f1d..3b790dd4669f 100644
--- a/contrib/llvm/tools/lld/ELF/LinkerScript.h
+++ b/contrib/llvm/tools/lld/ELF/LinkerScript.h
@@ -11,9 +11,9 @@
#define LLD_ELF_LINKER_SCRIPT_H
#include "Config.h"
-#include "Strings.h"
#include "Writer.h"
#include "lld/Common/LLVM.h"
+#include "lld/Common/Strings.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
@@ -75,7 +75,6 @@ enum SectionsCommandKind {
AssignmentKind, // . = expr or <sym> = expr
OutputSectionKind,
InputSectionKind,
- AssertKind, // ASSERT(expr)
ByteKind // BYTE(expr), SHORT(expr), LONG(expr) or QUAD(expr)
};
@@ -106,6 +105,16 @@ struct SymbolAssignment : BaseCommand {
// Holds file name and line number for error reporting.
std::string Location;
+
+ // A string representation of this command. We use this for -Map.
+ std::string CommandString;
+
+ // Address of this assignment command.
+ unsigned Addr;
+
+ // Size of this assignment command. This is usually 0, but if
+ // you move '.' this may be greater than 0.
+ unsigned Size;
};
// Linker scripts allow additional constraints to be put on ouput sections.
@@ -167,24 +176,23 @@ struct InputSectionDescription : BaseCommand {
std::vector<std::pair<ThunkSection *, uint32_t>> ThunkSections;
};
-// Represents an ASSERT().
-struct AssertCommand : BaseCommand {
- AssertCommand(Expr E) : BaseCommand(AssertKind), Expression(E) {}
-
- static bool classof(const BaseCommand *C) { return C->Kind == AssertKind; }
-
- Expr Expression;
-};
-
// Represents BYTE(), SHORT(), LONG(), or QUAD().
struct ByteCommand : BaseCommand {
- ByteCommand(Expr E, unsigned Size)
- : BaseCommand(ByteKind), Expression(E), Size(Size) {}
+ ByteCommand(Expr E, unsigned Size, std::string CommandString)
+ : BaseCommand(ByteKind), CommandString(CommandString), Expression(E),
+ Size(Size) {}
static bool classof(const BaseCommand *C) { return C->Kind == ByteKind; }
+ // Keeps string representing the command. Used for -Map" is perhaps better.
+ std::string CommandString;
+
Expr Expression;
+
+ // This is just an offset of this assignment command in the output section.
unsigned Offset;
+
+ // Size of this data command.
unsigned Size;
};
@@ -215,14 +223,13 @@ class LinkerScript final {
void addSymbol(SymbolAssignment *Cmd);
void assignSymbol(SymbolAssignment *Cmd, bool InSec);
void setDot(Expr E, const Twine &Loc, bool InSec);
+ void expandOutputSection(uint64_t Size);
+ void expandMemoryRegions(uint64_t Size);
std::vector<InputSection *>
- computeInputSections(const InputSectionDescription *,
- const llvm::DenseMap<SectionBase *, int> &Order);
+ computeInputSections(const InputSectionDescription *);
- std::vector<InputSection *>
- createInputSectionList(OutputSection &Cmd,
- const llvm::DenseMap<SectionBase *, int> &Order);
+ std::vector<InputSection *> createInputSectionList(OutputSection &Cmd);
std::vector<size_t> getPhdrIndices(OutputSection *Sec);
@@ -257,7 +264,6 @@ public:
ExprValue getSymbolValue(StringRef Name, const Twine &Loc);
void addOrphanSections();
- void removeEmptyCommands();
void adjustSectionsBeforeSorting();
void adjustSectionsAfterSorting();
@@ -268,6 +274,10 @@ public:
void assignAddresses();
void allocateHeaders(std::vector<PhdrEntry *> &Phdrs);
void processSectionCommands();
+ void declareSymbols();
+
+ // Used to handle INSERT AFTER statements.
+ void processInsertCommands();
// SECTIONS command list.
std::vector<BaseCommand *> SectionCommands;
@@ -287,6 +297,11 @@ public:
// A list of symbols referenced by the script.
std::vector<llvm::StringRef> ReferencedSymbols;
+
+ // Used to implement INSERT [AFTER|BEFORE]. Contains commands that need
+ // to be inserted into SECTIONS commands list.
+ llvm::DenseMap<StringRef, std::vector<BaseCommand *>> InsertAfterCommands;
+ llvm::DenseMap<StringRef, std::vector<BaseCommand *>> InsertBeforeCommands;
};
extern LinkerScript *Script;
diff --git a/contrib/llvm/tools/lld/ELF/MapFile.cpp b/contrib/llvm/tools/lld/ELF/MapFile.cpp
index dcc829315e64..54fddfb7b299 100644
--- a/contrib/llvm/tools/lld/ELF/MapFile.cpp
+++ b/contrib/llvm/tools/lld/ELF/MapFile.cpp
@@ -23,11 +23,13 @@
#include "InputFiles.h"
#include "LinkerScript.h"
#include "OutputSections.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -36,57 +38,46 @@ using namespace llvm::object;
using namespace lld;
using namespace lld::elf;
-typedef DenseMap<const SectionBase *, SmallVector<Symbol *, 4>> SymbolMapTy;
+typedef DenseMap<const SectionBase *, SmallVector<Defined *, 4>> SymbolMapTy;
+
+static const std::string Indent8 = " "; // 8 spaces
+static const std::string Indent16 = " "; // 16 spaces
// Print out the first three columns of a line.
-static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
- uint64_t Align) {
- int W = Config->Is64 ? 16 : 8;
- OS << format("%0*llx %0*llx %5lld ", W, Addr, W, Size, Align);
+static void writeHeader(raw_ostream &OS, uint64_t VMA, uint64_t LMA,
+ uint64_t Size, uint64_t Align) {
+ if (Config->Is64)
+ OS << format("%16llx %16llx %8llx %5lld ", VMA, LMA, Size, Align);
+ else
+ OS << format("%8llx %8llx %8llx %5lld ", VMA, LMA, Size, Align);
}
-static std::string indent(int Depth) { return std::string(Depth * 8, ' '); }
-
// Returns a list of all symbols that we want to print out.
-static std::vector<Symbol *> getSymbols() {
- std::vector<Symbol *> V;
- for (InputFile *File : ObjectFiles) {
- for (Symbol *B : File->getSymbols()) {
- if (auto *SS = dyn_cast<SharedSymbol>(B))
- if (SS->CopyRelSec || SS->NeedsPltAddr)
- V.push_back(SS);
+static std::vector<Defined *> getSymbols() {
+ std::vector<Defined *> V;
+ for (InputFile *File : ObjectFiles)
+ for (Symbol *B : File->getSymbols())
if (auto *DR = dyn_cast<Defined>(B))
- if (DR->File == File && !DR->isSection() && DR->Section &&
- DR->Section->Live)
+ if (!DR->isSection() && DR->Section && DR->Section->Live &&
+ (DR->File == File || DR->NeedsPltAddr || DR->Section->Bss))
V.push_back(DR);
- }
- }
return V;
}
// Returns a map from sections to their symbols.
-static SymbolMapTy getSectionSyms(ArrayRef<Symbol *> Syms) {
+static SymbolMapTy getSectionSyms(ArrayRef<Defined *> Syms) {
SymbolMapTy Ret;
- for (Symbol *S : Syms) {
- if (auto *DR = dyn_cast<Defined>(S)) {
- Ret[DR->Section].push_back(S);
- continue;
- }
-
- SharedSymbol *SS = cast<SharedSymbol>(S);
- if (SS->CopyRelSec)
- Ret[SS->CopyRelSec].push_back(S);
- else
- Ret[InX::Plt].push_back(S);
- }
+ for (Defined *DR : Syms)
+ Ret[DR->Section].push_back(DR);
// Sort symbols by address. We want to print out symbols in the
// order in the output file rather than the order they appeared
// in the input files.
for (auto &It : Ret) {
- SmallVectorImpl<Symbol *> &V = It.second;
- std::sort(V.begin(), V.end(),
- [](Symbol *A, Symbol *B) { return A->getVA() < B->getVA(); });
+ SmallVectorImpl<Defined *> &V = It.second;
+ std::stable_sort(V.begin(), V.end(), [](Defined *A, Defined *B) {
+ return A->getVA() < B->getVA();
+ });
}
return Ret;
}
@@ -95,12 +86,15 @@ static SymbolMapTy getSectionSyms(ArrayRef<Symbol *> Syms) {
// Demangling symbols (which is what toString() does) is slow, so
// we do that in batch using parallel-for.
static DenseMap<Symbol *, std::string>
-getSymbolStrings(ArrayRef<Symbol *> Syms) {
+getSymbolStrings(ArrayRef<Defined *> Syms) {
std::vector<std::string> Str(Syms.size());
parallelForEachN(0, Syms.size(), [&](size_t I) {
raw_string_ostream OS(Str[I]);
- writeHeader(OS, Syms[I]->getVA(), Syms[I]->getSize(), 0);
- OS << indent(2) << toString(*Syms[I]);
+ OutputSection *OSec = Syms[I]->getOutputSection();
+ uint64_t VMA = Syms[I]->getVA();
+ uint64_t LMA = OSec ? OSec->getLMA() + VMA - OSec->getVA(0) : 0;
+ writeHeader(OS, VMA, LMA, Syms[I]->getSize(), 1);
+ OS << Indent16 << toString(*Syms[I]);
});
DenseMap<Symbol *, std::string> Ret;
@@ -109,6 +103,44 @@ getSymbolStrings(ArrayRef<Symbol *> Syms) {
return Ret;
}
+// Print .eh_frame contents. Since the section consists of EhSectionPieces,
+// we need a specialized printer for that section.
+//
+// .eh_frame tend to contain a lot of section pieces that are contiguous
+// both in input file and output file. Such pieces are squashed before
+// being displayed to make output compact.
+static void printEhFrame(raw_ostream &OS, OutputSection *OSec) {
+ std::vector<EhSectionPiece> Pieces;
+
+ auto Add = [&](const EhSectionPiece &P) {
+ // If P is adjacent to Last, squash the two.
+ if (!Pieces.empty()) {
+ EhSectionPiece &Last = Pieces.back();
+ if (Last.Sec == P.Sec && Last.InputOff + Last.Size == P.InputOff &&
+ Last.OutputOff + Last.Size == P.OutputOff) {
+ Last.Size += P.Size;
+ return;
+ }
+ }
+ Pieces.push_back(P);
+ };
+
+ // Gather section pieces.
+ for (const CieRecord *Rec : InX::EhFrame->getCieRecords()) {
+ Add(*Rec->Cie);
+ for (const EhSectionPiece *Fde : Rec->Fdes)
+ Add(*Fde);
+ }
+
+ // Print out section pieces.
+ for (EhSectionPiece &P : Pieces) {
+ writeHeader(OS, OSec->Addr + P.OutputOff, OSec->getLMA() + P.OutputOff,
+ P.Size, 1);
+ OS << Indent8 << toString(P.Sec->File) << ":(" << P.Sec->Name << "+0x"
+ << Twine::utohexstr(P.InputOff) + ")\n";
+ }
+}
+
void elf::writeMapFile() {
if (Config->MapFile.empty())
return;
@@ -122,32 +154,109 @@ void elf::writeMapFile() {
}
// Collect symbol info that we want to print out.
- std::vector<Symbol *> Syms = getSymbols();
+ std::vector<Defined *> Syms = getSymbols();
SymbolMapTy SectionSyms = getSectionSyms(Syms);
DenseMap<Symbol *, std::string> SymStr = getSymbolStrings(Syms);
// Print out the header line.
int W = Config->Is64 ? 16 : 8;
- OS << left_justify("Address", W) << ' ' << left_justify("Size", W)
- << " Align Out In Symbol\n";
+ OS << right_justify("VMA", W) << ' ' << right_justify("LMA", W)
+ << " Size Align Out In Symbol\n";
+
+ for (BaseCommand *Base : Script->SectionCommands) {
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ if (Cmd->Provide && !Cmd->Sym)
+ continue;
+ //FIXME: calculate and print LMA.
+ writeHeader(OS, Cmd->Addr, 0, Cmd->Size, 1);
+ OS << Cmd->CommandString << '\n';
+ continue;
+ }
- // Print out file contents.
- for (OutputSection *OSec : OutputSections) {
- writeHeader(OS, OSec->Addr, OSec->Size, OSec->Alignment);
+ auto *OSec = cast<OutputSection>(Base);
+ writeHeader(OS, OSec->Addr, OSec->getLMA(), OSec->Size, OSec->Alignment);
OS << OSec->Name << '\n';
// Dump symbols for each input section.
for (BaseCommand *Base : OSec->SectionCommands) {
- auto *ISD = dyn_cast<InputSectionDescription>(Base);
- if (!ISD)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) {
+ for (InputSection *IS : ISD->Sections) {
+ if (IS == InX::EhFrame) {
+ printEhFrame(OS, OSec);
+ continue;
+ }
+
+ writeHeader(OS, IS->getVA(0), OSec->getLMA() + IS->getOffset(0),
+ IS->getSize(), IS->Alignment);
+ OS << Indent8 << toString(IS) << '\n';
+ for (Symbol *Sym : SectionSyms[IS])
+ OS << SymStr[Sym] << '\n';
+ }
+ continue;
+ }
+
+ if (auto *Cmd = dyn_cast<ByteCommand>(Base)) {
+ writeHeader(OS, OSec->Addr + Cmd->Offset, OSec->getLMA() + Cmd->Offset,
+ Cmd->Size, 1);
+ OS << Indent8 << Cmd->CommandString << '\n';
+ continue;
+ }
+
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ if (Cmd->Provide && !Cmd->Sym)
+ continue;
+ writeHeader(OS, Cmd->Addr, OSec->getLMA() + Cmd->Addr - OSec->getVA(0),
+ Cmd->Size, 1);
+ OS << Indent8 << Cmd->CommandString << '\n';
continue;
- for (InputSection *IS : ISD->Sections) {
- writeHeader(OS, OSec->Addr + IS->OutSecOff, IS->getSize(),
- IS->Alignment);
- OS << indent(1) << toString(IS) << '\n';
- for (Symbol *Sym : SectionSyms[IS])
- OS << SymStr[Sym] << '\n';
}
}
}
}
+
+static void print(StringRef A, StringRef B) {
+ outs() << left_justify(A, 49) << " " << B << "\n";
+}
+
+// Output a cross reference table to stdout. This is for --cref.
+//
+// For each global symbol, we print out a file that defines the symbol
+// followed by files that uses that symbol. Here is an example.
+//
+// strlen /lib/x86_64-linux-gnu/libc.so.6
+// tools/lld/tools/lld/CMakeFiles/lld.dir/lld.cpp.o
+// lib/libLLVMSupport.a(PrettyStackTrace.cpp.o)
+//
+// In this case, strlen is defined by libc.so.6 and used by other two
+// files.
+void elf::writeCrossReferenceTable() {
+ if (!Config->Cref)
+ return;
+
+ // Collect symbols and files.
+ MapVector<Symbol *, SetVector<InputFile *>> Map;
+ for (InputFile *File : ObjectFiles) {
+ for (Symbol *Sym : File->getSymbols()) {
+ if (isa<SharedSymbol>(Sym))
+ Map[Sym].insert(File);
+ if (auto *D = dyn_cast<Defined>(Sym))
+ if (!D->isLocal() && (!D->Section || D->Section->Live))
+ Map[D].insert(File);
+ }
+ }
+
+ // Print out a header.
+ outs() << "Cross Reference Table\n\n";
+ print("Symbol", "File");
+
+ // Print out a table.
+ for (auto KV : Map) {
+ Symbol *Sym = KV.first;
+ SetVector<InputFile *> &Files = KV.second;
+
+ print(toString(*Sym), toString(Sym->File));
+ for (InputFile *File : Files)
+ if (File != Sym->File)
+ print("", toString(File));
+ }
+}
diff --git a/contrib/llvm/tools/lld/ELF/MapFile.h b/contrib/llvm/tools/lld/ELF/MapFile.h
index 2d93e26d4cf8..0282425888b7 100644
--- a/contrib/llvm/tools/lld/ELF/MapFile.h
+++ b/contrib/llvm/tools/lld/ELF/MapFile.h
@@ -13,6 +13,7 @@
namespace lld {
namespace elf {
void writeMapFile();
+void writeCrossReferenceTable();
} // namespace elf
} // namespace lld
diff --git a/contrib/llvm/tools/lld/ELF/MarkLive.cpp b/contrib/llvm/tools/lld/ELF/MarkLive.cpp
index 88f558c7a3c6..a8371e212c3e 100644
--- a/contrib/llvm/tools/lld/ELF/MarkLive.cpp
+++ b/contrib/llvm/tools/lld/ELF/MarkLive.cpp
@@ -20,15 +20,15 @@
//
//===----------------------------------------------------------------------===//
+#include "MarkLive.h"
#include "InputSection.h"
#include "LinkerScript.h"
#include "OutputSections.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "Target.h"
-#include "Writer.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/ELF.h"
#include <functional>
@@ -60,8 +60,9 @@ static typename ELFT::uint getAddend(InputSectionBase &Sec,
static DenseMap<StringRef, std::vector<InputSectionBase *>> CNamedSections;
template <class ELFT, class RelT>
-static void resolveReloc(InputSectionBase &Sec, RelT &Rel,
- std::function<void(InputSectionBase *, uint64_t)> Fn) {
+static void
+resolveReloc(InputSectionBase &Sec, RelT &Rel,
+ llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
Symbol &B = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
// If a symbol is referenced in a live section, it is used.
@@ -90,7 +91,7 @@ static void resolveReloc(InputSectionBase &Sec, RelT &Rel,
template <class ELFT>
static void
forEachSuccessor(InputSection &Sec,
- std::function<void(InputSectionBase *, uint64_t)> Fn) {
+ llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
if (Sec.AreRelocsRela) {
for (const typename ELFT::Rela &Rel : Sec.template relas<ELFT>())
resolveReloc<ELFT>(Sec, Rel, Fn);
@@ -120,7 +121,7 @@ forEachSuccessor(InputSection &Sec,
template <class ELFT, class RelTy>
static void
scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels,
- std::function<void(InputSectionBase *, uint64_t)> Fn) {
+ llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
const endianness E = ELFT::TargetEndianness;
for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) {
@@ -155,14 +156,10 @@ scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels,
template <class ELFT>
static void
scanEhFrameSection(EhInputSection &EH,
- std::function<void(InputSectionBase *, uint64_t)> Fn) {
+ llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
if (!EH.NumRelocations)
return;
- // Unfortunately we need to split .eh_frame early since some relocations in
- // .eh_frame keep other section alive and some don't.
- EH.split<ELFT>();
-
if (EH.AreRelocsRela)
scanEhFrameSection<ELFT>(EH, EH.template relas<ELFT>(), Fn);
else
@@ -207,7 +204,7 @@ template <class ELFT> static void doGcSections() {
// (splittable) sections, each piece of data has independent liveness bit.
// So we explicitly tell it which offset is in use.
if (auto *MS = dyn_cast<MergeInputSection>(Sec))
- MS->markLiveAt(Offset);
+ MS->getSectionPiece(Offset)->Live = true;
if (Sec->Live)
return;
@@ -279,13 +276,18 @@ template <class ELFT> void elf::markLive() {
// The -gc-sections option works only for SHF_ALLOC sections
// (sections that are memory-mapped at runtime). So we can
- // unconditionally make non-SHF_ALLOC sections alive.
+ // unconditionally make non-SHF_ALLOC sections alive except
+ // SHF_LINK_ORDER and SHT_REL/SHT_RELA sections.
//
- // Non SHF_ALLOC sections are not removed even if they are
+ // Usually, SHF_ALLOC sections are not removed even if they are
// unreachable through relocations because reachability is not
// a good signal whether they are garbage or not (e.g. there is
// usually no section referring to a .comment section, but we
- // want to keep it.)
+ // want to keep it.).
+ //
+ // Note on SHF_LINK_ORDER: Such sections contain metadata and they
+ // have a reverse dependency on the InputSection they are linked with.
+ // We are able to garbage collect them.
//
// Note on SHF_REL{,A}: Such sections reach here only when -r
// or -emit-reloc were given. And they are subject of garbage
@@ -293,8 +295,9 @@ template <class ELFT> void elf::markLive() {
// remove its relocation section.
for (InputSectionBase *Sec : InputSections) {
bool IsAlloc = (Sec->Flags & SHF_ALLOC);
+ bool IsLinkOrder = (Sec->Flags & SHF_LINK_ORDER);
bool IsRel = (Sec->Type == SHT_REL || Sec->Type == SHT_RELA);
- if (!IsAlloc && !IsRel)
+ if (!IsAlloc && !IsLinkOrder && !IsRel)
Sec->Live = true;
}
@@ -305,8 +308,7 @@ template <class ELFT> void elf::markLive() {
if (Config->PrintGcSections)
for (InputSectionBase *Sec : InputSections)
if (!Sec->Live)
- message("removing unused section from '" + Sec->Name + "' in file '" +
- Sec->File->getName() + "'");
+ message("removing unused section " + toString(Sec));
}
template void elf::markLive<ELF32LE>();
diff --git a/contrib/llvm/tools/lld/ELF/MarkLive.h b/contrib/llvm/tools/lld/ELF/MarkLive.h
new file mode 100644
index 000000000000..c9b99add34de
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/MarkLive.h
@@ -0,0 +1,21 @@
+//===- MarkLive.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_MARKLIVE_H
+#define LLD_ELF_MARKLIVE_H
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> void markLive();
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_ELF_MARKLIVE_H
diff --git a/contrib/llvm/tools/lld/ELF/Options.td b/contrib/llvm/tools/lld/ELF/Options.td
index 20027e90aefd..04a4f8ffbe28 100644
--- a/contrib/llvm/tools/lld/ELF/Options.td
+++ b/contrib/llvm/tools/lld/ELF/Options.td
@@ -4,66 +4,91 @@ include "llvm/Option/OptParser.td"
// two can precede the option name except those that start with 'o'.
class F<string name>: Flag<["--", "-"], name>;
class J<string name>: Joined<["--", "-"], name>;
-class S<string name>: Separate<["--", "-"], name>;
-multiclass Eq<string name> {
- def "": Separate<["--", "-"], name>;
- def _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>;
+multiclass Eq<string name, string help> {
+ def NAME: Separate<["--", "-"], name>;
+ def NAME # _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>,
+ HelpText<help>;
}
-def auxiliary: S<"auxiliary">, HelpText<"Set DT_AUXILIARY field to the specified name">;
+multiclass B<string name, string help1, string help2> {
+ def NAME: Flag<["--", "-"], name>, HelpText<help1>;
+ def no_ # NAME: Flag<["--", "-"], "no-" # name>, HelpText<help2>;
+}
+
+defm auxiliary: Eq<"auxiliary", "Set DT_AUXILIARY field to the specified name">;
def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind defined symbols locally">;
def Bsymbolic_functions: F<"Bsymbolic-functions">,
HelpText<"Bind defined function symbols locally">;
-def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries">;
+def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries (default)">;
def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">;
-def build_id: F<"build-id">, HelpText<"Generate build ID note">;
+def build_id: F<"build-id">, HelpText<"Alias for --build-id=fast">;
+
+def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">,
+ MetaVarName<"[fast,md5,sha,uuid,0x<hexstring>]">;
-def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">;
+defm check_sections: B<"check-sections",
+ "Check section addresses for overlaps (default)",
+ "Do not check section addresses for overlaps">;
-defm compress_debug_sections : Eq<"compress-debug-sections">,
- HelpText<"Compress DWARF debug sections">;
+defm compress_debug_sections:
+ Eq<"compress-debug-sections", "Compress DWARF debug sections">,
+ MetaVarName<"[none,zlib]">;
-defm defsym: Eq<"defsym">, HelpText<"Define a symbol alias">;
+defm defsym: Eq<"defsym", "Define a symbol alias">, MetaVarName<"<symbol>=<value>">;
-defm library_path: Eq<"library-path">,
- HelpText<"Add a directory to the library search path">, MetaVarName<"<dir>">;
+defm library_path:
+ Eq<"library-path", "Add a directory to the library search path">, MetaVarName<"<dir>">;
def O: JoinedOrSeparate<["-"], "O">, HelpText<"Optimize output file size">;
-defm Tbss: Eq<"Tbss">,
- HelpText<"Same as --section-start with .bss as the sectionname">;
+defm Tbss: Eq<"Tbss", "Same as --section-start with .bss as the sectionname">;
-defm Tdata: Eq<"Tdata">,
- HelpText<"Same as --section-start with .data as the sectionname">;
+defm Tdata: Eq<"Tdata", "Same as --section-start with .data as the sectionname">;
-defm Ttext: Eq<"Ttext">,
- HelpText<"Same as --section-start with .text as the sectionname">;
+defm Ttext: Eq<"Ttext", "Same as --section-start with .text as the sectionname">;
-def allow_multiple_definition: F<"allow-multiple-definition">,
- HelpText<"Allow multiple definitions">;
+defm allow_multiple_definition: B<"allow-multiple-definition",
+ "Allow multiple definitions",
+ "Do not allow multiple definitions (default)">;
-def as_needed: F<"as-needed">,
- HelpText<"Only set DT_NEEDED for shared libraries if used">;
+defm apply_dynamic_relocs: B<"apply-dynamic-relocs",
+ "Apply link-time values for dynamic relocations",
+ "Do not apply link-time values for dynamic relocations (default)">;
+
+defm as_needed: B<"as-needed",
+ "Only set DT_NEEDED for shared libraries if used",
+ "Always set DT_NEEDED for shared libraries (default)">;
+
+defm call_graph_ordering_file:
+ Eq<"call-graph-ordering-file", "Layout sections to optimize the given callgraph">;
// -chroot doesn't have a help text because it is an internal option.
-def chroot: S<"chroot">;
+def chroot: Separate<["--", "-"], "chroot">;
def color_diagnostics: F<"color-diagnostics">,
- HelpText<"Use colors in diagnostics">;
+ HelpText<"Alias for --color-diagnostics=always">;
def color_diagnostics_eq: J<"color-diagnostics=">,
- HelpText<"Use colors in diagnostics">;
+ HelpText<"Use colors in diagnostics">,
+ MetaVarName<"[auto,always,never]">;
+
+defm cref: B<"cref",
+ "Output cross reference table",
+ "Do not output cross reference table">;
-def define_common: F<"define-common">,
- HelpText<"Assign space to common symbols">;
+defm define_common: B<"define-common",
+ "Assign space to common symbols",
+ "Do not assign space to common symbols">;
-def demangle: F<"demangle">, HelpText<"Demangle symbol names">;
+defm demangle: B<"demangle",
+ "Demangle symbol names (default)",
+ "Do not demangle symbol names">;
def disable_new_dtags: F<"disable-new-dtags">,
HelpText<"Disable new dynamic tags">;
@@ -76,158 +101,130 @@ def discard_locals: F<"discard-locals">,
def discard_none: F<"discard-none">,
HelpText<"Keep all symbols in the symbol table">;
-def dynamic_linker: S<"dynamic-linker">,
- HelpText<"Which dynamic linker to use">;
+defm dynamic_linker: Eq<"dynamic-linker", "Which dynamic linker to use">;
-defm dynamic_list: Eq<"dynamic-list">,
- HelpText<"Read a list of dynamic symbols">;
+defm dynamic_list: Eq<"dynamic-list", "Read a list of dynamic symbols">;
-def eh_frame_hdr: F<"eh-frame-hdr">,
- HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">;
+defm eh_frame_hdr: B<"eh-frame-hdr",
+ "Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header",
+ "Do not create .eh_frame_hdr section">;
def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">;
def enable_new_dtags: F<"enable-new-dtags">,
- HelpText<"Enable new dynamic tags">;
+ HelpText<"Enable new dynamic tags (default)">;
+
+def end_group: F<"end-group">,
+ HelpText<"Ignored for compatibility with GNU unless you pass --warn-backrefs">;
def end_lib: F<"end-lib">,
HelpText<"End a grouping of objects that should be treated as if they were together in an archive">;
-defm entry: Eq<"entry">, HelpText<"Name of entry point symbol">,
+defm entry: Eq<"entry", "Name of entry point symbol">,
MetaVarName<"<entry>">;
-defm error_limit: Eq<"error-limit">,
- HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">;
+defm error_limit:
+ Eq<"error-limit", "Maximum number of errors to emit before stopping (0 = no limit)">;
def error_unresolved_symbols: F<"error-unresolved-symbols">,
HelpText<"Report unresolved symbols as errors">;
-defm exclude_libs: Eq<"exclude-libs">,
- HelpText<"Exclude static libraries from automatic export">;
+defm exclude_libs: Eq<"exclude-libs", "Exclude static libraries from automatic export">;
+
+defm execute_only: B<"execute-only",
+ "Do not mark executable sections readable",
+ "Mark executable sections readable (default)">;
-def export_dynamic: F<"export-dynamic">,
- HelpText<"Put symbols in the dynamic symbol table">;
+defm export_dynamic: B<"export-dynamic",
+ "Put symbols in the dynamic symbol table",
+ "Do not put symbols in the dynamic symbol table (default)">;
-defm export_dynamic_symbol: Eq<"export-dynamic-symbol">,
- HelpText<"Put a symbol in the dynamic symbol table">;
+defm export_dynamic_symbol:
+ Eq<"export-dynamic-symbol", "Put a symbol in the dynamic symbol table">;
-def fatal_warnings: F<"fatal-warnings">,
- HelpText<"Treat warnings as errors">;
+defm fatal_warnings: B<"fatal-warnings",
+ "Treat warnings as errors",
+ "Do not treat warnings as errors (default)">;
-defm filter: Eq<"filter">,
- HelpText<"Set DT_FILTER field to the specified name">;
+defm filter: Eq<"filter", "Set DT_FILTER field to the specified name">;
-defm fini: Eq<"fini">,
- HelpText<"Specify a finalizer function">, MetaVarName<"<symbol>">;
+defm fini: Eq<"fini", "Specify a finalizer function">, MetaVarName<"<symbol>">;
def fix_cortex_a53_843419: F<"fix-cortex-a53-843419">,
HelpText<"Apply fixes for AArch64 Cortex-A53 erratum 843419">;
-def full_shutdown : F<"full-shutdown">,
- HelpText<"Perform a full shutdown instead of calling _exit">;
+defm format: Eq<"format", "Change the input format of the inputs following this option">,
+ MetaVarName<"[default,elf,binary]">;
-defm format: Eq<"format">,
- HelpText<"Change the input format of the inputs following this option">,
- MetaVarName<"<input-format>">;
+defm gc_sections: B<"gc-sections",
+ "Enable garbage collection of unused sections",
+ "Disable garbage collection of unused sections (default)">;
-def gc_sections: F<"gc-sections">,
- HelpText<"Enable garbage collection of unused sections">;
+defm gdb_index: B<"gdb-index",
+ "Generate .gdb_index section",
+ "Do not generate .gdb_index section (default)">;
-def gdb_index: F<"gdb-index">,
- HelpText<"Generate .gdb_index section">;
+defm gnu_unique: B<"gnu-unique",
+ "Enable STB_GNU_UNIQUE symbol binding (default)",
+ "Disable STB_GNU_UNIQUE symbol binding">;
-defm hash_style: Eq<"hash-style">,
- HelpText<"Specify hash style (sysv, gnu or both)">;
+defm hash_style: Eq<"hash-style", "Specify hash style (sysv, gnu or both)">;
def help: F<"help">, HelpText<"Print option help">;
def icf_all: F<"icf=all">, HelpText<"Enable identical code folding">;
-def icf_data: F<"icf-data">,
- HelpText<"Enable ICF to also fold identical read only data">;
+def icf_safe: F<"icf=safe">, HelpText<"Enable safe identical code folding">;
+
+def icf_none: F<"icf=none">, HelpText<"Disable identical code folding (default)">;
-def icf_none: F<"icf=none">, HelpText<"Disable identical code folding">;
+def ignore_function_address_equality: F<"ignore-function-address-equality">,
+ HelpText<"lld can break the address equality of functions">;
-defm image_base : Eq<"image-base">, HelpText<"Set the base address">;
+def ignore_data_address_equality: F<"ignore-data-address-equality">,
+ HelpText<"lld can break the address equality of data">;
-defm init: Eq<"init">, HelpText<"Specify an initializer function">,
+defm image_base: Eq<"image-base", "Set the base address">;
+
+defm init: Eq<"init", "Specify an initializer function">,
MetaVarName<"<symbol>">;
-defm library: Eq<"library">, HelpText<"Root name of library to use">,
- MetaVarName<"<libName>">;
+defm just_symbols: Eq<"just-symbols", "Just link symbols">;
-def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
- HelpText<"Optimization level for LTO">;
+defm keep_unique: Eq<"keep-unique", "Do not fold this symbol during ICF">;
+
+defm library: Eq<"library", "Root name of library to use">,
+ MetaVarName<"<libName>">;
def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
-defm Map: Eq<"Map">, HelpText<"Print a link map to the specified file">;
+defm Map: Eq<"Map", "Print a link map to the specified file">;
-def merge_exidx_entries: F<"merge-exidx-entries">,
- HelpText<"Enable merging .ARM.exidx entries">;
+defm merge_exidx_entries: B<"merge-exidx-entries",
+ "Enable merging .ARM.exidx entries (default)",
+ "Disable merging .ARM.exidx entries">;
def nostdlib: F<"nostdlib">,
HelpText<"Only search directories specified on the command line">;
-def no_as_needed: F<"no-as-needed">,
- HelpText<"Always DT_NEEDED for shared libraries">;
-
def no_color_diagnostics: F<"no-color-diagnostics">,
HelpText<"Do not use colors in diagnostics">;
-def no_define_common: F<"no-define-common">,
- HelpText<"Do not assign space to common symbols">;
-
-def no_demangle: F<"no-demangle">,
- HelpText<"Do not demangle symbol names">;
-
def no_dynamic_linker: F<"no-dynamic-linker">,
HelpText<"Inhibit output of .interp section">;
-def no_eh_frame_hdr: F<"no-eh-frame-hdr">,
- HelpText<"Do not create .eh_frame_hdr section">;
-
-def no_export_dynamic: F<"no-export-dynamic">;
-def no_fatal_warnings: F<"no-fatal-warnings">;
-
-def no_gc_sections: F<"no-gc-sections">,
- HelpText<"Disable garbage collection of unused sections">;
-
-def no_gdb_index: F<"no-gdb-index">,
- HelpText<"Do not generate .gdb_index section">;
-
-def no_gnu_unique: F<"no-gnu-unique">,
- HelpText<"Disable STB_GNU_UNIQUE symbol binding">;
-
-def no_merge_exidx_entries: F<"no-merge-exidx-entries">,
- HelpText<"Disable merging .ARM.exidx entries">;
-
-def no_threads: F<"no-threads">,
- HelpText<"Do not run the linker multi-threaded">;
-
-def no_whole_archive: F<"no-whole-archive">,
- HelpText<"Restores the default behavior of loading archive members">;
-
def noinhibit_exec: F<"noinhibit-exec">,
HelpText<"Retain the executable output file whenever it is still usable">;
-def nopie: F<"nopie">, HelpText<"Do not create a position independent executable">;
-
-def no_omagic: Flag<["--"], "no-omagic">, MetaVarName<"<magic>">,
+def no_omagic: F<"no-omagic">, MetaVarName<"<magic>">,
HelpText<"Do not set the text data sections to be writable">;
-def no_print_gc_sections: F<"no-print-gc-sections">,
- HelpText<"Do not list removed unused sections">;
-
def no_rosegment: F<"no-rosegment">,
HelpText<"Do not put read-only non-executable sections in their own segment">;
def no_undefined: F<"no-undefined">,
HelpText<"Report unresolved symbols even if the linker is creating a shared library">;
-def no_undefined_version: F<"no-undefined-version">,
- HelpText<"Report version scripts that refer undefined symbols">;
-
def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
HelpText<"Path to file to write output">;
@@ -237,42 +234,62 @@ def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">,
def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">,
HelpText<"Set the text and data sections to be readable and writable">;
-defm orphan_handling: Eq<"orphan-handling">,
- HelpText<"Control how orphan sections are handled when linker script used">;
+defm orphan_handling:
+ Eq<"orphan-handling", "Control how orphan sections are handled when linker script used">;
+
+defm pack_dyn_relocs:
+ Eq<"pack-dyn-relocs", "Pack dynamic relocations in the given format">,
+ MetaVarName<"[none,android,relr,android+relr]">;
+
+defm use_android_relr_tags: B<"use-android-relr-tags",
+ "Use SHT_ANDROID_RELR / DT_ANDROID_RELR* tags instead of SHT_RELR / DT_RELR*",
+ "Use SHT_RELR / DT_RELR* tags (default)">;
+
+defm pie: B<"pie",
+ "Create a position independent executable",
+ "Do not create a position independent executable (default)">;
+
+defm print_gc_sections: B<"print-gc-sections",
+ "List removed unused sections",
+ "Do not list removed unused sections (default)">;
-def pack_dyn_relocs_eq: J<"pack-dyn-relocs=">, MetaVarName<"<format>">,
- HelpText<"Pack dynamic relocations in the given format (none or android)">;
+defm print_icf_sections: B<"print-icf-sections",
+ "List identical folded sections",
+ "Do not list identical folded sections (default)">;
-def pie: F<"pie">, HelpText<"Create a position independent executable">;
+def pop_state: F<"pop-state">,
+ HelpText<"Undo the effect of -push-state">;
-def print_gc_sections: F<"print-gc-sections">,
- HelpText<"List removed unused sections">;
+def push_state: F<"push-state">,
+ HelpText<"Save the current state of -as-needed, -static and -whole-archive">;
def print_map: F<"print-map">,
HelpText<"Print a link map to the standard output">;
-defm reproduce: Eq<"reproduce">,
- HelpText<"Dump linker invocation and input files for debugging">;
+defm reproduce: Eq<"reproduce", "Dump linker invocation and input files for debugging">;
-defm rpath: Eq<"rpath">, HelpText<"Add a DT_RUNPATH to the output">;
+defm rpath: Eq<"rpath", "Add a DT_RUNPATH to the output">;
def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;
-defm retain_symbols_file: Eq<"retain-symbols-file">,
- HelpText<"Retain only the symbols listed in the file">,
+defm retain_symbols_file:
+ Eq<"retain-symbols-file", "Retain only the symbols listed in the file">,
MetaVarName<"<file>">;
-defm script: Eq<"script">, HelpText<"Read linker script">;
+defm script: Eq<"script", "Read linker script">;
-def section_start: S<"section-start">, MetaVarName<"<address>">,
- HelpText<"Set address of section">;
+defm section_start: Eq<"section-start", "Set address of section">,
+ MetaVarName<"<address>">;
def shared: F<"shared">, HelpText<"Build a shared object">;
-defm soname: Eq<"soname">, HelpText<"Set DT_SONAME">;
+defm soname: Eq<"soname", "Set DT_SONAME">;
-defm sort_section: Eq<"sort-section">,
- HelpText<"Specifies sections sorting rule when linkerscript is used">;
+defm sort_section:
+ Eq<"sort-section", "Specifies sections sorting rule when linkerscript is used">;
+
+def start_group: F<"start-group">,
+ HelpText<"Ignored for compatibility with GNU unless you pass --warn-backrefs">;
def start_lib: F<"start-lib">,
HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">;
@@ -281,33 +298,39 @@ def strip_all: F<"strip-all">, HelpText<"Strip all symbols">;
def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;
-def symbol_ordering_file: S<"symbol-ordering-file">,
- HelpText<"Layout sections in the order specified by symbol file">;
+defm symbol_ordering_file:
+ Eq<"symbol-ordering-file", "Layout sections to place symbols in the order specified by symbol ordering file">;
-defm sysroot: Eq<"sysroot">, HelpText<"Set the system root">;
+defm sysroot: Eq<"sysroot", "Set the system root">;
def target1_rel: F<"target1-rel">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_REL32">;
-def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32">;
+def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32 (default)">;
-defm target2: Eq<"target2">,
- HelpText<"Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">,
+defm target2:
+ Eq<"target2", "Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">,
MetaVarName<"<type>">;
-def threads: F<"threads">, HelpText<"Run the linker multi-threaded">;
+defm threads: B<"threads",
+ "Run the linker multi-threaded (default)",
+ "Do not run the linker multi-threaded">;
def trace: F<"trace">, HelpText<"Print the names of the input files">;
-defm trace_symbol : Eq<"trace-symbol">, HelpText<"Trace references to symbols">;
+defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">;
+
+defm undefined: Eq<"undefined", "Force undefined symbol during linking">,
+ MetaVarName<"<symbol>">;
-defm undefined: Eq<"undefined">,
- HelpText<"Force undefined symbol during linking">;
+defm unresolved_symbols:
+ Eq<"unresolved-symbols", "Determine how to handle unresolved symbols">;
-defm unresolved_symbols: Eq<"unresolved-symbols">,
- HelpText<"Determine how to handle unresolved symbols">;
+defm undefined_version: B<"undefined-version",
+ "Allow unused version in version script (default)",
+ "Report version scripts that refer undefined symbols">;
-defm rsp_quoting: Eq<"rsp-quoting">,
- HelpText<"Quoting style for response files. Values supported: windows|posix">;
+defm rsp_quoting: Eq<"rsp-quoting", "Quoting style for response files">,
+ MetaVarName<"[posix,windows]">;
def v: Flag<["-"], "v">, HelpText<"Display the version number">;
@@ -315,91 +338,123 @@ def verbose: F<"verbose">, HelpText<"Verbose mode">;
def version: F<"version">, HelpText<"Display the version number and exit">;
-defm version_script: Eq<"version-script">, HelpText<"Read a version script">;
+defm version_script: Eq<"version-script", "Read a version script">;
+
+defm warn_backrefs: B<"warn-backrefs",
+ "Warn about backward symbol references to fetch archive members",
+ "Do not warn about backward symbol references to fetch archive members (default)">;
+
+defm warn_common: B<"warn-common",
+ "Warn about duplicate common symbols",
+ "Do not warn about duplicate common symbols (default)">;
-def warn_common: F<"warn-common">,
- HelpText<"Warn about duplicate common symbols">;
+defm warn_symbol_ordering: B<"warn-symbol-ordering",
+ "Warn about problems with the symbol ordering file (default)",
+ "Do not warn about problems with the symbol ordering file">;
def warn_unresolved_symbols: F<"warn-unresolved-symbols">,
HelpText<"Report unresolved symbols as warnings">;
-def whole_archive: F<"whole-archive">,
- HelpText<"Force load of all members in a static library">;
+defm whole_archive: B<"whole-archive",
+ "Force load of all members in a static library",
+ "Do not force load of all members in a static library (default)">;
-defm wrap: Eq<"wrap">, HelpText<"Use wrapper functions for symbol">,
- MetaVarName<"<symbol>">;
+defm wrap: Eq<"wrap", "Use wrapper functions for symbol">,
+ MetaVarName<"<symbol>=<symbol>">;
def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
HelpText<"Linker option extensions">;
// Aliases
-def alias_auxiliary: Separate<["-"], "f">, Alias<auxiliary>;
-def alias_Bdynamic_call_shared: F<"call_shared">, Alias<Bdynamic>;
-def alias_Bdynamic_dy: F<"dy">, Alias<Bdynamic>;
-def alias_Bstatic_dn: F<"dn">, Alias<Bstatic>;
-def alias_Bstatic_non_shared: F<"non_shared">, Alias<Bstatic>;
-def alias_Bstatic_static: F<"static">, Alias<Bstatic>;
-def alias_define_common_d: Flag<["-"], "d">, Alias<define_common>;
-def alias_define_common_dc: F<"dc">, Alias<define_common>;
-def alias_define_common_dp: F<"dp">, Alias<define_common>;
-def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
-def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
-def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>;
-def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
-def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>;
-def alias_filter: Separate<["-"], "F">, Alias<filter>;
-def alias_format_b: S<"b">, Alias<format>;
-def alias_library: JoinedOrSeparate<["-"], "l">, Alias<library>;
-def alias_library_path: JoinedOrSeparate<["-"], "L">, Alias<library_path>;
-def alias_omagic: Flag<["-"], "N">, Alias<omagic>;
-def alias_o_output: Joined<["--"], "output=">, Alias<o>;
-def alias_o_output2 : Separate<["--"], "output">, Alias<o>;
-def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>;
-def alias_print_map_M: Flag<["-"], "M">, Alias<print_map>;
-def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>;
-def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias<rpath>;
-def alias_script_T: JoinedOrSeparate<["-"], "T">, Alias<script>;
-def alias_shared_Bshareable: F<"Bshareable">, Alias<shared>;
-def alias_soname_h: JoinedOrSeparate<["-"], "h">, Alias<soname>;
-def alias_strip_all: Flag<["-"], "s">, Alias<strip_all>;
-def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>;
-def alias_trace: Flag<["-"], "t">, Alias<trace>;
-def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>;
-def alias_Ttext_segment: S<"Ttext-segment">, Alias<Ttext>;
-def alias_Ttext_segment_eq: J<"Ttext-segment=">, Alias<Ttext>;
-def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
-def alias_version_V: Flag<["-"], "V">, Alias<version>;
-
-// Our symbol resolution algorithm handles symbols in archive files differently
-// than traditional linkers, so we don't need --start-group and --end-group.
-// These options are recongized for compatibility but ignored.
-def end_group: F<"end-group">;
-def end_group_paren: Flag<["-"], ")">;
-def start_group: F<"start-group">;
-def start_group_paren: Flag<["-"], "(">;
+def: Separate<["-"], "f">, Alias<auxiliary>, HelpText<"Alias for --auxiliary">;
+def: F<"call_shared">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">;
+def: F<"dy">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">;
+def: F<"dn">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: F<"non_shared">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: F<"static">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: Flag<["-"], "d">, Alias<define_common>, HelpText<"Alias for --define-common">;
+def: F<"dc">, Alias<define_common>, HelpText<"Alias for --define-common">;
+def: F<"dp">, Alias<define_common>, HelpText<"Alias for --define-common">;
+def: Flag<["-"], "x">, Alias<discard_all>, HelpText<"Alias for --discard-all">;
+def: Flag<["-"], "X">, Alias<discard_locals>, HelpText<"Alias for --discard-locals">;
+def: Flag<["-"], "q">, Alias<emit_relocs>, HelpText<"Alias for --emit-relocs">;
+def: Flag<["-"], ")">, Alias<end_group>, HelpText<"Alias for --end-group">;
+def: JoinedOrSeparate<["-"], "e">, Alias<entry>, HelpText<"Alias for --entry">;
+def: Flag<["-"], "E">, Alias<export_dynamic>, HelpText<"Alias for --export-dynamic">;
+def: Separate<["-"], "F">, Alias<filter>, HelpText<"Alias for --filter">;
+def: Separate<["-"], "b">, Alias<format>, HelpText<"Alias for --format">;
+def: JoinedOrSeparate<["-"], "l">, Alias<library>, HelpText<"Alias for --library">;
+def: JoinedOrSeparate<["-"], "L">, Alias<library_path>, HelpText<"Alias for --library-path">;
+def: F<"no-pic-executable">, Alias<no_pie>, HelpText<"Alias for --no-pie">;
+def: Flag<["-"], "N">, Alias<omagic>, HelpText<"Alias for --omagic">;
+def: Joined<["--"], "output=">, Alias<o>, HelpText<"Alias for -o">;
+def: Separate<["--"], "output">, Alias<o>, HelpText<"Alias for -o">;
+def: F<"pic-executable">, Alias<pie>, HelpText<"Alias for --pie">;
+def: Flag<["-"], "M">, Alias<print_map>, HelpText<"Alias for --print-map">;
+def: Flag<["-"], "r">, Alias<relocatable>, HelpText<"Alias for --relocatable">;
+def: JoinedOrSeparate<["-"], "R">, Alias<rpath>, HelpText<"Alias for --rpath">;
+def: JoinedOrSeparate<["-"], "T">, Alias<script>, HelpText<"Alias for --script">;
+def: F<"Bshareable">, Alias<shared>, HelpText<"Alias for --shared">;
+def: JoinedOrSeparate<["-"], "h">, Alias<soname>, HelpText<"Alias for --soname">;
+def: Flag<["-"], "(">, Alias<start_group>, HelpText<"Alias for --start-group">;
+def: Flag<["-"], "s">, Alias<strip_all>, HelpText<"Alias for --strip-all">;
+def: Flag<["-"], "S">, Alias<strip_debug>, HelpText<"Alias for --strip-debug">;
+def: Flag<["-"], "t">, Alias<trace>, HelpText<"Alias for --trace">;
+def: JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>, HelpText<"Alias for --trace-symbol">;
+def: Separate<["-", "--"], "Ttext-segment">, Alias<Ttext>, HelpText<"Alias for --Ttext">;
+def: Joined<["-", "--"], "Ttext-segment=">, Alias<Ttext>, HelpText<"Alias for --Ttext">;
+def: JoinedOrSeparate<["-"], "u">, Alias<undefined>, HelpText<"Alias for --undefined">;
+def: Flag<["-"], "V">, Alias<version>, HelpText<"Alias for --version">;
// LTO-related options.
def lto_aa_pipeline: J<"lto-aa-pipeline=">,
HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">;
+def lto_debug_pass_manager: F<"lto-debug-pass-manager">,
+ HelpText<"Debug new pass manager">;
+def lto_new_pass_manager: F<"lto-new-pass-manager">,
+ HelpText<"Use new pass manager">;
def lto_newpm_passes: J<"lto-newpm-passes=">,
HelpText<"Passes to run during LTO">;
+def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
+ HelpText<"Optimization level for LTO">;
def lto_partitions: J<"lto-partitions=">,
HelpText<"Number of LTO codegen partitions">;
+def lto_sample_profile: J<"lto-sample-profile=">,
+ HelpText<"Sample profile file path">;
def disable_verify: F<"disable-verify">;
-def mllvm: S<"mllvm">;
+defm mllvm: Eq<"mllvm", "Additional arguments to forward to LLVM's option processing">;
def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">,
HelpText<"YAML output file for optimization remarks">;
def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">,
- HelpText<"Include hotness informations in the optimization remarks file">;
-defm plugin_opt: Eq<"plugin-opt">,
- HelpText<"specifies LTO options for compatibility with GNU linkers">;
+ HelpText<"Include hotness information in the optimization remarks file">;
+defm plugin_opt: Eq<"plugin-opt", "specifies LTO options for compatibility with GNU linkers">;
def save_temps: F<"save-temps">;
def thinlto_cache_dir: J<"thinlto-cache-dir=">,
HelpText<"Path to ThinLTO cached object file directory">;
-def thinlto_cache_policy: S<"thinlto-cache-policy">,
- HelpText<"Pruning policy for the ThinLTO cache">;
+defm thinlto_cache_policy: Eq<"thinlto-cache-policy", "Pruning policy for the ThinLTO cache">;
def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
+def: J<"plugin-opt=O">, Alias<lto_O>, HelpText<"Alias for -lto-O">;
+def: F<"plugin-opt=debug-pass-manager">,
+ Alias<lto_debug_pass_manager>, HelpText<"Alias for -lto-debug-pass-manager">;
+def: F<"plugin-opt=disable-verify">, Alias<disable_verify>, HelpText<"Alias for -disable-verify">;
+def plugin_opt_dwo_dir_eq: J<"plugin-opt=dwo_dir=">,
+ HelpText<"Directory to store .dwo files when LTO and debug fission are used">;
+def: J<"plugin-opt=jobs=">, Alias<thinlto_jobs>, HelpText<"Alias for -thinlto-jobs">;
+def: J<"plugin-opt=lto-partitions=">, Alias<lto_partitions>, HelpText<"Alias for -lto-partitions">;
+def plugin_opt_mcpu_eq: J<"plugin-opt=mcpu=">;
+def: F<"plugin-opt=new-pass-manager">,
+ Alias<lto_new_pass_manager>, HelpText<"Alias for -lto-new-pass-manager">;
+def plugin_opt_obj_path_eq: J<"plugin-opt=obj-path=">;
+def: J<"plugin-opt=sample-profile=">,
+ Alias<lto_sample_profile>, HelpText<"Alias for -lto-sample-profile">;
+def: F<"plugin-opt=save-temps">, Alias<save_temps>, HelpText<"Alias for -save-temps">;
+def plugin_opt_thinlto_emit_imports_files: F<"plugin-opt=thinlto-emit-imports-files">;
+def plugin_opt_thinlto_index_only: F<"plugin-opt=thinlto-index-only">;
+def plugin_opt_thinlto_index_only_eq: J<"plugin-opt=thinlto-index-only=">;
+def plugin_opt_thinlto_object_suffix_replace_eq: J<"plugin-opt=thinlto-object-suffix-replace=">;
+def plugin_opt_thinlto_prefix_replace_eq: J<"plugin-opt=thinlto-prefix-replace=">;
+
// Ignore LTO plugin-related options.
// clang -flto passes -plugin and -plugin-opt to the linker. This is required
// for ld.gold and ld.bfd to get LTO working. But it's not for lld which doesn't
@@ -407,31 +462,38 @@ def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
// just ignore the option on lld side as it's easier. In fact, the linker could
// be called 'ld' and understanding which linker is used would require parsing of
// --version output.
-def plugin: S<"plugin">;
-def plugin_eq: J<"plugin=">;
+defm plugin: Eq<"plugin", "Ignored for compatibility with GNU linkers">;
+
+def plugin_opt_fresolution_eq: J<"plugin-opt=-fresolution=">;
+def plugin_opt_pass_through_eq: J<"plugin-opt=-pass-through=">;
+def plugin_opt_thinlto: J<"plugin-opt=thinlto">;
+def plugin_opt_slash: J<"plugin-opt=/">;
// Options listed below are silently ignored for now for compatibility.
-def allow_shlib_undefined: F<"allow-shlib-undefined">;
-def cref: F<"cref">;
-def detect_odr_violations: F<"detect-odr-violations">;
-def g: Flag<["-"], "g">;
-def long_plt: F<"long-plt">;
-def no_add_needed: F<"no-add-needed">;
-def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">;
-def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">;
-def no_ctors_in_init_array: F<"no-ctors-in-init-array">;
-def no_keep_memory: F<"no-keep-memory">;
-def no_mmap_output_file: F<"no-mmap-output-file">;
-def no_warn_common: F<"no-warn-common">;
-def no_warn_mismatch: F<"no-warn-mismatch">;
-def rpath_link: S<"rpath-link">;
-def rpath_link_eq: J<"rpath-link=">;
-def sort_common: F<"sort-common">;
-def stats: F<"stats">;
-def warn_execstack: F<"warn-execstack">;
-def warn_once: F<"warn-once">;
-def warn_shared_textrel: F<"warn-shared-textrel">;
-def EB : F<"EB">;
-def EL : F<"EL">;
-def G: JoinedOrSeparate<["-"], "G">;
-def Qy : F<"Qy">;
+def: F<"allow-shlib-undefined">;
+def: F<"detect-odr-violations">;
+def: Flag<["-"], "g">;
+def: F<"long-plt">;
+def: F<"no-add-needed">;
+def: F<"no-allow-shlib-undefined">;
+def: F<"no-copy-dt-needed-entries">;
+def: F<"no-ctors-in-init-array">;
+def: F<"no-keep-memory">;
+def: F<"no-mmap-output-file">;
+def: F<"no-warn-mismatch">;
+def: Separate<["--", "-"], "rpath-link">;
+def: J<"rpath-link=">;
+def: F<"sort-common">;
+def: F<"stats">;
+def: F<"warn-execstack">;
+def: F<"warn-once">;
+def: F<"warn-shared-textrel">;
+def: F<"EB">;
+def: F<"EL">;
+def: JoinedOrSeparate<["-"], "G">;
+def: F<"Qy">;
+
+// Hidden option used for testing MIPS multi-GOT implementation.
+defm mips_got_size:
+ Eq<"mips-got-size", "Max size of a single MIPS GOT. 0x10000 by default.">,
+ Flags<[HelpHidden]>;
diff --git a/contrib/llvm/tools/lld/ELF/OutputSections.cpp b/contrib/llvm/tools/lld/ELF/OutputSections.cpp
index 94c98284196f..8253b18b486c 100644
--- a/contrib/llvm/tools/lld/ELF/OutputSections.cpp
+++ b/contrib/llvm/tools/lld/ELF/OutputSections.cpp
@@ -10,11 +10,11 @@
#include "OutputSections.h"
#include "Config.h"
#include "LinkerScript.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Support/Compression.h"
@@ -25,15 +25,12 @@
using namespace llvm;
using namespace llvm::dwarf;
using namespace llvm::object;
-using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
uint8_t Out::First;
-OutputSection *Out::Opd;
-uint8_t *Out::OpdBuf;
PhdrEntry *Out::TlsPhdr;
OutputSection *Out::DebugInfo;
OutputSection *Out::ElfHeader;
@@ -45,7 +42,9 @@ OutputSection *Out::FiniArray;
std::vector<OutputSection *> elf::OutputSections;
uint32_t OutputSection::getPhdrFlags() const {
- uint32_t Ret = PF_R;
+ uint32_t Ret = 0;
+ if (Config->EMachine != EM_ARM || !(Flags & SHF_ARM_PURECODE))
+ Ret |= PF_R;
if (Flags & SHF_WRITE)
Ret |= PF_W;
if (Flags & SHF_EXECINSTR)
@@ -70,9 +69,7 @@ void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) {
OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags)
: BaseCommand(OutputSectionKind),
SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type,
- /*Info*/ 0,
- /*Link*/ 0),
- SectionIndex(INT_MAX) {
+ /*Info*/ 0, /*Link*/ 0) {
Live = false;
}
@@ -91,13 +88,15 @@ static bool canMergeToProgbits(unsigned Type) {
void OutputSection::addSection(InputSection *IS) {
if (!Live) {
// If IS is the first section to be added to this section,
- // initialize Type and Entsize from IS.
+ // initialize Type, Entsize and flags from IS.
Live = true;
Type = IS->Type;
Entsize = IS->Entsize;
+ Flags = IS->Flags;
} else {
// Otherwise, check if new type or flags are compatible with existing ones.
- if ((Flags & (SHF_ALLOC | SHF_TLS)) != (IS->Flags & (SHF_ALLOC | SHF_TLS)))
+ unsigned Mask = SHF_ALLOC | SHF_TLS | SHF_LINK_ORDER;
+ if ((Flags & Mask) != (IS->Flags & Mask))
error("incompatible section flags for " + Name + "\n>>> " + toString(IS) +
": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Name +
": 0x" + utohexstr(Flags));
@@ -114,9 +113,14 @@ void OutputSection::addSection(InputSection *IS) {
}
IS->Parent = this;
- Flags |= IS->Flags;
+ uint64_t AndMask =
+ Config->EMachine == EM_ARM ? (uint64_t)SHF_ARM_PURECODE : 0;
+ uint64_t OrMask = ~AndMask;
+ uint64_t AndFlags = (Flags & IS->Flags) & AndMask;
+ uint64_t OrFlags = (Flags | IS->Flags) & OrMask;
+ Flags = AndFlags | OrFlags;
+
Alignment = std::max(Alignment, IS->Alignment);
- IS->OutSecOff = Size++;
// If this section contains a table of fixed-size entries, sh_entsize
// holds the element size. If it contains elements of different size we
@@ -134,8 +138,8 @@ void OutputSection::addSection(InputSection *IS) {
}
}
-void elf::sortByOrder(MutableArrayRef<InputSection *> In,
- std::function<int(InputSectionBase *S)> Order) {
+static void sortByOrder(MutableArrayRef<InputSection *> In,
+ llvm::function_ref<int(InputSectionBase *S)> Order) {
typedef std::pair<int, InputSection *> Pair;
auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
@@ -158,11 +162,11 @@ bool OutputSection::classof(const BaseCommand *C) {
return C->Kind == OutputSectionKind;
}
-void OutputSection::sort(std::function<int(InputSectionBase *S)> Order) {
+void OutputSection::sort(llvm::function_ref<int(InputSectionBase *S)> Order) {
assert(Live);
- assert(SectionCommands.size() == 1);
- sortByOrder(cast<InputSectionDescription>(SectionCommands[0])->Sections,
- Order);
+ for (BaseCommand *B : SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(B))
+ sortByOrder(ISD->Sections, Order);
}
// Fill [Buf, Buf + Size) with Filler.
@@ -205,11 +209,11 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
if (Size == 1)
*Buf = Data;
else if (Size == 2)
- write16(Buf, Data, Config->Endianness);
+ write16(Buf, Data);
else if (Size == 4)
- write32(Buf, Data, Config->Endianness);
+ write32(Buf, Data);
else if (Size == 8)
- write64(Buf, Data, Config->Endianness);
+ write64(Buf, Data);
else
llvm_unreachable("unsupported Size argument");
}
@@ -231,12 +235,7 @@ template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
}
// Write leading padding.
- std::vector<InputSection *> Sections;
- for (BaseCommand *Cmd : SectionCommands)
- if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
- for (InputSection *IS : ISD->Sections)
- if (IS->Live)
- Sections.push_back(IS);
+ std::vector<InputSection *> Sections = getInputSections(this);
uint32_t Filler = getFiller();
if (Filler)
fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler);
@@ -281,17 +280,13 @@ static void finalizeShtGroup(OutputSection *OS,
}
template <class ELFT> void OutputSection::finalize() {
- InputSection *First = nullptr;
- for (BaseCommand *Base : SectionCommands) {
- if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) {
- if (ISD->Sections.empty())
- continue;
- if (First == nullptr)
- First = ISD->Sections.front();
- }
- if (isa<ByteCommand>(Base) && Type == SHT_NOBITS)
- Type = SHT_PROGBITS;
- }
+ if (Type == SHT_NOBITS)
+ for (BaseCommand *Base : SectionCommands)
+ if (isa<ByteCommand>(Base))
+ Type = SHT_PROGBITS;
+
+ std::vector<InputSection *> V = getInputSections(this);
+ InputSection *First = V.empty() ? nullptr : V[0];
if (Flags & SHF_LINK_ORDER) {
// We must preserve the link order dependency of sections with the
@@ -367,8 +362,6 @@ static bool compCtors(const InputSection *A, const InputSection *B) {
assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
X = X.substr(6);
Y = Y.substr(6);
- if (X.empty() && Y.empty())
- return false;
return X < Y;
}
@@ -394,6 +387,14 @@ int elf::getPriority(StringRef S) {
return V;
}
+std::vector<InputSection *> elf::getInputSections(OutputSection *OS) {
+ std::vector<InputSection *> Ret;
+ for (BaseCommand *Base : OS->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
+ Ret.insert(Ret.end(), ISD->Sections.begin(), ISD->Sections.end());
+ return Ret;
+}
+
// Sorts input sections by section name suffixes, so that .foo.N comes
// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections.
// We want to keep the original order if the priorities are the same
diff --git a/contrib/llvm/tools/lld/ELF/OutputSections.h b/contrib/llvm/tools/lld/ELF/OutputSections.h
index c006eae0c04b..efb6aabe9743 100644
--- a/contrib/llvm/tools/lld/ELF/OutputSections.h
+++ b/contrib/llvm/tools/lld/ELF/OutputSections.h
@@ -14,7 +14,6 @@
#include "InputSection.h"
#include "LinkerScript.h"
#include "Relocations.h"
-
#include "lld/Common/LLVM.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELF.h"
@@ -52,7 +51,7 @@ public:
uint64_t getLMA() const { return PtLoad ? Addr + PtLoad->LMAOffset : Addr; }
template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *SHdr);
- unsigned SectionIndex;
+ uint32_t SectionIndex = UINT32_MAX;
unsigned SortRank;
uint32_t getPhdrFlags() const;
@@ -100,13 +99,16 @@ public:
std::string Location;
std::string MemoryRegionName;
std::string LMARegionName;
+ bool NonAlloc = false;
bool Noload = false;
+ bool ExpressionsUseSymbols = false;
+ bool InOverlay = false;
template <class ELFT> void finalize();
template <class ELFT> void writeTo(uint8_t *Buf);
template <class ELFT> void maybeCompress();
- void sort(std::function<int(InputSectionBase *S)> Order);
+ void sort(llvm::function_ref<int(InputSectionBase *S)> Order);
void sortInitFini();
void sortCtorsDtors();
@@ -120,13 +122,13 @@ private:
int getPriority(StringRef S);
+std::vector<InputSection *> getInputSections(OutputSection* OS);
+
// All output sections that are handled by the linker specially are
// globally accessible. Writer initializes them, so don't use them
// until Writer is initialized.
struct Out {
static uint8_t First;
- static OutputSection *Opd;
- static uint8_t *OpdBuf;
static PhdrEntry *TlsPhdr;
static OutputSection *DebugInfo;
static OutputSection *ElfHeader;
@@ -143,8 +145,6 @@ namespace lld {
namespace elf {
uint64_t getHeaderSize();
-void sortByOrder(llvm::MutableArrayRef<InputSection *> In,
- std::function<int(InputSectionBase *S)> Order);
extern std::vector<OutputSection *> OutputSections;
} // namespace elf
diff --git a/contrib/llvm/tools/lld/ELF/Relocations.cpp b/contrib/llvm/tools/lld/ELF/Relocations.cpp
index 37bc8bcbd571..467219ad0542 100644
--- a/contrib/llvm/tools/lld/ELF/Relocations.cpp
+++ b/contrib/llvm/tools/lld/ELF/Relocations.cpp
@@ -45,14 +45,14 @@
#include "Config.h"
#include "LinkerScript.h"
#include "OutputSections.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"
#include "lld/Common/Memory.h"
-
+#include "lld/Common/Strings.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -80,55 +80,22 @@ static std::string getLocation(InputSectionBase &S, const Symbol &Sym,
return Msg + S.getObjMsg(Off);
}
-// This is a MIPS-specific rule.
-//
-// In case of MIPS GP-relative relocations always resolve to a definition
-// in a regular input file, ignoring the one-definition rule. So we,
-// for example, should not attempt to create a dynamic relocation even
-// if the target symbol is preemptible. There are two two MIPS GP-relative
-// relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16
-// can be against a preemptible symbol.
-//
-// To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all
-// relocation types occupy eight bit. In case of N64 ABI we extract first
-// relocation from 3-in-1 packet because only the first relocation can
-// be against a real symbol.
-static bool isMipsGprel(RelType Type) {
- if (Config->EMachine != EM_MIPS)
- return false;
- Type &= 0xff;
- return Type == R_MIPS_GPREL16 || Type == R_MICROMIPS_GPREL16 ||
- Type == R_MICROMIPS_GPREL7_S2;
-}
-
// This function is similar to the `handleTlsRelocation`. MIPS does not
// support any relaxations for TLS relocations so by factoring out MIPS
// handling in to the separate function we can simplify the code and do not
// pollute other `handleTlsRelocation` by MIPS `ifs` statements.
// Mips has a custom MipsGotSection that handles the writing of GOT entries
// without dynamic relocations.
-template <class ELFT>
static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym,
InputSectionBase &C, uint64_t Offset,
int64_t Addend, RelExpr Expr) {
if (Expr == R_MIPS_TLSLD) {
- if (InX::MipsGot->addTlsIndex() && Config->Pic)
- InX::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::MipsGot,
- InX::MipsGot->getTlsIndexOff(), false, nullptr,
- 0});
+ InX::MipsGot->addTlsIndex(*C.File);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
-
if (Expr == R_MIPS_TLSGD) {
- if (InX::MipsGot->addDynTlsEntry(Sym) && Sym.IsPreemptible) {
- uint64_t Off = InX::MipsGot->getGlobalDynOffset(Sym);
- InX::RelaDyn->addReloc(
- {Target->TlsModuleIndexRel, InX::MipsGot, Off, false, &Sym, 0});
- if (Sym.IsPreemptible)
- InX::RelaDyn->addReloc({Target->TlsOffsetRel, InX::MipsGot,
- Off + Config->Wordsize, false, &Sym, 0});
- }
+ InX::MipsGot->addDynTlsEntry(*C.File, Sym);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
@@ -161,7 +128,7 @@ static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym,
auto AddTlsReloc = [&](uint64_t Off, RelType Type, Symbol *Dest, bool Dyn) {
if (Dyn)
- InX::RelaDyn->addReloc({Type, InX::Got, Off, false, Dest, 0});
+ InX::RelaDyn->addReloc(Type, InX::Got, Off, Dest);
else
InX::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest});
};
@@ -207,7 +174,7 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
if (Config->EMachine == EM_ARM)
return handleARMTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr);
if (Config->EMachine == EM_MIPS)
- return handleMipsTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr);
+ return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr);
if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
Config->Shared) {
@@ -221,40 +188,62 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
return 1;
}
- if (isRelExprOneOf<R_TLSLD_PC, R_TLSLD>(Expr)) {
+ if (isRelExprOneOf<R_TLSLD_GOT, R_TLSLD_GOT_FROM_END, R_TLSLD_PC,
+ R_TLSLD_HINT>(Expr)) {
// Local-Dynamic relocs can be relaxed to Local-Exec.
if (!Config->Shared) {
C.Relocations.push_back(
- {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym});
- return 2;
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type,
+ Offset, Addend, &Sym});
+ return Target->TlsGdRelaxSkip;
}
+ if (Expr == R_TLSLD_HINT)
+ return 1;
if (InX::Got->addTlsIndex())
- InX::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::Got,
- InX::Got->getTlsIndexOff(), false, nullptr, 0});
+ InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got,
+ InX::Got->getTlsIndexOff(), nullptr);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
// Local-Dynamic relocs can be relaxed to Local-Exec.
- if (isRelExprOneOf<R_ABS, R_TLSLD, R_TLSLD_PC>(Expr) && !Config->Shared) {
- C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym});
+ if (Expr == R_ABS && !Config->Shared) {
+ C.Relocations.push_back(
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type,
+ Offset, Addend, &Sym});
return 1;
}
- if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD,
- R_TLSGD_PC>(Expr)) {
+ // Local-Dynamic sequence where offset of tls variable relative to dynamic
+ // thread pointer is stored in the got.
+ if (Expr == R_TLSLD_GOT_OFF) {
+ // Local-Dynamic relocs can be relaxed to local-exec
+ if (!Config->Shared) {
+ C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+ if (!Sym.isInGot()) {
+ InX::Got->addEntry(Sym);
+ uint64_t Off = Sym.getGotOffset();
+ InX::Got->Relocations.push_back({R_ABS, Target->TlsOffsetRel, Off, 0, &Sym});
+ }
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+
+ if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD_GOT,
+ R_TLSGD_GOT_FROM_END, R_TLSGD_PC>(Expr)) {
if (Config->Shared) {
if (InX::Got->addDynTlsEntry(Sym)) {
uint64_t Off = InX::Got->getGlobalDynOffset(Sym);
- InX::RelaDyn->addReloc(
- {Target->TlsModuleIndexRel, InX::Got, Off, false, &Sym, 0});
+ InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got, Off, &Sym);
// If the symbol is preemptible we need the dynamic linker to write
// the offset too.
uint64_t OffsetOff = Off + Config->Wordsize;
if (Sym.IsPreemptible)
- InX::RelaDyn->addReloc(
- {Target->TlsOffsetRel, InX::Got, OffsetOff, false, &Sym, 0});
+ InX::RelaDyn->addReloc(Target->TlsOffsetRel, InX::Got, OffsetOff,
+ &Sym);
else
InX::Got->Relocations.push_back(
{R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Sym});
@@ -271,8 +260,8 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
Offset, Addend, &Sym});
if (!Sym.isInGot()) {
InX::Got->addEntry(Sym);
- InX::RelaDyn->addReloc(
- {Target->TlsGotRel, InX::Got, Sym.getGotOffset(), false, &Sym, 0});
+ InX::RelaDyn->addReloc(Target->TlsGotRel, InX::Got, Sym.getGotOffset(),
+ &Sym);
}
} else {
C.Relocations.push_back(
@@ -336,7 +325,7 @@ static bool isAbsoluteValue(const Symbol &Sym) {
// Returns true if Expr refers a PLT entry.
static bool needsPlt(RelExpr Expr) {
- return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC>(Expr);
+ return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_PLT_PAGE_PC>(Expr);
}
// Returns true if Expr refers a GOT entry. Note that this function
@@ -352,7 +341,8 @@ static bool needsGot(RelExpr Expr) {
// file (PC, or GOT for example).
static bool isRelExpr(RelExpr Expr) {
return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
- R_PAGE_PC, R_RELAX_GOT_PC>(Expr);
+ R_PPC_CALL, R_PPC_CALL_PLT, R_PAGE_PC,
+ R_RELAX_GOT_PC>(Expr);
}
// Returns true if a given relocation can be computed at link-time.
@@ -367,11 +357,13 @@ static bool isRelExpr(RelExpr Expr) {
static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
InputSectionBase &S, uint64_t RelOff) {
// These expressions always compute a constant
- if (isRelExprOneOf<R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
- R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
- R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
- R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC, R_TLSGD,
- R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E))
+ if (isRelExprOneOf<
+ R_GOT_FROM_END, R_GOT_OFF, R_TLSLD_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
+ R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
+ R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
+ R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOT_FROM_END,
+ R_TLSGD_PC, R_PPC_CALL_PLT, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT,
+ R_TLSLD_HINT>(E))
return true;
// These never do, except if the entire file is position dependent or if
@@ -417,39 +409,45 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
}
static RelExpr toPlt(RelExpr Expr) {
- if (Expr == R_PPC_OPD)
- return R_PPC_PLT_OPD;
- if (Expr == R_PC)
+ switch (Expr) {
+ case R_PPC_CALL:
+ return R_PPC_CALL_PLT;
+ case R_PC:
return R_PLT_PC;
- if (Expr == R_PAGE_PC)
+ case R_PAGE_PC:
return R_PLT_PAGE_PC;
- if (Expr == R_ABS)
+ case R_ABS:
return R_PLT;
- return Expr;
+ default:
+ return Expr;
+ }
}
static RelExpr fromPlt(RelExpr Expr) {
// We decided not to use a plt. Optimize a reference to the plt to a
// reference to the symbol itself.
- if (Expr == R_PLT_PC)
+ switch (Expr) {
+ case R_PLT_PC:
return R_PC;
- if (Expr == R_PPC_PLT_OPD)
- return R_PPC_OPD;
- if (Expr == R_PLT)
+ case R_PPC_CALL_PLT:
+ return R_PPC_CALL;
+ case R_PLT:
return R_ABS;
- return Expr;
+ default:
+ return Expr;
+ }
}
// Returns true if a given shared symbol is in a read-only segment in a DSO.
-template <class ELFT> static bool isReadOnly(SharedSymbol *SS) {
+template <class ELFT> static bool isReadOnly(SharedSymbol &SS) {
typedef typename ELFT::Phdr Elf_Phdr;
// Determine if the symbol is read-only by scanning the DSO's program headers.
- const SharedFile<ELFT> &File = SS->getFile<ELFT>();
+ const SharedFile<ELFT> &File = SS.getFile<ELFT>();
for (const Elf_Phdr &Phdr : check(File.getObj().program_headers()))
if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) &&
- !(Phdr.p_flags & ELF::PF_W) && SS->Value >= Phdr.p_vaddr &&
- SS->Value < Phdr.p_vaddr + Phdr.p_memsz)
+ !(Phdr.p_flags & ELF::PF_W) && SS.Value >= Phdr.p_vaddr &&
+ SS.Value < Phdr.p_vaddr + Phdr.p_memsz)
return true;
return false;
}
@@ -458,26 +456,45 @@ template <class ELFT> static bool isReadOnly(SharedSymbol *SS) {
//
// If two or more symbols are at the same offset, and at least one of
// them are copied by a copy relocation, all of them need to be copied.
-// Otherwise, they would refer different places at runtime.
+// Otherwise, they would refer to different places at runtime.
template <class ELFT>
-static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) {
+static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &SS) {
typedef typename ELFT::Sym Elf_Sym;
- SharedFile<ELFT> &File = SS->getFile<ELFT>();
+ SharedFile<ELFT> &File = SS.getFile<ELFT>();
- std::vector<SharedSymbol *> Ret;
+ SmallSet<SharedSymbol *, 4> Ret;
for (const Elf_Sym &S : File.getGlobalELFSyms()) {
if (S.st_shndx == SHN_UNDEF || S.st_shndx == SHN_ABS ||
- S.st_value != SS->Value)
+ S.st_value != SS.Value)
continue;
StringRef Name = check(S.getName(File.getStringTable()));
Symbol *Sym = Symtab->find(Name);
if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym))
- Ret.push_back(Alias);
+ Ret.insert(Alias);
}
return Ret;
}
+// When a symbol is copy relocated or we create a canonical plt entry, it is
+// effectively a defined symbol. In the case of copy relocation the symbol is
+// in .bss and in the case of a canonical plt entry it is in .plt. This function
+// replaces the existing symbol with a Defined pointing to the appropriate
+// location.
+static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value,
+ uint64_t Size) {
+ Symbol Old = Sym;
+ replaceSymbol<Defined>(&Sym, Sym.File, Sym.getName(), Sym.Binding,
+ Sym.StOther, Sym.Type, Value, Size, Sec);
+ Sym.PltIndex = Old.PltIndex;
+ Sym.GotIndex = Old.GotIndex;
+ Sym.VerdefIndex = Old.VerdefIndex;
+ Sym.IsPreemptible = true;
+ Sym.ExportDynamic = true;
+ Sym.IsUsedInRegularObj = true;
+ Sym.Used = true;
+}
+
// Reserve space in .bss or .bss.rel.ro for copy relocation.
//
// The copy relocation is pretty much a hack. If you use a copy relocation
@@ -520,17 +537,17 @@ static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) {
// to the variable in .bss. This kind of issue is sometimes very hard to
// debug. What's a solution? Instead of exporting a varaible V from a DSO,
// define an accessor getV().
-template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) {
+template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) {
// Copy relocation against zero-sized symbol doesn't make sense.
- uint64_t SymSize = SS->getSize();
- if (SymSize == 0)
- fatal("cannot create a copy relocation for symbol " + toString(*SS));
+ uint64_t SymSize = SS.getSize();
+ if (SymSize == 0 || SS.Alignment == 0)
+ fatal("cannot create a copy relocation for symbol " + toString(SS));
// See if this symbol is in a read-only segment. If so, preserve the symbol's
// memory protection by reserving space in the .bss.rel.ro section.
bool IsReadOnly = isReadOnly<ELFT>(SS);
BssSection *Sec = make<BssSection>(IsReadOnly ? ".bss.rel.ro" : ".bss",
- SymSize, SS->Alignment);
+ SymSize, SS.Alignment);
if (IsReadOnly)
InX::BssRelRo->getParent()->addSection(Sec);
else
@@ -539,125 +556,10 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) {
// Look through the DSO's dynamic symbol table for aliases and create a
// dynamic symbol for each one. This causes the copy relocation to correctly
// interpose any aliases.
- for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) {
- Sym->CopyRelSec = Sec;
- Sym->IsPreemptible = false;
- Sym->IsUsedInRegularObj = true;
- Sym->Used = true;
- }
+ for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS))
+ replaceWithDefined(*Sym, Sec, 0, Sym->Size);
- InX::RelaDyn->addReloc({Target->CopyRel, Sec, 0, false, SS, 0});
-}
-
-static void errorOrWarn(const Twine &Msg) {
- if (!Config->NoinhibitExec)
- error(Msg);
- else
- warn(Msg);
-}
-
-// Returns PLT relocation expression.
-//
-// This handles a non PIC program call to function in a shared library. In
-// an ideal world, we could just report an error saying the relocation can
-// overflow at runtime. In the real world with glibc, crt1.o has a
-// R_X86_64_PC32 pointing to libc.so.
-//
-// The general idea on how to handle such cases is to create a PLT entry and
-// use that as the function value.
-//
-// For the static linking part, we just return a plt expr and everything
-// else will use the the PLT entry as the address.
-//
-// The remaining problem is making sure pointer equality still works. We
-// need the help of the dynamic linker for that. We let it know that we have
-// a direct reference to a so symbol by creating an undefined symbol with a
-// non zero st_value. Seeing that, the dynamic linker resolves the symbol to
-// the value of the symbol we created. This is true even for got entries, so
-// pointer equality is maintained. To avoid an infinite loop, the only entry
-// that points to the real function is a dedicated got entry used by the
-// plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT,
-// R_386_JMP_SLOT, etc).
-static RelExpr getPltExpr(Symbol &Sym, RelExpr Expr, bool &IsConstant) {
- Sym.NeedsPltAddr = true;
- Sym.IsPreemptible = false;
- IsConstant = true;
- return toPlt(Expr);
-}
-
-// This modifies the expression if we can use a copy relocation or point the
-// symbol to the PLT.
-template <class ELFT>
-static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type,
- InputSectionBase &S, uint64_t RelOff,
- bool &IsConstant) {
- // If a relocation can be applied at link-time, we don't need to
- // create a dynamic relocation in the first place.
- if (IsConstant)
- return Expr;
-
- // We can create any dynamic relocation supported by the dynamic linker if a
- // section is writable or we are passed -z notext.
- bool CanWrite = (S.Flags & SHF_WRITE) || !Config->ZText;
- if (CanWrite && Target->isPicRel(Type))
- return Expr;
-
- // If the relocation is to a weak undef, and we are producing
- // executable, give up on it and produce a non preemptible 0.
- if (!Config->Shared && Sym.isUndefWeak()) {
- Sym.IsPreemptible = false;
- IsConstant = true;
- return Expr;
- }
-
- // If we got here we know that this relocation would require the dynamic
- // linker to write a value to read only memory or use an unsupported
- // relocation.
-
- // We can hack around it if we are producing an executable and
- // the refered symbol can be preemepted to refer to the executable.
- if (!CanWrite && (Config->Shared || (Config->Pic && !isRelExpr(Expr)))) {
- error(
- "can't create dynamic relocation " + toString(Type) + " against " +
- (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) +
- " in readonly segment; recompile object files with -fPIC" +
- getLocation(S, Sym, RelOff));
- return Expr;
- }
-
- // Copy relocations are only possible if we are creating an executable and the
- // symbol is shared.
- if (!Sym.isShared() || Config->Shared)
- return Expr;
-
- if (Sym.getVisibility() != STV_DEFAULT) {
- error("cannot preempt symbol: " + toString(Sym) +
- getLocation(S, Sym, RelOff));
- return Expr;
- }
-
- if (Sym.isObject()) {
- // Produce a copy relocation.
- auto *B = dyn_cast<SharedSymbol>(&Sym);
- if (B && !B->CopyRelSec) {
- if (Config->ZNocopyreloc)
- error("unresolvable relocation " + toString(Type) +
- " against symbol '" + toString(*B) +
- "'; recompile with -fPIC or remove '-z nocopyreloc'" +
- getLocation(S, Sym, RelOff));
-
- addCopyRelSymbol<ELFT>(B);
- }
- IsConstant = true;
- return Expr;
- }
-
- if (Sym.isFunc())
- return getPltExpr(Sym, Expr, IsConstant);
-
- errorOrWarn("symbol '" + toString(Sym) + "' defined in " +
- toString(Sym.File) + " has no type");
- return Expr;
+ InX::RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS);
}
// MIPS has an odd notion of "paired" relocations to calculate addends.
@@ -732,7 +634,7 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,
return false;
bool CanBeExternal =
- Sym.computeBinding() != STB_LOCAL && Sym.getVisibility() == STV_DEFAULT;
+ Sym.computeBinding() != STB_LOCAL && Sym.Visibility == STV_DEFAULT;
if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal)
return false;
@@ -760,12 +662,12 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,
// this for the N32 ABI. Iterate over relocation with the same offset and put
// theirs types into the single bit-set.
template <class RelTy> static RelType getMipsN32RelType(RelTy *&Rel, RelTy *End) {
- RelType Type = Rel->getType(Config->IsMips64EL);
+ RelType Type = 0;
uint64_t Offset = Rel->r_offset;
int N = 0;
- while (Rel + 1 != End && (Rel + 1)->r_offset == Offset)
- Type |= (++Rel)->getType(Config->IsMips64EL) << (8 * ++N);
+ while (Rel != End && Rel->r_offset == Offset)
+ Type |= (Rel++)->getType(Config->IsMips64EL) << (8 * N++);
return Type;
}
@@ -815,16 +717,34 @@ private:
};
} // namespace
+static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec,
+ Symbol *Sym, int64_t Addend, RelExpr Expr,
+ RelType Type) {
+ // Add a relative relocation. If RelrDyn section is enabled, and the
+ // relocation offset is guaranteed to be even, add the relocation to
+ // the RelrDyn section, otherwise add it to the RelaDyn section.
+ // RelrDyn sections don't support odd offsets. Also, RelrDyn sections
+ // don't store the addend values, so we must write it to the relocated
+ // address.
+ if (InX::RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) {
+ IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym});
+ InX::RelrDyn->Relocs.push_back({IS, OffsetInSec});
+ return;
+ }
+ InX::RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend,
+ Expr, Type);
+}
+
template <class ELFT, class GotPltSection>
static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt,
- RelocationBaseSection *Rel, RelType Type, Symbol &Sym,
- bool UseSymVA) {
+ RelocationBaseSection *Rel, RelType Type, Symbol &Sym) {
Plt->addEntry<ELFT>(Sym);
GotPlt->addEntry(Sym);
- Rel->addReloc({Type, GotPlt, Sym.getGotPltOffset(), UseSymVA, &Sym, 0});
+ Rel->addReloc(
+ {Type, GotPlt, Sym.getGotPltOffset(), !Sym.IsPreemptible, &Sym, 0});
}
-template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) {
+template <class ELFT> static void addGotEntry(Symbol &Sym) {
InX::Got->addEntry(Sym);
RelExpr Expr = Sym.isTls() ? R_TLS : R_ABS;
@@ -837,7 +757,8 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) {
// add a static relocation to a Relocations vector so that
// InputSection::relocate will do the work for us. We may be able
// to just write a value now, but it is a TODO.)
- bool IsLinkTimeConstant = !Preemptible && (!Config->Pic || isAbsolute(Sym));
+ bool IsLinkTimeConstant =
+ !Sym.IsPreemptible && (!Config->Pic || isAbsolute(Sym));
if (IsLinkTimeConstant) {
InX::Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym});
return;
@@ -845,23 +766,33 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) {
// Otherwise, we emit a dynamic relocation to .rel[a].dyn so that
// the GOT slot will be fixed at load-time.
- RelType Type;
- if (Sym.isTls())
- Type = Target->TlsGotRel;
- else if (!Preemptible && Config->Pic && !isAbsolute(Sym))
- Type = Target->RelativeRel;
- else
- Type = Target->GotRel;
- InX::RelaDyn->addReloc({Type, InX::Got, Off, !Preemptible, &Sym, 0});
+ if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) {
+ addRelativeReloc(InX::Got, Off, &Sym, 0, R_ABS, Target->GotRel);
+ return;
+ }
+ InX::RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel,
+ InX::Got, Off, &Sym, 0,
+ Sym.IsPreemptible ? R_ADDEND : R_ABS, Target->GotRel);
+}
- // REL type relocations don't have addend fields unlike RELAs, and
- // their addends are stored to the section to which they are applied.
- // So, store addends if we need to.
- //
- // This is ugly -- the difference between REL and RELA should be
- // handled in a better way. It's a TODO.
- if (!Config->IsRela && !Preemptible)
- InX::Got->Relocations.push_back({R_ABS, Target->GotRel, Off, 0, &Sym});
+// Return true if we can define a symbol in the executable that
+// contains the value/function of a symbol defined in a shared
+// library.
+static bool canDefineSymbolInExecutable(Symbol &Sym) {
+ // If the symbol has default visibility the symbol defined in the
+ // executable will preempt it.
+ // Note that we want the visibility of the shared symbol itself, not
+ // the visibility of the symbol in the output file we are producing. That is
+ // why we use Sym.StOther.
+ if ((Sym.StOther & 0x3) == STV_DEFAULT)
+ return true;
+
+ // If we are allowed to break address equality of functions, defining
+ // a plt entry will allow the program to call the function in the
+ // .so, but the .so and the executable will no agree on the address
+ // of the function. Similar logic for objects.
+ return ((Sym.isFunc() && Config->IgnoreFunctionAddressEquality) ||
+ (Sym.isObject() && Config->IgnoreDataAddressEquality));
}
// The reason we have to do this early scan is as follows
@@ -878,129 +809,23 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) {
// complicates things for the dynamic linker and means we would have to reserve
// space for the extra PT_LOAD even if we end up not using it.
template <class ELFT, class RelTy>
-static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
- OffsetGetter GetOffset(Sec);
-
- // Not all relocations end up in Sec.Relocations, but a lot do.
- Sec.Relocations.reserve(Rels.size());
-
- for (auto I = Rels.begin(), End = Rels.end(); I != End; ++I) {
- const RelTy &Rel = *I;
- Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
- RelType Type = Rel.getType(Config->IsMips64EL);
-
- // Deal with MIPS oddity.
- if (Config->MipsN32Abi)
- Type = getMipsN32RelType(I, End);
-
- // Get an offset in an output section this relocation is applied to.
- uint64_t Offset = GetOffset.get(Rel.r_offset);
- if (Offset == uint64_t(-1))
- continue;
-
- // Skip if the target symbol is an erroneous undefined symbol.
- if (maybeReportUndefined(Sym, Sec, Rel.r_offset))
- continue;
-
- RelExpr Expr =
- Target->getRelExpr(Type, Sym, Sec.Data.begin() + Rel.r_offset);
-
- // Ignore "hint" relocations because they are only markers for relaxation.
- if (isRelExprOneOf<R_HINT, R_NONE>(Expr))
- continue;
-
- // Handle yet another MIPS-ness.
- if (isMipsGprel(Type)) {
- int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal());
- Sec.Relocations.push_back({R_MIPS_GOTREL, Type, Offset, Addend, &Sym});
- continue;
- }
-
- bool Preemptible = Sym.IsPreemptible;
-
- // Strenghten or relax a PLT access.
- //
- // GNU ifunc symbols must be accessed via PLT because their addresses
- // are determined by runtime.
- //
- // On the other hand, if we know that a PLT entry will be resolved within
- // the same ELF module, we can skip PLT access and directly jump to the
- // destination function. For example, if we are linking a main exectuable,
- // all dynamic symbols that can be resolved within the executable will
- // actually be resolved that way at runtime, because the main exectuable
- // is always at the beginning of a search list. We can leverage that fact.
- if (Sym.isGnuIFunc())
- Expr = toPlt(Expr);
- else if (!Preemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym))
- Expr =
- Target->adjustRelaxExpr(Type, Sec.Data.data() + Rel.r_offset, Expr);
- else if (!Preemptible)
- Expr = fromPlt(Expr);
-
- bool IsConstant =
- isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Rel.r_offset);
-
- Expr = adjustExpr<ELFT>(Sym, Expr, Type, Sec, Rel.r_offset, IsConstant);
- if (errorCount())
- continue;
-
- // This relocation does not require got entry, but it is relative to got and
- // needs it to be created. Here we request for that.
- if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL,
- R_GOTREL_FROM_END, R_PPC_TOC>(Expr))
- InX::Got->HasGotOffRel = true;
-
- // Read an addend.
- int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal());
-
- // Process some TLS relocations, including relaxing TLS relocations.
- // Note that this function does not handle all TLS relocations.
- if (unsigned Processed =
- handleTlsRelocation<ELFT>(Type, Sym, Sec, Offset, Addend, Expr)) {
- I += (Processed - 1);
- continue;
- }
-
- // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
- if (needsPlt(Expr) && !Sym.isInPlt()) {
- if (Sym.isGnuIFunc() && !Preemptible)
- addPltEntry<ELFT>(InX::Iplt, InX::IgotPlt, InX::RelaIplt,
- Target->IRelativeRel, Sym, true);
- else
- addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel,
- Sym, !Preemptible);
- }
-
- // Create a GOT slot if a relocation needs GOT.
- if (needsGot(Expr)) {
- if (Config->EMachine == EM_MIPS) {
- // MIPS ABI has special rules to process GOT entries and doesn't
- // require relocation entries for them. A special case is TLS
- // relocations. In that case dynamic loader applies dynamic
- // relocations to initialize TLS GOT entries.
- // See "Global Offset Table" in Chapter 5 in the following document
- // for detailed description:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- InX::MipsGot->addEntry(Sym, Addend, Expr);
- if (Sym.isTls() && Sym.IsPreemptible)
- InX::RelaDyn->addReloc({Target->TlsGotRel, InX::MipsGot,
- Sym.getGotOffset(), false, &Sym, 0});
- } else if (!Sym.isInGot()) {
- addGotEntry<ELFT>(Sym, Preemptible);
- }
- }
-
- if (!needsPlt(Expr) && !needsGot(Expr) && Sym.IsPreemptible) {
- // We don't know anything about the finaly symbol. Just ask the dynamic
- // linker to handle the relocation for us.
- if (!Target->isPicRel(Type))
- errorOrWarn(
- "relocation " + toString(Type) +
- " cannot be used against shared object; recompile with -fPIC" +
- getLocation(Sec, Sym, Offset));
+static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
+ uint64_t Offset, Symbol &Sym, const RelTy &Rel,
+ int64_t Addend) {
+ if (isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Offset)) {
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
+ bool CanWrite = (Sec.Flags & SHF_WRITE) || !Config->ZText;
+ if (CanWrite) {
+ // R_GOT refers to a position in the got, even if the symbol is preemptible.
+ bool IsPreemptibleValue = Sym.IsPreemptible && Expr != R_GOT;
- InX::RelaDyn->addReloc(
- {Target->getDynRel(Type), &Sec, Offset, false, &Sym, Addend});
+ if (!IsPreemptibleValue) {
+ addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type);
+ return;
+ } else if (RelType Rel = Target->getDynRel(Type)) {
+ InX::RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type);
// MIPS ABI turns using of GOT and dynamic relocations inside out.
// While regular ABI uses dynamic relocations to fill up GOT entries
@@ -1018,37 +843,210 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
// a dynamic relocation.
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
if (Config->EMachine == EM_MIPS)
- InX::MipsGot->addEntry(Sym, Addend, Expr);
- continue;
+ InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
+ return;
}
+ }
- // The size is not going to change, so we fold it in here.
- if (Expr == R_SIZE)
- Addend += Sym.getSize();
+ // If the relocation is to a weak undef, and we are producing
+ // executable, give up on it and produce a non preemptible 0.
+ if (!Config->Shared && Sym.isUndefWeak()) {
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
- // If the produced value is a constant, we just remember to write it
- // when outputting this section. We also have to do it if the format
- // uses Elf_Rel, since in that case the written value is the addend.
- if (IsConstant) {
- Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
- continue;
+ if (!CanWrite && (Config->Pic && !isRelExpr(Expr))) {
+ error(
+ "can't create dynamic relocation " + toString(Type) + " against " +
+ (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) +
+ " in readonly segment; recompile object files with -fPIC "
+ "or pass '-Wl,-z,notext' to allow text relocations in the output" +
+ getLocation(Sec, Sym, Offset));
+ return;
+ }
+
+ // Copy relocations are only possible if we are creating an executable.
+ if (Config->Shared) {
+ errorOrWarn("relocation " + toString(Type) +
+ " cannot be used against symbol " + toString(Sym) +
+ "; recompile with -fPIC" + getLocation(Sec, Sym, Offset));
+ return;
+ }
+
+ // If the symbol is undefined we already reported any relevant errors.
+ if (Sym.isUndefined())
+ return;
+
+ if (!canDefineSymbolInExecutable(Sym)) {
+ error("cannot preempt symbol: " + toString(Sym) +
+ getLocation(Sec, Sym, Offset));
+ return;
+ }
+
+ if (Sym.isObject()) {
+ // Produce a copy relocation.
+ if (auto *SS = dyn_cast<SharedSymbol>(&Sym)) {
+ if (!Config->ZCopyreloc)
+ error("unresolvable relocation " + toString(Type) +
+ " against symbol '" + toString(*SS) +
+ "'; recompile with -fPIC or remove '-z nocopyreloc'" +
+ getLocation(Sec, Sym, Offset));
+ addCopyRelSymbol<ELFT>(*SS);
}
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
- // If the output being produced is position independent, the final value
- // is still not known. In that case we still need some help from the
- // dynamic linker. We can however do better than just copying the incoming
- // relocation. We can process some of it and and just ask the dynamic
- // linker to add the load address.
- if (Config->IsRela) {
- InX::RelaDyn->addReloc(
- {Target->RelativeRel, &Sec, Offset, true, &Sym, Addend});
- } else {
- // In REL, addends are stored to the target section.
- InX::RelaDyn->addReloc(
- {Target->RelativeRel, &Sec, Offset, true, &Sym, 0});
- Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ if (Sym.isFunc()) {
+ // This handles a non PIC program call to function in a shared library. In
+ // an ideal world, we could just report an error saying the relocation can
+ // overflow at runtime. In the real world with glibc, crt1.o has a
+ // R_X86_64_PC32 pointing to libc.so.
+ //
+ // The general idea on how to handle such cases is to create a PLT entry and
+ // use that as the function value.
+ //
+ // For the static linking part, we just return a plt expr and everything
+ // else will use the PLT entry as the address.
+ //
+ // The remaining problem is making sure pointer equality still works. We
+ // need the help of the dynamic linker for that. We let it know that we have
+ // a direct reference to a so symbol by creating an undefined symbol with a
+ // non zero st_value. Seeing that, the dynamic linker resolves the symbol to
+ // the value of the symbol we created. This is true even for got entries, so
+ // pointer equality is maintained. To avoid an infinite loop, the only entry
+ // that points to the real function is a dedicated got entry used by the
+ // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT,
+ // R_386_JMP_SLOT, etc).
+
+ // For position independent executable on i386, the plt entry requires ebx
+ // to be set. This causes two problems:
+ // * If some code has a direct reference to a function, it was probably
+ // compiled without -fPIE/-fPIC and doesn't maintain ebx.
+ // * If a library definition gets preempted to the executable, it will have
+ // the wrong ebx value.
+ if (Config->Pie && Config->EMachine == EM_386)
+ errorOrWarn("symbol '" + toString(Sym) +
+ "' cannot be preempted; recompile with -fPIE" +
+ getLocation(Sec, Sym, Offset));
+ if (!Sym.isInPlt())
+ addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel,
+ Sym);
+ if (!Sym.isDefined())
+ replaceWithDefined(Sym, InX::Plt, Sym.getPltOffset(), 0);
+ Sym.NeedsPltAddr = true;
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
+
+ errorOrWarn("symbol '" + toString(Sym) + "' has no type" +
+ getLocation(Sec, Sym, Offset));
+}
+
+template <class ELFT, class RelTy>
+static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
+ RelTy *End) {
+ const RelTy &Rel = *I;
+ Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
+ RelType Type;
+
+ // Deal with MIPS oddity.
+ if (Config->MipsN32Abi) {
+ Type = getMipsN32RelType(I, End);
+ } else {
+ Type = Rel.getType(Config->IsMips64EL);
+ ++I;
+ }
+
+ // Get an offset in an output section this relocation is applied to.
+ uint64_t Offset = GetOffset.get(Rel.r_offset);
+ if (Offset == uint64_t(-1))
+ return;
+
+ // Skip if the target symbol is an erroneous undefined symbol.
+ if (maybeReportUndefined(Sym, Sec, Rel.r_offset))
+ return;
+
+ const uint8_t *RelocatedAddr = Sec.Data.begin() + Rel.r_offset;
+ RelExpr Expr = Target->getRelExpr(Type, Sym, RelocatedAddr);
+
+ // Ignore "hint" relocations because they are only markers for relaxation.
+ if (isRelExprOneOf<R_HINT, R_NONE>(Expr))
+ return;
+
+ // Strenghten or relax relocations.
+ //
+ // GNU ifunc symbols must be accessed via PLT because their addresses
+ // are determined by runtime.
+ //
+ // On the other hand, if we know that a PLT entry will be resolved within
+ // the same ELF module, we can skip PLT access and directly jump to the
+ // destination function. For example, if we are linking a main exectuable,
+ // all dynamic symbols that can be resolved within the executable will
+ // actually be resolved that way at runtime, because the main exectuable
+ // is always at the beginning of a search list. We can leverage that fact.
+ if (Sym.isGnuIFunc())
+ Expr = toPlt(Expr);
+ else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym))
+ Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr);
+ else if (!Sym.IsPreemptible)
+ Expr = fromPlt(Expr);
+
+ // This relocation does not require got entry, but it is relative to got and
+ // needs it to be created. Here we request for that.
+ if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL,
+ R_GOTREL_FROM_END, R_PPC_TOC>(Expr))
+ InX::Got->HasGotOffRel = true;
+
+ // Read an addend.
+ int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal());
+
+ // Process some TLS relocations, including relaxing TLS relocations.
+ // Note that this function does not handle all TLS relocations.
+ if (unsigned Processed =
+ handleTlsRelocation<ELFT>(Type, Sym, Sec, Offset, Addend, Expr)) {
+ I += (Processed - 1);
+ return;
+ }
+
+ // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
+ if (needsPlt(Expr) && !Sym.isInPlt()) {
+ if (Sym.isGnuIFunc() && !Sym.IsPreemptible)
+ addPltEntry<ELFT>(InX::Iplt, InX::IgotPlt, InX::RelaIplt,
+ Target->IRelativeRel, Sym);
+ else
+ addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel,
+ Sym);
+ }
+
+ // Create a GOT slot if a relocation needs GOT.
+ if (needsGot(Expr)) {
+ if (Config->EMachine == EM_MIPS) {
+ // MIPS ABI has special rules to process GOT entries and doesn't
+ // require relocation entries for them. A special case is TLS
+ // relocations. In that case dynamic loader applies dynamic
+ // relocations to initialize TLS GOT entries.
+ // See "Global Offset Table" in Chapter 5 in the following document
+ // for detailed description:
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
+ } else if (!Sym.isInGot()) {
+ addGotEntry<ELFT>(Sym);
}
}
+
+ processRelocAux<ELFT>(Sec, Expr, Type, Offset, Sym, Rel, Addend);
+}
+
+template <class ELFT, class RelTy>
+static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
+ OffsetGetter GetOffset(Sec);
+
+ // Not all relocations end up in Sec.Relocations, but a lot do.
+ Sec.Relocations.reserve(Rels.size());
+
+ for (auto I = Rels.begin(), End = Rels.end(); I != End;)
+ scanReloc<ELFT>(Sec, GetOffset, I, End);
}
template <class ELFT> void elf::scanRelocations(InputSectionBase &S) {
@@ -1263,17 +1261,30 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) {
//
// We follow a simple but conservative heuristic to place ThunkSections at
// offsets that are multiples of a Target specific branch range.
-// For an InputSectionRange that is smaller than the range, a single
+// For an InputSectionDescription that is smaller than the range, a single
// ThunkSection at the end of the range will do.
+//
+// For an InputSectionDescription that is more than twice the size of the range,
+// we place the last ThunkSection at range bytes from the end of the
+// InputSectionDescription in order to increase the likelihood that the
+// distance from a thunk to its target will be sufficiently small to
+// allow for the creation of a short thunk.
void ThunkCreator::createInitialThunkSections(
ArrayRef<OutputSection *> OutputSections) {
forEachInputSectionDescription(
OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) {
if (ISD->Sections.empty())
return;
+ uint32_t ISDBegin = ISD->Sections.front()->OutSecOff;
+ uint32_t ISDEnd =
+ ISD->Sections.back()->OutSecOff + ISD->Sections.back()->getSize();
+ uint32_t LastThunkLowerBound = -1;
+ if (ISDEnd - ISDBegin > Target->ThunkSectionSpacing * 2)
+ LastThunkLowerBound = ISDEnd - Target->ThunkSectionSpacing;
+
uint32_t ISLimit;
- uint32_t PrevISLimit = ISD->Sections.front()->OutSecOff;
- uint32_t ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing;
+ uint32_t PrevISLimit = ISDBegin;
+ uint32_t ThunkUpperBound = ISDBegin + Target->ThunkSectionSpacing;
for (const InputSection *IS : ISD->Sections) {
ISLimit = IS->OutSecOff + IS->getSize();
@@ -1281,6 +1292,8 @@ void ThunkCreator::createInitialThunkSections(
addThunkSection(OS, ISD, PrevISLimit);
ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing;
}
+ if (ISLimit > LastThunkLowerBound)
+ break;
PrevISLimit = ISLimit;
}
addThunkSection(OS, ISD, ISLimit);
@@ -1297,17 +1310,22 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS,
std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type,
uint64_t Src) {
- auto Res = ThunkedSymbols.insert({&Sym, std::vector<Thunk *>()});
- if (!Res.second) {
- // Check existing Thunks for Sym to see if they can be reused
- for (Thunk *ET : Res.first->second)
- if (ET->isCompatibleWith(Type) &&
- Target->inBranchRange(Type, Src, ET->ThunkSym->getVA()))
- return std::make_pair(ET, false);
- }
+ std::vector<Thunk *> *ThunkVec = nullptr;
+ // We use (section, offset) pair to find the thunk position if possible so
+ // that we create only one thunk for aliased symbols or ICFed sections.
+ if (auto *D = dyn_cast<Defined>(&Sym))
+ if (!D->isInPlt() && D->Section)
+ ThunkVec = &ThunkedSymbolsBySection[{D->Section->Repl, D->Value}];
+ if (!ThunkVec)
+ ThunkVec = &ThunkedSymbols[&Sym];
+ // Check existing Thunks for Sym to see if they can be reused
+ for (Thunk *ET : *ThunkVec)
+ if (ET->isCompatibleWith(Type) &&
+ Target->inBranchRange(Type, Src, ET->getThunkTargetSym()->getVA()))
+ return std::make_pair(ET, false);
// No existing compatible Thunk in range, create a new one
Thunk *T = addThunk(Type, Sym);
- Res.first->second.push_back(T);
+ ThunkVec->push_back(T);
return std::make_pair(T, true);
}
@@ -1315,7 +1333,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type,
// InputSectionDescription::Sections.
void ThunkCreator::forEachInputSectionDescription(
ArrayRef<OutputSection *> OutputSections,
- std::function<void(OutputSection *, InputSectionDescription *)> Fn) {
+ llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn) {
for (OutputSection *OS : OutputSections) {
if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
continue;
@@ -1383,7 +1401,7 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) {
for (InputSection *IS : ISD->Sections)
for (Relocation &Rel : IS->Relocations) {
- uint64_t Src = OS->Addr + IS->OutSecOff + Rel.Offset;
+ uint64_t Src = IS->getVA(Rel.Offset);
// If we are a relocation to an existing Thunk, check if it is
// still in range. If not then Rel will be altered to point to its
@@ -1398,7 +1416,6 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
bool IsNew;
std::tie(T, IsNew) = getThunk(*Rel.Sym, Rel.Type, Src);
if (IsNew) {
- AddressesChanged = true;
// Find or create a ThunkSection for the new Thunk
ThunkSection *TS;
if (auto *TIS = T->getTargetInputSection())
@@ -1406,13 +1423,18 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
else
TS = getISDThunkSec(OS, IS, ISD, Rel.Type, Src);
TS->addThunk(T);
- Thunks[T->ThunkSym] = T;
+ Thunks[T->getThunkTargetSym()] = T;
}
// Redirect relocation to Thunk, we never go via the PLT to a Thunk
- Rel.Sym = T->ThunkSym;
+ Rel.Sym = T->getThunkTargetSym();
Rel.Expr = fromPlt(Rel.Expr);
}
+ for (auto &P : ISD->ThunkSections)
+ AddressesChanged |= P.first->assignOffsets();
});
+ for (auto &P : ThunkedSections)
+ AddressesChanged |= P.second->assignOffsets();
+
// Merge all created synthetic ThunkSections back into OutputSection
mergeThunks(OutputSections);
++Pass;
diff --git a/contrib/llvm/tools/lld/ELF/Relocations.h b/contrib/llvm/tools/lld/ELF/Relocations.h
index 2cc8adfa5985..a4125111c4fe 100644
--- a/contrib/llvm/tools/lld/ELF/Relocations.h
+++ b/contrib/llvm/tools/lld/ELF/Relocations.h
@@ -21,7 +21,7 @@ class Symbol;
class InputSection;
class InputSectionBase;
class OutputSection;
-class OutputSection;
+class SectionBase;
// Represents a relocation type, such as R_X86_64_PC32 or R_ARM_THM_CALL.
typedef uint32_t RelType;
@@ -32,6 +32,7 @@ typedef uint32_t RelType;
enum RelExpr {
R_INVALID,
R_ABS,
+ R_ADDEND,
R_ARM_SBREL,
R_GOT,
R_GOTONLY_PC,
@@ -58,27 +59,33 @@ enum RelExpr {
R_PLT,
R_PLT_PAGE_PC,
R_PLT_PC,
- R_PPC_OPD,
- R_PPC_PLT_OPD,
+ R_PPC_CALL,
+ R_PPC_CALL_PLT,
R_PPC_TOC,
R_RELAX_GOT_PC,
R_RELAX_GOT_PC_NOPIC,
R_RELAX_TLS_GD_TO_IE,
R_RELAX_TLS_GD_TO_IE_ABS,
R_RELAX_TLS_GD_TO_IE_END,
+ R_RELAX_TLS_GD_TO_IE_GOT_OFF,
R_RELAX_TLS_GD_TO_IE_PAGE_PC,
R_RELAX_TLS_GD_TO_LE,
R_RELAX_TLS_GD_TO_LE_NEG,
R_RELAX_TLS_IE_TO_LE,
R_RELAX_TLS_LD_TO_LE,
+ R_RELAX_TLS_LD_TO_LE_ABS,
R_SIZE,
R_TLS,
R_TLSDESC,
R_TLSDESC_CALL,
R_TLSDESC_PAGE,
- R_TLSGD,
+ R_TLSGD_GOT,
+ R_TLSGD_GOT_FROM_END,
R_TLSGD_PC,
- R_TLSLD,
+ R_TLSLD_GOT,
+ R_TLSLD_GOT_FROM_END,
+ R_TLSLD_GOT_OFF,
+ R_TLSLD_HINT,
R_TLSLD_PC,
};
@@ -150,7 +157,7 @@ private:
void forEachInputSectionDescription(
ArrayRef<OutputSection *> OutputSections,
- std::function<void(OutputSection *, InputSectionDescription *)> Fn);
+ llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn);
std::pair<Thunk *, bool> getThunk(Symbol &Sym, RelType Type, uint64_t Src);
@@ -160,6 +167,8 @@ private:
bool normalizeExistingThunk(Relocation &Rel, uint64_t Src);
// Record all the available Thunks for a Symbol
+ llvm::DenseMap<std::pair<SectionBase *, uint64_t>, std::vector<Thunk *>>
+ ThunkedSymbolsBySection;
llvm::DenseMap<Symbol *, std::vector<Thunk *>> ThunkedSymbols;
// Find a Thunk from the Thunks symbol definition, we can use this to find
diff --git a/contrib/llvm/tools/lld/ELF/ScriptLexer.cpp b/contrib/llvm/tools/lld/ELF/ScriptLexer.cpp
index ef5a1cff7590..d4b1f6d99cc1 100644
--- a/contrib/llvm/tools/lld/ELF/ScriptLexer.cpp
+++ b/contrib/llvm/tools/lld/ELF/ScriptLexer.cpp
@@ -66,8 +66,6 @@ size_t ScriptLexer::getColumnNumber() {
std::string ScriptLexer::getCurrentLocation() {
std::string Filename = getCurrentMB().getBufferIdentifier();
- if (!Pos)
- return Filename;
return (Filename + ":" + Twine(getLineNumber())).str();
}
@@ -116,8 +114,9 @@ void ScriptLexer::tokenize(MemoryBufferRef MB) {
}
// ">foo" is parsed to ">" and "foo", but ">>" is parsed to ">>".
+ // "|", "||", "&" and "&&" are different operators.
if (S.startswith("<<") || S.startswith("<=") || S.startswith(">>") ||
- S.startswith(">=")) {
+ S.startswith(">=") || S.startswith("||") || S.startswith("&&")) {
Vec.push_back(S.substr(0, 2));
S = S.substr(2);
continue;
@@ -282,10 +281,7 @@ static bool encloses(StringRef S, StringRef T) {
MemoryBufferRef ScriptLexer::getCurrentMB() {
// Find input buffer containing the current token.
- assert(!MBs.empty());
- if (!Pos)
- return MBs[0];
-
+ assert(!MBs.empty() && Pos > 0);
for (MemoryBufferRef MB : MBs)
if (encloses(MB.getBuffer(), Tokens[Pos - 1]))
return MB;
diff --git a/contrib/llvm/tools/lld/ELF/ScriptParser.cpp b/contrib/llvm/tools/lld/ELF/ScriptParser.cpp
index 3d2606db8d06..ddb4a49a3e5e 100644
--- a/contrib/llvm/tools/lld/ELF/ScriptParser.cpp
+++ b/contrib/llvm/tools/lld/ELF/ScriptParser.cpp
@@ -63,6 +63,7 @@ private:
void readExtern();
void readGroup();
void readInclude();
+ void readInput();
void readMemory();
void readOutput();
void readOutputArch();
@@ -74,12 +75,14 @@ private:
void readVersion();
void readVersionScriptCommand();
- SymbolAssignment *readAssignment(StringRef Name);
+ SymbolAssignment *readSymbolAssignment(StringRef Name);
ByteCommand *readByteCommand(StringRef Tok);
uint32_t readFill();
uint32_t parseFill(StringRef Tok);
void readSectionAddressType(OutputSection *Cmd);
+ OutputSection *readOverlaySectionDescription();
OutputSection *readOutputSectionDescription(StringRef OutSec);
+ std::vector<BaseCommand *> readOverlay();
std::vector<StringRef> readOutputSectionPhdrs();
InputSectionDescription *readInputSectionDescription(StringRef Tok);
StringMatcher readFilePatterns();
@@ -88,16 +91,16 @@ private:
unsigned readPhdrType();
SortSectionPolicy readSortKind();
SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
- SymbolAssignment *readProvideOrAssignment(StringRef Tok);
+ SymbolAssignment *readAssignment(StringRef Tok);
void readSort();
- AssertCommand *readAssert();
- Expr readAssertExpr();
+ Expr readAssert();
Expr readConstant();
Expr getPageSize();
uint64_t readMemoryAssignment(StringRef, StringRef, StringRef);
std::pair<uint32_t, uint32_t> readMemoryAttributes();
+ Expr combine(StringRef Op, Expr L, Expr R);
Expr readExpr();
Expr readExpr1(Expr Lhs, int MinPrec);
StringRef readParenLiteral();
@@ -157,17 +160,6 @@ static ExprValue sub(ExprValue A, ExprValue B) {
return {A.Sec, false, A.getSectionOffset() - B.getValue(), A.Loc};
}
-static ExprValue mul(ExprValue A, ExprValue B) {
- return A.getValue() * B.getValue();
-}
-
-static ExprValue div(ExprValue A, ExprValue B) {
- if (uint64_t BV = B.getValue())
- return A.getValue() / BV;
- error("division by zero");
- return 0;
-}
-
static ExprValue bitAnd(ExprValue A, ExprValue B) {
moveAbsRight(A, B);
return {A.Sec, A.ForceAbsolute,
@@ -237,16 +229,16 @@ void ScriptParser::readLinkerScript() {
if (Tok == ";")
continue;
- if (Tok == "ASSERT") {
- Script->SectionCommands.push_back(readAssert());
- } else if (Tok == "ENTRY") {
+ if (Tok == "ENTRY") {
readEntry();
} else if (Tok == "EXTERN") {
readExtern();
- } else if (Tok == "GROUP" || Tok == "INPUT") {
+ } else if (Tok == "GROUP") {
readGroup();
} else if (Tok == "INCLUDE") {
readInclude();
+ } else if (Tok == "INPUT") {
+ readInput();
} else if (Tok == "MEMORY") {
readMemory();
} else if (Tok == "OUTPUT") {
@@ -265,7 +257,7 @@ void ScriptParser::readLinkerScript() {
readSections();
} else if (Tok == "VERSION") {
readVersion();
- } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) {
+ } else if (SymbolAssignment *Cmd = readAssignment(Tok)) {
Script->SectionCommands.push_back(Cmd);
} else {
setError("unknown directive: " + Tok);
@@ -336,13 +328,12 @@ void ScriptParser::readExtern() {
}
void ScriptParser::readGroup() {
- expect("(");
- while (!errorCount() && !consume(")")) {
- if (consume("AS_NEEDED"))
- readAsNeeded();
- else
- addFile(unquote(next()));
- }
+ bool Orig = InputFile::IsInGroup;
+ InputFile::IsInGroup = true;
+ readInput();
+ InputFile::IsInGroup = Orig;
+ if (!Orig)
+ ++InputFile::NextGroupId;
}
void ScriptParser::readInclude() {
@@ -353,7 +344,7 @@ void ScriptParser::readInclude() {
return;
}
- if (Optional<std::string> Path = searchLinkerScript(Tok)) {
+ if (Optional<std::string> Path = searchScript(Tok)) {
if (Optional<MemoryBufferRef> MB = readFile(*Path))
tokenize(*MB);
return;
@@ -361,6 +352,16 @@ void ScriptParser::readInclude() {
setError("cannot find linker script " + Tok);
}
+void ScriptParser::readInput() {
+ expect("(");
+ while (!errorCount() && !consume(")")) {
+ if (consume("AS_NEEDED"))
+ readAsNeeded();
+ else
+ addFile(unquote(next()));
+ }
+}
+
void ScriptParser::readOutput() {
// -o <file> takes predecence over OUTPUT(<file>).
expect("(");
@@ -437,6 +438,49 @@ void ScriptParser::readSearchDir() {
expect(")");
}
+// This reads an overlay description. Overlays are used to describe output
+// sections that use the same virtual memory range and normally would trigger
+// linker's sections sanity check failures.
+// https://sourceware.org/binutils/docs/ld/Overlay-Description.html#Overlay-Description
+std::vector<BaseCommand *> ScriptParser::readOverlay() {
+ // VA and LMA expressions are optional, though for simplicity of
+ // implementation we assume they are not. That is what OVERLAY was designed
+ // for first of all: to allow sections with overlapping VAs at different LMAs.
+ Expr AddrExpr = readExpr();
+ expect(":");
+ expect("AT");
+ Expr LMAExpr = readParenExpr();
+ expect("{");
+
+ std::vector<BaseCommand *> V;
+ OutputSection *Prev = nullptr;
+ while (!errorCount() && !consume("}")) {
+ // VA is the same for all sections. The LMAs are consecutive in memory
+ // starting from the base load address specified.
+ OutputSection *OS = readOverlaySectionDescription();
+ OS->AddrExpr = AddrExpr;
+ if (Prev)
+ OS->LMAExpr = [=] { return Prev->getLMA() + Prev->Size; };
+ else
+ OS->LMAExpr = LMAExpr;
+ V.push_back(OS);
+ Prev = OS;
+ }
+
+ // According to the specification, at the end of the overlay, the location
+ // counter should be equal to the overlay base address plus size of the
+ // largest section seen in the overlay.
+ // Here we want to create the Dot assignment command to achieve that.
+ Expr MoveDot = [=] {
+ uint64_t Max = 0;
+ for (BaseCommand *Cmd : V)
+ Max = std::max(Max, cast<OutputSection>(Cmd)->Size);
+ return AddrExpr().getValue() + Max;
+ };
+ V.push_back(make<SymbolAssignment>(".", MoveDot, getCurrentLocation()));
+ return V;
+}
+
void ScriptParser::readSections() {
Script->HasSectionsCommand = true;
@@ -446,26 +490,48 @@ void ScriptParser::readSections() {
Config->SingleRoRx = true;
expect("{");
+ std::vector<BaseCommand *> V;
while (!errorCount() && !consume("}")) {
StringRef Tok = next();
- BaseCommand *Cmd = readProvideOrAssignment(Tok);
- if (!Cmd) {
- if (Tok == "ASSERT")
- Cmd = readAssert();
- else
- Cmd = readOutputSectionDescription(Tok);
+ if (Tok == "OVERLAY") {
+ for (BaseCommand *Cmd : readOverlay())
+ V.push_back(Cmd);
+ continue;
}
- Script->SectionCommands.push_back(Cmd);
+
+ if (BaseCommand *Cmd = readAssignment(Tok))
+ V.push_back(Cmd);
+ else
+ V.push_back(readOutputSectionDescription(Tok));
+ }
+
+ if (!atEOF() && consume("INSERT")) {
+ std::vector<BaseCommand *> *Dest = nullptr;
+ if (consume("AFTER"))
+ Dest = &Script->InsertAfterCommands[next()];
+ else if (consume("BEFORE"))
+ Dest = &Script->InsertBeforeCommands[next()];
+ else
+ setError("expected AFTER/BEFORE, but got '" + next() + "'");
+ if (Dest)
+ Dest->insert(Dest->end(), V.begin(), V.end());
+ return;
}
+
+ Script->SectionCommands.insert(Script->SectionCommands.end(), V.begin(),
+ V.end());
}
static int precedence(StringRef Op) {
return StringSwitch<int>(Op)
- .Cases("*", "/", 5)
- .Cases("+", "-", 4)
- .Cases("<<", ">>", 3)
- .Cases("<", "<=", ">", ">=", "==", "!=", 2)
- .Cases("&", "|", 1)
+ .Cases("*", "/", "%", 8)
+ .Cases("+", "-", 7)
+ .Cases("<<", ">>", 6)
+ .Cases("<", "<=", ">", ">=", "==", "!=", 5)
+ .Case("&", 4)
+ .Case("|", 3)
+ .Case("&&", 2)
+ .Case("||", 1)
.Default(-1);
}
@@ -588,11 +654,7 @@ void ScriptParser::readSort() {
expect(")");
}
-AssertCommand *ScriptParser::readAssert() {
- return make<AssertCommand>(readAssertExpr());
-}
-
-Expr ScriptParser::readAssertExpr() {
+Expr ScriptParser::readAssert() {
expect("(");
Expr E = readExpr();
expect(",");
@@ -617,12 +679,14 @@ uint32_t ScriptParser::readFill() {
return V;
}
-// Reads an expression and/or the special directive "(NOLOAD)" for an
-// output section definition.
+// Reads an expression and/or the special directive for an output
+// section definition. Directive is one of following: "(NOLOAD)",
+// "(COPY)", "(INFO)" or "(OVERLAY)".
//
// An output section name can be followed by an address expression
-// and/or by "(NOLOAD)". This grammar is not LL(1) because "(" can be
-// interpreted as either the beginning of some expression or "(NOLOAD)".
+// and/or directive. This grammar is not LL(1) because "(" can be
+// interpreted as either the beginning of some expression or beginning
+// of directive.
//
// https://sourceware.org/binutils/docs/ld/Output-Section-Address.html
// https://sourceware.org/binutils/docs/ld/Output-Section-Type.html
@@ -633,6 +697,11 @@ void ScriptParser::readSectionAddressType(OutputSection *Cmd) {
Cmd->Noload = true;
return;
}
+ if (consume("COPY") || consume("INFO") || consume("OVERLAY")) {
+ expect(")");
+ Cmd->NonAlloc = true;
+ return;
+ }
Cmd->AddrExpr = readExpr();
expect(")");
} else {
@@ -657,10 +726,23 @@ static Expr checkAlignment(Expr E, std::string &Loc) {
};
}
+OutputSection *ScriptParser::readOverlaySectionDescription() {
+ OutputSection *Cmd =
+ Script->createOutputSection(next(), getCurrentLocation());
+ Cmd->InOverlay = true;
+ expect("{");
+ while (!errorCount() && !consume("}"))
+ Cmd->SectionCommands.push_back(readInputSectionRules(next()));
+ Cmd->Phdrs = readOutputSectionPhdrs();
+ return Cmd;
+}
+
OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
OutputSection *Cmd =
Script->createOutputSection(OutSec, getCurrentLocation());
+ size_t SymbolsReferenced = Script->ReferencedSymbols.size();
+
if (peek() != ":")
readSectionAddressType(Cmd);
expect(":");
@@ -684,13 +766,10 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
StringRef Tok = next();
if (Tok == ";") {
// Empty commands are allowed. Do nothing here.
- } else if (SymbolAssignment *Assign = readProvideOrAssignment(Tok)) {
+ } else if (SymbolAssignment *Assign = readAssignment(Tok)) {
Cmd->SectionCommands.push_back(Assign);
} else if (ByteCommand *Data = readByteCommand(Tok)) {
Cmd->SectionCommands.push_back(Data);
- } else if (Tok == "ASSERT") {
- Cmd->SectionCommands.push_back(readAssert());
- expect(";");
} else if (Tok == "CONSTRUCTORS") {
// CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors
// by name. This is for very old file formats such as ECOFF/XCOFF.
@@ -727,6 +806,8 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
// Consume optional comma following output section command.
consume(",");
+ if (Script->ReferencedSymbols.size() > SymbolsReferenced)
+ Cmd->ExpressionsUseSymbols = true;
return Cmd;
}
@@ -749,30 +830,39 @@ uint32_t ScriptParser::parseFill(StringRef Tok) {
SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) {
expect("(");
- SymbolAssignment *Cmd = readAssignment(next());
+ SymbolAssignment *Cmd = readSymbolAssignment(next());
Cmd->Provide = Provide;
Cmd->Hidden = Hidden;
expect(")");
- expect(";");
return Cmd;
}
-SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) {
+SymbolAssignment *ScriptParser::readAssignment(StringRef Tok) {
+ // Assert expression returns Dot, so this is equal to ".=."
+ if (Tok == "ASSERT")
+ return make<SymbolAssignment>(".", readAssert(), getCurrentLocation());
+
+ size_t OldPos = Pos;
SymbolAssignment *Cmd = nullptr;
- if (peek() == "=" || peek() == "+=") {
- Cmd = readAssignment(Tok);
- expect(";");
- } else if (Tok == "PROVIDE") {
+ if (peek() == "=" || peek() == "+=")
+ Cmd = readSymbolAssignment(Tok);
+ else if (Tok == "PROVIDE")
Cmd = readProvideHidden(true, false);
- } else if (Tok == "HIDDEN") {
+ else if (Tok == "HIDDEN")
Cmd = readProvideHidden(false, true);
- } else if (Tok == "PROVIDE_HIDDEN") {
+ else if (Tok == "PROVIDE_HIDDEN")
Cmd = readProvideHidden(true, true);
+
+ if (Cmd) {
+ Cmd->CommandString =
+ Tok.str() + " " +
+ llvm::join(Tokens.begin() + OldPos, Tokens.begin() + Pos, " ");
+ expect(";");
}
return Cmd;
}
-SymbolAssignment *ScriptParser::readAssignment(StringRef Name) {
+SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef Name) {
StringRef Op = next();
assert(Op == "=" || Op == "+=");
Expr E = readExpr();
@@ -795,15 +885,31 @@ Expr ScriptParser::readExpr() {
return E;
}
-static Expr combine(StringRef Op, Expr L, Expr R) {
+Expr ScriptParser::combine(StringRef Op, Expr L, Expr R) {
if (Op == "+")
return [=] { return add(L(), R()); };
if (Op == "-")
return [=] { return sub(L(), R()); };
if (Op == "*")
- return [=] { return mul(L(), R()); };
- if (Op == "/")
- return [=] { return div(L(), R()); };
+ return [=] { return L().getValue() * R().getValue(); };
+ if (Op == "/") {
+ std::string Loc = getCurrentLocation();
+ return [=]() -> uint64_t {
+ if (uint64_t RV = R().getValue())
+ return L().getValue() / RV;
+ error(Loc + ": division by zero");
+ return 0;
+ };
+ }
+ if (Op == "%") {
+ std::string Loc = getCurrentLocation();
+ return [=]() -> uint64_t {
+ if (uint64_t RV = R().getValue())
+ return L().getValue() % RV;
+ error(Loc + ": modulo by zero");
+ return 0;
+ };
+ }
if (Op == "<<")
return [=] { return L().getValue() << R().getValue(); };
if (Op == ">>")
@@ -820,6 +926,10 @@ static Expr combine(StringRef Op, Expr L, Expr R) {
return [=] { return L().getValue() == R().getValue(); };
if (Op == "!=")
return [=] { return L().getValue() != R().getValue(); };
+ if (Op == "||")
+ return [=] { return L().getValue() || R().getValue(); };
+ if (Op == "&&")
+ return [=] { return L().getValue() && R().getValue(); };
if (Op == "&")
return [=] { return bitAnd(L(), R()); };
if (Op == "|")
@@ -873,20 +983,13 @@ Expr ScriptParser::readConstant() {
if (S == "MAXPAGESIZE")
return [] { return Config->MaxPageSize; };
setError("unknown constant: " + S);
- return {};
+ return [] { return 0; };
}
// Parses Tok as an integer. It recognizes hexadecimal (prefixed with
// "0x" or suffixed with "H") and decimal numbers. Decimal numbers may
// have "K" (Ki) or "M" (Mi) suffixes.
static Optional<uint64_t> parseInt(StringRef Tok) {
- // Negative number
- if (Tok.startswith("-")) {
- if (Optional<uint64_t> Val = parseInt(Tok.substr(1)))
- return -*Val;
- return None;
- }
-
// Hexadecimal
uint64_t Val;
if (Tok.startswith_lower("0x")) {
@@ -925,7 +1028,13 @@ ByteCommand *ScriptParser::readByteCommand(StringRef Tok) {
.Default(-1);
if (Size == -1)
return nullptr;
- return make<ByteCommand>(readParenExpr(), Size);
+
+ size_t OldPos = Pos;
+ Expr E = readParenExpr();
+ std::string CommandString =
+ Tok.str() + " " +
+ llvm::join(Tokens.begin() + OldPos, Tokens.begin() + Pos, " ");
+ return make<ByteCommand>(E, Size, CommandString);
}
StringRef ScriptParser::readParenLiteral() {
@@ -1006,7 +1115,7 @@ Expr ScriptParser::readPrimary() {
};
}
if (Tok == "ASSERT")
- return readAssertExpr();
+ return readAssert();
if (Tok == "CONSTANT")
return readConstant();
if (Tok == "DATA_SEGMENT_ALIGN") {
@@ -1043,8 +1152,10 @@ Expr ScriptParser::readPrimary() {
}
if (Tok == "LENGTH") {
StringRef Name = readParenLiteral();
- if (Script->MemoryRegions.count(Name) == 0)
+ if (Script->MemoryRegions.count(Name) == 0) {
setError("memory region not defined: " + Name);
+ return [] { return 0; };
+ }
return [=] { return Script->MemoryRegions[Name]->Length; };
}
if (Tok == "LOADADDR") {
@@ -1055,10 +1166,22 @@ Expr ScriptParser::readPrimary() {
return Cmd->getLMA();
};
}
+ if (Tok == "MAX" || Tok == "MIN") {
+ expect("(");
+ Expr A = readExpr();
+ expect(",");
+ Expr B = readExpr();
+ expect(")");
+ if (Tok == "MIN")
+ return [=] { return std::min(A().getValue(), B().getValue()); };
+ return [=] { return std::max(A().getValue(), B().getValue()); };
+ }
if (Tok == "ORIGIN") {
StringRef Name = readParenLiteral();
- if (Script->MemoryRegions.count(Name) == 0)
+ if (Script->MemoryRegions.count(Name) == 0) {
setError("memory region not defined: " + Name);
+ return [] { return 0; };
+ }
return [=] { return Script->MemoryRegions[Name]->Origin; };
}
if (Tok == "SEGMENT_START") {
@@ -1240,6 +1363,9 @@ ScriptParser::readSymbols() {
// Reads an "extern C++" directive, e.g.,
// "extern "C++" { ns::*; "f(int, double)"; };"
+//
+// The last semicolon is optional. E.g. this is OK:
+// "extern "C++" { ns::*; "f(int, double)" };"
std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
StringRef Tok = next();
bool IsCXX = Tok == "\"C++\"";
@@ -1252,6 +1378,8 @@ std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
StringRef Tok = next();
bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok);
Ret.push_back({unquote(Tok), IsCXX, HasWildcard});
+ if (consume("}"))
+ return Ret;
expect(";");
}
@@ -1291,11 +1419,10 @@ void ScriptParser::readMemory() {
uint64_t Length = readMemoryAssignment("LENGTH", "len", "l");
// Add the memory region to the region map.
- if (Script->MemoryRegions.count(Name))
- setError("region '" + Name + "' already defined");
MemoryRegion *MR =
make<MemoryRegion>(Name, Origin, Length, Flags, NegFlags);
- Script->MemoryRegions[Name] = MR;
+ if (!Script->MemoryRegions.insert({Name, MR}).second)
+ setError("region '" + Name + "' already defined");
}
}
diff --git a/contrib/llvm/tools/lld/ELF/Strings.cpp b/contrib/llvm/tools/lld/ELF/Strings.cpp
deleted file mode 100644
index 0ef33a14bc3d..000000000000
--- a/contrib/llvm/tools/lld/ELF/Strings.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-//===- Strings.cpp -------------------------------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "Strings.h"
-#include "Config.h"
-#include "lld/Common/ErrorHandler.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Demangle/Demangle.h"
-#include <algorithm>
-#include <cstring>
-
-using namespace llvm;
-using namespace lld;
-using namespace lld::elf;
-
-StringMatcher::StringMatcher(ArrayRef<StringRef> Pat) {
- for (StringRef S : Pat) {
- Expected<GlobPattern> Pat = GlobPattern::create(S);
- if (!Pat)
- error(toString(Pat.takeError()));
- else
- Patterns.push_back(*Pat);
- }
-}
-
-bool StringMatcher::match(StringRef S) const {
- for (const GlobPattern &Pat : Patterns)
- if (Pat.match(S))
- return true;
- return false;
-}
-
-// Converts a hex string (e.g. "deadbeef") to a vector.
-std::vector<uint8_t> elf::parseHex(StringRef S) {
- std::vector<uint8_t> Hex;
- while (!S.empty()) {
- StringRef B = S.substr(0, 2);
- S = S.substr(2);
- uint8_t H;
- if (!to_integer(B, H, 16)) {
- error("not a hexadecimal value: " + B);
- return {};
- }
- Hex.push_back(H);
- }
- return Hex;
-}
-
-// Returns true if S is valid as a C language identifier.
-bool elf::isValidCIdentifier(StringRef S) {
- return !S.empty() && (isAlpha(S[0]) || S[0] == '_') &&
- std::all_of(S.begin() + 1, S.end(),
- [](char C) { return C == '_' || isAlnum(C); });
-}
diff --git a/contrib/llvm/tools/lld/ELF/Strings.h b/contrib/llvm/tools/lld/ELF/Strings.h
deleted file mode 100644
index 5009df65f4c1..000000000000
--- a/contrib/llvm/tools/lld/ELF/Strings.h
+++ /dev/null
@@ -1,75 +0,0 @@
-//===- Strings.h ------------------------------------------------*- C++ -*-===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_ELF_STRINGS_H
-#define LLD_ELF_STRINGS_H
-
-#include "lld/Common/LLVM.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/GlobPattern.h"
-#include <vector>
-
-namespace lld {
-namespace elf {
-
-std::vector<uint8_t> parseHex(StringRef S);
-bool isValidCIdentifier(StringRef S);
-
-// This is a lazy version of StringRef. String size is computed lazily
-// when it is needed. It is more efficient than StringRef to instantiate
-// if you have a string whose size is unknown.
-//
-// ELF string tables contain a lot of null-terminated strings.
-// Most of them are not necessary for the linker because they are names
-// of local symbols and the linker doesn't use local symbol names for
-// name resolution. So, we use this class to represents strings read
-// from string tables.
-class StringRefZ {
-public:
- StringRefZ() : Start(nullptr), Size(0) {}
- StringRefZ(const char *S, size_t Size) : Start(S), Size(Size) {}
-
- /*implicit*/ StringRefZ(const char *S) : Start(S), Size(-1) {}
-
- /*implicit*/ StringRefZ(llvm::StringRef S)
- : Start(S.data()), Size(S.size()) {}
-
- operator llvm::StringRef() const {
- if (Size == (size_t)-1)
- Size = strlen(Start);
- return {Start, Size};
- }
-
-private:
- const char *Start;
- mutable size_t Size;
-};
-
-// This class represents multiple glob patterns.
-class StringMatcher {
-public:
- StringMatcher() = default;
- explicit StringMatcher(ArrayRef<StringRef> Pat);
-
- bool match(StringRef S) const;
-
-private:
- std::vector<llvm::GlobPattern> Patterns;
-};
-
-inline ArrayRef<uint8_t> toArrayRef(StringRef S) {
- return {(const uint8_t *)S.data(), S.size()};
-}
-} // namespace elf
-} // namespace lld
-
-#endif
diff --git a/contrib/llvm/tools/lld/ELF/SymbolTable.cpp b/contrib/llvm/tools/lld/ELF/SymbolTable.cpp
index c41e2b2de748..1f5a84ec2c7d 100644
--- a/contrib/llvm/tools/lld/ELF/SymbolTable.cpp
+++ b/contrib/llvm/tools/lld/ELF/SymbolTable.cpp
@@ -38,7 +38,7 @@ static InputFile *getFirstElf() {
return ObjectFiles[0];
if (!SharedFiles.empty())
return SharedFiles[0];
- return nullptr;
+ return BitcodeFiles[0];
}
// All input object files must be for the same architecture
@@ -82,6 +82,7 @@ template <class ELFT> void SymbolTable::addFile(InputFile *File) {
// Lazy object file
if (auto *F = dyn_cast<LazyObjFile>(File)) {
+ LazyObjFiles.push_back(F);
F->parse<ELFT>();
return;
}
@@ -117,7 +118,7 @@ template <class ELFT> void SymbolTable::addFile(InputFile *File) {
// not in native object file format but in the LLVM bitcode format.
// This function compiles bitcode files into a few big native files
// using LLVM functions and replaces bitcode symbols with the results.
-// Because all bitcode files that consist of a program are passed
+// Because all bitcode files that the program consists of are passed
// to the compiler at once, it can do whole-program optimization.
template <class ELFT> void SymbolTable::addCombinedLTOObject() {
if (BitcodeFiles.empty())
@@ -157,6 +158,12 @@ template <class ELFT> void SymbolTable::addSymbolWrap(StringRef Name) {
Symbol *Sym = find(Name);
if (!Sym)
return;
+
+ // Do not wrap the same symbol twice.
+ for (const WrappedSymbol &S : WrappedSymbols)
+ if (S.Sym == Sym)
+ return;
+
Symbol *Real = addUndefined<ELFT>(Saver.save("__real_" + Name));
Symbol *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name));
WrappedSymbols.push_back({Sym, Real, Wrap});
@@ -189,7 +196,7 @@ void SymbolTable::applySymbolWrap() {
// First, make a copy of __real_sym.
Symbol *Real = nullptr;
if (W.Real->isDefined()) {
- Real = (Symbol *)make<SymbolUnion>();
+ Real = reinterpret_cast<Symbol *>(make<SymbolUnion>());
memcpy(Real, W.Real, sizeof(SymbolUnion));
}
@@ -237,8 +244,7 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
Symbol *Sym;
if (IsNew) {
- Sym = (Symbol *)make<SymbolUnion>();
- Sym->InVersionScript = false;
+ Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
Sym->Visibility = STV_DEFAULT;
Sym->IsUsedInRegularObj = false;
Sym->ExportDynamic = false;
@@ -297,26 +303,88 @@ Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding,
uint8_t Visibility = getVisibility(StOther);
std::tie(S, WasInserted) =
insert(Name, Type, Visibility, CanOmitFromDynSym, File);
+
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
if (WasInserted || (isa<SharedSymbol>(S) && Visibility != STV_DEFAULT)) {
replaceSymbol<Undefined>(S, File, Name, Binding, StOther, Type);
return S;
}
+
if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK))
S->Binding = Binding;
- if (Binding != STB_WEAK) {
+
+ if (!Config->GcSections && Binding != STB_WEAK)
if (auto *SS = dyn_cast<SharedSymbol>(S))
- if (!Config->GcSections)
- SS->getFile<ELFT>().IsNeeded = true;
- }
- if (auto *L = dyn_cast<Lazy>(S)) {
+ SS->getFile<ELFT>().IsNeeded = true;
+
+ if (S->isLazy()) {
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
- if (Binding == STB_WEAK)
- L->Type = Type;
- else if (InputFile *F = L->fetch())
- addFile<ELFT>(F);
+ if (Binding == STB_WEAK) {
+ S->Type = Type;
+ return S;
+ }
+
+ // Do extra check for --warn-backrefs.
+ //
+ // --warn-backrefs is an option to prevent an undefined reference from
+ // fetching an archive member written earlier in the command line. It can be
+ // used to keep compatibility with GNU linkers to some degree.
+ // I'll explain the feature and why you may find it useful in this comment.
+ //
+ // lld's symbol resolution semantics is more relaxed than traditional Unix
+ // linkers. For example,
+ //
+ // ld.lld foo.a bar.o
+ //
+ // succeeds even if bar.o contains an undefined symbol that has to be
+ // resolved by some object file in foo.a. Traditional Unix linkers don't
+ // allow this kind of backward reference, as they visit each file only once
+ // from left to right in the command line while resolving all undefined
+ // symbols at the moment of visiting.
+ //
+ // In the above case, since there's no undefined symbol when a linker visits
+ // foo.a, no files are pulled out from foo.a, and because the linker forgets
+ // about foo.a after visiting, it can't resolve undefined symbols in bar.o
+ // that could have been resolved otherwise.
+ //
+ // That lld accepts more relaxed form means that (besides it'd make more
+ // sense) you can accidentally write a command line or a build file that
+ // works only with lld, even if you have a plan to distribute it to wider
+ // users who may be using GNU linkers. With --warn-backrefs, you can detect
+ // a library order that doesn't work with other Unix linkers.
+ //
+ // The option is also useful to detect cyclic dependencies between static
+ // archives. Again, lld accepts
+ //
+ // ld.lld foo.a bar.a
+ //
+ // even if foo.a and bar.a depend on each other. With --warn-backrefs, it is
+ // handled as an error.
+ //
+ // Here is how the option works. We assign a group ID to each file. A file
+ // with a smaller group ID can pull out object files from an archive file
+ // with an equal or greater group ID. Otherwise, it is a reverse dependency
+ // and an error.
+ //
+ // A file outside --{start,end}-group gets a fresh ID when instantiated. All
+ // files within the same --{start,end}-group get the same group ID. E.g.
+ //
+ // ld.lld A B --start-group C D --end-group E
+ //
+ // A forms group 0. B form group 1. C and D (including their member object
+ // files) form group 2. E forms group 3. I think that you can see how this
+ // group assignment rule simulates the traditional linker's semantics.
+ bool Backref =
+ Config->WarnBackrefs && File && S->File->GroupId < File->GroupId;
+ fetchLazy<ELFT>(S);
+
+ // We don't report backward references to weak symbols as they can be
+ // overridden later.
+ if (Backref && S->Binding != STB_WEAK)
+ warn("backward reference detected: " + Name + " in " + toString(File) +
+ " refers to " + toString(S->File));
}
return S;
}
@@ -384,7 +452,11 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
bool WasInserted;
std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, &File);
+
int Cmp = compareDefined(S, WasInserted, Binding, N);
+ if (Cmp < 0)
+ return S;
+
if (Cmp > 0) {
auto *Bss = make<BssSection>("COMMON", Size, Alignment);
Bss->File = &File;
@@ -392,45 +464,43 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
InputSections.push_back(Bss);
replaceSymbol<Defined>(S, &File, N, Binding, StOther, Type, 0, Size, Bss);
- } else if (Cmp == 0) {
- auto *D = cast<Defined>(S);
- auto *Bss = dyn_cast_or_null<BssSection>(D->Section);
- if (!Bss) {
- // Non-common symbols take precedence over common symbols.
- if (Config->WarnCommon)
- warn("common " + S->getName() + " is overridden");
- return S;
- }
+ return S;
+ }
+ auto *D = cast<Defined>(S);
+ auto *Bss = dyn_cast_or_null<BssSection>(D->Section);
+ if (!Bss) {
+ // Non-common symbols take precedence over common symbols.
if (Config->WarnCommon)
- warn("multiple common of " + D->getName());
+ warn("common " + S->getName() + " is overridden");
+ return S;
+ }
- Bss->Alignment = std::max(Bss->Alignment, Alignment);
- if (Size > Bss->Size) {
- D->File = Bss->File = &File;
- D->Size = Bss->Size = Size;
- }
+ if (Config->WarnCommon)
+ warn("multiple common of " + D->getName());
+
+ Bss->Alignment = std::max(Bss->Alignment, Alignment);
+ if (Size > Bss->Size) {
+ D->File = Bss->File = &File;
+ D->Size = Bss->Size = Size;
}
return S;
}
-static void warnOrError(const Twine &Msg) {
- if (Config->AllowMultipleDefinition)
- warn(Msg);
- else
- error(Msg);
-}
-
static void reportDuplicate(Symbol *Sym, InputFile *NewFile) {
- warnOrError("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
- toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
+ if (!Config->AllowMultipleDefinition)
+ error("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
+ toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
}
-static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec,
- uint64_t ErrOffset) {
+static void reportDuplicate(Symbol *Sym, InputFile *NewFile,
+ InputSectionBase *ErrSec, uint64_t ErrOffset) {
+ if (Config->AllowMultipleDefinition)
+ return;
+
Defined *D = cast<Defined>(Sym);
if (!D->Section || !ErrSec) {
- reportDuplicate(Sym, ErrSec ? ErrSec->File : nullptr);
+ reportDuplicate(Sym, NewFile);
return;
}
@@ -454,7 +524,7 @@ static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec,
if (!Src2.empty())
Msg += Src2 + "\n>>> ";
Msg += Obj2;
- warnOrError(Msg);
+ error(Msg);
}
Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
@@ -470,7 +540,8 @@ Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
replaceSymbol<Defined>(S, File, Name, Binding, StOther, Type, Value, Size,
Section);
else if (Cmp == 0)
- reportDuplicate(S, dyn_cast_or_null<InputSectionBase>(Section), Value);
+ reportDuplicate(S, File, dyn_cast_or_null<InputSectionBase>(Section),
+ Value);
return S;
}
@@ -491,8 +562,8 @@ void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File,
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
- if (WasInserted || ((S->isUndefined() || S->isLazy()) &&
- S->getVisibility() == STV_DEFAULT)) {
+ if (WasInserted ||
+ ((S->isUndefined() || S->isLazy()) && S->Visibility == STV_DEFAULT)) {
uint8_t Binding = S->Binding;
bool WasUndefined = S->isUndefined();
replaceSymbol<SharedSymbol>(S, File, Name, Sym.getBinding(), Sym.st_other,
@@ -531,85 +602,58 @@ Symbol *SymbolTable::find(StringRef Name) {
return SymVector[It->second];
}
-template <class ELFT>
-Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F,
- const object::Archive::Symbol Sym) {
+// This is used to handle lazy symbols. May replace existent
+// symbol with lazy version or request to Fetch it.
+template <class ELFT, typename LazyT, typename... ArgT>
+static void replaceOrFetchLazy(StringRef Name, InputFile &File,
+ llvm::function_ref<InputFile *()> Fetch,
+ ArgT &&... Arg) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
+ std::tie(S, WasInserted) = Symtab->insert(Name);
if (WasInserted) {
- replaceSymbol<LazyArchive>(S, F, Sym, Symbol::UnknownType);
- return S;
+ replaceSymbol<LazyT>(S, File, Symbol::UnknownType,
+ std::forward<ArgT>(Arg)...);
+ return;
}
if (!S->isUndefined())
- return S;
+ return;
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
if (S->isWeak()) {
- replaceSymbol<LazyArchive>(S, F, Sym, S->Type);
+ replaceSymbol<LazyT>(S, File, S->Type, std::forward<ArgT>(Arg)...);
S->Binding = STB_WEAK;
- return S;
+ return;
}
- std::pair<MemoryBufferRef, uint64_t> MBInfo = F.getMember(&Sym);
- if (!MBInfo.first.getBuffer().empty())
- addFile<ELFT>(createObjectFile(MBInfo.first, F.getName(), MBInfo.second));
- return S;
+
+ if (InputFile *F = Fetch())
+ Symtab->addFile<ELFT>(F);
}
template <class ELFT>
-void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
- if (WasInserted) {
- replaceSymbol<LazyObject>(S, Obj, Name, Symbol::UnknownType);
- return;
- }
- if (!S->isUndefined())
- return;
-
- // See comment for addLazyArchive above.
- if (S->isWeak())
- replaceSymbol<LazyObject>(S, Obj, Name, S->Type);
- else if (InputFile *F = Obj.fetch())
- addFile<ELFT>(F);
-}
-
-// If we already saw this symbol, force loading its file.
-template <class ELFT> void SymbolTable::fetchIfLazy(StringRef Name) {
- if (Symbol *B = find(Name)) {
- // Mark the symbol not to be eliminated by LTO
- // even if it is a bitcode symbol.
- B->IsUsedInRegularObj = true;
- if (auto *L = dyn_cast<Lazy>(B))
- if (InputFile *File = L->fetch())
- addFile<ELFT>(File);
- }
+void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F,
+ const object::Archive::Symbol Sym) {
+ replaceOrFetchLazy<ELFT, LazyArchive>(Name, F, [&]() { return F.fetch(Sym); },
+ Sym);
}
-// This function takes care of the case in which shared libraries depend on
-// the user program (not the other way, which is usual). Shared libraries
-// may have undefined symbols, expecting that the user program provides
-// the definitions for them. An example is BSD's __progname symbol.
-// We need to put such symbols to the main program's .dynsym so that
-// shared libraries can find them.
-// Except this, we ignore undefined symbols in DSOs.
-template <class ELFT> void SymbolTable::scanShlibUndefined() {
- for (InputFile *F : SharedFiles) {
- for (StringRef U : cast<SharedFile<ELFT>>(F)->getUndefinedSymbols()) {
- Symbol *Sym = find(U);
- if (!Sym || !Sym->isDefined())
- continue;
- Sym->ExportDynamic = true;
+template <class ELFT>
+void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) {
+ replaceOrFetchLazy<ELFT, LazyObject>(Name, Obj, [&]() { return Obj.fetch(); },
+ Name);
+}
- // If -dynamic-list is given, the default version is set to
- // VER_NDX_LOCAL, which prevents a symbol to be exported via .dynsym.
- // Set to VER_NDX_GLOBAL so the symbol will be handled as if it were
- // specified by -dynamic-list.
- Sym->VersionId = VER_NDX_GLOBAL;
- }
+template <class ELFT> void SymbolTable::fetchLazy(Symbol *Sym) {
+ if (auto *S = dyn_cast<LazyArchive>(Sym)) {
+ if (InputFile *File = S->fetch())
+ addFile<ELFT>(File);
+ return;
}
+
+ auto *S = cast<LazyObject>(Sym);
+ if (InputFile *File = cast<LazyObjFile>(S->File)->fetch())
+ addFile<ELFT>(File);
}
// Initialize DemangledSyms with a map from demangled symbols to symbol
@@ -708,7 +752,7 @@ void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
// Get a list of symbols which we need to assign the version to.
std::vector<Symbol *> Syms = findByVersion(Ver);
if (Syms.empty()) {
- if (Config->NoUndefinedVersion)
+ if (!Config->UndefinedVersion)
error("version script assignment of '" + VersionName + "' to symbol '" +
Ver.Name + "' failed: symbol not defined");
return;
@@ -722,10 +766,10 @@ void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
if (Sym->getName().contains('@'))
continue;
- if (Sym->InVersionScript)
- warn("duplicate symbol '" + Ver.Name + "' in version script");
+ if (Sym->VersionId != Config->DefaultSymbolVersion &&
+ Sym->VersionId != VersionId)
+ error("duplicate symbol '" + Ver.Name + "' in version script");
Sym->VersionId = VersionId;
- Sym->InVersionScript = true;
}
}
@@ -773,6 +817,11 @@ void SymbolTable::scanVersionScript() {
Sym->parseSymbolVersion();
}
+template void SymbolTable::addFile<ELF32LE>(InputFile *);
+template void SymbolTable::addFile<ELF32BE>(InputFile *);
+template void SymbolTable::addFile<ELF64LE>(InputFile *);
+template void SymbolTable::addFile<ELF64BE>(InputFile *);
+
template void SymbolTable::addSymbolWrap<ELF32LE>(StringRef);
template void SymbolTable::addSymbolWrap<ELF32BE>(StringRef);
template void SymbolTable::addSymbolWrap<ELF64LE>(StringRef);
@@ -797,16 +846,16 @@ template void SymbolTable::addCombinedLTOObject<ELF32BE>();
template void SymbolTable::addCombinedLTOObject<ELF64LE>();
template void SymbolTable::addCombinedLTOObject<ELF64BE>();
-template Symbol *
+template void
SymbolTable::addLazyArchive<ELF32LE>(StringRef, ArchiveFile &,
const object::Archive::Symbol);
-template Symbol *
+template void
SymbolTable::addLazyArchive<ELF32BE>(StringRef, ArchiveFile &,
const object::Archive::Symbol);
-template Symbol *
+template void
SymbolTable::addLazyArchive<ELF64LE>(StringRef, ArchiveFile &,
const object::Archive::Symbol);
-template Symbol *
+template void
SymbolTable::addLazyArchive<ELF64BE>(StringRef, ArchiveFile &,
const object::Archive::Symbol);
@@ -815,6 +864,11 @@ template void SymbolTable::addLazyObject<ELF32BE>(StringRef, LazyObjFile &);
template void SymbolTable::addLazyObject<ELF64LE>(StringRef, LazyObjFile &);
template void SymbolTable::addLazyObject<ELF64BE>(StringRef, LazyObjFile &);
+template void SymbolTable::fetchLazy<ELF32LE>(Symbol *);
+template void SymbolTable::fetchLazy<ELF32BE>(Symbol *);
+template void SymbolTable::fetchLazy<ELF64LE>(Symbol *);
+template void SymbolTable::fetchLazy<ELF64BE>(Symbol *);
+
template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile<ELF32LE> &,
const typename ELF32LE::Sym &,
uint32_t Alignment, uint32_t);
@@ -827,13 +881,3 @@ template void SymbolTable::addShared<ELF64LE>(StringRef, SharedFile<ELF64LE> &,
template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile<ELF64BE> &,
const typename ELF64BE::Sym &,
uint32_t Alignment, uint32_t);
-
-template void SymbolTable::fetchIfLazy<ELF32LE>(StringRef);
-template void SymbolTable::fetchIfLazy<ELF32BE>(StringRef);
-template void SymbolTable::fetchIfLazy<ELF64LE>(StringRef);
-template void SymbolTable::fetchIfLazy<ELF64BE>(StringRef);
-
-template void SymbolTable::scanShlibUndefined<ELF32LE>();
-template void SymbolTable::scanShlibUndefined<ELF32BE>();
-template void SymbolTable::scanShlibUndefined<ELF64LE>();
-template void SymbolTable::scanShlibUndefined<ELF64BE>();
diff --git a/contrib/llvm/tools/lld/ELF/SymbolTable.h b/contrib/llvm/tools/lld/ELF/SymbolTable.h
index e7341b05baf5..5e6d44dfe4f9 100644
--- a/contrib/llvm/tools/lld/ELF/SymbolTable.h
+++ b/contrib/llvm/tools/lld/ELF/SymbolTable.h
@@ -12,7 +12,7 @@
#include "InputFiles.h"
#include "LTO.h"
-#include "Strings.h"
+#include "lld/Common/Strings.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseMap.h"
@@ -60,8 +60,8 @@ public:
uint32_t VerdefIndex);
template <class ELFT>
- Symbol *addLazyArchive(StringRef Name, ArchiveFile &F,
- const llvm::object::Archive::Symbol S);
+ void addLazyArchive(StringRef Name, ArchiveFile &F,
+ const llvm::object::Archive::Symbol S);
template <class ELFT> void addLazyObject(StringRef Name, LazyObjFile &Obj);
@@ -77,8 +77,8 @@ public:
uint8_t Visibility, bool CanOmitFromDynSym,
InputFile *File);
- template <class ELFT> void fetchIfLazy(StringRef Name);
- template <class ELFT> void scanShlibUndefined();
+ template <class ELFT> void fetchLazy(Symbol *Sym);
+
void scanVersionScript();
Symbol *find(StringRef Name);
@@ -90,7 +90,6 @@ public:
private:
std::vector<Symbol *> findByVersion(SymbolVersion Ver);
std::vector<Symbol *> findAllByVersion(SymbolVersion Ver);
- void defsym(Symbol *Dst, Symbol *Src);
llvm::StringMap<std::vector<Symbol *>> &getDemangledSyms();
void handleAnonymousVersion();
diff --git a/contrib/llvm/tools/lld/ELF/Symbols.cpp b/contrib/llvm/tools/lld/ELF/Symbols.cpp
index 13a91aab80bb..4243cb1e80ef 100644
--- a/contrib/llvm/tools/lld/ELF/Symbols.cpp
+++ b/contrib/llvm/tools/lld/ELF/Symbols.cpp
@@ -14,7 +14,6 @@
#include "SyntheticSections.h"
#include "Target.h"
#include "Writer.h"
-
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
@@ -39,6 +38,7 @@ Defined *ElfSym::GlobalOffsetTable;
Defined *ElfSym::MipsGp;
Defined *ElfSym::MipsGpDisp;
Defined *ElfSym::MipsLocalGp;
+Defined *ElfSym::RelaIpltEnd;
static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
switch (Sym.kind()) {
@@ -58,6 +58,7 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
return D.Value;
IS = IS->Repl;
+
uint64_t Offset = D.Value;
// An object in an SHF_MERGE section might be referenced via a
@@ -76,8 +77,6 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
Addend = 0;
}
- const OutputSection *OutSec = IS->getOutputSection();
-
// In the typical case, this is actually very simple and boils
// down to adding together 3 numbers:
// 1. The address of the output section.
@@ -88,7 +87,7 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
// If you understand the data structures involved with this next
// line (and how they get built), then you have a pretty good
// understanding of the linker.
- uint64_t VA = (OutSec ? OutSec->Addr : 0) + IS->getOffset(Offset);
+ uint64_t VA = IS->getVA(Offset);
if (D.isTls() && !Config->Relocatable) {
if (!Out::TlsPhdr)
@@ -98,20 +97,12 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
}
return VA;
}
- case Symbol::SharedKind: {
- auto &SS = cast<SharedSymbol>(Sym);
- if (SS.CopyRelSec)
- return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff;
- if (SS.NeedsPltAddr)
- return Sym.getPltVA();
- return 0;
- }
+ case Symbol::SharedKind:
case Symbol::UndefinedKind:
return 0;
case Symbol::LazyArchiveKind:
case Symbol::LazyObjectKind:
- assert(Sym.IsUsedInRegularObj && "lazy symbol reached writer");
- return 0;
+ llvm_unreachable("lazy symbol reached writer");
}
llvm_unreachable("invalid symbol kind");
}
@@ -134,22 +125,26 @@ uint64_t Symbol::getGotPltVA() const {
}
uint64_t Symbol::getGotPltOffset() const {
- return GotPltIndex * Target->GotPltEntrySize;
+ if (IsInIgot)
+ return PltIndex * Target->GotPltEntrySize;
+ return (PltIndex + Target->GotPltHeaderEntriesNum) * Target->GotPltEntrySize;
}
uint64_t Symbol::getPltVA() const {
if (this->IsInIplt)
return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize;
- return InX::Plt->getVA() + Target->PltHeaderSize +
- PltIndex * Target->PltEntrySize;
+ return InX::Plt->getVA() + Target->getPltEntryOffset(PltIndex);
+}
+
+uint64_t Symbol::getPltOffset() const {
+ assert(!this->IsInIplt);
+ return Target->getPltEntryOffset(PltIndex);
}
uint64_t Symbol::getSize() const {
if (const auto *DR = dyn_cast<Defined>(this))
return DR->Size;
- if (const auto *S = dyn_cast<SharedSymbol>(this))
- return S->Size;
- return 0;
+ return cast<SharedSymbol>(this)->Size;
}
OutputSection *Symbol::getOutputSection() const {
@@ -158,13 +153,6 @@ OutputSection *Symbol::getOutputSection() const {
return Sec->Repl->getOutputSection();
return nullptr;
}
-
- if (auto *S = dyn_cast<SharedSymbol>(this)) {
- if (S->CopyRelSec)
- return S->CopyRelSec->getParent();
- return nullptr;
- }
-
return nullptr;
}
@@ -180,7 +168,7 @@ void Symbol::parseSymbolVersion() {
return;
// Truncate the symbol name so that it doesn't include the version string.
- Name = {S.data(), Pos};
+ NameSize = Pos;
// If this is not in this DSO, it is not a definition.
if (!isDefined())
@@ -206,33 +194,15 @@ void Symbol::parseSymbolVersion() {
// It is an error if the specified version is not defined.
// Usually version script is not provided when linking executable,
// but we may still want to override a versioned symbol from DSO,
- // so we do not report error in this case.
- if (Config->Shared)
+ // so we do not report error in this case. We also do not error
+ // if the symbol has a local version as it won't be in the dynamic
+ // symbol table.
+ if (Config->Shared && VersionId != VER_NDX_LOCAL)
error(toString(File) + ": symbol " + S + " has undefined version " +
Verstr);
}
-InputFile *Lazy::fetch() {
- if (auto *S = dyn_cast<LazyArchive>(this))
- return S->fetch();
- return cast<LazyObject>(this)->fetch();
-}
-
-ArchiveFile &LazyArchive::getFile() { return *cast<ArchiveFile>(File); }
-
-InputFile *LazyArchive::fetch() {
- std::pair<MemoryBufferRef, uint64_t> MBInfo = getFile().getMember(&Sym);
-
- // getMember returns an empty buffer if the member was already
- // read from the library.
- if (MBInfo.first.getBuffer().empty())
- return nullptr;
- return createObjectFile(MBInfo.first, getFile().getName(), MBInfo.second);
-}
-
-LazyObjFile &LazyObject::getFile() { return *cast<LazyObjFile>(File); }
-
-InputFile *LazyObject::fetch() { return getFile().fetch(); }
+InputFile *LazyArchive::fetch() { return cast<ArchiveFile>(File)->fetch(Sym); }
uint8_t Symbol::computeBinding() const {
if (Config->Relocatable)
@@ -241,7 +211,7 @@ uint8_t Symbol::computeBinding() const {
return STB_LOCAL;
if (VersionId == VER_NDX_LOCAL && isDefined())
return STB_LOCAL;
- if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE)
+ if (!Config->GnuUnique && Binding == STB_GNU_UNIQUE)
return STB_GLOBAL;
return Binding;
}
@@ -273,6 +243,27 @@ void elf::printTraceSymbol(Symbol *Sym) {
message(toString(Sym->File) + S + Sym->getName());
}
+void elf::warnUnorderableSymbol(const Symbol *Sym) {
+ if (!Config->WarnSymbolOrdering)
+ return;
+
+ const InputFile *File = Sym->File;
+ auto *D = dyn_cast<Defined>(Sym);
+
+ auto Warn = [&](StringRef S) { warn(toString(File) + S + Sym->getName()); };
+
+ if (Sym->isUndefined())
+ Warn(": unable to order undefined symbol: ");
+ else if (Sym->isShared())
+ Warn(": unable to order shared symbol: ");
+ else if (D && !D->Section)
+ Warn(": unable to order absolute symbol: ");
+ else if (D && isa<OutputSection>(D->Section))
+ Warn(": unable to order synthetic symbol: ");
+ else if (D && !D->Section->Repl->Live)
+ Warn(": unable to order discarded symbol: ");
+}
+
// Returns a symbol for an error message.
std::string lld::toString(const Symbol &B) {
if (Config->Demangle)
diff --git a/contrib/llvm/tools/lld/ELF/Symbols.h b/contrib/llvm/tools/lld/ELF/Symbols.h
index 9b7207383345..8c9513b9368b 100644
--- a/contrib/llvm/tools/lld/ELF/Symbols.h
+++ b/contrib/llvm/tools/lld/ELF/Symbols.h
@@ -7,8 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// All symbols are handled as SymbolBodies regardless of their types.
-// This file defines various types of SymbolBodies.
+// This file defines various types of Symbols.
//
//===----------------------------------------------------------------------===//
@@ -16,9 +15,8 @@
#define LLD_ELF_SYMBOLS_H
#include "InputSection.h"
-#include "Strings.h"
-
#include "lld/Common/LLVM.h"
+#include "lld/Common/Strings.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ELF.h"
@@ -34,6 +32,20 @@ template <class ELFT> class ObjFile;
class OutputSection;
template <class ELFT> class SharedFile;
+// This is a StringRef-like container that doesn't run strlen().
+//
+// ELF string tables contain a lot of null-terminated strings. Most of them
+// are not necessary for the linker because they are names of local symbols,
+// and the linker doesn't use local symbol names for name resolution. So, we
+// use this class to represents strings read from string tables.
+struct StringRefZ {
+ StringRefZ(const char *S) : Data(S), Size(-1) {}
+ StringRefZ(StringRef S) : Data(S.data()), Size(S.size()) {}
+
+ const char *Data;
+ const uint32_t Size;
+};
+
// The base class for real symbol classes.
class Symbol {
public:
@@ -47,6 +59,25 @@ public:
Kind kind() const { return static_cast<Kind>(SymbolKind); }
+ // The file from which this symbol was created.
+ InputFile *File;
+
+protected:
+ const char *NameData;
+ mutable uint32_t NameSize;
+
+public:
+ uint32_t DynsymIndex = 0;
+ uint32_t GotIndex = -1;
+ uint32_t PltIndex = -1;
+ uint32_t GlobalDynIndex = -1;
+
+ // This field is a index to the symbol's version definition.
+ uint32_t VerdefIndex = -1;
+
+ // Version definition index.
+ uint16_t VersionId;
+
// Symbol binding. This is not overwritten by replaceSymbol to track
// changes during resolution. In particular:
// - An undefined weak is still weak when it resolves to a shared library.
@@ -54,8 +85,11 @@ public:
// remember it is weak.
uint8_t Binding;
- // Version definition index.
- uint16_t VersionId;
+ // The following fields have the same meaning as the ELF symbol attributes.
+ uint8_t Type; // symbol type
+ uint8_t StOther; // st_other field value
+
+ const uint8_t SymbolKind;
// Symbol visibility. This is the computed minimum visibility of all
// observed non-DSO symbols.
@@ -81,12 +115,6 @@ public:
// True if this symbol is specified by --trace-symbol option.
unsigned Traced : 1;
- // This symbol version was found in a version script.
- unsigned InVersionScript : 1;
-
- // The file from which this symbol was created.
- InputFile *File;
-
bool includeInDynsym() const;
uint8_t computeBinding() const;
bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
@@ -100,15 +128,15 @@ public:
return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
}
- // True is this is an undefined weak symbol. This only works once
- // all input files have been added.
- bool isUndefWeak() const {
- // See comment on Lazy the details.
- return isWeak() && (isUndefined() || isLazy());
+ // True if this is an undefined weak symbol.
+ bool isUndefWeak() const { return isWeak() && isUndefined(); }
+
+ StringRef getName() const {
+ if (NameSize == (uint32_t)-1)
+ NameSize = strlen(NameData);
+ return {NameData, NameSize};
}
- StringRef getName() const { return Name; }
- uint8_t getVisibility() const { return StOther & 0x3; }
void parseSymbolVersion();
bool isInGot() const { return GotIndex != -1U; }
@@ -121,34 +149,22 @@ public:
uint64_t getGotPltOffset() const;
uint64_t getGotPltVA() const;
uint64_t getPltVA() const;
+ uint64_t getPltOffset() const;
uint64_t getSize() const;
OutputSection *getOutputSection() const;
- uint32_t DynsymIndex = 0;
- uint32_t GotIndex = -1;
- uint32_t GotPltIndex = -1;
- uint32_t PltIndex = -1;
- uint32_t GlobalDynIndex = -1;
-
protected:
Symbol(Kind K, InputFile *File, StringRefZ Name, uint8_t Binding,
uint8_t StOther, uint8_t Type)
- : Binding(Binding), File(File), SymbolKind(K), NeedsPltAddr(false),
- IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false),
- IsInIgot(false), IsPreemptible(false), Used(!Config->GcSections),
- Type(Type), StOther(StOther), Name(Name) {}
-
- const unsigned SymbolKind : 8;
+ : File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding),
+ Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false),
+ IsInIplt(false), IsInIgot(false), IsPreemptible(false),
+ Used(!Config->GcSections), NeedsTocRestore(false) {}
public:
// True the symbol should point to its PLT entry.
// For SharedSymbol only.
unsigned NeedsPltAddr : 1;
- // True if this symbol has an entry in the global part of MIPS GOT.
- unsigned IsInGlobalMipsGot : 1;
-
- // True if this symbol is referenced by 32-bit GOT relocations.
- unsigned Is32BitMipsGot : 1;
// True if this symbol is in the Iplt sub-section of the Plt.
unsigned IsInIplt : 1;
@@ -156,14 +172,15 @@ public:
// True if this symbol is in the Igot sub-section of the .got.plt or .got.
unsigned IsInIgot : 1;
+ // True if this symbol is preemptible at load time.
unsigned IsPreemptible : 1;
// True if an undefined or shared symbol is used from a live section.
unsigned Used : 1;
- // The following fields have the same meaning as the ELF symbol attributes.
- uint8_t Type; // symbol type
- uint8_t StOther; // st_other field value
+ // True if a call to this symbol needs to be followed by a restore of the
+ // PPC64 toc pointer.
+ unsigned NeedsTocRestore : 1;
// The Type field may also have this value. It means that we have not yet seen
// a non-Lazy symbol with this name, so we don't know what its type is. The
@@ -178,9 +195,6 @@ public:
bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; }
bool isObject() const { return Type == llvm::ELF::STT_OBJECT; }
bool isFile() const { return Type == llvm::ELF::STT_FILE; }
-
-protected:
- StringRefZ Name;
};
// Represents a symbol that is defined in the current output file.
@@ -214,8 +228,9 @@ public:
SharedSymbol(InputFile &File, StringRef Name, uint8_t Binding,
uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size,
uint32_t Alignment, uint32_t VerdefIndex)
- : Symbol(SharedKind, &File, Name, Binding, StOther, Type), Value(Value),
- Size(Size), VerdefIndex(VerdefIndex), Alignment(Alignment) {
+ : Symbol(SharedKind, &File, Name, Binding, StOther, Type),
+ Alignment(Alignment), Value(Value), Size(Size) {
+ this->VerdefIndex = VerdefIndex;
// GNU ifunc is a mechanism to allow user-supplied functions to
// resolve PLT slot values at load-time. This is contrary to the
// regular symbol resolution scheme in which symbols are resolved just
@@ -240,54 +255,36 @@ public:
return *cast<SharedFile<ELFT>>(File);
}
- // If not null, there is a copy relocation to this section.
- InputSection *CopyRelSec = nullptr;
+ uint32_t Alignment;
uint64_t Value; // st_value
uint64_t Size; // st_size
-
- // This field is a index to the symbol's version definition.
- uint32_t VerdefIndex;
-
- uint32_t Alignment;
};
-// This represents a symbol that is not yet in the link, but we know where to
-// find it if needed. If the resolver finds both Undefined and Lazy for the same
-// name, it will ask the Lazy to load a file.
+// LazyArchive and LazyObject represent a symbols that is not yet in the link,
+// but we know where to find it if needed. If the resolver finds both Undefined
+// and Lazy for the same name, it will ask the Lazy to load a file.
//
// A special complication is the handling of weak undefined symbols. They should
// not load a file, but we have to remember we have seen both the weak undefined
// and the lazy. We represent that with a lazy symbol with a weak binding. This
// means that code looking for undefined symbols normally also has to take lazy
// symbols into consideration.
-class Lazy : public Symbol {
-public:
- static bool classof(const Symbol *S) { return S->isLazy(); }
-
- // Returns an object file for this symbol, or a nullptr if the file
- // was already returned.
- InputFile *fetch();
-
-protected:
- Lazy(Kind K, InputFile &File, StringRef Name, uint8_t Type)
- : Symbol(K, &File, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT,
- Type) {}
-};
// This class represents a symbol defined in an archive file. It is
// created from an archive file header, and it knows how to load an
// object file from an archive to replace itself with a defined
// symbol.
-class LazyArchive : public Lazy {
+class LazyArchive : public Symbol {
public:
- LazyArchive(InputFile &File, const llvm::object::Archive::Symbol S,
- uint8_t Type)
- : Lazy(LazyArchiveKind, File, S.getName(), Type), Sym(S) {}
+ LazyArchive(InputFile &File, uint8_t Type,
+ const llvm::object::Archive::Symbol S)
+ : Symbol(LazyArchiveKind, &File, S.getName(), llvm::ELF::STB_GLOBAL,
+ llvm::ELF::STV_DEFAULT, Type),
+ Sym(S) {}
static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; }
- ArchiveFile &getFile();
InputFile *fetch();
private:
@@ -296,15 +293,13 @@ private:
// LazyObject symbols represents symbols in object files between
// --start-lib and --end-lib options.
-class LazyObject : public Lazy {
+class LazyObject : public Symbol {
public:
- LazyObject(InputFile &File, StringRef Name, uint8_t Type)
- : Lazy(LazyObjectKind, File, Name, Type) {}
+ LazyObject(InputFile &File, uint8_t Type, StringRef Name)
+ : Symbol(LazyObjectKind, &File, Name, llvm::ELF::STB_GLOBAL,
+ llvm::ELF::STV_DEFAULT, Type) {}
static bool classof(const Symbol *S) { return S->kind() == LazyObjectKind; }
-
- LazyObjFile &getFile();
- InputFile *fetch();
};
// Some linker-generated symbols need to be created as
@@ -334,6 +329,9 @@ struct ElfSym {
static Defined *MipsGp;
static Defined *MipsGpDisp;
static Defined *MipsLocalGp;
+
+ // __rela_iplt_end or __rel_iplt_end
+ static Defined *RelaIpltEnd;
};
// A buffer class that is large enough to hold any Symbol-derived
@@ -351,6 +349,8 @@ void printTraceSymbol(Symbol *Sym);
template <typename T, typename... ArgT>
void replaceSymbol(Symbol *S, ArgT &&... Arg) {
+ static_assert(std::is_trivially_destructible<T>(),
+ "Symbol types must be trivially destructible");
static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
static_assert(alignof(T) <= alignof(SymbolUnion),
"SymbolUnion not aligned enough");
@@ -367,13 +367,14 @@ void replaceSymbol(Symbol *S, ArgT &&... Arg) {
S->ExportDynamic = Sym.ExportDynamic;
S->CanInline = Sym.CanInline;
S->Traced = Sym.Traced;
- S->InVersionScript = Sym.InVersionScript;
// Print out a log message if --trace-symbol was specified.
// This is for debugging.
if (S->Traced)
printTraceSymbol(S);
}
+
+void warnUnorderableSymbol(const Symbol *Sym);
} // namespace elf
std::string toString(const elf::Symbol &B);
diff --git a/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp b/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
index a5a851f95400..ae02434572c2 100644
--- a/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
+++ b/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
@@ -20,15 +20,16 @@
#include "InputFiles.h"
#include "LinkerScript.h"
#include "OutputSections.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "Target.h"
#include "Writer.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "lld/Common/Version.h"
+#include "llvm/ADT/SetOperations.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
#include "llvm/Object/Decompressor.h"
@@ -47,27 +48,20 @@ using namespace llvm::dwarf;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support;
-using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
-constexpr size_t MergeNoTailSection::NumShards;
-
-static void write32(void *Buf, uint32_t Val) {
- endian::write32(Buf, Val, Config->Endianness);
-}
+using llvm::support::endian::read32le;
+using llvm::support::endian::write32le;
+using llvm::support::endian::write64le;
-uint64_t SyntheticSection::getVA() const {
- if (OutputSection *Sec = getParent())
- return Sec->Addr + OutSecOff;
- return 0;
-}
+constexpr size_t MergeNoTailSection::NumShards;
// Returns an LLD version string.
static ArrayRef<uint8_t> getVersion() {
// Check LLD_VERSION first for ease of testing.
- // You can get consitent output by using the environment variable.
+ // You can get consistent output by using the environment variable.
// This is only for testing.
StringRef S = getenv("LLD_VERSION");
if (S.empty())
@@ -192,8 +186,6 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
auto *Opt = reinterpret_cast<const Elf_Mips_Options *>(D.data());
if (Opt->kind == ODK_REGINFO) {
- if (Config->Relocatable && Opt->getRegInfo().ri_gp_value)
- error(Filename + ": unsupported non-zero ri_gp_value");
Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask;
Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value;
break;
@@ -244,10 +236,8 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
error(toString(Sec->File) + ": invalid size of .reginfo section");
return nullptr;
}
- auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data());
- if (Config->Relocatable && R->ri_gp_value)
- error(toString(Sec->File) + ": unsupported non-zero ri_gp_value");
+ auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data());
Reginfo.ri_gprmask |= R->ri_gprmask;
Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value;
};
@@ -266,8 +256,8 @@ InputSection *elf::createInterpSection() {
return Sec;
}
-Symbol *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
- uint64_t Size, InputSectionBase &Section) {
+Defined *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
+ uint64_t Size, InputSectionBase &Section) {
auto *S = make<Defined>(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type,
Value, Size, &Section);
if (InX::SymTab)
@@ -338,8 +328,6 @@ void BuildIdSection::computeHash(
BssSection::BssSection(StringRef Name, uint64_t Size, uint32_t Alignment)
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, Alignment, Name) {
this->Bss = true;
- if (OutputSection *Sec = getParent())
- Sec->Alignment = std::max(Sec->Alignment, Alignment);
this->Size = Size;
}
@@ -347,7 +335,7 @@ void BuildIdSection::writeBuildId(ArrayRef<uint8_t> Buf) {
switch (Config->BuildId) {
case BuildIdKind::Fast:
computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
- write64le(Dest, xxHash64(toStringRef(Arr)));
+ write64le(Dest, xxHash64(Arr));
});
break;
case BuildIdKind::Md5:
@@ -380,15 +368,11 @@ EhFrameSection::EhFrameSection()
// and where their relocations point to.
template <class ELFT, class RelTy>
CieRecord *EhFrameSection::addCie(EhSectionPiece &Cie, ArrayRef<RelTy> Rels) {
- auto *Sec = cast<EhInputSection>(Cie.Sec);
- if (read32(Cie.data().data() + 4, Config->Endianness) != 0)
- fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame");
-
Symbol *Personality = nullptr;
unsigned FirstRelI = Cie.FirstRelocation;
if (FirstRelI != (unsigned)-1)
Personality =
- &Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]);
+ &Cie.Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]);
// Search for an existing CIE by CIE contents/relocation target pair.
CieRecord *&Rec = CieMap[{Cie.data(), Personality}];
@@ -433,14 +417,14 @@ bool EhFrameSection::isFdeLive(EhSectionPiece &Fde, ArrayRef<RelTy> Rels) {
// one and associates FDEs to the CIE.
template <class ELFT, class RelTy>
void EhFrameSection::addSectionAux(EhInputSection *Sec, ArrayRef<RelTy> Rels) {
- DenseMap<size_t, CieRecord *> OffsetToCie;
+ OffsetToCie.clear();
for (EhSectionPiece &Piece : Sec->Pieces) {
// The empty record is the end marker.
if (Piece.Size == 4)
return;
size_t Offset = Piece.InputOff;
- uint32_t ID = read32(Piece.data().data() + 4, Config->Endianness);
+ uint32_t ID = read32(Piece.data().data() + 4);
if (ID == 0) {
OffsetToCie[Offset] = addCie<ELFT>(Piece, Rels);
continue;
@@ -468,10 +452,6 @@ template <class ELFT> void EhFrameSection::addSection(InputSectionBase *C) {
for (auto *DS : Sec->DependentSections)
DependentSections.push_back(DS);
- // .eh_frame is a sequence of CIE or FDE records. This function
- // splits it into pieces so that we can call
- // SplitInputSection::getSectionPiece on the section.
- Sec->split<ELFT>();
if (Sec->Pieces.empty())
return;
@@ -494,9 +474,7 @@ static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
}
void EhFrameSection::finalizeContents() {
- if (this->Size)
- return; // Already finalized.
-
+ assert(!this->Size); // Not finalized.
size_t Off = 0;
for (CieRecord *Rec : CieRecords) {
Rec->Cie->OutputOff = Off;
@@ -509,10 +487,10 @@ void EhFrameSection::finalizeContents() {
}
// The LSB standard does not allow a .eh_frame section with zero
- // Call Frame Information records. Therefore add a CIE record length
- // 0 as a terminator if this .eh_frame section is empty.
- if (Off == 0)
- Off = 4;
+ // Call Frame Information records. glibc unwind-dw2-fde.c
+ // classify_object_over_fdes expects there is a CIE record length 0 as a
+ // terminator. Thus we add one unconditionally.
+ Off += 4;
this->Size = Off;
}
@@ -524,25 +502,47 @@ std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const {
uint8_t *Buf = getParent()->Loc + OutSecOff;
std::vector<FdeData> Ret;
+ uint64_t VA = InX::EhFrameHdr->getVA();
for (CieRecord *Rec : CieRecords) {
uint8_t Enc = getFdeEncoding(Rec->Cie);
for (EhSectionPiece *Fde : Rec->Fdes) {
- uint32_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
- uint32_t FdeVA = getParent()->Addr + Fde->OutputOff;
- Ret.push_back({Pc, FdeVA});
+ uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
+ uint64_t FdeVA = getParent()->Addr + Fde->OutputOff;
+ if (!isInt<32>(Pc - VA))
+ fatal(toString(Fde->Sec) + ": PC offset is too large: 0x" +
+ Twine::utohexstr(Pc - VA));
+ Ret.push_back({uint32_t(Pc - VA), uint32_t(FdeVA - VA)});
}
}
+
+ // Sort the FDE list by their PC and uniqueify. Usually there is only
+ // one FDE for a PC (i.e. function), but if ICF merges two functions
+ // into one, there can be more than one FDEs pointing to the address.
+ auto Less = [](const FdeData &A, const FdeData &B) {
+ return A.PcRel < B.PcRel;
+ };
+ std::stable_sort(Ret.begin(), Ret.end(), Less);
+ auto Eq = [](const FdeData &A, const FdeData &B) {
+ return A.PcRel == B.PcRel;
+ };
+ Ret.erase(std::unique(Ret.begin(), Ret.end(), Eq), Ret.end());
+
return Ret;
}
static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
switch (Size) {
case DW_EH_PE_udata2:
- return read16(Buf, Config->Endianness);
+ return read16(Buf);
+ case DW_EH_PE_sdata2:
+ return (int16_t)read16(Buf);
case DW_EH_PE_udata4:
- return read32(Buf, Config->Endianness);
+ return read32(Buf);
+ case DW_EH_PE_sdata4:
+ return (int32_t)read32(Buf);
case DW_EH_PE_udata8:
- return read64(Buf, Config->Endianness);
+ case DW_EH_PE_sdata8:
+ return read64(Buf);
case DW_EH_PE_absptr:
return readUint(Buf);
}
@@ -556,7 +556,7 @@ uint64_t EhFrameSection::getFdePc(uint8_t *Buf, size_t FdeOff,
// The starting address to which this FDE applies is
// stored at FDE + 8 byte.
size_t Off = FdeOff + 8;
- uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0x7);
+ uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0xf);
if ((Enc & 0x70) == DW_EH_PE_absptr)
return Addr;
if ((Enc & 0x70) == DW_EH_PE_pcrel)
@@ -589,7 +589,15 @@ void EhFrameSection::writeTo(uint8_t *Buf) {
GotSection::GotSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotEntrySize, ".got") {}
+ Target->GotEntrySize, ".got") {
+ // PPC64 saves the ElfSym::GlobalOffsetTable .TOC. as the first entry in the
+ // .got. If there are no references to .TOC. in the symbol table,
+ // ElfSym::GlobalOffsetTable will not be defined and we won't need to save
+ // .TOC. in the .got. When it is defined, we increase NumEntries by the number
+ // of entries used to emit ElfSym::GlobalOffsetTable.
+ if (ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt)
+ NumEntries += Target->GotHeaderEntriesNum;
+}
void GotSection::addEntry(Symbol &Sym) {
Sym.GotIndex = NumEntries;
@@ -623,196 +631,383 @@ uint64_t GotSection::getGlobalDynOffset(const Symbol &B) const {
return B.GlobalDynIndex * Config->Wordsize;
}
-void GotSection::finalizeContents() { Size = NumEntries * Config->Wordsize; }
+void GotSection::finalizeContents() {
+ Size = NumEntries * Config->Wordsize;
+}
bool GotSection::empty() const {
// We need to emit a GOT even if it's empty if there's a relocation that is
// relative to GOT(such as GOTOFFREL) or there's a symbol that points to a GOT
- // (i.e. _GLOBAL_OFFSET_TABLE_).
- return NumEntries == 0 && !HasGotOffRel && !ElfSym::GlobalOffsetTable;
+ // (i.e. _GLOBAL_OFFSET_TABLE_) that the target defines relative to the .got.
+ return NumEntries == 0 && !HasGotOffRel &&
+ !(ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt);
}
void GotSection::writeTo(uint8_t *Buf) {
// Buf points to the start of this section's buffer,
// whereas InputSectionBase::relocateAlloc() expects its argument
// to point to the start of the output section.
+ Target->writeGotHeader(Buf);
relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size);
}
+static uint64_t getMipsPageAddr(uint64_t Addr) {
+ return (Addr + 0x8000) & ~0xffff;
+}
+
+static uint64_t getMipsPageCount(uint64_t Size) {
+ return (Size + 0xfffe) / 0xffff + 1;
+}
+
MipsGotSection::MipsGotSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16,
".got") {}
-void MipsGotSection::addEntry(Symbol &Sym, int64_t Addend, RelExpr Expr) {
- // For "true" local symbols which can be referenced from the same module
- // only compiler creates two instructions for address loading:
- //
- // lw $8, 0($gp) # R_MIPS_GOT16
- // addi $8, $8, 0 # R_MIPS_LO16
- //
- // The first instruction loads high 16 bits of the symbol address while
- // the second adds an offset. That allows to reduce number of required
- // GOT entries because only one global offset table entry is necessary
- // for every 64 KBytes of local data. So for local symbols we need to
- // allocate number of GOT entries to hold all required "page" addresses.
- //
- // All global symbols (hidden and regular) considered by compiler uniformly.
- // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation
- // to load address of the symbol. So for each such symbol we need to
- // allocate dedicated GOT entry to store its address.
- //
- // If a symbol is preemptible we need help of dynamic linker to get its
- // final address. The corresponding GOT entries are allocated in the
- // "global" part of GOT. Entries for non preemptible global symbol allocated
- // in the "local" part of GOT.
- //
- // See "Global Offset Table" in Chapter 5:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+void MipsGotSection::addEntry(InputFile &File, Symbol &Sym, int64_t Addend,
+ RelExpr Expr) {
+ FileGot &G = getGot(File);
if (Expr == R_MIPS_GOT_LOCAL_PAGE) {
- // At this point we do not know final symbol value so to reduce number
- // of allocated GOT entries do the following trick. Save all output
- // sections referenced by GOT relocations. Then later in the `finalize`
- // method calculate number of "pages" required to cover all saved output
- // section and allocate appropriate number of GOT entries.
- PageIndexMap.insert({Sym.getOutputSection(), 0});
- return;
- }
- if (Sym.isTls()) {
- // GOT entries created for MIPS TLS relocations behave like
- // almost GOT entries from other ABIs. They go to the end
- // of the global offset table.
- Sym.GotIndex = TlsEntries.size();
- TlsEntries.push_back(&Sym);
- return;
- }
- auto AddEntry = [&](Symbol &S, uint64_t A, GotEntries &Items) {
- if (S.isInGot() && !A)
- return;
- size_t NewIndex = Items.size();
- if (!EntryIndexMap.insert({{&S, A}, NewIndex}).second)
- return;
- Items.emplace_back(&S, A);
- if (!A)
- S.GotIndex = NewIndex;
- };
- if (Sym.IsPreemptible) {
- // Ignore addends for preemptible symbols. They got single GOT entry anyway.
- AddEntry(Sym, 0, GlobalEntries);
- Sym.IsInGlobalMipsGot = true;
- } else if (Expr == R_MIPS_GOT_OFF32) {
- AddEntry(Sym, Addend, LocalEntries32);
- Sym.Is32BitMipsGot = true;
- } else {
- // Hold local GOT entries accessed via a 16-bit index separately.
- // That allows to write them in the beginning of the GOT and keep
- // their indexes as less as possible to escape relocation's overflow.
- AddEntry(Sym, Addend, LocalEntries);
- }
+ if (const OutputSection *OS = Sym.getOutputSection())
+ G.PagesMap.insert({OS, {}});
+ else
+ G.Local16.insert({{nullptr, getMipsPageAddr(Sym.getVA(Addend))}, 0});
+ } else if (Sym.isTls())
+ G.Tls.insert({&Sym, 0});
+ else if (Sym.IsPreemptible && Expr == R_ABS)
+ G.Relocs.insert({&Sym, 0});
+ else if (Sym.IsPreemptible)
+ G.Global.insert({&Sym, 0});
+ else if (Expr == R_MIPS_GOT_OFF32)
+ G.Local32.insert({{&Sym, Addend}, 0});
+ else
+ G.Local16.insert({{&Sym, Addend}, 0});
}
-bool MipsGotSection::addDynTlsEntry(Symbol &Sym) {
- if (Sym.GlobalDynIndex != -1U)
- return false;
- Sym.GlobalDynIndex = TlsEntries.size();
- // Global Dynamic TLS entries take two GOT slots.
- TlsEntries.push_back(nullptr);
- TlsEntries.push_back(&Sym);
- return true;
+void MipsGotSection::addDynTlsEntry(InputFile &File, Symbol &Sym) {
+ getGot(File).DynTlsSymbols.insert({&Sym, 0});
}
-// Reserves TLS entries for a TLS module ID and a TLS block offset.
-// In total it takes two GOT slots.
-bool MipsGotSection::addTlsIndex() {
- if (TlsIndexOff != uint32_t(-1))
- return false;
- TlsIndexOff = TlsEntries.size() * Config->Wordsize;
- TlsEntries.push_back(nullptr);
- TlsEntries.push_back(nullptr);
- return true;
+void MipsGotSection::addTlsIndex(InputFile &File) {
+ getGot(File).DynTlsSymbols.insert({nullptr, 0});
}
-static uint64_t getMipsPageAddr(uint64_t Addr) {
- return (Addr + 0x8000) & ~0xffff;
+size_t MipsGotSection::FileGot::getEntriesNum() const {
+ return getPageEntriesNum() + Local16.size() + Global.size() + Relocs.size() +
+ Tls.size() + DynTlsSymbols.size() * 2;
}
-static uint64_t getMipsPageCount(uint64_t Size) {
- return (Size + 0xfffe) / 0xffff + 1;
+size_t MipsGotSection::FileGot::getPageEntriesNum() const {
+ size_t Num = 0;
+ for (const std::pair<const OutputSection *, FileGot::PageBlock> &P : PagesMap)
+ Num += P.second.Count;
+ return Num;
}
-uint64_t MipsGotSection::getPageEntryOffset(const Symbol &B,
- int64_t Addend) const {
- const OutputSection *OutSec = B.getOutputSection();
- uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
- uint64_t SymAddr = getMipsPageAddr(B.getVA(Addend));
- uint64_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff;
- assert(Index < PageEntriesNum);
- return (HeaderEntriesNum + Index) * Config->Wordsize;
+size_t MipsGotSection::FileGot::getIndexedEntriesNum() const {
+ size_t Count = getPageEntriesNum() + Local16.size() + Global.size();
+ // If there are relocation-only entries in the GOT, TLS entries
+ // are allocated after them. TLS entries should be addressable
+ // by 16-bit index so count both reloc-only and TLS entries.
+ if (!Tls.empty() || !DynTlsSymbols.empty())
+ Count += Relocs.size() + Tls.size() + DynTlsSymbols.size() * 2;
+ return Count;
}
-uint64_t MipsGotSection::getSymEntryOffset(const Symbol &B,
- int64_t Addend) const {
- // Calculate offset of the GOT entries block: TLS, global, local.
- uint64_t Index = HeaderEntriesNum + PageEntriesNum;
- if (B.isTls())
- Index += LocalEntries.size() + LocalEntries32.size() + GlobalEntries.size();
- else if (B.IsInGlobalMipsGot)
- Index += LocalEntries.size() + LocalEntries32.size();
- else if (B.Is32BitMipsGot)
- Index += LocalEntries.size();
- // Calculate offset of the GOT entry in the block.
- if (B.isInGot())
- Index += B.GotIndex;
- else {
- auto It = EntryIndexMap.find({&B, Addend});
- assert(It != EntryIndexMap.end());
- Index += It->second;
+MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &F) {
+ if (!F.MipsGotIndex.hasValue()) {
+ Gots.emplace_back();
+ Gots.back().File = &F;
+ F.MipsGotIndex = Gots.size() - 1;
+ }
+ return Gots[*F.MipsGotIndex];
+}
+
+uint64_t MipsGotSection::getPageEntryOffset(const InputFile *F,
+ const Symbol &Sym,
+ int64_t Addend) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ uint64_t Index = 0;
+ if (const OutputSection *OutSec = Sym.getOutputSection()) {
+ uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
+ uint64_t SymAddr = getMipsPageAddr(Sym.getVA(Addend));
+ Index = G.PagesMap.lookup(OutSec).FirstIndex + (SymAddr - SecAddr) / 0xffff;
+ } else {
+ Index = G.Local16.lookup({nullptr, getMipsPageAddr(Sym.getVA(Addend))});
}
return Index * Config->Wordsize;
}
-uint64_t MipsGotSection::getTlsOffset() const {
- return (getLocalEntriesNum() + GlobalEntries.size()) * Config->Wordsize;
+uint64_t MipsGotSection::getSymEntryOffset(const InputFile *F, const Symbol &S,
+ int64_t Addend) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ Symbol *Sym = const_cast<Symbol *>(&S);
+ if (Sym->isTls())
+ return G.Tls.lookup(Sym) * Config->Wordsize;
+ if (Sym->IsPreemptible)
+ return G.Global.lookup(Sym) * Config->Wordsize;
+ return G.Local16.lookup({Sym, Addend}) * Config->Wordsize;
}
-uint64_t MipsGotSection::getGlobalDynOffset(const Symbol &B) const {
- return B.GlobalDynIndex * Config->Wordsize;
+uint64_t MipsGotSection::getTlsIndexOffset(const InputFile *F) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ return G.DynTlsSymbols.lookup(nullptr) * Config->Wordsize;
+}
+
+uint64_t MipsGotSection::getGlobalDynOffset(const InputFile *F,
+ const Symbol &S) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ Symbol *Sym = const_cast<Symbol *>(&S);
+ return G.DynTlsSymbols.lookup(Sym) * Config->Wordsize;
}
const Symbol *MipsGotSection::getFirstGlobalEntry() const {
- return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first;
+ if (Gots.empty())
+ return nullptr;
+ const FileGot &PrimGot = Gots.front();
+ if (!PrimGot.Global.empty())
+ return PrimGot.Global.front().first;
+ if (!PrimGot.Relocs.empty())
+ return PrimGot.Relocs.front().first;
+ return nullptr;
}
unsigned MipsGotSection::getLocalEntriesNum() const {
- return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() +
- LocalEntries32.size();
+ if (Gots.empty())
+ return HeaderEntriesNum;
+ return HeaderEntriesNum + Gots.front().getPageEntriesNum() +
+ Gots.front().Local16.size();
+}
+
+bool MipsGotSection::tryMergeGots(FileGot &Dst, FileGot &Src, bool IsPrimary) {
+ FileGot Tmp = Dst;
+ set_union(Tmp.PagesMap, Src.PagesMap);
+ set_union(Tmp.Local16, Src.Local16);
+ set_union(Tmp.Global, Src.Global);
+ set_union(Tmp.Relocs, Src.Relocs);
+ set_union(Tmp.Tls, Src.Tls);
+ set_union(Tmp.DynTlsSymbols, Src.DynTlsSymbols);
+
+ size_t Count = IsPrimary ? HeaderEntriesNum : 0;
+ Count += Tmp.getIndexedEntriesNum();
+
+ if (Count * Config->Wordsize > Config->MipsGotSize)
+ return false;
+
+ std::swap(Tmp, Dst);
+ return true;
}
void MipsGotSection::finalizeContents() { updateAllocSize(); }
bool MipsGotSection::updateAllocSize() {
- PageEntriesNum = 0;
- for (std::pair<const OutputSection *, size_t> &P : PageIndexMap) {
- // For each output section referenced by GOT page relocations calculate
- // and save into PageIndexMap an upper bound of MIPS GOT entries required
- // to store page addresses of local symbols. We assume the worst case -
- // each 64kb page of the output section has at least one GOT relocation
- // against it. And take in account the case when the section intersects
- // page boundaries.
- P.second = PageEntriesNum;
- PageEntriesNum += getMipsPageCount(P.first->Size);
- }
- Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) *
- Config->Wordsize;
+ Size = HeaderEntriesNum * Config->Wordsize;
+ for (const FileGot &G : Gots)
+ Size += G.getEntriesNum() * Config->Wordsize;
return false;
}
+template <class ELFT> void MipsGotSection::build() {
+ if (Gots.empty())
+ return;
+
+ std::vector<FileGot> MergedGots(1);
+
+ // For each GOT move non-preemptible symbols from the `Global`
+ // to `Local16` list. Preemptible symbol might become non-preemptible
+ // one if, for example, it gets a related copy relocation.
+ for (FileGot &Got : Gots) {
+ for (auto &P: Got.Global)
+ if (!P.first->IsPreemptible)
+ Got.Local16.insert({{P.first, 0}, 0});
+ Got.Global.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+ return !P.first->IsPreemptible;
+ });
+ }
+
+ // For each GOT remove "reloc-only" entry if there is "global"
+ // entry for the same symbol. And add local entries which indexed
+ // using 32-bit value at the end of 16-bit entries.
+ for (FileGot &Got : Gots) {
+ Got.Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+ return Got.Global.count(P.first);
+ });
+ set_union(Got.Local16, Got.Local32);
+ Got.Local32.clear();
+ }
+
+ // Evaluate number of "reloc-only" entries in the resulting GOT.
+ // To do that put all unique "reloc-only" and "global" entries
+ // from all GOTs to the future primary GOT.
+ FileGot *PrimGot = &MergedGots.front();
+ for (FileGot &Got : Gots) {
+ set_union(PrimGot->Relocs, Got.Global);
+ set_union(PrimGot->Relocs, Got.Relocs);
+ Got.Relocs.clear();
+ }
+
+ // Evaluate number of "page" entries in each GOT.
+ for (FileGot &Got : Gots) {
+ for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
+ Got.PagesMap) {
+ const OutputSection *OS = P.first;
+ uint64_t SecSize = 0;
+ for (BaseCommand *Cmd : OS->SectionCommands) {
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
+ for (InputSection *IS : ISD->Sections) {
+ uint64_t Off = alignTo(SecSize, IS->Alignment);
+ SecSize = Off + IS->getSize();
+ }
+ }
+ P.second.Count = getMipsPageCount(SecSize);
+ }
+ }
+
+ // Merge GOTs. Try to join as much as possible GOTs but do not exceed
+ // maximum GOT size. At first, try to fill the primary GOT because
+ // the primary GOT can be accessed in the most effective way. If it
+ // is not possible, try to fill the last GOT in the list, and finally
+ // create a new GOT if both attempts failed.
+ for (FileGot &SrcGot : Gots) {
+ InputFile *File = SrcGot.File;
+ if (tryMergeGots(MergedGots.front(), SrcGot, true)) {
+ File->MipsGotIndex = 0;
+ } else {
+ // If this is the first time we failed to merge with the primary GOT,
+ // MergedGots.back() will also be the primary GOT. We must make sure not
+ // to try to merge again with IsPrimary=false, as otherwise, if the
+ // inputs are just right, we could allow the primary GOT to become 1 or 2
+ // words too big due to ignoring the header size.
+ if (MergedGots.size() == 1 ||
+ !tryMergeGots(MergedGots.back(), SrcGot, false)) {
+ MergedGots.emplace_back();
+ std::swap(MergedGots.back(), SrcGot);
+ }
+ File->MipsGotIndex = MergedGots.size() - 1;
+ }
+ }
+ std::swap(Gots, MergedGots);
+
+ // Reduce number of "reloc-only" entries in the primary GOT
+ // by substracting "global" entries exist in the primary GOT.
+ PrimGot = &Gots.front();
+ PrimGot->Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+ return PrimGot->Global.count(P.first);
+ });
+
+ // Calculate indexes for each GOT entry.
+ size_t Index = HeaderEntriesNum;
+ for (FileGot &Got : Gots) {
+ Got.StartIndex = &Got == PrimGot ? 0 : Index;
+ for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
+ Got.PagesMap) {
+ // For each output section referenced by GOT page relocations calculate
+ // and save into PagesMap an upper bound of MIPS GOT entries required
+ // to store page addresses of local symbols. We assume the worst case -
+ // each 64kb page of the output section has at least one GOT relocation
+ // against it. And take in account the case when the section intersects
+ // page boundaries.
+ P.second.FirstIndex = Index;
+ Index += P.second.Count;
+ }
+ for (auto &P: Got.Local16)
+ P.second = Index++;
+ for (auto &P: Got.Global)
+ P.second = Index++;
+ for (auto &P: Got.Relocs)
+ P.second = Index++;
+ for (auto &P: Got.Tls)
+ P.second = Index++;
+ for (auto &P: Got.DynTlsSymbols) {
+ P.second = Index;
+ Index += 2;
+ }
+ }
+
+ // Update Symbol::GotIndex field to use this
+ // value later in the `sortMipsSymbols` function.
+ for (auto &P : PrimGot->Global)
+ P.first->GotIndex = P.second;
+ for (auto &P : PrimGot->Relocs)
+ P.first->GotIndex = P.second;
+
+ // Create dynamic relocations.
+ for (FileGot &Got : Gots) {
+ // Create dynamic relocations for TLS entries.
+ for (std::pair<Symbol *, size_t> &P : Got.Tls) {
+ Symbol *S = P.first;
+ uint64_t Offset = P.second * Config->Wordsize;
+ if (S->IsPreemptible)
+ InX::RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S);
+ }
+ for (std::pair<Symbol *, size_t> &P : Got.DynTlsSymbols) {
+ Symbol *S = P.first;
+ uint64_t Offset = P.second * Config->Wordsize;
+ if (S == nullptr) {
+ if (!Config->Pic)
+ continue;
+ InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
+ } else {
+ // When building a shared library we still need a dynamic relocation
+ // for the module index. Therefore only checking for
+ // S->IsPreemptible is not sufficient (this happens e.g. for
+ // thread-locals that have been marked as local through a linker script)
+ if (!S->IsPreemptible && !Config->Pic)
+ continue;
+ InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
+ // However, we can skip writing the TLS offset reloc for non-preemptible
+ // symbols since it is known even in shared libraries
+ if (!S->IsPreemptible)
+ continue;
+ Offset += Config->Wordsize;
+ InX::RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S);
+ }
+ }
+
+ // Do not create dynamic relocations for non-TLS
+ // entries in the primary GOT.
+ if (&Got == PrimGot)
+ continue;
+
+ // Dynamic relocations for "global" entries.
+ for (const std::pair<Symbol *, size_t> &P : Got.Global) {
+ uint64_t Offset = P.second * Config->Wordsize;
+ InX::RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first);
+ }
+ if (!Config->Pic)
+ continue;
+ // Dynamic relocations for "local" entries in case of PIC.
+ for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
+ Got.PagesMap) {
+ size_t PageCount = L.second.Count;
+ for (size_t PI = 0; PI < PageCount; ++PI) {
+ uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize;
+ InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first,
+ int64_t(PI * 0x10000)});
+ }
+ }
+ for (const std::pair<GotEntry, size_t> &P : Got.Local16) {
+ uint64_t Offset = P.second * Config->Wordsize;
+ InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, true,
+ P.first.first, P.first.second});
+ }
+ }
+}
+
bool MipsGotSection::empty() const {
// We add the .got section to the result for dynamic MIPS target because
// its address and properties are mentioned in the .dynamic section.
return Config->Relocatable;
}
-uint64_t MipsGotSection::getGp() const { return ElfSym::MipsGp->getVA(0); }
+uint64_t MipsGotSection::getGp(const InputFile *F) const {
+ // For files without related GOT or files refer a primary GOT
+ // returns "common" _gp value. For secondary GOTs calculate
+ // individual _gp values.
+ if (!F || !F->MipsGotIndex.hasValue() || *F->MipsGotIndex == 0)
+ return ElfSym::MipsGp->getVA(0);
+ return getVA() + Gots[*F->MipsGotIndex].StartIndex * Config->Wordsize +
+ 0x7ff0;
+}
void MipsGotSection::writeTo(uint8_t *Buf) {
// Set the MSB of the second GOT slot. This is not required by any
@@ -830,59 +1025,67 @@ void MipsGotSection::writeTo(uint8_t *Buf) {
// keep doing this for now. We really need to revisit this to see
// if we had to do this.
writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1));
- Buf += HeaderEntriesNum * Config->Wordsize;
- // Write 'page address' entries to the local part of the GOT.
- for (std::pair<const OutputSection *, size_t> &L : PageIndexMap) {
- size_t PageCount = getMipsPageCount(L.first->Size);
- uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
- for (size_t PI = 0; PI < PageCount; ++PI) {
- uint8_t *Entry = Buf + (L.second + PI) * Config->Wordsize;
- writeUint(Entry, FirstPageAddr + PI * 0x10000);
- }
- }
- Buf += PageEntriesNum * Config->Wordsize;
- auto AddEntry = [&](const GotEntry &SA) {
- uint8_t *Entry = Buf;
- Buf += Config->Wordsize;
- const Symbol *Sym = SA.first;
- uint64_t VA = Sym->getVA(SA.second);
- if (Sym->StOther & STO_MIPS_MICROMIPS)
- VA |= 1;
- writeUint(Entry, VA);
- };
- std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry);
- std::for_each(std::begin(LocalEntries32), std::end(LocalEntries32), AddEntry);
- std::for_each(std::begin(GlobalEntries), std::end(GlobalEntries), AddEntry);
- // Initialize TLS-related GOT entries. If the entry has a corresponding
- // dynamic relocations, leave it initialized by zero. Write down adjusted
- // TLS symbol's values otherwise. To calculate the adjustments use offsets
- // for thread-local storage.
- // https://www.linux-mips.org/wiki/NPTL
- if (TlsIndexOff != -1U && !Config->Pic)
- writeUint(Buf + TlsIndexOff, 1);
- for (const Symbol *B : TlsEntries) {
- if (!B || B->IsPreemptible)
- continue;
- uint64_t VA = B->getVA();
- if (B->GotIndex != -1U) {
- uint8_t *Entry = Buf + B->GotIndex * Config->Wordsize;
- writeUint(Entry, VA - 0x7000);
+ for (const FileGot &G : Gots) {
+ auto Write = [&](size_t I, const Symbol *S, int64_t A) {
+ uint64_t VA = A;
+ if (S) {
+ VA = S->getVA(A);
+ if (S->StOther & STO_MIPS_MICROMIPS)
+ VA |= 1;
+ }
+ writeUint(Buf + I * Config->Wordsize, VA);
+ };
+ // Write 'page address' entries to the local part of the GOT.
+ for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
+ G.PagesMap) {
+ size_t PageCount = L.second.Count;
+ uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
+ for (size_t PI = 0; PI < PageCount; ++PI)
+ Write(L.second.FirstIndex + PI, nullptr, FirstPageAddr + PI * 0x10000);
}
- if (B->GlobalDynIndex != -1U) {
- uint8_t *Entry = Buf + B->GlobalDynIndex * Config->Wordsize;
- writeUint(Entry, 1);
- Entry += Config->Wordsize;
- writeUint(Entry, VA - 0x8000);
+ // Local, global, TLS, reloc-only entries.
+ // If TLS entry has a corresponding dynamic relocations, leave it
+ // initialized by zero. Write down adjusted TLS symbol's values otherwise.
+ // To calculate the adjustments use offsets for thread-local storage.
+ // https://www.linux-mips.org/wiki/NPTL
+ for (const std::pair<GotEntry, size_t> &P : G.Local16)
+ Write(P.second, P.first.first, P.first.second);
+ // Write VA to the primary GOT only. For secondary GOTs that
+ // will be done by REL32 dynamic relocations.
+ if (&G == &Gots.front())
+ for (const std::pair<const Symbol *, size_t> &P : G.Global)
+ Write(P.second, P.first, 0);
+ for (const std::pair<Symbol *, size_t> &P : G.Relocs)
+ Write(P.second, P.first, 0);
+ for (const std::pair<Symbol *, size_t> &P : G.Tls)
+ Write(P.second, P.first, P.first->IsPreemptible ? 0 : -0x7000);
+ for (const std::pair<Symbol *, size_t> &P : G.DynTlsSymbols) {
+ if (P.first == nullptr && !Config->Pic)
+ Write(P.second, nullptr, 1);
+ else if (P.first && !P.first->IsPreemptible) {
+ // If we are emitting PIC code with relocations we mustn't write
+ // anything to the GOT here. When using Elf_Rel relocations the value
+ // one will be treated as an addend and will cause crashes at runtime
+ if (!Config->Pic)
+ Write(P.second, nullptr, 1);
+ Write(P.second + 1, P.first, -0x8000);
+ }
}
}
}
+// On PowerPC the .plt section is used to hold the table of function addresses
+// instead of the .got.plt, and the type is SHT_NOBITS similar to a .bss
+// section. I don't know why we have a BSS style type for the section but it is
+// consitent across both 64-bit PowerPC ABIs as well as the 32-bit PowerPC ABI.
GotPltSection::GotPltSection()
- : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotPltEntrySize, ".got.plt") {}
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+ Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
+ Target->GotPltEntrySize,
+ Config->EMachine == EM_PPC64 ? ".plt" : ".got.plt") {}
void GotPltSection::addEntry(Symbol &Sym) {
- Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size();
+ assert(Sym.PltIndex == Entries.size());
Entries.push_back(&Sym);
}
@@ -900,16 +1103,37 @@ void GotPltSection::writeTo(uint8_t *Buf) {
}
}
-// On ARM the IgotPltSection is part of the GotSection, on other Targets it is
-// part of the .got.plt
+bool GotPltSection::empty() const {
+ // We need to emit a GOT.PLT even if it's empty if there's a symbol that
+ // references the _GLOBAL_OFFSET_TABLE_ and the Target defines the symbol
+ // relative to the .got.plt section.
+ return Entries.empty() &&
+ !(ElfSym::GlobalOffsetTable && Target->GotBaseSymInGotPlt);
+}
+
+static StringRef getIgotPltName() {
+ // On ARM the IgotPltSection is part of the GotSection.
+ if (Config->EMachine == EM_ARM)
+ return ".got";
+
+ // On PowerPC64 the GotPltSection is renamed to '.plt' so the IgotPltSection
+ // needs to be named the same.
+ if (Config->EMachine == EM_PPC64)
+ return ".plt";
+
+ return ".got.plt";
+}
+
+// On PowerPC64 the GotPltSection type is SHT_NOBITS so we have to follow suit
+// with the IgotPltSection.
IgotPltSection::IgotPltSection()
- : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotPltEntrySize,
- Config->EMachine == EM_ARM ? ".got" : ".got.plt") {}
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+ Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
+ Target->GotPltEntrySize, getIgotPltName()) {}
void IgotPltSection::addEntry(Symbol &Sym) {
Sym.IsInIgot = true;
- Sym.GotPltIndex = Entries.size();
+ assert(Sym.PltIndex == Entries.size());
Entries.push_back(&Sym);
}
@@ -1005,8 +1229,14 @@ void DynamicSection<ELFT>::addInt(int32_t Tag, uint64_t Val) {
template <class ELFT>
void DynamicSection<ELFT>::addInSec(int32_t Tag, InputSection *Sec) {
+ Entries.push_back({Tag, [=] { return Sec->getVA(0); }});
+}
+
+template <class ELFT>
+void DynamicSection<ELFT>::addInSecRelative(int32_t Tag, InputSection *Sec) {
+ size_t TagOffset = Entries.size() * Entsize;
Entries.push_back(
- {Tag, [=] { return Sec->getParent()->Addr + Sec->OutSecOff; }});
+ {Tag, [=] { return Sec->getVA(0) - (getVA() + TagOffset); }});
}
template <class ELFT>
@@ -1034,6 +1264,8 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
uint32_t DtFlags1 = 0;
if (Config->Bsymbolic)
DtFlags |= DF_SYMBOLIC;
+ if (Config->ZInitfirst)
+ DtFlags1 |= DF_1_INITFIRST;
if (Config->ZNodelete)
DtFlags1 |= DF_1_NODELETE;
if (Config->ZNodlopen)
@@ -1046,6 +1278,8 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
DtFlags |= DF_ORIGIN;
DtFlags1 |= DF_1_ORIGIN;
}
+ if (!Config->ZText)
+ DtFlags |= DF_TEXTREL;
if (DtFlags)
addInt(DT_FLAGS, DtFlags);
@@ -1081,6 +1315,14 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels);
}
}
+ if (InX::RelrDyn && !InX::RelrDyn->Relocs.empty()) {
+ addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR,
+ InX::RelrDyn);
+ addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ,
+ InX::RelrDyn->getParent());
+ addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
+ sizeof(Elf_Relr));
+ }
// .rel[a].plt section usually consists of two parts, containing plt and
// iplt relocations. It is possible to have only iplt relocations in the
// output. In that case RelaPlt is empty and have zero offset, the same offset
@@ -1160,8 +1402,23 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
else
addInt(DT_MIPS_GOTSYM, InX::DynSymTab->getNumSymbols());
addInSec(DT_PLTGOT, InX::MipsGot);
- if (InX::MipsRldMap)
- addInSec(DT_MIPS_RLD_MAP, InX::MipsRldMap);
+ if (InX::MipsRldMap) {
+ if (!Config->Pie)
+ addInSec(DT_MIPS_RLD_MAP, InX::MipsRldMap);
+ // Store the offset to the .rld_map section
+ // relative to the address of the tag.
+ addInSecRelative(DT_MIPS_RLD_MAP_REL, InX::MipsRldMap);
+ }
+ }
+
+ // Glink dynamic tag is required by the V2 abi if the plt section isn't empty.
+ if (Config->EMachine == EM_PPC64 && !InX::Plt->empty()) {
+ // The Glink tag points to 32 bytes before the first lazy symbol resolution
+ // stub, which starts directly after the header.
+ Entries.push_back({DT_PPC64_GLINK, [=] {
+ unsigned Offset = Target->PltHeaderSize - 32;
+ return InX::Plt->getVA(0) + Offset;
+ }});
}
addInt(DT_NULL, 0);
@@ -1181,13 +1438,16 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
}
uint64_t DynamicReloc::getOffset() const {
- return InputSec->getOutputSection()->Addr + InputSec->getOffset(OffsetInSec);
+ return InputSec->getVA(OffsetInSec);
}
-int64_t DynamicReloc::getAddend() const {
+int64_t DynamicReloc::computeAddend() const {
if (UseSymVA)
return Sym->getVA(Addend);
- return Addend;
+ if (!OutputSec)
+ return Addend;
+ // See the comment in the DynamicReloc ctor.
+ return getMipsPageAddr(OutputSec->Addr) + Addend;
}
uint32_t DynamicReloc::getSymIndex() const {
@@ -1202,6 +1462,23 @@ RelocationBaseSection::RelocationBaseSection(StringRef Name, uint32_t Type,
: SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name),
DynamicTag(DynamicTag), SizeDynamicTag(SizeDynamicTag) {}
+void RelocationBaseSection::addReloc(RelType DynType, InputSectionBase *IS,
+ uint64_t OffsetInSec, Symbol *Sym) {
+ addReloc({DynType, IS, OffsetInSec, false, Sym, 0});
+}
+
+void RelocationBaseSection::addReloc(RelType DynType,
+ InputSectionBase *InputSec,
+ uint64_t OffsetInSec, Symbol *Sym,
+ int64_t Addend, RelExpr Expr,
+ RelType Type) {
+ // Write the addends to the relocated address if required. We skip
+ // it if the written value would be zero.
+ if (Config->WriteAddends && (Expr != R_ADDEND || Addend != 0))
+ InputSec->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym});
+ addReloc({DynType, InputSec, OffsetInSec, Expr != R_ADDEND, Sym, Addend});
+}
+
void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) {
if (Reloc.Type == Target->RelativeRel)
++NumRelativeRelocs;
@@ -1218,23 +1495,17 @@ void RelocationBaseSection::finalizeContents() {
getParent()->Link = Link;
}
+RelrBaseSection::RelrBaseSection()
+ : SyntheticSection(SHF_ALLOC,
+ Config->UseAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR,
+ Config->Wordsize, ".relr.dyn") {}
+
template <class ELFT>
static void encodeDynamicReloc(typename ELFT::Rela *P,
const DynamicReloc &Rel) {
if (Config->IsRela)
- P->r_addend = Rel.getAddend();
+ P->r_addend = Rel.computeAddend();
P->r_offset = Rel.getOffset();
- if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot)
- // The MIPS GOT section contains dynamic relocations that correspond to TLS
- // entries. These entries are placed after the global and local sections of
- // the GOT. At the point when we create these relocations, the size of the
- // global and local sections is unknown, so the offset that we store in the
- // TLS entry's DynamicReloc is relative to the start of the TLS section of
- // the GOT, rather than being relative to the start of the GOT. This line of
- // code adds the size of the global and local sections to the virtual
- // address computed by getOffset() in order to adjust it into the TLS
- // section.
- P->r_offset += InX::MipsGot->getTlsOffset();
P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL);
}
@@ -1247,32 +1518,22 @@ RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort)
this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
}
-template <class ELFT, class RelTy>
-static bool compRelocations(const RelTy &A, const RelTy &B) {
- bool AIsRel = A.getType(Config->IsMips64EL) == Target->RelativeRel;
- bool BIsRel = B.getType(Config->IsMips64EL) == Target->RelativeRel;
+static bool compRelocations(const DynamicReloc &A, const DynamicReloc &B) {
+ bool AIsRel = A.Type == Target->RelativeRel;
+ bool BIsRel = B.Type == Target->RelativeRel;
if (AIsRel != BIsRel)
return AIsRel;
-
- return A.getSymbol(Config->IsMips64EL) < B.getSymbol(Config->IsMips64EL);
+ return A.getSymIndex() < B.getSymIndex();
}
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
- uint8_t *BufBegin = Buf;
+ if (Sort)
+ std::stable_sort(Relocs.begin(), Relocs.end(), compRelocations);
+
for (const DynamicReloc &Rel : Relocs) {
encodeDynamicReloc<ELFT>(reinterpret_cast<Elf_Rela *>(Buf), Rel);
Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
}
-
- if (Sort) {
- if (Config->IsRela)
- std::stable_sort((Elf_Rela *)BufBegin,
- (Elf_Rela *)BufBegin + Relocs.size(),
- compRelocations<ELFT, Elf_Rela>);
- else
- std::stable_sort((Elf_Rel *)BufBegin, (Elf_Rel *)BufBegin + Relocs.size(),
- compRelocations<ELFT, Elf_Rel>);
- }
}
template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
@@ -1360,10 +1621,10 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
NonRelatives.push_back(R);
}
- std::sort(Relatives.begin(), Relatives.end(),
- [](const Elf_Rel &A, const Elf_Rel &B) {
- return A.r_offset < B.r_offset;
- });
+ llvm::sort(Relatives.begin(), Relatives.end(),
+ [](const Elf_Rel &A, const Elf_Rel &B) {
+ return A.r_offset < B.r_offset;
+ });
// Try to find groups of relative relocations which are spaced one word
// apart from one another. These generally correspond to vtable entries. The
@@ -1441,10 +1702,10 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
}
// Finally the non-relative relocations.
- std::sort(NonRelatives.begin(), NonRelatives.end(),
- [](const Elf_Rela &A, const Elf_Rela &B) {
- return A.r_offset < B.r_offset;
- });
+ llvm::sort(NonRelatives.begin(), NonRelatives.end(),
+ [](const Elf_Rela &A, const Elf_Rela &B) {
+ return A.r_offset < B.r_offset;
+ });
if (!NonRelatives.empty()) {
Add(NonRelatives.size());
Add(HasAddendIfRela);
@@ -1467,6 +1728,97 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
return RelocData.size() != OldSize;
}
+template <class ELFT> RelrSection<ELFT>::RelrSection() {
+ this->Entsize = Config->Wordsize;
+}
+
+template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() {
+ // This function computes the contents of an SHT_RELR packed relocation
+ // section.
+ //
+ // Proposal for adding SHT_RELR sections to generic-abi is here:
+ // https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+ //
+ // The encoded sequence of Elf64_Relr entries in a SHT_RELR section looks
+ // like [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ]
+ //
+ // i.e. start with an address, followed by any number of bitmaps. The address
+ // entry encodes 1 relocation. The subsequent bitmap entries encode up to 63
+ // relocations each, at subsequent offsets following the last address entry.
+ //
+ // The bitmap entries must have 1 in the least significant bit. The assumption
+ // here is that an address cannot have 1 in lsb. Odd addresses are not
+ // supported.
+ //
+ // Excluding the least significant bit in the bitmap, each non-zero bit in
+ // the bitmap represents a relocation to be applied to a corresponding machine
+ // word that follows the base address word. The second least significant bit
+ // represents the machine word immediately following the initial address, and
+ // each bit that follows represents the next word, in linear order. As such,
+ // a single bitmap can encode up to 31 relocations in a 32-bit object, and
+ // 63 relocations in a 64-bit object.
+ //
+ // This encoding has a couple of interesting properties:
+ // 1. Looking at any entry, it is clear whether it's an address or a bitmap:
+ // even means address, odd means bitmap.
+ // 2. Just a simple list of addresses is a valid encoding.
+
+ size_t OldSize = RelrRelocs.size();
+ RelrRelocs.clear();
+
+ // Same as Config->Wordsize but faster because this is a compile-time
+ // constant.
+ const size_t Wordsize = sizeof(typename ELFT::uint);
+
+ // Number of bits to use for the relocation offsets bitmap.
+ // Must be either 63 or 31.
+ const size_t NBits = Wordsize * 8 - 1;
+
+ // Get offsets for all relative relocations and sort them.
+ std::vector<uint64_t> Offsets;
+ for (const RelativeReloc &Rel : Relocs)
+ Offsets.push_back(Rel.getOffset());
+ llvm::sort(Offsets.begin(), Offsets.end());
+
+ // For each leading relocation, find following ones that can be folded
+ // as a bitmap and fold them.
+ for (size_t I = 0, E = Offsets.size(); I < E;) {
+ // Add a leading relocation.
+ RelrRelocs.push_back(Elf_Relr(Offsets[I]));
+ uint64_t Base = Offsets[I] + Wordsize;
+ ++I;
+
+ // Find foldable relocations to construct bitmaps.
+ while (I < E) {
+ uint64_t Bitmap = 0;
+
+ while (I < E) {
+ uint64_t Delta = Offsets[I] - Base;
+
+ // If it is too far, it cannot be folded.
+ if (Delta >= NBits * Wordsize)
+ break;
+
+ // If it is not a multiple of wordsize away, it cannot be folded.
+ if (Delta % Wordsize)
+ break;
+
+ // Fold it.
+ Bitmap |= 1ULL << (Delta / Wordsize);
+ ++I;
+ }
+
+ if (!Bitmap)
+ break;
+
+ RelrRelocs.push_back(Elf_Relr((Bitmap << 1) | 1));
+ Base += NBits * Wordsize;
+ }
+ }
+
+ return RelrRelocs.size() != OldSize;
+}
+
SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
: SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0,
StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
@@ -1482,50 +1834,70 @@ SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
static bool sortMipsSymbols(const SymbolTableEntry &L,
const SymbolTableEntry &R) {
// Sort entries related to non-local preemptible symbols by GOT indexes.
- // All other entries go to the first part of GOT in arbitrary order.
- bool LIsInLocalGot = !L.Sym->IsInGlobalMipsGot;
- bool RIsInLocalGot = !R.Sym->IsInGlobalMipsGot;
- if (LIsInLocalGot || RIsInLocalGot)
- return !RIsInLocalGot;
- return L.Sym->GotIndex < R.Sym->GotIndex;
+ // All other entries go to the beginning of a dynsym in arbitrary order.
+ if (L.Sym->isInGot() && R.Sym->isInGot())
+ return L.Sym->GotIndex < R.Sym->GotIndex;
+ if (!L.Sym->isInGot() && !R.Sym->isInGot())
+ return false;
+ return !L.Sym->isInGot();
}
void SymbolTableBaseSection::finalizeContents() {
getParent()->Link = StrTabSec.getParent()->SectionIndex;
+ if (this->Type != SHT_DYNSYM)
+ return;
+
// If it is a .dynsym, there should be no local symbols, but we need
// to do a few things for the dynamic linker.
- if (this->Type == SHT_DYNSYM) {
- // Section's Info field has the index of the first non-local symbol.
- // Because the first symbol entry is a null entry, 1 is the first.
- getParent()->Info = 1;
-
- if (InX::GnuHashTab) {
- // NB: It also sorts Symbols to meet the GNU hash table requirements.
- InX::GnuHashTab->addSymbols(Symbols);
- } else if (Config->EMachine == EM_MIPS) {
- std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
- }
- size_t I = 0;
- for (const SymbolTableEntry &S : Symbols) S.Sym->DynsymIndex = ++I;
- return;
+ // Section's Info field has the index of the first non-local symbol.
+ // Because the first symbol entry is a null entry, 1 is the first.
+ getParent()->Info = 1;
+
+ if (InX::GnuHashTab) {
+ // NB: It also sorts Symbols to meet the GNU hash table requirements.
+ InX::GnuHashTab->addSymbols(Symbols);
+ } else if (Config->EMachine == EM_MIPS) {
+ std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
}
+
+ size_t I = 0;
+ for (const SymbolTableEntry &S : Symbols)
+ S.Sym->DynsymIndex = ++I;
}
// The ELF spec requires that all local symbols precede global symbols, so we
// sort symbol entries in this function. (For .dynsym, we don't do that because
// symbols for dynamic linking are inherently all globals.)
+//
+// Aside from above, we put local symbols in groups starting with the STT_FILE
+// symbol. That is convenient for purpose of identifying where are local symbols
+// coming from.
void SymbolTableBaseSection::postThunkContents() {
- if (this->Type == SHT_DYNSYM)
- return;
- // move all local symbols before global symbols.
- auto It = std::stable_partition(
+ assert(this->Type == SHT_SYMTAB);
+
+ // Move all local symbols before global symbols.
+ auto E = std::stable_partition(
Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) {
return S.Sym->isLocal() || S.Sym->computeBinding() == STB_LOCAL;
});
- size_t NumLocals = It - Symbols.begin();
+ size_t NumLocals = E - Symbols.begin();
getParent()->Info = NumLocals + 1;
+
+ // We want to group the local symbols by file. For that we rebuild the local
+ // part of the symbols vector. We do not need to care about the STT_FILE
+ // symbols, they are already naturally placed first in each group. That
+ // happens because STT_FILE is always the first symbol in the object and hence
+ // precede all other local symbols we add for a file.
+ MapVector<InputFile *, std::vector<SymbolTableEntry>> Arr;
+ for (const SymbolTableEntry &S : llvm::make_range(Symbols.begin(), E))
+ Arr[S.Sym->File].push_back(S);
+
+ auto I = Symbols.begin();
+ for (std::pair<InputFile *, std::vector<SymbolTableEntry>> &P : Arr)
+ for (SymbolTableEntry &Entry : P.second)
+ *I++ = Entry;
}
void SymbolTableBaseSection::addSymbol(Symbol *B) {
@@ -1563,6 +1935,23 @@ SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &StrTabSec)
this->Entsize = sizeof(Elf_Sym);
}
+static BssSection *getCommonSec(Symbol *Sym) {
+ if (!Config->DefineCommon)
+ if (auto *D = dyn_cast<Defined>(Sym))
+ return dyn_cast_or_null<BssSection>(D->Section);
+ return nullptr;
+}
+
+static uint32_t getSymSectionIndex(Symbol *Sym) {
+ if (getCommonSec(Sym))
+ return SHN_COMMON;
+ if (!isa<Defined>(Sym) || Sym->NeedsPltAddr)
+ return SHN_UNDEF;
+ if (const OutputSection *OS = Sym->getOutputSection())
+ return OS->SectionIndex >= SHN_LORESERVE ? SHN_XINDEX : OS->SectionIndex;
+ return SHN_ABS;
+}
+
// Write the internal symbol table contents to the output symbol table.
template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
// The first entry is a null entry as per the ELF spec.
@@ -1584,20 +1973,7 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
}
ESym->st_name = Ent.StrTabOffset;
-
- // Set a section index.
- BssSection *CommonSec = nullptr;
- if (!Config->DefineCommon)
- if (auto *D = dyn_cast<Defined>(Sym))
- CommonSec = dyn_cast_or_null<BssSection>(D->Section);
- if (CommonSec)
- ESym->st_shndx = SHN_COMMON;
- else if (const OutputSection *OutSec = Sym->getOutputSection())
- ESym->st_shndx = OutSec->SectionIndex;
- else if (isa<Defined>(Sym))
- ESym->st_shndx = SHN_ABS;
- else
- ESym->st_shndx = SHN_UNDEF;
+ ESym->st_shndx = getSymSectionIndex(Ent.Sym);
// Copy symbol size if it is a defined symbol. st_size is not significant
// for undefined symbols, so whether copying it or not is up to us if that's
@@ -1612,7 +1988,7 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
// st_value is usually an address of a symbol, but that has a
// special meaining for uninstantiated common symbols (this can
// occur if -r is given).
- if (CommonSec)
+ if (BssSection *CommonSec = getCommonSec(Ent.Sym))
ESym->st_value = CommonSec->Alignment;
else
ESym->st_value = Sym->getVA();
@@ -1633,9 +2009,11 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
ESym->st_other |= STO_MIPS_PLT;
if (isMicroMips()) {
// Set STO_MIPS_MICROMIPS flag and less-significant bit for
- // defined microMIPS symbols and shared symbols with PLT record.
- if ((Sym->isDefined() && (Sym->StOther & STO_MIPS_MICROMIPS)) ||
- (Sym->isShared() && Sym->NeedsPltAddr)) {
+ // a defined microMIPS symbol and symbol should point to its
+ // PLT entry (in case of microMIPS, PLT entries always contain
+ // microMIPS code).
+ if (Sym->isDefined() &&
+ ((Sym->StOther & STO_MIPS_MICROMIPS) || Sym->NeedsPltAddr)) {
if (StrTabSec.isDynamic())
ESym->st_value |= 1;
ESym->st_other |= STO_MIPS_MICROMIPS;
@@ -1650,6 +2028,44 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
}
}
+SymtabShndxSection::SymtabShndxSection()
+ : SyntheticSection(0, SHT_SYMTAB_SHNDX, 4, ".symtab_shndxr") {
+ this->Entsize = 4;
+}
+
+void SymtabShndxSection::writeTo(uint8_t *Buf) {
+ // We write an array of 32 bit values, where each value has 1:1 association
+ // with an entry in .symtab. If the corresponding entry contains SHN_XINDEX,
+ // we need to write actual index, otherwise, we must write SHN_UNDEF(0).
+ Buf += 4; // Ignore .symtab[0] entry.
+ for (const SymbolTableEntry &Entry : InX::SymTab->getSymbols()) {
+ if (getSymSectionIndex(Entry.Sym) == SHN_XINDEX)
+ write32(Buf, Entry.Sym->getOutputSection()->SectionIndex);
+ Buf += 4;
+ }
+}
+
+bool SymtabShndxSection::empty() const {
+ // SHT_SYMTAB can hold symbols with section indices values up to
+ // SHN_LORESERVE. If we need more, we want to use extension SHT_SYMTAB_SHNDX
+ // section. Problem is that we reveal the final section indices a bit too
+ // late, and we do not know them here. For simplicity, we just always create
+ // a .symtab_shndxr section when the amount of output sections is huge.
+ size_t Size = 0;
+ for (BaseCommand *Base : Script->SectionCommands)
+ if (isa<OutputSection>(Base))
+ ++Size;
+ return Size < SHN_LORESERVE;
+}
+
+void SymtabShndxSection::finalizeContents() {
+ getParent()->Link = InX::SymTab->getParent()->SectionIndex;
+}
+
+size_t SymtabShndxSection::getSize() const {
+ return InX::SymTab->getNumSymbols() * 4;
+}
+
// .hash and .gnu.hash sections contain on-disk hash tables that map
// symbol names to their dynamic symbol table indices. Their purpose
// is to help the dynamic linker resolve symbols quickly. If ELF files
@@ -1688,12 +2104,14 @@ GnuHashTableSection::GnuHashTableSection()
void GnuHashTableSection::finalizeContents() {
getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
- // Computes bloom filter size in word size. We want to allocate 8
+ // Computes bloom filter size in word size. We want to allocate 12
// bits for each symbol. It must be a power of two.
- if (Symbols.empty())
+ if (Symbols.empty()) {
MaskWords = 1;
- else
- MaskWords = NextPowerOf2((Symbols.size() - 1) / Config->Wordsize);
+ } else {
+ uint64_t NumBits = Symbols.size() * 12;
+ MaskWords = NextPowerOf2(NumBits / (Config->Wordsize * 8));
+ }
Size = 16; // Header
Size += Config->Wordsize * MaskWords; // Bloom filter
@@ -1711,7 +2129,7 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) {
write32(Buf, NBuckets);
write32(Buf + 4, InX::DynSymTab->getNumSymbols() - Symbols.size());
write32(Buf + 8, MaskWords);
- write32(Buf + 12, getShift2());
+ write32(Buf + 12, Shift2);
Buf += 16;
// Write a bloom filter and a hash table.
@@ -1728,12 +2146,12 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) {
// [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2),
// p.9, https://www.akkadia.org/drepper/dsohowto.pdf
void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) {
- const unsigned C = Config->Wordsize * 8;
+ unsigned C = Config->Is64 ? 64 : 32;
for (const Entry &Sym : Symbols) {
size_t I = (Sym.Hash / C) & (MaskWords - 1);
uint64_t Val = readUint(Buf + I * Config->Wordsize);
Val |= uint64_t(1) << (Sym.Hash % C);
- Val |= uint64_t(1) << ((Sym.Hash >> getShift2()) % C);
+ Val |= uint64_t(1) << ((Sym.Hash >> Shift2) % C);
writeUint(Buf + I * Config->Wordsize, Val);
}
}
@@ -1775,21 +2193,23 @@ void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) {
// its type correctly.
std::vector<SymbolTableEntry>::iterator Mid =
std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) {
- // Shared symbols that this executable preempts are special. The dynamic
- // linker has to look them up, so they have to be in the hash table.
- if (auto *SS = dyn_cast<SharedSymbol>(S.Sym))
- return SS->CopyRelSec == nullptr && !SS->NeedsPltAddr;
return !S.Sym->isDefined();
});
- if (Mid == V.end())
- return;
// We chose load factor 4 for the on-disk hash table. For each hash
// collision, the dynamic linker will compare a uint32_t hash value.
- // Since the integer comparison is quite fast, we believe we can make
- // the load factor even larger. 4 is just a conservative choice.
+ // Since the integer comparison is quite fast, we believe we can
+ // make the load factor even larger. 4 is just a conservative choice.
+ //
+ // Note that we don't want to create a zero-sized hash table because
+ // Android loader as of 2018 doesn't like a .gnu.hash containing such
+ // table. If that's the case, we create a hash table with one unused
+ // dummy slot.
NBuckets = std::max<size_t>((V.end() - Mid) / 4, 1);
+ if (Mid == V.end())
+ return;
+
for (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) {
Symbol *B = Ent.Sym;
uint32_t Hash = hashGnu(B->getName());
@@ -1845,9 +2265,12 @@ void HashTableSection::writeTo(uint8_t *Buf) {
}
}
-PltSection::PltSection(size_t S)
- : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"),
- HeaderSize(S) {
+// On PowerPC64 the lazy symbol resolvers go into the `global linkage table`
+// in the .glink section, rather then the typical .plt section.
+PltSection::PltSection(bool IsIplt)
+ : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
+ Config->EMachine == EM_PPC64 ? ".glink" : ".plt"),
+ HeaderSize(IsIplt ? 0 : Target->PltHeaderSize), IsIplt(IsIplt) {
// The PLT needs to be writable on SPARC as the dynamic linker will
// modify the instructions in the PLT entries.
if (Config->EMachine == EM_SPARCV9)
@@ -1857,7 +2280,7 @@ PltSection::PltSection(size_t S)
void PltSection::writeTo(uint8_t *Buf) {
// At beginning of PLT but not the IPLT, we have code to call the dynamic
// linker to resolve dynsyms at runtime. Write such code.
- if (HeaderSize != 0)
+ if (!IsIplt)
Target->writePltHeader(Buf);
size_t Off = HeaderSize;
// The IPlt is immediately after the Plt, account for this in RelOff
@@ -1876,7 +2299,7 @@ void PltSection::writeTo(uint8_t *Buf) {
template <class ELFT> void PltSection::addEntry(Symbol &Sym) {
Sym.PltIndex = Entries.size();
RelocationBaseSection *PltRelocSection = InX::RelaPlt;
- if (HeaderSize == 0) {
+ if (IsIplt) {
PltRelocSection = InX::RelaIplt;
Sym.IsInIplt = true;
}
@@ -1893,7 +2316,7 @@ size_t PltSection::getSize() const {
// example ARM uses mapping symbols to aid disassembly
void PltSection::addSymbols() {
// The PLT may have symbols defined for the Header, the IPLT has no header
- if (HeaderSize != 0)
+ if (!IsIplt)
Target->addPltHeaderSymbols(*this);
size_t Off = HeaderSize;
for (size_t I = 0; I < Entries.size(); ++I) {
@@ -1903,7 +2326,7 @@ void PltSection::addSymbols() {
}
unsigned PltSection::getPltRelocOff() const {
- return (HeaderSize == 0) ? InX::Plt->getSize() : 0;
+ return IsIplt ? InX::Plt->getSize() : 0;
}
// The string hash function for .gdb_index.
@@ -1914,16 +2337,48 @@ static uint32_t computeGdbHash(StringRef S) {
return H;
}
-static std::vector<GdbIndexChunk::CuEntry> readCuList(DWARFContext &Dwarf) {
- std::vector<GdbIndexChunk::CuEntry> Ret;
+GdbIndexSection::GdbIndexSection()
+ : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index") {}
+
+// Returns the desired size of an on-disk hash table for a .gdb_index section.
+// There's a tradeoff between size and collision rate. We aim 75% utilization.
+size_t GdbIndexSection::computeSymtabSize() const {
+ return std::max<size_t>(NextPowerOf2(Symbols.size() * 4 / 3), 1024);
+}
+
+// Compute the output section size.
+void GdbIndexSection::initOutputSize() {
+ Size = sizeof(GdbIndexHeader) + computeSymtabSize() * 8;
+
+ for (GdbChunk &Chunk : Chunks)
+ Size += Chunk.CompilationUnits.size() * 16 + Chunk.AddressAreas.size() * 20;
+
+ // Add the constant pool size if exists.
+ if (!Symbols.empty()) {
+ GdbSymbol &Sym = Symbols.back();
+ Size += Sym.NameOff + Sym.Name.size() + 1;
+ }
+}
+
+static std::vector<InputSection *> getDebugInfoSections() {
+ std::vector<InputSection *> Ret;
+ for (InputSectionBase *S : InputSections)
+ if (InputSection *IS = dyn_cast<InputSection>(S))
+ if (IS->Name == ".debug_info")
+ Ret.push_back(IS);
+ return Ret;
+}
+
+static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &Dwarf) {
+ std::vector<GdbIndexSection::CuEntry> Ret;
for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units())
Ret.push_back({Cu->getOffset(), Cu->getLength() + 4});
return Ret;
}
-static std::vector<GdbIndexChunk::AddressEntry>
+static std::vector<GdbIndexSection::AddressEntry>
readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) {
- std::vector<GdbIndexChunk::AddressEntry> Ret;
+ std::vector<GdbIndexSection::AddressEntry> Ret;
uint32_t CuIdx = 0;
for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units()) {
@@ -1947,218 +2402,192 @@ readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) {
return Ret;
}
-static std::vector<GdbIndexChunk::NameTypeEntry>
-readPubNamesAndTypes(DWARFContext &Dwarf) {
+static std::vector<GdbIndexSection::NameTypeEntry>
+readPubNamesAndTypes(DWARFContext &Dwarf, uint32_t Idx) {
StringRef Sec1 = Dwarf.getDWARFObj().getGnuPubNamesSection();
StringRef Sec2 = Dwarf.getDWARFObj().getGnuPubTypesSection();
- std::vector<GdbIndexChunk::NameTypeEntry> Ret;
+ std::vector<GdbIndexSection::NameTypeEntry> Ret;
for (StringRef Sec : {Sec1, Sec2}) {
DWARFDebugPubTable Table(Sec, Config->IsLE, true);
- for (const DWARFDebugPubTable::Set &Set : Table.getData()) {
- for (const DWARFDebugPubTable::Entry &Ent : Set.Entries) {
- CachedHashStringRef S(Ent.Name, computeGdbHash(Ent.Name));
- Ret.push_back({S, Ent.Descriptor.toBits()});
- }
- }
+ for (const DWARFDebugPubTable::Set &Set : Table.getData())
+ for (const DWARFDebugPubTable::Entry &Ent : Set.Entries)
+ Ret.push_back({{Ent.Name, computeGdbHash(Ent.Name)},
+ (Ent.Descriptor.toBits() << 24) | Idx});
}
return Ret;
}
-static std::vector<InputSection *> getDebugInfoSections() {
- std::vector<InputSection *> Ret;
- for (InputSectionBase *S : InputSections)
- if (InputSection *IS = dyn_cast<InputSection>(S))
- if (IS->Name == ".debug_info")
- Ret.push_back(IS);
- return Ret;
-}
+// Create a list of symbols from a given list of symbol names and types
+// by uniquifying them by name.
+static std::vector<GdbIndexSection::GdbSymbol>
+createSymbols(ArrayRef<std::vector<GdbIndexSection::NameTypeEntry>> NameTypes) {
+ typedef GdbIndexSection::GdbSymbol GdbSymbol;
+ typedef GdbIndexSection::NameTypeEntry NameTypeEntry;
-void GdbIndexSection::fixCuIndex() {
- uint32_t Idx = 0;
- for (GdbIndexChunk &Chunk : Chunks) {
- for (GdbIndexChunk::AddressEntry &Ent : Chunk.AddressAreas)
- Ent.CuIndex += Idx;
- Idx += Chunk.CompilationUnits.size();
- }
-}
+ // The number of symbols we will handle in this function is of the order
+ // of millions for very large executables, so we use multi-threading to
+ // speed it up.
+ size_t NumShards = 32;
+ size_t Concurrency = 1;
+ if (ThreadsEnabled)
+ Concurrency =
+ std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards);
-std::vector<std::vector<uint32_t>> GdbIndexSection::createCuVectors() {
- std::vector<std::vector<uint32_t>> Ret;
- uint32_t Idx = 0;
- uint32_t Off = 0;
+ // A sharded map to uniquify symbols by name.
+ std::vector<DenseMap<CachedHashStringRef, size_t>> Map(NumShards);
+ size_t Shift = 32 - countTrailingZeros(NumShards);
- for (GdbIndexChunk &Chunk : Chunks) {
- for (GdbIndexChunk::NameTypeEntry &Ent : Chunk.NamesAndTypes) {
- GdbSymbol *&Sym = Symbols[Ent.Name];
- if (!Sym) {
- Sym = make<GdbSymbol>(GdbSymbol{Ent.Name.hash(), Off, Ret.size()});
- Off += Ent.Name.size() + 1;
- Ret.push_back({});
- }
+ // Instantiate GdbSymbols while uniqufying them by name.
+ std::vector<std::vector<GdbSymbol>> Symbols(NumShards);
+ parallelForEachN(0, Concurrency, [&](size_t ThreadId) {
+ for (ArrayRef<NameTypeEntry> Entries : NameTypes) {
+ for (const NameTypeEntry &Ent : Entries) {
+ size_t ShardId = Ent.Name.hash() >> Shift;
+ if ((ShardId & (Concurrency - 1)) != ThreadId)
+ continue;
+
+ size_t &Idx = Map[ShardId][Ent.Name];
+ if (Idx) {
+ Symbols[ShardId][Idx - 1].CuVector.push_back(Ent.Type);
+ continue;
+ }
- // gcc 5.4.1 produces a buggy .debug_gnu_pubnames that contains
- // duplicate entries, so we want to dedup them.
- std::vector<uint32_t> &Vec = Ret[Sym->CuVectorIndex];
- uint32_t Val = (Ent.Type << 24) | Idx;
- if (Vec.empty() || Vec.back() != Val)
- Vec.push_back(Val);
+ Idx = Symbols[ShardId].size() + 1;
+ Symbols[ShardId].push_back({Ent.Name, {Ent.Type}, 0, 0});
+ }
}
- Idx += Chunk.CompilationUnits.size();
+ });
+
+ size_t NumSymbols = 0;
+ for (ArrayRef<GdbSymbol> V : Symbols)
+ NumSymbols += V.size();
+
+ // The return type is a flattened vector, so we'll copy each vector
+ // contents to Ret.
+ std::vector<GdbSymbol> Ret;
+ Ret.reserve(NumSymbols);
+ for (std::vector<GdbSymbol> &Vec : Symbols)
+ for (GdbSymbol &Sym : Vec)
+ Ret.push_back(std::move(Sym));
+
+ // CU vectors and symbol names are adjacent in the output file.
+ // We can compute their offsets in the output file now.
+ size_t Off = 0;
+ for (GdbSymbol &Sym : Ret) {
+ Sym.CuVectorOff = Off;
+ Off += (Sym.CuVector.size() + 1) * 4;
+ }
+ for (GdbSymbol &Sym : Ret) {
+ Sym.NameOff = Off;
+ Off += Sym.Name.size() + 1;
}
- StringPoolSize = Off;
return Ret;
}
-template <class ELFT> GdbIndexSection *elf::createGdbIndex() {
- // Gather debug info to create a .gdb_index section.
+// Returns a newly-created .gdb_index section.
+template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
std::vector<InputSection *> Sections = getDebugInfoSections();
- std::vector<GdbIndexChunk> Chunks(Sections.size());
-
- parallelForEachN(0, Chunks.size(), [&](size_t I) {
- ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>();
- DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File));
-
- Chunks[I].DebugInfoSec = Sections[I];
- Chunks[I].CompilationUnits = readCuList(Dwarf);
- Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]);
- Chunks[I].NamesAndTypes = readPubNamesAndTypes(Dwarf);
- });
// .debug_gnu_pub{names,types} are useless in executables.
// They are present in input object files solely for creating
- // a .gdb_index. So we can remove it from the output.
+ // a .gdb_index. So we can remove them from the output.
for (InputSectionBase *S : InputSections)
if (S->Name == ".debug_gnu_pubnames" || S->Name == ".debug_gnu_pubtypes")
S->Live = false;
- // Create a .gdb_index and returns it.
- return make<GdbIndexSection>(std::move(Chunks));
-}
-
-static size_t getCuSize(ArrayRef<GdbIndexChunk> Arr) {
- size_t Ret = 0;
- for (const GdbIndexChunk &D : Arr)
- Ret += D.CompilationUnits.size();
- return Ret;
-}
-
-static size_t getAddressAreaSize(ArrayRef<GdbIndexChunk> Arr) {
- size_t Ret = 0;
- for (const GdbIndexChunk &D : Arr)
- Ret += D.AddressAreas.size();
- return Ret;
-}
+ std::vector<GdbChunk> Chunks(Sections.size());
+ std::vector<std::vector<NameTypeEntry>> NameTypes(Sections.size());
-std::vector<GdbSymbol *> GdbIndexSection::createGdbSymtab() {
- uint32_t Size = NextPowerOf2(Symbols.size() * 4 / 3);
- if (Size < 1024)
- Size = 1024;
-
- uint32_t Mask = Size - 1;
- std::vector<GdbSymbol *> Ret(Size);
+ parallelForEachN(0, Sections.size(), [&](size_t I) {
+ ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>();
+ DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File));
- for (auto &KV : Symbols) {
- GdbSymbol *Sym = KV.second;
- uint32_t I = Sym->NameHash & Mask;
- uint32_t Step = ((Sym->NameHash * 17) & Mask) | 1;
+ Chunks[I].Sec = Sections[I];
+ Chunks[I].CompilationUnits = readCuList(Dwarf);
+ Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]);
+ NameTypes[I] = readPubNamesAndTypes(Dwarf, I);
+ });
- while (Ret[I])
- I = (I + Step) & Mask;
- Ret[I] = Sym;
- }
+ auto *Ret = make<GdbIndexSection>();
+ Ret->Chunks = std::move(Chunks);
+ Ret->Symbols = createSymbols(NameTypes);
+ Ret->initOutputSize();
return Ret;
}
-GdbIndexSection::GdbIndexSection(std::vector<GdbIndexChunk> &&C)
- : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"), Chunks(std::move(C)) {
- fixCuIndex();
- CuVectors = createCuVectors();
- GdbSymtab = createGdbSymtab();
-
- // Compute offsets early to know the section size.
- // Each chunk size needs to be in sync with what we write in writeTo.
- CuTypesOffset = CuListOffset + getCuSize(Chunks) * 16;
- SymtabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * 20;
- ConstantPoolOffset = SymtabOffset + GdbSymtab.size() * 8;
-
- size_t Off = 0;
- for (ArrayRef<uint32_t> Vec : CuVectors) {
- CuVectorOffsets.push_back(Off);
- Off += (Vec.size() + 1) * 4;
- }
- StringPoolOffset = ConstantPoolOffset + Off;
-}
-
-size_t GdbIndexSection::getSize() const {
- return StringPoolOffset + StringPoolSize;
-}
-
void GdbIndexSection::writeTo(uint8_t *Buf) {
- // Write the section header.
- write32le(Buf, 7);
- write32le(Buf + 4, CuListOffset);
- write32le(Buf + 8, CuTypesOffset);
- write32le(Buf + 12, CuTypesOffset);
- write32le(Buf + 16, SymtabOffset);
- write32le(Buf + 20, ConstantPoolOffset);
- Buf += 24;
+ // Write the header.
+ auto *Hdr = reinterpret_cast<GdbIndexHeader *>(Buf);
+ uint8_t *Start = Buf;
+ Hdr->Version = 7;
+ Buf += sizeof(*Hdr);
// Write the CU list.
- for (GdbIndexChunk &D : Chunks) {
- for (GdbIndexChunk::CuEntry &Cu : D.CompilationUnits) {
- write64le(Buf, D.DebugInfoSec->OutSecOff + Cu.CuOffset);
+ Hdr->CuListOff = Buf - Start;
+ for (GdbChunk &Chunk : Chunks) {
+ for (CuEntry &Cu : Chunk.CompilationUnits) {
+ write64le(Buf, Chunk.Sec->OutSecOff + Cu.CuOffset);
write64le(Buf + 8, Cu.CuLength);
Buf += 16;
}
}
// Write the address area.
- for (GdbIndexChunk &D : Chunks) {
- for (GdbIndexChunk::AddressEntry &E : D.AddressAreas) {
- uint64_t BaseAddr =
- E.Section->getParent()->Addr + E.Section->getOffset(0);
+ Hdr->CuTypesOff = Buf - Start;
+ Hdr->AddressAreaOff = Buf - Start;
+ uint32_t CuOff = 0;
+ for (GdbChunk &Chunk : Chunks) {
+ for (AddressEntry &E : Chunk.AddressAreas) {
+ uint64_t BaseAddr = E.Section->getVA(0);
write64le(Buf, BaseAddr + E.LowAddress);
write64le(Buf + 8, BaseAddr + E.HighAddress);
- write32le(Buf + 16, E.CuIndex);
+ write32le(Buf + 16, E.CuIndex + CuOff);
Buf += 20;
}
+ CuOff += Chunk.CompilationUnits.size();
}
- // Write the symbol table.
- for (GdbSymbol *Sym : GdbSymtab) {
- if (Sym) {
- write32le(Buf, Sym->NameOffset + StringPoolOffset - ConstantPoolOffset);
- write32le(Buf + 4, CuVectorOffsets[Sym->CuVectorIndex]);
- }
- Buf += 8;
+ // Write the on-disk open-addressing hash table containing symbols.
+ Hdr->SymtabOff = Buf - Start;
+ size_t SymtabSize = computeSymtabSize();
+ uint32_t Mask = SymtabSize - 1;
+
+ for (GdbSymbol &Sym : Symbols) {
+ uint32_t H = Sym.Name.hash();
+ uint32_t I = H & Mask;
+ uint32_t Step = ((H * 17) & Mask) | 1;
+
+ while (read32le(Buf + I * 8))
+ I = (I + Step) & Mask;
+
+ write32le(Buf + I * 8, Sym.NameOff);
+ write32le(Buf + I * 8 + 4, Sym.CuVectorOff);
}
+ Buf += SymtabSize * 8;
+
+ // Write the string pool.
+ Hdr->ConstantPoolOff = Buf - Start;
+ for (GdbSymbol &Sym : Symbols)
+ memcpy(Buf + Sym.NameOff, Sym.Name.data(), Sym.Name.size());
+
// Write the CU vectors.
- for (ArrayRef<uint32_t> Vec : CuVectors) {
- write32le(Buf, Vec.size());
+ for (GdbSymbol &Sym : Symbols) {
+ write32le(Buf, Sym.CuVector.size());
Buf += 4;
- for (uint32_t Val : Vec) {
+ for (uint32_t Val : Sym.CuVector) {
write32le(Buf, Val);
Buf += 4;
}
}
-
- // Write the string pool.
- for (auto &KV : Symbols) {
- CachedHashStringRef S = KV.first;
- GdbSymbol *Sym = KV.second;
- size_t Off = Sym->NameOffset;
- memcpy(Buf + Off, S.val().data(), S.size());
- Buf[Off + S.size()] = '\0';
- }
}
bool GdbIndexSection::empty() const { return !Out::DebugInfo; }
EhFrameHeader::EhFrameHeader()
- : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {}
+ : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {}
// .eh_frame_hdr contains a binary search table of pointers to FDEs.
// Each entry of the search table consists of two values,
@@ -2169,14 +2598,6 @@ void EhFrameHeader::writeTo(uint8_t *Buf) {
std::vector<FdeData> Fdes = InX::EhFrame->getFdeData();
- // Sort the FDE list by their PC and uniqueify. Usually there is only
- // one FDE for a PC (i.e. function), but if ICF merges two functions
- // into one, there can be more than one FDEs pointing to the address.
- auto Less = [](const FdeData &A, const FdeData &B) { return A.Pc < B.Pc; };
- std::stable_sort(Fdes.begin(), Fdes.end(), Less);
- auto Eq = [](const FdeData &A, const FdeData &B) { return A.Pc == B.Pc; };
- Fdes.erase(std::unique(Fdes.begin(), Fdes.end(), Eq), Fdes.end());
-
Buf[0] = 1;
Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
Buf[2] = DW_EH_PE_udata4;
@@ -2185,10 +2606,9 @@ void EhFrameHeader::writeTo(uint8_t *Buf) {
write32(Buf + 8, Fdes.size());
Buf += 12;
- uint64_t VA = this->getVA();
for (FdeData &Fde : Fdes) {
- write32(Buf, Fde.Pc - VA);
- write32(Buf + 4, Fde.FdeVA - VA);
+ write32(Buf, Fde.PcRel);
+ write32(Buf + 4, Fde.FdeVARel);
Buf += 8;
}
}
@@ -2298,11 +2718,9 @@ VersionNeedSection<ELFT>::VersionNeedSection()
NextIndex = getVerDefNum() + 1;
}
-template <class ELFT>
-void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) {
- SharedFile<ELFT> &File = SS->getFile<ELFT>();
- const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex];
- if (!Ver) {
+template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) {
+ auto &File = cast<SharedFile<ELFT>>(*SS->File);
+ if (SS->VerdefIndex == VER_NDX_GLOBAL) {
SS->VersionId = VER_NDX_GLOBAL;
return;
}
@@ -2312,7 +2730,9 @@ void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) {
// for the soname.
if (File.VerdefMap.empty())
Needed.push_back({&File, InX::DynStrTab->addString(File.SoName)});
+ const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex];
typename SharedFile<ELFT>::NeededVer &NV = File.VerdefMap[Ver];
+
// If we don't already know that we need an Elf_Vernaux for this Elf_Verdef,
// prepare to create one by allocating a version identifier and creating a
// dynstr entry for the version name.
@@ -2476,11 +2896,20 @@ static MergeSyntheticSection *createMergeSynthetic(StringRef Name,
return make<MergeNoTailSection>(Name, Type, Flags, Alignment);
}
-// Debug sections may be compressed by zlib. Uncompress if exists.
+// Debug sections may be compressed by zlib. Decompress if exists.
void elf::decompressSections() {
+ parallelForEach(InputSections,
+ [](InputSectionBase *Sec) { Sec->maybeDecompress(); });
+}
+
+template <class ELFT> void elf::splitSections() {
+ // splitIntoPieces needs to be called on each MergeInputSection
+ // before calling finalizeContents().
parallelForEach(InputSections, [](InputSectionBase *Sec) {
- if (Sec->Live)
- Sec->maybeUncompress();
+ if (auto *S = dyn_cast<MergeInputSection>(Sec))
+ S->splitIntoPieces();
+ else if (auto *Eh = dyn_cast<EhInputSection>(Sec))
+ Eh->split<ELFT>();
});
}
@@ -2492,14 +2921,6 @@ void elf::decompressSections() {
// that it replaces. It then finalizes each synthetic section in order
// to compute an output offset for each piece of each input section.
void elf::mergeSections() {
- // splitIntoPieces needs to be called on each MergeInputSection
- // before calling finalizeContents(). Do that first.
- parallelForEach(InputSections, [](InputSectionBase *Sec) {
- if (Sec->Live)
- if (auto *S = dyn_cast<MergeInputSection>(Sec))
- S->splitIntoPieces();
- });
-
std::vector<MergeSyntheticSection *> MergeSections;
for (InputSectionBase *&S : InputSections) {
MergeInputSection *MS = dyn_cast<MergeInputSection>(S);
@@ -2561,8 +2982,7 @@ ARMExidxSentinelSection::ARMExidxSentinelSection()
// address described by any other table entry.
void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
assert(Highest);
- uint64_t S =
- Highest->getParent()->Addr + Highest->getOffset(Highest->getSize());
+ uint64_t S = Highest->getVA(Highest->getSize());
uint64_t P = getVA();
Target->relocateOne(Buf, R_ARM_PREL31, S - P);
write32le(Buf + 4, 1);
@@ -2570,15 +2990,16 @@ void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
// The sentinel has to be removed if there are no other .ARM.exidx entries.
bool ARMExidxSentinelSection::empty() const {
- OutputSection *OS = getParent();
- for (auto *B : OS->SectionCommands)
- if (auto *ISD = dyn_cast<InputSectionDescription>(B))
- for (auto *S : ISD->Sections)
- if (!isa<ARMExidxSentinelSection>(S))
- return false;
+ for (InputSection *IS : getInputSections(getParent()))
+ if (!isa<ARMExidxSentinelSection>(IS))
+ return false;
return true;
}
+bool ARMExidxSentinelSection::classof(const SectionBase *D) {
+ return D->kind() == InputSectionBase::Synthetic && D->Type == SHT_ARM_EXIDX;
+}
+
ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off)
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS,
Config->Wordsize, ".text.thunk") {
@@ -2587,16 +3008,13 @@ ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off)
}
void ThunkSection::addThunk(Thunk *T) {
- uint64_t Off = alignTo(Size, T->Alignment);
- T->Offset = Off;
Thunks.push_back(T);
T->addSymbols(*this);
- Size = Off + T->size();
}
void ThunkSection::writeTo(uint8_t *Buf) {
- for (const Thunk *T : Thunks)
- T->writeTo(Buf + T->Offset, *this);
+ for (Thunk *T : Thunks)
+ T->writeTo(Buf + T->Offset);
}
InputSection *ThunkSection::getTargetInputSection() const {
@@ -2606,6 +3024,20 @@ InputSection *ThunkSection::getTargetInputSection() const {
return T->getTargetInputSection();
}
+bool ThunkSection::assignOffsets() {
+ uint64_t Off = 0;
+ for (Thunk *T : Thunks) {
+ Off = alignTo(Off, T->Alignment);
+ T->setOffset(Off);
+ uint32_t Size = T->size();
+ T->getThunkTargetSym()->Size = Size;
+ Off += Size;
+ }
+ bool Changed = Off != Size;
+ Size = Off;
+ return Changed;
+}
+
InputSection *InX::ARMAttributes;
BssSection *InX::Bss;
BssSection *InX::BssRelRo;
@@ -2627,16 +3059,23 @@ MipsRldMapSection *InX::MipsRldMap;
PltSection *InX::Plt;
PltSection *InX::Iplt;
RelocationBaseSection *InX::RelaDyn;
+RelrBaseSection *InX::RelrDyn;
RelocationBaseSection *InX::RelaPlt;
RelocationBaseSection *InX::RelaIplt;
StringTableSection *InX::ShStrTab;
StringTableSection *InX::StrTab;
SymbolTableBaseSection *InX::SymTab;
+SymtabShndxSection *InX::SymTabShndx;
+
+template GdbIndexSection *GdbIndexSection::create<ELF32LE>();
+template GdbIndexSection *GdbIndexSection::create<ELF32BE>();
+template GdbIndexSection *GdbIndexSection::create<ELF64LE>();
+template GdbIndexSection *GdbIndexSection::create<ELF64BE>();
-template GdbIndexSection *elf::createGdbIndex<ELF32LE>();
-template GdbIndexSection *elf::createGdbIndex<ELF32BE>();
-template GdbIndexSection *elf::createGdbIndex<ELF64LE>();
-template GdbIndexSection *elf::createGdbIndex<ELF64BE>();
+template void elf::splitSections<ELF32LE>();
+template void elf::splitSections<ELF32BE>();
+template void elf::splitSections<ELF64LE>();
+template void elf::splitSections<ELF64BE>();
template void EhFrameSection::addSection<ELF32LE>(InputSectionBase *);
template void EhFrameSection::addSection<ELF32BE>(InputSectionBase *);
@@ -2648,6 +3087,11 @@ template void PltSection::addEntry<ELF32BE>(Symbol &Sym);
template void PltSection::addEntry<ELF64LE>(Symbol &Sym);
template void PltSection::addEntry<ELF64BE>(Symbol &Sym);
+template void MipsGotSection::build<ELF32LE>();
+template void MipsGotSection::build<ELF32BE>();
+template void MipsGotSection::build<ELF64LE>();
+template void MipsGotSection::build<ELF64BE>();
+
template class elf::MipsAbiFlagsSection<ELF32LE>;
template class elf::MipsAbiFlagsSection<ELF32BE>;
template class elf::MipsAbiFlagsSection<ELF64LE>;
@@ -2678,6 +3122,11 @@ template class elf::AndroidPackedRelocationSection<ELF32BE>;
template class elf::AndroidPackedRelocationSection<ELF64LE>;
template class elf::AndroidPackedRelocationSection<ELF64BE>;
+template class elf::RelrSection<ELF32LE>;
+template class elf::RelrSection<ELF32BE>;
+template class elf::RelrSection<ELF64LE>;
+template class elf::RelrSection<ELF64BE>;
+
template class elf::SymbolTableSection<ELF32LE>;
template class elf::SymbolTableSection<ELF32BE>;
template class elf::SymbolTableSection<ELF64LE>;
diff --git a/contrib/llvm/tools/lld/ELF/SyntheticSections.h b/contrib/llvm/tools/lld/ELF/SyntheticSections.h
index a990590513bb..a780c6631374 100644
--- a/contrib/llvm/tools/lld/ELF/SyntheticSections.h
+++ b/contrib/llvm/tools/lld/ELF/SyntheticSections.h
@@ -26,10 +26,12 @@
#include "InputSection.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Support/Endian.h"
#include <functional>
namespace lld {
namespace elf {
+class Defined;
class SharedSymbol;
class SyntheticSection : public InputSection {
@@ -51,7 +53,6 @@ public:
// If any additional finalization of contents are needed post thunk creation.
virtual void postThunkContents() {}
virtual bool empty() const { return false; }
- uint64_t getVA() const;
static bool classof(const SectionBase *D) {
return D->kind() == InputSectionBase::Synthetic;
@@ -78,13 +79,18 @@ public:
size_t NumFdes = 0;
struct FdeData {
- uint32_t Pc;
- uint32_t FdeVA;
+ uint32_t PcRel;
+ uint32_t FdeVARel;
};
std::vector<FdeData> getFdeData() const;
+ ArrayRef<CieRecord *> getCieRecords() const { return CieRecords; }
private:
+ // This is used only when parsing EhInputSection. We keep it here to avoid
+ // allocating one for each EhInputSection.
+ llvm::DenseMap<size_t, CieRecord *> OffsetToCie;
+
uint64_t Size = 0;
template <class ELFT, class RelTy>
@@ -173,12 +179,21 @@ public:
bool updateAllocSize() override;
void finalizeContents() override;
bool empty() const override;
- void addEntry(Symbol &Sym, int64_t Addend, RelExpr Expr);
- bool addDynTlsEntry(Symbol &Sym);
- bool addTlsIndex();
- uint64_t getPageEntryOffset(const Symbol &B, int64_t Addend) const;
- uint64_t getSymEntryOffset(const Symbol &B, int64_t Addend) const;
- uint64_t getGlobalDynOffset(const Symbol &B) const;
+
+ // Join separate GOTs built for each input file to generate
+ // primary and optional multiple secondary GOTs.
+ template <class ELFT> void build();
+
+ void addEntry(InputFile &File, Symbol &Sym, int64_t Addend, RelExpr Expr);
+ void addDynTlsEntry(InputFile &File, Symbol &Sym);
+ void addTlsIndex(InputFile &File);
+
+ uint64_t getPageEntryOffset(const InputFile *F, const Symbol &S,
+ int64_t Addend) const;
+ uint64_t getSymEntryOffset(const InputFile *F, const Symbol &S,
+ int64_t Addend) const;
+ uint64_t getGlobalDynOffset(const InputFile *F, const Symbol &S) const;
+ uint64_t getTlsIndexOffset(const InputFile *F) const;
// Returns the symbol which corresponds to the first entry of the global part
// of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic
@@ -190,13 +205,8 @@ public:
// the number of reserved entries.
unsigned getLocalEntriesNum() const;
- // Returns offset of TLS part of the MIPS GOT table. This part goes
- // after 'local' and 'global' entries.
- uint64_t getTlsOffset() const;
-
- uint32_t getTlsIndexOff() const { return TlsIndexOff; }
-
- uint64_t getGp() const;
+ // Return _gp value for primary GOT (nullptr) or particular input file.
+ uint64_t getGp(const InputFile *F = nullptr) const;
private:
// MIPS GOT consists of three parts: local, global and tls. Each part
@@ -235,32 +245,110 @@ private:
// addressing, but MIPS ABI requires that these entries be present in GOT.
// TLS entries:
// Entries created by TLS relocations.
+ //
+ // If the sum of local, global and tls entries is less than 64K only single
+ // got is enough. Otherwise, multi-got is created. Series of primary and
+ // multiple secondary GOTs have the following layout:
+ // - Primary GOT
+ // Header
+ // Local entries
+ // Global entries
+ // Relocation only entries
+ // TLS entries
+ //
+ // - Secondary GOT
+ // Local entries
+ // Global entries
+ // TLS entries
+ // ...
+ //
+ // All GOT entries required by relocations from a single input file entirely
+ // belong to either primary or one of secondary GOTs. To reference GOT entries
+ // each GOT has its own _gp value points to the "middle" of the GOT.
+ // In the code this value loaded to the register which is used for GOT access.
+ //
+ // MIPS 32 function's prologue:
+ // lui v0,0x0
+ // 0: R_MIPS_HI16 _gp_disp
+ // addiu v0,v0,0
+ // 4: R_MIPS_LO16 _gp_disp
+ //
+ // MIPS 64:
+ // lui at,0x0
+ // 14: R_MIPS_GPREL16 main
+ //
+ // Dynamic linker does not know anything about secondary GOTs and cannot
+ // use a regular MIPS mechanism for GOT entries initialization. So we have
+ // to use an approach accepted by other architectures and create dynamic
+ // relocations R_MIPS_REL32 to initialize global entries (and local in case
+ // of PIC code) in secondary GOTs. But ironically MIPS dynamic linker
+ // requires GOT entries and correspondingly ordered dynamic symbol table
+ // entries to deal with dynamic relocations. To handle this problem
+ // relocation-only section in the primary GOT contains entries for all
+ // symbols referenced in global parts of secondary GOTs. Although the sum
+ // of local and normal global entries of the primary got should be less
+ // than 64K, the size of the primary got (including relocation-only entries
+ // can be greater than 64K, because parts of the primary got that overflow
+ // the 64K limit are used only by the dynamic linker at dynamic link-time
+ // and not by 16-bit gp-relative addressing at run-time.
+ //
+ // For complete multi-GOT description see the following link
+ // https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT
// Number of "Header" entries.
static const unsigned HeaderEntriesNum = 2;
- // Number of allocated "Page" entries.
- uint32_t PageEntriesNum = 0;
- // Map output sections referenced by MIPS GOT relocations
- // to the first index of "Page" entries allocated for this section.
- llvm::SmallMapVector<const OutputSection *, size_t, 16> PageIndexMap;
-
- typedef std::pair<const Symbol *, uint64_t> GotEntry;
- typedef std::vector<GotEntry> GotEntries;
- // Map from Symbol-Addend pair to the GOT index.
- llvm::DenseMap<GotEntry, size_t> EntryIndexMap;
- // Local entries (16-bit access).
- GotEntries LocalEntries;
- // Local entries (32-bit access).
- GotEntries LocalEntries32;
-
- // Normal and reloc-only global entries.
- GotEntries GlobalEntries;
-
- // TLS entries.
- std::vector<const Symbol *> TlsEntries;
- uint32_t TlsIndexOff = -1;
uint64_t Size = 0;
+
+ size_t LocalEntriesNum = 0;
+
+ // Symbol and addend.
+ typedef std::pair<Symbol *, int64_t> GotEntry;
+
+ struct FileGot {
+ InputFile *File = nullptr;
+ size_t StartIndex = 0;
+
+ struct PageBlock {
+ size_t FirstIndex = 0;
+ size_t Count = 0;
+ };
+
+ // Map output sections referenced by MIPS GOT relocations
+ // to the description (index/count) "page" entries allocated
+ // for this section.
+ llvm::SmallMapVector<const OutputSection *, PageBlock, 16> PagesMap;
+ // Maps from Symbol+Addend pair or just Symbol to the GOT entry index.
+ llvm::MapVector<GotEntry, size_t> Local16;
+ llvm::MapVector<GotEntry, size_t> Local32;
+ llvm::MapVector<Symbol *, size_t> Global;
+ llvm::MapVector<Symbol *, size_t> Relocs;
+ llvm::MapVector<Symbol *, size_t> Tls;
+ // Set of symbols referenced by dynamic TLS relocations.
+ llvm::MapVector<Symbol *, size_t> DynTlsSymbols;
+
+ // Total number of all entries.
+ size_t getEntriesNum() const;
+ // Number of "page" entries.
+ size_t getPageEntriesNum() const;
+ // Number of entries require 16-bit index to access.
+ size_t getIndexedEntriesNum() const;
+
+ bool isOverflow() const;
+ };
+
+ // Container of GOT created for each input file.
+ // After building a final series of GOTs this container
+ // holds primary and secondary GOT's.
+ std::vector<FileGot> Gots;
+
+ // Return (and create if necessary) `FileGot`.
+ FileGot &getGot(InputFile &F);
+
+ // Try to merge two GOTs. In case of success the `Dst` contains
+ // result of merging and the function returns true. In case of
+ // ovwerflow the `Dst` is unchanged and the function returns false.
+ bool tryMergeGots(FileGot & Dst, FileGot & Src, bool IsPrimary);
};
class GotPltSection final : public SyntheticSection {
@@ -269,7 +357,7 @@ public:
void addEntry(Symbol &Sym);
size_t getSize() const override;
void writeTo(uint8_t *Buf) override;
- bool empty() const override { return Entries.empty(); }
+ bool empty() const override;
private:
std::vector<const Symbol *> Entries;
@@ -310,30 +398,48 @@ private:
class DynamicReloc {
public:
- DynamicReloc(uint32_t Type, const InputSectionBase *InputSec,
+ DynamicReloc(RelType Type, const InputSectionBase *InputSec,
uint64_t OffsetInSec, bool UseSymVA, Symbol *Sym, int64_t Addend)
: Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec),
- UseSymVA(UseSymVA), Addend(Addend) {}
+ UseSymVA(UseSymVA), Addend(Addend), OutputSec(nullptr) {}
+ // This constructor records dynamic relocation settings used by MIPS
+ // multi-GOT implementation. It's to relocate addresses of 64kb pages
+ // lie inside the output section.
+ DynamicReloc(RelType Type, const InputSectionBase *InputSec,
+ uint64_t OffsetInSec, const OutputSection *OutputSec,
+ int64_t Addend)
+ : Type(Type), Sym(nullptr), InputSec(InputSec), OffsetInSec(OffsetInSec),
+ UseSymVA(false), Addend(Addend), OutputSec(OutputSec) {}
uint64_t getOffset() const;
- int64_t getAddend() const;
uint32_t getSymIndex() const;
const InputSectionBase *getInputSec() const { return InputSec; }
- uint32_t Type;
+ // Computes the addend of the dynamic relocation. Note that this is not the
+ // same as the Addend member variable as it also includes the symbol address
+ // if UseSymVA is true.
+ int64_t computeAddend() const;
+
+ RelType Type;
private:
Symbol *Sym;
const InputSectionBase *InputSec = nullptr;
uint64_t OffsetInSec;
+ // If this member is true, the dynamic relocation will not be against the
+ // symbol but will instead be a relative relocation that simply adds the
+ // load address. This means we need to write the symbol virtual address
+ // plus the original addend as the final relocation addend.
bool UseSymVA;
int64_t Addend;
+ const OutputSection *OutputSec;
};
template <class ELFT> class DynamicSection final : public SyntheticSection {
typedef typename ELFT::Dyn Elf_Dyn;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
+ typedef typename ELFT::Relr Elf_Relr;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Sym Elf_Sym;
@@ -350,6 +456,7 @@ private:
void add(int32_t Tag, std::function<uint64_t()> Fn);
void addInt(int32_t Tag, uint64_t Val);
void addInSec(int32_t Tag, InputSection *Sec);
+ void addInSecRelative(int32_t Tag, InputSection *Sec);
void addOutSec(int32_t Tag, OutputSection *Sec);
void addSize(int32_t Tag, OutputSection *Sec);
void addSym(int32_t Tag, Symbol *Sym);
@@ -361,6 +468,13 @@ class RelocationBaseSection : public SyntheticSection {
public:
RelocationBaseSection(StringRef Name, uint32_t Type, int32_t DynamicTag,
int32_t SizeDynamicTag);
+ void addReloc(RelType DynType, InputSectionBase *IS, uint64_t OffsetInSec,
+ Symbol *Sym);
+ // Add a dynamic relocation that might need an addend. This takes care of
+ // writing the addend to the output section if needed.
+ void addReloc(RelType DynType, InputSectionBase *InputSec,
+ uint64_t OffsetInSec, Symbol *Sym, int64_t Addend, RelExpr Expr,
+ RelType Type);
void addReloc(const DynamicReloc &Reloc);
bool empty() const override { return Relocs.empty(); }
size_t getSize() const override { return Relocs.size() * this->Entsize; }
@@ -405,6 +519,39 @@ private:
SmallVector<char, 0> RelocData;
};
+struct RelativeReloc {
+ uint64_t getOffset() const { return InputSec->getVA(OffsetInSec); }
+
+ const InputSectionBase *InputSec;
+ uint64_t OffsetInSec;
+};
+
+class RelrBaseSection : public SyntheticSection {
+public:
+ RelrBaseSection();
+ std::vector<RelativeReloc> Relocs;
+};
+
+// RelrSection is used to encode offsets for relative relocations.
+// Proposal for adding SHT_RELR sections to generic-abi is here:
+// https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+// For more details, see the comment in RelrSection::updateAllocSize().
+template <class ELFT> class RelrSection final : public RelrBaseSection {
+ typedef typename ELFT::Relr Elf_Relr;
+
+public:
+ RelrSection();
+
+ bool updateAllocSize() override;
+ size_t getSize() const override { return RelrRelocs.size() * this->Entsize; }
+ void writeTo(uint8_t *Buf) override {
+ memcpy(Buf, RelrRelocs.data(), getSize());
+ }
+
+private:
+ std::vector<Elf_Relr> RelrRelocs;
+};
+
struct SymbolTableEntry {
Symbol *Sym;
size_t StrTabOffset;
@@ -441,6 +588,16 @@ public:
void writeTo(uint8_t *Buf) override;
};
+class SymtabShndxSection final : public SyntheticSection {
+public:
+ SymtabShndxSection();
+
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override;
+ bool empty() const override;
+ void finalizeContents() override;
+};
+
// Outputs GNU Hash section. For detailed explanation see:
// https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections
class GnuHashTableSection final : public SyntheticSection {
@@ -455,7 +612,7 @@ public:
void addSymbols(std::vector<SymbolTableEntry> &Symbols);
private:
- size_t getShift2() const { return Config->Is64 ? 6 : 5; }
+ enum { Shift2 = 6 };
void writeBloomFilter(uint8_t *Buf);
void writeHashTable(uint8_t *Buf);
@@ -484,13 +641,13 @@ private:
size_t Size = 0;
};
-// The PltSection is used for both the Plt and Iplt. The former always has a
+// The PltSection is used for both the Plt and Iplt. The former usually has a
// header as its first entry that is used at run-time to resolve lazy binding.
// The latter is used for GNU Ifunc symbols, that will be subject to a
// Target->IRelativeRel.
class PltSection : public SyntheticSection {
public:
- PltSection(size_t HeaderSize);
+ PltSection(bool IsIplt);
void writeTo(uint8_t *Buf) override;
size_t getSize() const override;
bool empty() const override { return Entries.empty(); }
@@ -501,13 +658,12 @@ public:
private:
unsigned getPltRelocOff() const;
std::vector<std::pair<const Symbol *, unsigned>> Entries;
- // Iplt always has HeaderSize of 0, the Plt HeaderSize is always non-zero
size_t HeaderSize;
+ bool IsIplt;
};
-// GdbIndexChunk is created for each .debug_info section and contains
-// information to create a part of .gdb_index for a given input section.
-struct GdbIndexChunk {
+class GdbIndexSection final : public SyntheticSection {
+public:
struct AddressEntry {
InputSection *Section;
uint64_t LowAddress;
@@ -522,59 +678,51 @@ struct GdbIndexChunk {
struct NameTypeEntry {
llvm::CachedHashStringRef Name;
- uint8_t Type;
+ uint32_t Type;
};
- InputSection *DebugInfoSec;
- std::vector<AddressEntry> AddressAreas;
- std::vector<CuEntry> CompilationUnits;
- std::vector<NameTypeEntry> NamesAndTypes;
-};
+ struct GdbChunk {
+ InputSection *Sec;
+ std::vector<AddressEntry> AddressAreas;
+ std::vector<CuEntry> CompilationUnits;
+ };
-// The symbol type for the .gdb_index section.
-struct GdbSymbol {
- uint32_t NameHash;
- size_t NameOffset;
- size_t CuVectorIndex;
-};
+ struct GdbSymbol {
+ llvm::CachedHashStringRef Name;
+ std::vector<uint32_t> CuVector;
+ uint32_t NameOff;
+ uint32_t CuVectorOff;
+ };
-class GdbIndexSection final : public SyntheticSection {
-public:
- GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks);
+ GdbIndexSection();
+ template <typename ELFT> static GdbIndexSection *create();
void writeTo(uint8_t *Buf) override;
- size_t getSize() const override;
+ size_t getSize() const override { return Size; }
bool empty() const override;
private:
- void fixCuIndex();
- std::vector<std::vector<uint32_t>> createCuVectors();
- std::vector<GdbSymbol *> createGdbSymtab();
-
- // A symbol table for this .gdb_index section.
- std::vector<GdbSymbol *> GdbSymtab;
-
- // CU vector is a part of constant pool area of section.
- std::vector<std::vector<uint32_t>> CuVectors;
+ struct GdbIndexHeader {
+ llvm::support::ulittle32_t Version;
+ llvm::support::ulittle32_t CuListOff;
+ llvm::support::ulittle32_t CuTypesOff;
+ llvm::support::ulittle32_t AddressAreaOff;
+ llvm::support::ulittle32_t SymtabOff;
+ llvm::support::ulittle32_t ConstantPoolOff;
+ };
- // Symbol table contents.
- llvm::DenseMap<llvm::CachedHashStringRef, GdbSymbol *> Symbols;
+ void initOutputSize();
+ size_t computeSymtabSize() const;
- // Each chunk contains information gathered from a debug sections of single
- // object and used to build different areas of gdb index.
- std::vector<GdbIndexChunk> Chunks;
+ // Each chunk contains information gathered from debug sections of a
+ // single object file.
+ std::vector<GdbChunk> Chunks;
- static constexpr uint32_t CuListOffset = 24;
- uint32_t CuTypesOffset;
- uint32_t SymtabOffset;
- uint32_t ConstantPoolOffset;
- uint32_t StringPoolOffset;
- uint32_t StringPoolSize;
+ // A symbol table for this .gdb_index section.
+ std::vector<GdbSymbol> Symbols;
- std::vector<size_t> CuVectorOffsets;
+ size_t Size;
};
-template <class ELFT> GdbIndexSection *createGdbIndex();
-
// --eh-frame-hdr option tells linker to construct a header for all the
// .eh_frame sections. This header is placed to a section named .eh_frame_hdr
// and also to a PT_GNU_EH_FRAME segment.
@@ -653,7 +801,7 @@ template <class ELFT> class VersionNeedSection final : public SyntheticSection {
public:
VersionNeedSection();
- void addSymbol(SharedSymbol *SS);
+ void addSymbol(Symbol *Sym);
void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
size_t getSize() const override;
@@ -668,13 +816,12 @@ public:
class MergeSyntheticSection : public SyntheticSection {
public:
void addSection(MergeInputSection *MS);
+ std::vector<MergeInputSection *> Sections;
protected:
MergeSyntheticSection(StringRef Name, uint32_t Type, uint64_t Flags,
uint32_t Alignment)
: SyntheticSection(Flags, Type, Alignment, Name) {}
-
- std::vector<MergeInputSection *> Sections;
};
class MergeTailSection final : public MergeSyntheticSection {
@@ -787,7 +934,12 @@ public:
void writeTo(uint8_t *Buf) override;
bool empty() const override;
- InputSection *Highest = 0;
+ static bool classof(const SectionBase *D);
+
+ // The last section referenced by a regular .ARM.exidx section.
+ // It is found and filled in Writer<ELFT>::resolveShfLinkOrder().
+ // The sentinel points at the end of that section.
+ InputSection *Highest = nullptr;
};
// A container for one or more linker generated thunks. Instances of these
@@ -805,19 +957,21 @@ public:
size_t getSize() const override { return Size; }
void writeTo(uint8_t *Buf) override;
InputSection *getTargetInputSection() const;
+ bool assignOffsets();
private:
- std::vector<const Thunk *> Thunks;
+ std::vector<Thunk *> Thunks;
size_t Size = 0;
};
InputSection *createInterpSection();
MergeInputSection *createCommentSection();
void decompressSections();
+template <class ELFT> void splitSections();
void mergeSections();
-Symbol *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
- uint64_t Size, InputSectionBase &Section);
+Defined *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
+ uint64_t Size, InputSectionBase &Section);
// Linker generated sections which can be used as inputs.
struct InX {
@@ -842,11 +996,13 @@ struct InX {
static PltSection *Plt;
static PltSection *Iplt;
static RelocationBaseSection *RelaDyn;
+ static RelrBaseSection *RelrDyn;
static RelocationBaseSection *RelaPlt;
static RelocationBaseSection *RelaIplt;
static StringTableSection *ShStrTab;
static StringTableSection *StrTab;
static SymbolTableBaseSection *SymTab;
+ static SymtabShndxSection* SymTabShndx;
};
template <class ELFT> struct In {
diff --git a/contrib/llvm/tools/lld/ELF/Target.cpp b/contrib/llvm/tools/lld/ELF/Target.cpp
index b528fd583c1a..815f3a045551 100644
--- a/contrib/llvm/tools/lld/ELF/Target.cpp
+++ b/contrib/llvm/tools/lld/ELF/Target.cpp
@@ -60,6 +60,8 @@ TargetInfo *elf::getTarget() {
return getARMTargetInfo();
case EM_AVR:
return getAVRTargetInfo();
+ case EM_HEXAGON:
+ return getHexagonTargetInfo();
case EM_MIPS:
switch (Config->EKind) {
case ELF32LEKind:
@@ -87,29 +89,29 @@ TargetInfo *elf::getTarget() {
fatal("unknown target machine");
}
-template <class ELFT> static std::string getErrorLoc(const uint8_t *Loc) {
+template <class ELFT> static ErrorPlace getErrPlace(const uint8_t *Loc) {
for (InputSectionBase *D : InputSections) {
- auto *IS = dyn_cast<InputSection>(D);
- if (!IS || !IS->getParent())
+ auto *IS = cast<InputSection>(D);
+ if (!IS->getParent())
continue;
uint8_t *ISLoc = IS->getParent()->Loc + IS->OutSecOff;
if (ISLoc <= Loc && Loc < ISLoc + IS->getSize())
- return IS->template getLocation<ELFT>(Loc - ISLoc) + ": ";
+ return {IS, IS->template getLocation<ELFT>(Loc - ISLoc) + ": "};
}
- return "";
+ return {};
}
-std::string elf::getErrorLocation(const uint8_t *Loc) {
+ErrorPlace elf::getErrorPlace(const uint8_t *Loc) {
switch (Config->EKind) {
case ELF32LEKind:
- return getErrorLoc<ELF32LE>(Loc);
+ return getErrPlace<ELF32LE>(Loc);
case ELF32BEKind:
- return getErrorLoc<ELF32BE>(Loc);
+ return getErrPlace<ELF32BE>(Loc);
case ELF64LEKind:
- return getErrorLoc<ELF64LE>(Loc);
+ return getErrPlace<ELF64LE>(Loc);
case ELF64BEKind:
- return getErrorLoc<ELF64BE>(Loc);
+ return getErrPlace<ELF64BE>(Loc);
default:
llvm_unreachable("unknown ELF type");
}
@@ -128,6 +130,12 @@ bool TargetInfo::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
return false;
}
+bool TargetInfo::adjustPrologueForCrossSplitStack(uint8_t *Loc,
+ uint8_t *End) const {
+ llvm_unreachable("Target doesn't support split stacks.");
+}
+
+
bool TargetInfo::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
return true;
}
diff --git a/contrib/llvm/tools/lld/ELF/Target.h b/contrib/llvm/tools/lld/ELF/Target.h
index 1f58adba1817..82c7b8f7b6c5 100644
--- a/contrib/llvm/tools/lld/ELF/Target.h
+++ b/contrib/llvm/tools/lld/ELF/Target.h
@@ -25,9 +25,9 @@ class Symbol;
class TargetInfo {
public:
virtual uint32_t calcEFlags() const { return 0; }
- virtual bool isPicRel(RelType Type) const { return true; }
virtual RelType getDynRel(RelType Type) const { return Type; }
virtual void writeGotPltHeader(uint8_t *Buf) const {}
+ virtual void writeGotHeader(uint8_t *Buf) const {}
virtual void writeGotPlt(uint8_t *Buf, const Symbol &S) const {};
virtual void writeIgotPlt(uint8_t *Buf, const Symbol &S) const;
virtual int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const;
@@ -43,8 +43,12 @@ public:
virtual void addPltHeaderSymbols(InputSection &IS) const {}
virtual void addPltSymbols(InputSection &IS, uint64_t Off) const {}
+ unsigned getPltEntryOffset(unsigned Index) const {
+ return Index * PltEntrySize + PltHeaderSize;
+ }
+
// Returns true if a relocation only uses the low bits of a value such that
- // all those bits are in in the same page. For example, if the relocation
+ // all those bits are in the same page. For example, if the relocation
// only uses the low 12 bits in a system with 4k pages. If this is true, the
// bits will always have the same value at runtime and we don't have to emit
// a dynamic relocation.
@@ -55,6 +59,13 @@ public:
virtual bool needsThunk(RelExpr Expr, RelType RelocType,
const InputFile *File, uint64_t BranchAddr,
const Symbol &S) const;
+
+ // The function with a prologue starting at Loc was compiled with
+ // -fsplit-stack and it calls a function compiled without. Adjust the prologue
+ // to do the right thing. See https://gcc.gnu.org/wiki/SplitStacks.
+ virtual bool adjustPrologueForCrossSplitStack(uint8_t *Loc,
+ uint8_t *End) const;
+
// Return true if we can reach Dst from Src with Relocation RelocType
virtual bool inBranchRange(RelType Type, uint64_t Src,
uint64_t Dst) const;
@@ -71,9 +82,10 @@ public:
uint64_t getImageBase();
- // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got section. Use -1 for
- // end of .got
+ // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got or .got.plt section.
uint64_t GotBaseSymOff = 0;
+ // True if _GLOBAL_OFFSET_TABLE_ is relative to .got.plt, false if .got.
+ bool GotBaseSymInGotPlt = true;
// On systems with range extensions we place collections of Thunks at
// regular spacings that enable the majority of branches reach the Thunks.
@@ -97,9 +109,18 @@ public:
// to support lazy loading.
unsigned GotPltHeaderEntriesNum = 3;
- // Set to 0 for variant 2
+ // On PPC ELF V2 abi, the first entry in the .got is the .TOC.
+ unsigned GotHeaderEntriesNum = 0;
+
+ // For TLS variant 1, the TCB is a fixed size specified by the Target.
+ // For variant 2, the TCB is an unspecified size.
+ // Set to 0 for variant 2.
unsigned TcbSize = 0;
+ // Set to the offset (in bytes) that the thread pointer is initialized to
+ // point to, relative to the start of the thread local storage.
+ unsigned TlsTpOffset = 0;
+
bool NeedsThunks = false;
// A 4-byte field corresponding to one or more trap instructions, used to pad
@@ -126,6 +147,7 @@ TargetInfo *getAArch64TargetInfo();
TargetInfo *getAMDGPUTargetInfo();
TargetInfo *getARMTargetInfo();
TargetInfo *getAVRTargetInfo();
+TargetInfo *getHexagonTargetInfo();
TargetInfo *getPPC64TargetInfo();
TargetInfo *getPPCTargetInfo();
TargetInfo *getSPARCV9TargetInfo();
@@ -134,7 +156,17 @@ TargetInfo *getX86TargetInfo();
TargetInfo *getX86_64TargetInfo();
template <class ELFT> TargetInfo *getMipsTargetInfo();
-std::string getErrorLocation(const uint8_t *Loc);
+struct ErrorPlace {
+ InputSectionBase *IS;
+ std::string Loc;
+};
+
+// Returns input section and corresponding source string for the given location.
+ErrorPlace getErrorPlace(const uint8_t *Loc);
+
+static inline std::string getErrorLocation(const uint8_t *Loc) {
+ return getErrorPlace(Loc).Loc;
+}
uint64_t getPPC64TocBase();
uint64_t getAArch64Page(uint64_t Expr);
@@ -146,39 +178,74 @@ template <class ELFT> bool isMipsPIC(const Defined *Sym);
static inline void reportRangeError(uint8_t *Loc, RelType Type, const Twine &V,
int64_t Min, uint64_t Max) {
- error(getErrorLocation(Loc) + "relocation " + lld::toString(Type) +
- " out of range: " + V + " is not in [" + Twine(Min) + ", " +
- Twine(Max) + "]");
+ ErrorPlace ErrPlace = getErrorPlace(Loc);
+ StringRef Hint;
+ if (ErrPlace.IS && ErrPlace.IS->Name.startswith(".debug"))
+ Hint = "; consider recompiling with -fdebug-types-section to reduce size "
+ "of debug sections";
+
+ error(ErrPlace.Loc + "relocation " + lld::toString(Type) +
+ " out of range: " + V.str() + " is not in [" + Twine(Min).str() + ", " +
+ Twine(Max).str() + "]" + Hint);
}
-template <unsigned N>
-static void checkInt(uint8_t *Loc, int64_t V, RelType Type) {
- if (!llvm::isInt<N>(V))
+// Sign-extend Nth bit all the way to MSB.
+inline int64_t signExtend(uint64_t V, int N) {
+ return int64_t(V << (64 - N)) >> (64 - N);
+}
+
+// Make sure that V can be represented as an N bit signed integer.
+inline void checkInt(uint8_t *Loc, int64_t V, int N, RelType Type) {
+ if (V != signExtend(V, N))
reportRangeError(Loc, Type, Twine(V), llvm::minIntN(N), llvm::maxIntN(N));
}
-template <unsigned N>
-static void checkUInt(uint8_t *Loc, uint64_t V, RelType Type) {
- if (!llvm::isUInt<N>(V))
+// Make sure that V can be represented as an N bit unsigned integer.
+inline void checkUInt(uint8_t *Loc, uint64_t V, int N, RelType Type) {
+ if ((V >> N) != 0)
reportRangeError(Loc, Type, Twine(V), 0, llvm::maxUIntN(N));
}
-template <unsigned N>
-static void checkIntUInt(uint8_t *Loc, uint64_t V, RelType Type) {
- if (!llvm::isInt<N>(V) && !llvm::isUInt<N>(V))
- // For the error message we should cast V to a signed integer so that error
- // messages show a small negative value rather than an extremely large one
+// Make sure that V can be represented as an N bit signed or unsigned integer.
+inline void checkIntUInt(uint8_t *Loc, uint64_t V, int N, RelType Type) {
+ // For the error message we should cast V to a signed integer so that error
+ // messages show a small negative value rather than an extremely large one
+ if (V != (uint64_t)signExtend(V, N) && (V >> N) != 0)
reportRangeError(Loc, Type, Twine((int64_t)V), llvm::minIntN(N),
- llvm::maxUIntN(N));
+ llvm::maxIntN(N));
}
-template <unsigned N>
-static void checkAlignment(uint8_t *Loc, uint64_t V, RelType Type) {
+inline void checkAlignment(uint8_t *Loc, uint64_t V, int N, RelType Type) {
if ((V & (N - 1)) != 0)
error(getErrorLocation(Loc) + "improper alignment for relocation " +
lld::toString(Type) + ": 0x" + llvm::utohexstr(V) +
" is not aligned to " + Twine(N) + " bytes");
}
+
+// Endianness-aware read/write.
+inline uint16_t read16(const void *P) {
+ return llvm::support::endian::read16(P, Config->Endianness);
+}
+
+inline uint32_t read32(const void *P) {
+ return llvm::support::endian::read32(P, Config->Endianness);
+}
+
+inline uint64_t read64(const void *P) {
+ return llvm::support::endian::read64(P, Config->Endianness);
+}
+
+inline void write16(void *P, uint16_t V) {
+ llvm::support::endian::write16(P, V, Config->Endianness);
+}
+
+inline void write32(void *P, uint32_t V) {
+ llvm::support::endian::write32(P, V, Config->Endianness);
+}
+
+inline void write64(void *P, uint64_t V) {
+ llvm::support::endian::write64(P, V, Config->Endianness);
+}
} // namespace elf
} // namespace lld
diff --git a/contrib/llvm/tools/lld/ELF/Thunks.cpp b/contrib/llvm/tools/lld/ELF/Thunks.cpp
index b0bbf6da705a..2cd7e51ae357 100644
--- a/contrib/llvm/tools/lld/ELF/Thunks.cpp
+++ b/contrib/llvm/tools/lld/ELF/Thunks.cpp
@@ -40,7 +40,6 @@
using namespace llvm;
using namespace llvm::object;
-using namespace llvm::support::endian;
using namespace llvm::ELF;
namespace lld {
@@ -52,59 +51,112 @@ namespace {
class AArch64ABSLongThunk final : public Thunk {
public:
AArch64ABSLongThunk(Symbol &Dest) : Thunk(Dest) {}
- uint32_t size() const override { return 16; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t size() override { return 16; }
+ void writeTo(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
};
class AArch64ADRPThunk final : public Thunk {
public:
AArch64ADRPThunk(Symbol &Dest) : Thunk(Dest) {}
- uint32_t size() const override { return 12; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t size() override { return 12; }
+ void writeTo(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
};
+// Base class for ARM thunks.
+//
+// An ARM thunk may be either short or long. A short thunk is simply a branch
+// (B) instruction, and it may be used to call ARM functions when the distance
+// from the thunk to the target is less than 32MB. Long thunks can branch to any
+// virtual address and can switch between ARM and Thumb, and they are
+// implemented in the derived classes. This class tries to create a short thunk
+// if the target is in range, otherwise it creates a long thunk.
+class ARMThunk : public Thunk {
+public:
+ ARMThunk(Symbol &Dest) : Thunk(Dest) {}
+
+ bool mayUseShortThunk();
+ uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); }
+ void writeTo(uint8_t *Buf) override;
+ bool isCompatibleWith(RelType Type) const override;
+
+ // Returns the size of a long thunk.
+ virtual uint32_t sizeLong() = 0;
+
+ // Writes a long thunk to Buf.
+ virtual void writeLong(uint8_t *Buf) = 0;
+
+private:
+ // This field tracks whether all previously considered layouts would allow
+ // this thunk to be short. If we have ever needed a long thunk, we always
+ // create a long thunk, even if the thunk may be short given the current
+ // distance to the target. We do this because transitioning from long to short
+ // can create layout oscillations in certain corner cases which would prevent
+ // the layout from converging.
+ bool MayUseShortThunk = true;
+};
+
+// Base class for Thumb-2 thunks.
+//
+// This class is similar to ARMThunk, but it uses the Thumb-2 B.W instruction
+// which has a range of 16MB.
+class ThumbThunk : public Thunk {
+public:
+ ThumbThunk(Symbol &Dest) : Thunk(Dest) { Alignment = 2; }
+
+ bool mayUseShortThunk();
+ uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); }
+ void writeTo(uint8_t *Buf) override;
+ bool isCompatibleWith(RelType Type) const override;
+
+ // Returns the size of a long thunk.
+ virtual uint32_t sizeLong() = 0;
+
+ // Writes a long thunk to Buf.
+ virtual void writeLong(uint8_t *Buf) = 0;
+
+private:
+ // See comment in ARMThunk above.
+ bool MayUseShortThunk = true;
+};
+
// Specific ARM Thunk implementations. The naming convention is:
// Source State, TargetState, Target Requirement, ABS or PI, Range
-class ARMV7ABSLongThunk final : public Thunk {
+class ARMV7ABSLongThunk final : public ARMThunk {
public:
- ARMV7ABSLongThunk(Symbol &Dest) : Thunk(Dest) {}
+ ARMV7ABSLongThunk(Symbol &Dest) : ARMThunk(Dest) {}
- uint32_t size() const override { return 12; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t sizeLong() override { return 12; }
+ void writeLong(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
- bool isCompatibleWith(RelType Type) const override;
};
-class ARMV7PILongThunk final : public Thunk {
+class ARMV7PILongThunk final : public ARMThunk {
public:
- ARMV7PILongThunk(Symbol &Dest) : Thunk(Dest) {}
+ ARMV7PILongThunk(Symbol &Dest) : ARMThunk(Dest) {}
- uint32_t size() const override { return 16; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t sizeLong() override { return 16; }
+ void writeLong(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
- bool isCompatibleWith(RelType Type) const override;
};
-class ThumbV7ABSLongThunk final : public Thunk {
+class ThumbV7ABSLongThunk final : public ThumbThunk {
public:
- ThumbV7ABSLongThunk(Symbol &Dest) : Thunk(Dest) { Alignment = 2; }
+ ThumbV7ABSLongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
- uint32_t size() const override { return 10; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t sizeLong() override { return 10; }
+ void writeLong(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
- bool isCompatibleWith(RelType Type) const override;
};
-class ThumbV7PILongThunk final : public Thunk {
+class ThumbV7PILongThunk final : public ThumbThunk {
public:
- ThumbV7PILongThunk(Symbol &Dest) : Thunk(Dest) { Alignment = 2; }
+ ThumbV7PILongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
- uint32_t size() const override { return 12; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t sizeLong() override { return 12; }
+ void writeLong(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
- bool isCompatibleWith(RelType Type) const override;
};
// MIPS LA25 thunk
@@ -112,8 +164,8 @@ class MipsThunk final : public Thunk {
public:
MipsThunk(Symbol &Dest) : Thunk(Dest) {}
- uint32_t size() const override { return 16; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t size() override { return 16; }
+ void writeTo(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
InputSection *getTargetInputSection() const override;
};
@@ -123,8 +175,8 @@ class MicroMipsThunk final : public Thunk {
public:
MicroMipsThunk(Symbol &Dest) : Thunk(Dest) {}
- uint32_t size() const override { return 14; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t size() override { return 14; }
+ void writeTo(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
InputSection *getTargetInputSection() const override;
};
@@ -134,14 +186,44 @@ class MicroMipsR6Thunk final : public Thunk {
public:
MicroMipsR6Thunk(Symbol &Dest) : Thunk(Dest) {}
- uint32_t size() const override { return 12; }
- void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ uint32_t size() override { return 12; }
+ void writeTo(uint8_t *Buf) override;
void addSymbols(ThunkSection &IS) override;
InputSection *getTargetInputSection() const override;
};
+
+// PPC64 Plt call stubs.
+// Any call site that needs to call through a plt entry needs a call stub in
+// the .text section. The call stub is responsible for:
+// 1) Saving the toc-pointer to the stack.
+// 2) Loading the target functions address from the procedure linkage table into
+// r12 for use by the target functions global entry point, and into the count
+// register.
+// 3) Transfering control to the target function through an indirect branch.
+class PPC64PltCallStub final : public Thunk {
+public:
+ PPC64PltCallStub(Symbol &Dest) : Thunk(Dest) {}
+ uint32_t size() override { return 20; }
+ void writeTo(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
} // end anonymous namespace
+Defined *Thunk::addSymbol(StringRef Name, uint8_t Type, uint64_t Value,
+ InputSectionBase &Section) {
+ Defined *D = addSyntheticLocal(Name, Type, Value, /*Size=*/0, Section);
+ Syms.push_back(D);
+ return D;
+}
+
+void Thunk::setOffset(uint64_t NewOffset) {
+ for (Defined *D : Syms)
+ D->Value = D->Value - Offset + NewOffset;
+ Offset = NewOffset;
+}
+
// AArch64 long range Thunks
static uint64_t getAArch64ThunkDestVA(const Symbol &S) {
@@ -149,7 +231,7 @@ static uint64_t getAArch64ThunkDestVA(const Symbol &S) {
return V;
}
-void AArch64ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+void AArch64ABSLongThunk::writeTo(uint8_t *Buf) {
const uint8_t Data[] = {
0x50, 0x00, 0x00, 0x58, // ldr x16, L0
0x00, 0x02, 0x1f, 0xd6, // br x16
@@ -162,11 +244,10 @@ void AArch64ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
}
void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) {
- ThunkSym = addSyntheticLocal(
- Saver.save("__AArch64AbsLongThunk_" + Destination.getName()), STT_FUNC,
- Offset, size(), IS);
- addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, IS);
- addSyntheticLocal("$d", STT_NOTYPE, Offset + 8, 0, IS);
+ addSymbol(Saver.save("__AArch64AbsLongThunk_" + Destination.getName()),
+ STT_FUNC, 0, IS);
+ addSymbol("$x", STT_NOTYPE, 0, IS);
+ addSymbol("$d", STT_NOTYPE, 8, IS);
}
// This Thunk has a maximum range of 4Gb, this is sufficient for all programs
@@ -174,26 +255,24 @@ void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) {
// clang and gcc do not support the large code model for position independent
// code so it is safe to use this for position independent thunks without
// worrying about the destination being more than 4Gb away.
-void AArch64ADRPThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+void AArch64ADRPThunk::writeTo(uint8_t *Buf) {
const uint8_t Data[] = {
0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest)
0x10, 0x02, 0x00, 0x91, // add x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest)
0x00, 0x02, 0x1f, 0xd6, // br x16
};
uint64_t S = getAArch64ThunkDestVA(Destination);
- uint64_t P = ThunkSym->getVA();
+ uint64_t P = getThunkTargetSym()->getVA();
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(S) - getAArch64Page(P));
Target->relocateOne(Buf + 4, R_AARCH64_ADD_ABS_LO12_NC, S);
}
-void AArch64ADRPThunk::addSymbols(ThunkSection &IS)
-{
- ThunkSym = addSyntheticLocal(
- Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC,
- Offset, size(), IS);
- addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, IS);
+void AArch64ADRPThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC,
+ 0, IS);
+ addSymbol("$x", STT_NOTYPE, 0, IS);
}
// ARM Target Thunks
@@ -202,7 +281,81 @@ static uint64_t getARMThunkDestVA(const Symbol &S) {
return SignExtend64<32>(V);
}
-void ARMV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+// This function returns true if the target is not Thumb and is within 2^26, and
+// it has not previously returned false (see comment for MayUseShortThunk).
+bool ARMThunk::mayUseShortThunk() {
+ if (!MayUseShortThunk)
+ return false;
+ uint64_t S = getARMThunkDestVA(Destination);
+ if (S & 1) {
+ MayUseShortThunk = false;
+ return false;
+ }
+ uint64_t P = getThunkTargetSym()->getVA();
+ int64_t Offset = S - P - 8;
+ MayUseShortThunk = llvm::isInt<26>(Offset);
+ return MayUseShortThunk;
+}
+
+void ARMThunk::writeTo(uint8_t *Buf) {
+ if (!mayUseShortThunk()) {
+ writeLong(Buf);
+ return;
+ }
+
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = getThunkTargetSym()->getVA();
+ int64_t Offset = S - P - 8;
+ const uint8_t Data[] = {
+ 0x00, 0x00, 0x00, 0xea, // b S
+ };
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf, R_ARM_JUMP24, Offset);
+}
+
+bool ARMThunk::isCompatibleWith(RelType Type) const {
+ // Thumb branch relocations can't use BLX
+ return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24;
+}
+
+// This function returns true if the target is Thumb and is within 2^25, and
+// it has not previously returned false (see comment for MayUseShortThunk).
+bool ThumbThunk::mayUseShortThunk() {
+ if (!MayUseShortThunk)
+ return false;
+ uint64_t S = getARMThunkDestVA(Destination);
+ if ((S & 1) == 0) {
+ MayUseShortThunk = false;
+ return false;
+ }
+ uint64_t P = getThunkTargetSym()->getVA() & ~1;
+ int64_t Offset = S - P - 4;
+ MayUseShortThunk = llvm::isInt<25>(Offset);
+ return MayUseShortThunk;
+}
+
+void ThumbThunk::writeTo(uint8_t *Buf) {
+ if (!mayUseShortThunk()) {
+ writeLong(Buf);
+ return;
+ }
+
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = getThunkTargetSym()->getVA();
+ int64_t Offset = S - P - 4;
+ const uint8_t Data[] = {
+ 0x00, 0xf0, 0x00, 0xb0, // b.w S
+ };
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf, R_ARM_THM_JUMP24, Offset);
+}
+
+bool ThumbThunk::isCompatibleWith(RelType Type) const {
+ // ARM branch relocations can't use BLX
+ return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32;
+}
+
+void ARMV7ABSLongThunk::writeLong(uint8_t *Buf) {
const uint8_t Data[] = {
0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S
0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S
@@ -215,18 +368,12 @@ void ARMV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
}
void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) {
- ThunkSym = addSyntheticLocal(
- Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()), STT_FUNC,
- Offset, size(), IS);
- addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, IS);
-}
-
-bool ARMV7ABSLongThunk::isCompatibleWith(RelType Type) const {
- // Thumb branch relocations can't use BLX
- return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24;
+ addSymbol(Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()),
+ STT_FUNC, 0, IS);
+ addSymbol("$a", STT_NOTYPE, 0, IS);
}
-void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+void ThumbV7ABSLongThunk::writeLong(uint8_t *Buf) {
const uint8_t Data[] = {
0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S
0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S
@@ -239,18 +386,12 @@ void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
}
void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) {
- ThunkSym = addSyntheticLocal(
- Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), STT_FUNC,
- Offset | 0x1, size(), IS);
- addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, IS);
+ addSymbol(Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()),
+ STT_FUNC, 1, IS);
+ addSymbol("$t", STT_NOTYPE, 0, IS);
}
-bool ThumbV7ABSLongThunk::isCompatibleWith(RelType Type) const {
- // ARM branch relocations can't use BLX
- return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32;
-}
-
-void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+void ARMV7PILongThunk::writeLong(uint8_t *Buf) {
const uint8_t Data[] = {
0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) + 8)
0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P) + 8)
@@ -258,7 +399,7 @@ void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
0x1c, 0xff, 0x2f, 0xe1, // bx r12
};
uint64_t S = getARMThunkDestVA(Destination);
- uint64_t P = ThunkSym->getVA();
+ uint64_t P = getThunkTargetSym()->getVA();
uint64_t Offset = S - P - 16;
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, Offset);
@@ -266,18 +407,12 @@ void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
}
void ARMV7PILongThunk::addSymbols(ThunkSection &IS) {
- ThunkSym = addSyntheticLocal(
- Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC,
- Offset, size(), IS);
- addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, IS);
+ addSymbol(Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC,
+ 0, IS);
+ addSymbol("$a", STT_NOTYPE, 0, IS);
}
-bool ARMV7PILongThunk::isCompatibleWith(RelType Type) const {
- // Thumb branch relocations can't use BLX
- return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24;
-}
-
-void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+void ThumbV7PILongThunk::writeLong(uint8_t *Buf) {
const uint8_t Data[] = {
0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4)
@@ -285,7 +420,7 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
0x60, 0x47, // bx r12
};
uint64_t S = getARMThunkDestVA(Destination);
- uint64_t P = ThunkSym->getVA() & ~0x1;
+ uint64_t P = getThunkTargetSym()->getVA() & ~0x1;
uint64_t Offset = S - P - 12;
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, Offset);
@@ -293,32 +428,25 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
}
void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) {
- ThunkSym = addSyntheticLocal(
- Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), STT_FUNC,
- Offset | 0x1, size(), IS);
- addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, IS);
-}
-
-bool ThumbV7PILongThunk::isCompatibleWith(RelType Type) const {
- // ARM branch relocations can't use BLX
- return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32;
+ addSymbol(Saver.save("__ThumbV7PILongThunk_" + Destination.getName()),
+ STT_FUNC, 1, IS);
+ addSymbol("$t", STT_NOTYPE, 0, IS);
}
// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
-void MipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const {
+void MipsThunk::writeTo(uint8_t *Buf) {
uint64_t S = Destination.getVA();
- write32(Buf, 0x3c190000, Config->Endianness); // lui $25, %hi(func)
- write32(Buf + 4, 0x08000000 | (S >> 2), Config->Endianness); // j func
- write32(Buf + 8, 0x27390000, Config->Endianness); // addiu $25, $25, %lo(func)
- write32(Buf + 12, 0x00000000, Config->Endianness); // nop
+ write32(Buf, 0x3c190000); // lui $25, %hi(func)
+ write32(Buf + 4, 0x08000000 | (S >> 2)); // j func
+ write32(Buf + 8, 0x27390000); // addiu $25, $25, %lo(func)
+ write32(Buf + 12, 0x00000000); // nop
Target->relocateOne(Buf, R_MIPS_HI16, S);
Target->relocateOne(Buf + 8, R_MIPS_LO16, S);
}
void MipsThunk::addSymbols(ThunkSection &IS) {
- ThunkSym =
- addSyntheticLocal(Saver.save("__LA25Thunk_" + Destination.getName()),
- STT_FUNC, Offset, size(), IS);
+ addSymbol(Saver.save("__LA25Thunk_" + Destination.getName()), STT_FUNC, 0,
+ IS);
}
InputSection *MipsThunk::getTargetInputSection() const {
@@ -328,22 +456,21 @@ InputSection *MipsThunk::getTargetInputSection() const {
// Write microMIPS R2-R5 LA25 thunk code
// to call PIC function from the non-PIC one.
-void MicroMipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const {
+void MicroMipsThunk::writeTo(uint8_t *Buf) {
uint64_t S = Destination.getVA() | 1;
- write16(Buf, 0x41b9, Config->Endianness); // lui $25, %hi(func)
- write16(Buf + 4, 0xd400, Config->Endianness); // j func
- write16(Buf + 8, 0x3339, Config->Endianness); // addiu $25, $25, %lo(func)
- write16(Buf + 12, 0x0c00, Config->Endianness); // nop
+ write16(Buf, 0x41b9); // lui $25, %hi(func)
+ write16(Buf + 4, 0xd400); // j func
+ write16(Buf + 8, 0x3339); // addiu $25, $25, %lo(func)
+ write16(Buf + 12, 0x0c00); // nop
Target->relocateOne(Buf, R_MICROMIPS_HI16, S);
Target->relocateOne(Buf + 4, R_MICROMIPS_26_S1, S);
Target->relocateOne(Buf + 8, R_MICROMIPS_LO16, S);
}
void MicroMipsThunk::addSymbols(ThunkSection &IS) {
- ThunkSym =
- addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()),
- STT_FUNC, Offset, size(), IS);
- ThunkSym->StOther |= STO_MIPS_MICROMIPS;
+ Defined *D = addSymbol(
+ Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS);
+ D->StOther |= STO_MIPS_MICROMIPS;
}
InputSection *MicroMipsThunk::getTargetInputSection() const {
@@ -353,22 +480,21 @@ InputSection *MicroMipsThunk::getTargetInputSection() const {
// Write microMIPS R6 LA25 thunk code
// to call PIC function from the non-PIC one.
-void MicroMipsR6Thunk::writeTo(uint8_t *Buf, ThunkSection &) const {
+void MicroMipsR6Thunk::writeTo(uint8_t *Buf) {
uint64_t S = Destination.getVA() | 1;
- uint64_t P = ThunkSym->getVA();
- write16(Buf, 0x1320, Config->Endianness); // lui $25, %hi(func)
- write16(Buf + 4, 0x3339, Config->Endianness); // addiu $25, $25, %lo(func)
- write16(Buf + 8, 0x9400, Config->Endianness); // bc func
+ uint64_t P = getThunkTargetSym()->getVA();
+ write16(Buf, 0x1320); // lui $25, %hi(func)
+ write16(Buf + 4, 0x3339); // addiu $25, $25, %lo(func)
+ write16(Buf + 8, 0x9400); // bc func
Target->relocateOne(Buf, R_MICROMIPS_HI16, S);
Target->relocateOne(Buf + 4, R_MICROMIPS_LO16, S);
Target->relocateOne(Buf + 8, R_MICROMIPS_PC26_S1, S - P - 12);
}
void MicroMipsR6Thunk::addSymbols(ThunkSection &IS) {
- ThunkSym =
- addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()),
- STT_FUNC, Offset, size(), IS);
- ThunkSym->StOther |= STO_MIPS_MICROMIPS;
+ Defined *D = addSymbol(
+ Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS);
+ D->StOther |= STO_MIPS_MICROMIPS;
}
InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
@@ -376,6 +502,25 @@ InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
return dyn_cast<InputSection>(DR.Section);
}
+void PPC64PltCallStub::writeTo(uint8_t *Buf) {
+ int64_t Off = Destination.getGotPltVA() - getPPC64TocBase();
+ // Need to add 0x8000 to offset to account for the low bits being signed.
+ uint16_t OffHa = (Off + 0x8000) >> 16;
+ uint16_t OffLo = Off;
+
+ write32(Buf + 0, 0xf8410018); // std r2,24(r1)
+ write32(Buf + 4, 0x3d820000 | OffHa); // addis r12,r2, X@plt@to@ha
+ write32(Buf + 8, 0xe98c0000 | OffLo); // ld r12,X@plt@toc@l(r12)
+ write32(Buf + 12, 0x7d8903a6); // mtctr r12
+ write32(Buf + 16, 0x4e800420); // bctr
+}
+
+void PPC64PltCallStub::addSymbols(ThunkSection &IS) {
+ Defined *S = addSymbol(Saver.save("__plt_" + Destination.getName()), STT_FUNC,
+ 0, IS);
+ S->NeedsTocRestore = true;
+}
+
Thunk::Thunk(Symbol &D) : Destination(D), Offset(0) {}
Thunk::~Thunk() = default;
@@ -419,15 +564,26 @@ static Thunk *addThunkMips(RelType Type, Symbol &S) {
return make<MipsThunk>(S);
}
+static Thunk *addThunkPPC64(RelType Type, Symbol &S) {
+ if (Type == R_PPC64_REL24)
+ return make<PPC64PltCallStub>(S);
+ fatal("unexpected relocation type");
+}
+
Thunk *addThunk(RelType Type, Symbol &S) {
if (Config->EMachine == EM_AARCH64)
return addThunkAArch64(Type, S);
- else if (Config->EMachine == EM_ARM)
+
+ if (Config->EMachine == EM_ARM)
return addThunkArm(Type, S);
- else if (Config->EMachine == EM_MIPS)
+
+ if (Config->EMachine == EM_MIPS)
return addThunkMips(Type, S);
- llvm_unreachable("add Thunk only supported for ARM and Mips");
- return nullptr;
+
+ if (Config->EMachine == EM_PPC64)
+ return addThunkPPC64(Type, S);
+
+ llvm_unreachable("add Thunk only supported for ARM, Mips and PowerPC");
}
} // end namespace elf
diff --git a/contrib/llvm/tools/lld/ELF/Thunks.h b/contrib/llvm/tools/lld/ELF/Thunks.h
index 828fac0bf53b..ed82b4d946ac 100644
--- a/contrib/llvm/tools/lld/ELF/Thunks.h
+++ b/contrib/llvm/tools/lld/ELF/Thunks.h
@@ -14,6 +14,7 @@
namespace lld {
namespace elf {
+class Defined;
class Symbol;
class ThunkSection;
// Class to describe an instance of a Thunk.
@@ -30,12 +31,17 @@ public:
Thunk(Symbol &Destination);
virtual ~Thunk();
- virtual uint32_t size() const { return 0; }
- virtual void writeTo(uint8_t *Buf, ThunkSection &IS) const {}
+ virtual uint32_t size() = 0;
+ virtual void writeTo(uint8_t *Buf) = 0;
- // All Thunks must define at least one symbol ThunkSym so that we can
- // redirect relocations to it.
- virtual void addSymbols(ThunkSection &IS) {}
+ // All Thunks must define at least one symbol, known as the thunk target
+ // symbol, so that we can redirect relocations to it. The thunk may define
+ // additional symbols, but these are never targets for relocations.
+ virtual void addSymbols(ThunkSection &IS) = 0;
+
+ void setOffset(uint64_t Offset);
+ Defined *addSymbol(StringRef Name, uint8_t Type, uint64_t Value,
+ InputSectionBase &Section);
// Some Thunks must be placed immediately before their Target as they elide
// a branch and fall through to the first Symbol in the Target.
@@ -45,10 +51,12 @@ public:
// compatible with it.
virtual bool isCompatibleWith(RelType Type) const { return true; }
+ Defined *getThunkTargetSym() const { return Syms[0]; }
+
// The alignment requirement for this Thunk, defaults to the size of the
// typical code section alignment.
Symbol &Destination;
- Symbol *ThunkSym;
+ llvm::SmallVector<Defined *, 3> Syms;
uint64_t Offset = 0;
uint32_t Alignment = 4;
};
diff --git a/contrib/llvm/tools/lld/ELF/Writer.cpp b/contrib/llvm/tools/lld/ELF/Writer.cpp
index d130bd603933..73a97380b54b 100644
--- a/contrib/llvm/tools/lld/ELF/Writer.cpp
+++ b/contrib/llvm/tools/lld/ELF/Writer.cpp
@@ -9,18 +9,19 @@
#include "Writer.h"
#include "AArch64ErrataFix.h"
+#include "CallGraphSort.h"
#include "Config.h"
#include "Filesystem.h"
#include "LinkerScript.h"
#include "MapFile.h"
#include "OutputSections.h"
#include "Relocations.h"
-#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
@@ -49,7 +50,7 @@ public:
private:
void copyLocalSymbols();
void addSectionSymbols();
- void forEachRelSec(std::function<void(InputSectionBase &)> Fn);
+ void forEachRelSec(llvm::function_ref<void(InputSectionBase &)> Fn);
void sortSections();
void resolveShfLinkOrder();
void sortInputSections();
@@ -62,6 +63,7 @@ private:
void assignFileOffsets();
void assignFileOffsetsBinary();
void setPhdrs();
+ void checkSections();
void fixSectionAlignments();
void openFile();
void writeTrapInstr();
@@ -81,39 +83,48 @@ private:
uint64_t FileSize;
uint64_t SectionHeaderOff;
-
- bool HasGotBaseSym = false;
};
} // anonymous namespace
-StringRef elf::getOutputSectionName(InputSectionBase *S) {
- // ".zdebug_" is a prefix for ZLIB-compressed sections.
- // Because we decompressed input sections, we want to remove 'z'.
- if (S->Name.startswith(".zdebug_"))
- return Saver.save("." + S->Name.substr(2));
+static bool isSectionPrefix(StringRef Prefix, StringRef Name) {
+ return Name.startswith(Prefix) || Name == Prefix.drop_back();
+}
+StringRef elf::getOutputSectionName(const InputSectionBase *S) {
if (Config->Relocatable)
return S->Name;
// This is for --emit-relocs. If .text.foo is emitted as .text.bar, we want
// to emit .rela.text.foo as .rela.text.bar for consistency (this is not
// technically required, but not doing it is odd). This code guarantees that.
- if ((S->Type == SHT_REL || S->Type == SHT_RELA) &&
- !isa<SyntheticSection>(S)) {
- OutputSection *Out =
- cast<InputSection>(S)->getRelocatedSection()->getOutputSection();
- if (S->Type == SHT_RELA)
- return Saver.save(".rela" + Out->Name);
- return Saver.save(".rel" + Out->Name);
+ if (auto *IS = dyn_cast<InputSection>(S)) {
+ if (InputSectionBase *Rel = IS->getRelocatedSection()) {
+ OutputSection *Out = Rel->getOutputSection();
+ if (S->Type == SHT_RELA)
+ return Saver.save(".rela" + Out->Name);
+ return Saver.save(".rel" + Out->Name);
+ }
}
+ // This check is for -z keep-text-section-prefix. This option separates text
+ // sections with prefix ".text.hot", ".text.unlikely", ".text.startup" or
+ // ".text.exit".
+ // When enabled, this allows identifying the hot code region (.text.hot) in
+ // the final binary which can be selectively mapped to huge pages or mlocked,
+ // for instance.
+ if (Config->ZKeepTextSectionPrefix)
+ for (StringRef V :
+ {".text.hot.", ".text.unlikely.", ".text.startup.", ".text.exit."}) {
+ if (isSectionPrefix(V, S->Name))
+ return V.drop_back();
+ }
+
for (StringRef V :
{".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.",
".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."}) {
- StringRef Prefix = V.drop_back();
- if (S->Name.startswith(V) || S->Name == Prefix)
- return Prefix;
+ if (isSectionPrefix(V, S->Name))
+ return V.drop_back();
}
// CommonSection is identified as "COMMON" in linker scripts.
@@ -194,21 +205,30 @@ void elf::addReservedSymbols() {
Symtab->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_GLOBAL);
}
+ // The Power Architecture 64-bit v2 ABI defines a TableOfContents (TOC) which
+ // combines the typical ELF GOT with the small data sections. It commonly
+ // includes .got .toc .sdata .sbss. The .TOC. symbol replaces both
+ // _GLOBAL_OFFSET_TABLE_ and _SDA_BASE_ from the 32-bit ABI. It is used to
+ // represent the TOC base which is offset by 0x8000 bytes from the start of
+ // the .got section.
ElfSym::GlobalOffsetTable = addOptionalRegular(
- "_GLOBAL_OFFSET_TABLE_", Out::ElfHeader, Target->GotBaseSymOff);
+ (Config->EMachine == EM_PPC64) ? ".TOC." : "_GLOBAL_OFFSET_TABLE_",
+ Out::ElfHeader, Target->GotBaseSymOff);
// __ehdr_start is the location of ELF file headers. Note that we define
// this symbol unconditionally even when using a linker script, which
// differs from the behavior implemented by GNU linker which only define
// this symbol if ELF headers are in the memory mapped segment.
+ addOptionalRegular("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN);
+
// __executable_start is not documented, but the expectation of at
- // least the android libc is that it points to the elf header too.
+ // least the Android libc is that it points to the ELF header.
+ addOptionalRegular("__executable_start", Out::ElfHeader, 0, STV_HIDDEN);
+
// __dso_handle symbol is passed to cxa_finalize as a marker to identify
// each DSO. The address of the symbol doesn't matter as long as they are
// different in different DSOs, so we chose the start address of the DSO.
- for (const char *Name :
- {"__ehdr_start", "__executable_start", "__dso_handle"})
- addOptionalRegular(Name, Out::ElfHeader, 0, STV_HIDDEN);
+ addOptionalRegular("__dso_handle", Out::ElfHeader, 0, STV_HIDDEN);
// If linker script do layout we do not need to create any standart symbols.
if (Script->HasSectionsCommand)
@@ -267,6 +287,7 @@ template <class ELFT> static void createSyntheticSections() {
if (Config->Strip != StripPolicy::All) {
InX::StrTab = make<StringTableSection>(".strtab", false);
InX::SymTab = make<SymbolTableSection<ELFT>>(*InX::StrTab);
+ InX::SymTabShndx = make<SymtabShndxSection>();
}
if (Config->BuildId != BuildIdKind::None) {
@@ -280,10 +301,9 @@ template <class ELFT> static void createSyntheticSections() {
// If there is a SECTIONS command and a .data.rel.ro section name use name
// .data.rel.ro.bss so that we match in the .data.rel.ro output section.
// This makes sure our relro is contiguous.
- bool HasDataRelRo =
- Script->HasSectionsCommand && findSection(".data.rel.ro");
- InX::BssRelRo = make<BssSection>(
- HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1);
+ bool HasDataRelRo = Script->HasSectionsCommand && findSection(".data.rel.ro");
+ InX::BssRelRo =
+ make<BssSection>(HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1);
Add(InX::BssRelRo);
// Add MIPS-specific sections.
@@ -330,6 +350,11 @@ template <class ELFT> static void createSyntheticSections() {
Add(InX::RelaDyn);
}
+ if (Config->RelrPackDynRelocs) {
+ InX::RelrDyn = make<RelrSection<ELFT>>();
+ Add(InX::RelrDyn);
+ }
+
// Add .got. MIPS' .got is so different from the other archs,
// it has its own class.
if (Config->EMachine == EM_MIPS) {
@@ -346,7 +371,7 @@ template <class ELFT> static void createSyntheticSections() {
Add(InX::IgotPlt);
if (Config->GdbIndex) {
- InX::GdbIndex = createGdbIndex<ELFT>();
+ InX::GdbIndex = GdbIndexSection::create<ELFT>();
Add(InX::GdbIndex);
}
@@ -369,9 +394,9 @@ template <class ELFT> static void createSyntheticSections() {
false /*Sort*/);
Add(InX::RelaIplt);
- InX::Plt = make<PltSection>(Target->PltHeaderSize);
+ InX::Plt = make<PltSection>(false);
Add(InX::Plt);
- InX::Iplt = make<PltSection>(0);
+ InX::Iplt = make<PltSection>(true);
Add(InX::Iplt);
if (!Config->Relocatable) {
@@ -385,6 +410,8 @@ template <class ELFT> static void createSyntheticSections() {
if (InX::SymTab)
Add(InX::SymTab);
+ if (InX::SymTabShndx)
+ Add(InX::SymTabShndx);
Add(InX::ShStrTab);
if (InX::StrTab)
Add(InX::StrTab);
@@ -454,6 +481,9 @@ template <class ELFT> void Writer<ELFT>::run() {
Sec->Addr = 0;
}
+ if (Config->CheckSections)
+ checkSections();
+
// It does not make sense try to open the file if we have error already.
if (errorCount())
return;
@@ -476,8 +506,9 @@ template <class ELFT> void Writer<ELFT>::run() {
if (errorCount())
return;
- // Handle -Map option.
+ // Handle -Map and -cref options.
writeMapFile();
+ writeCrossReferenceTable();
if (errorCount())
return;
@@ -487,11 +518,7 @@ template <class ELFT> void Writer<ELFT>::run() {
static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName,
const Symbol &B) {
- if (B.isFile() || B.isSection())
- return false;
-
- // If sym references a section in a discarded group, don't keep it.
- if (Sec == &InputSection::Discarded)
+ if (B.isSection())
return false;
if (Config->Discard == DiscardPolicy::None)
@@ -638,6 +665,9 @@ static bool isRelroSection(const OutputSection *Sec) {
if (InX::Got && Sec == InX::Got->getParent())
return true;
+ if (Sec->Name.equals(".toc"))
+ return true;
+
// .got.plt contains pointers to external function symbols. They are
// by default resolved lazily, so we usually cannot put it into RELRO.
// However, if "-z now" is given, the lazy symbol resolution is
@@ -669,20 +699,22 @@ static bool isRelroSection(const OutputSection *Sec) {
// * It is easy to check if a give branch was taken.
// * It is easy two see how similar two ranks are (see getRankProximity).
enum RankFlags {
- RF_NOT_ADDR_SET = 1 << 16,
- RF_NOT_INTERP = 1 << 15,
- RF_NOT_ALLOC = 1 << 14,
- RF_WRITE = 1 << 13,
- RF_EXEC_WRITE = 1 << 12,
- RF_EXEC = 1 << 11,
- RF_NON_TLS_BSS = 1 << 10,
- RF_NON_TLS_BSS_RO = 1 << 9,
- RF_NOT_TLS = 1 << 8,
- RF_BSS = 1 << 7,
+ RF_NOT_ADDR_SET = 1 << 18,
+ RF_NOT_INTERP = 1 << 17,
+ RF_NOT_ALLOC = 1 << 16,
+ RF_WRITE = 1 << 15,
+ RF_EXEC_WRITE = 1 << 14,
+ RF_EXEC = 1 << 13,
+ RF_RODATA = 1 << 12,
+ RF_NON_TLS_BSS = 1 << 11,
+ RF_NON_TLS_BSS_RO = 1 << 10,
+ RF_NOT_TLS = 1 << 9,
+ RF_BSS = 1 << 8,
+ RF_NOTE = 1 << 7,
RF_PPC_NOT_TOCBSS = 1 << 6,
- RF_PPC_OPD = 1 << 5,
- RF_PPC_TOCL = 1 << 4,
- RF_PPC_TOC = 1 << 3,
+ RF_PPC_TOCL = 1 << 5,
+ RF_PPC_TOC = 1 << 4,
+ RF_PPC_GOT = 1 << 3,
RF_PPC_BRANCH_LT = 1 << 2,
RF_MIPS_GPREL = 1 << 1,
RF_MIPS_NOT_GOT = 1 << 0
@@ -713,8 +745,7 @@ static unsigned getSectionRank(const OutputSection *Sec) {
// considerations:
// * Read-only sections come first such that they go in the
// PT_LOAD covering the program headers at the start of the file.
- // * Read-only, executable sections come next, unless the
- // -no-rosegment option is used.
+ // * Read-only, executable sections come next.
// * Writable, executable sections follow such that .plt on
// architectures where it needs to be writable will be placed
// between .text and .data.
@@ -726,11 +757,16 @@ static unsigned getSectionRank(const OutputSection *Sec) {
if (IsExec) {
if (IsWrite)
Rank |= RF_EXEC_WRITE;
- else if (!Config->SingleRoRx)
+ else
Rank |= RF_EXEC;
- } else {
- if (IsWrite)
- Rank |= RF_WRITE;
+ } else if (IsWrite) {
+ Rank |= RF_WRITE;
+ } else if (Sec->Type == SHT_PROGBITS) {
+ // Make non-executable and non-writable PROGBITS sections (e.g .rodata
+ // .eh_frame) closer to .text. They likely contain PC or GOT relative
+ // relocations and there could be relocation overflow if other huge sections
+ // (.dynstr .dynsym) were placed in between.
+ Rank |= RF_RODATA;
}
// If we got here we know that both A and B are in the same PT_LOAD.
@@ -766,6 +802,12 @@ static unsigned getSectionRank(const OutputSection *Sec) {
if (IsNoBits)
Rank |= RF_BSS;
+ // We create a NOTE segment for contiguous .note sections, so make
+ // them contigous if there are more than one .note section with the
+ // same attributes.
+ if (Sec->Type == SHT_NOTE)
+ Rank |= RF_NOTE;
+
// Some architectures have additional ordering restrictions for sections
// within the same PT_LOAD.
if (Config->EMachine == EM_PPC64) {
@@ -779,18 +821,19 @@ static unsigned getSectionRank(const OutputSection *Sec) {
if (Name != ".tocbss")
Rank |= RF_PPC_NOT_TOCBSS;
- if (Name == ".opd")
- Rank |= RF_PPC_OPD;
-
if (Name == ".toc1")
Rank |= RF_PPC_TOCL;
if (Name == ".toc")
Rank |= RF_PPC_TOC;
+ if (Name == ".got")
+ Rank |= RF_PPC_GOT;
+
if (Name == ".branch_lt")
Rank |= RF_PPC_BRANCH_LT;
}
+
if (Config->EMachine == EM_MIPS) {
// All sections with SHF_MIPS_GPREL flag should be grouped together
// because data in these sections is addressable with a gp relative address.
@@ -822,8 +865,6 @@ void PhdrEntry::add(OutputSection *Sec) {
p_align = std::max(p_align, Sec->Alignment);
if (p_type == PT_LOAD)
Sec->PtLoad = this;
- if (Sec->LMAExpr)
- ASectionHasLMA = true;
}
// The beginning and the ending of .rel[a].plt section are marked
@@ -833,17 +874,19 @@ void PhdrEntry::add(OutputSection *Sec) {
// need these symbols, since IRELATIVE relocs are resolved through GOT
// and PLT. For details, see http://www.airs.com/blog/archives/403.
template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
- if (!Config->Static)
+ if (needsInterpSection())
return;
StringRef S = Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start";
addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK);
S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end";
- addOptionalRegular(S, InX::RelaIplt, -1, STV_HIDDEN, STB_WEAK);
+ ElfSym::RelaIpltEnd =
+ addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK);
}
template <class ELFT>
-void Writer<ELFT>::forEachRelSec(std::function<void(InputSectionBase &)> Fn) {
+void Writer<ELFT>::forEachRelSec(
+ llvm::function_ref<void(InputSectionBase &)> Fn) {
// Scan all relocations. Each relocation goes through a series
// of tests to determine if it needs special treatment, such as
// creating GOT, PLT, copy relocations, etc.
@@ -863,14 +906,18 @@ void Writer<ELFT>::forEachRelSec(std::function<void(InputSectionBase &)> Fn) {
// defining these symbols explicitly in the linker script.
template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
if (ElfSym::GlobalOffsetTable) {
- // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to
- // be at some offset from the base of the .got section, usually 0 or the end
- // of the .got
- InputSection *GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot)
- : cast<InputSection>(InX::Got);
+ // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention usually
+ // to the start of the .got or .got.plt section.
+ InputSection *GotSection = InX::GotPlt;
+ if (!Target->GotBaseSymInGotPlt)
+ GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot)
+ : cast<InputSection>(InX::Got);
ElfSym::GlobalOffsetTable->Section = GotSection;
}
+ if (ElfSym::RelaIpltEnd)
+ ElfSym::RelaIpltEnd->Value = InX::RelaIplt->getSize();
+
PhdrEntry *Last = nullptr;
PhdrEntry *LastRO = nullptr;
@@ -940,8 +987,7 @@ static int getRankProximityAux(OutputSection *A, OutputSection *B) {
static int getRankProximity(OutputSection *A, BaseCommand *B) {
if (auto *Sec = dyn_cast<OutputSection>(B))
- if (Sec->Live)
- return getRankProximityAux(A, Sec);
+ return getRankProximityAux(A, Sec);
return -1;
}
@@ -960,11 +1006,9 @@ static int getRankProximity(OutputSection *A, BaseCommand *B) {
// rw_sec : { *(rw_sec) }
// would mean that the RW PT_LOAD would become unaligned.
static bool shouldSkip(BaseCommand *Cmd) {
- if (isa<OutputSection>(Cmd))
- return false;
if (auto *Assign = dyn_cast<SymbolAssignment>(Cmd))
return Assign->Name != ".";
- return true;
+ return false;
}
// We want to place orphan sections so that they share as much
@@ -987,20 +1031,16 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B,
int Proximity = getRankProximity(Sec, *I);
for (; I != E; ++I) {
auto *CurSec = dyn_cast<OutputSection>(*I);
- if (!CurSec || !CurSec->Live)
+ if (!CurSec)
continue;
if (getRankProximity(Sec, CurSec) != Proximity ||
Sec->SortRank < CurSec->SortRank)
break;
}
- auto IsLiveSection = [](BaseCommand *Cmd) {
- auto *OS = dyn_cast<OutputSection>(Cmd);
- return OS && OS->Live;
- };
-
+ auto IsOutputSec = [](BaseCommand *Cmd) { return isa<OutputSection>(Cmd); };
auto J = std::find_if(llvm::make_reverse_iterator(I),
- llvm::make_reverse_iterator(B), IsLiveSection);
+ llvm::make_reverse_iterator(B), IsOutputSec);
I = J.base();
// As a special case, if the orphan section is the last section, put
@@ -1008,7 +1048,7 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B,
// This matches bfd's behavior and is convenient when the linker script fully
// specifies the start of the file, but doesn't care about the end (the non
// alloc sections for example).
- auto NextSec = std::find_if(I, E, IsLiveSection);
+ auto NextSec = std::find_if(I, E, IsOutputSec);
if (NextSec == E)
return E;
@@ -1017,32 +1057,172 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B,
return I;
}
-// If no layout was provided by linker script, we want to apply default
-// sorting for special input sections and handle --symbol-ordering-file.
-template <class ELFT> void Writer<ELFT>::sortInputSections() {
- assert(!Script->HasSectionsCommand);
+// Builds section order for handling --symbol-ordering-file.
+static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
+ DenseMap<const InputSectionBase *, int> SectionOrder;
+ // Use the rarely used option -call-graph-ordering-file to sort sections.
+ if (!Config->CallGraphProfile.empty())
+ return computeCallGraphProfileOrder();
- // Sort input sections by priority using the list provided
- // by --symbol-ordering-file.
- DenseMap<SectionBase *, int> Order = buildSectionOrder();
- if (!Order.empty())
- for (BaseCommand *Base : Script->SectionCommands)
- if (auto *Sec = dyn_cast<OutputSection>(Base))
- if (Sec->Live)
- Sec->sort([&](InputSectionBase *S) { return Order.lookup(S); });
+ if (Config->SymbolOrderingFile.empty())
+ return SectionOrder;
+
+ struct SymbolOrderEntry {
+ int Priority;
+ bool Present;
+ };
+
+ // Build a map from symbols to their priorities. Symbols that didn't
+ // appear in the symbol ordering file have the lowest priority 0.
+ // All explicitly mentioned symbols have negative (higher) priorities.
+ DenseMap<StringRef, SymbolOrderEntry> SymbolOrder;
+ int Priority = -Config->SymbolOrderingFile.size();
+ for (StringRef S : Config->SymbolOrderingFile)
+ SymbolOrder.insert({S, {Priority++, false}});
+
+ // Build a map from sections to their priorities.
+ auto AddSym = [&](Symbol &Sym) {
+ auto It = SymbolOrder.find(Sym.getName());
+ if (It == SymbolOrder.end())
+ return;
+ SymbolOrderEntry &Ent = It->second;
+ Ent.Present = true;
+
+ warnUnorderableSymbol(&Sym);
+
+ if (auto *D = dyn_cast<Defined>(&Sym)) {
+ if (auto *Sec = dyn_cast_or_null<InputSectionBase>(D->Section)) {
+ int &Priority = SectionOrder[cast<InputSectionBase>(Sec->Repl)];
+ Priority = std::min(Priority, Ent.Priority);
+ }
+ }
+ };
+ // We want both global and local symbols. We get the global ones from the
+ // symbol table and iterate the object files for the local ones.
+ for (Symbol *Sym : Symtab->getSymbols())
+ if (!Sym->isLazy())
+ AddSym(*Sym);
+ for (InputFile *File : ObjectFiles)
+ for (Symbol *Sym : File->getSymbols())
+ if (Sym->isLocal())
+ AddSym(*Sym);
+
+ if (Config->WarnSymbolOrdering)
+ for (auto OrderEntry : SymbolOrder)
+ if (!OrderEntry.second.Present)
+ warn("symbol ordering file: no such symbol: " + OrderEntry.first);
+
+ return SectionOrder;
+}
+
+// Sorts the sections in ISD according to the provided section order.
+static void
+sortISDBySectionOrder(InputSectionDescription *ISD,
+ const DenseMap<const InputSectionBase *, int> &Order) {
+ std::vector<InputSection *> UnorderedSections;
+ std::vector<std::pair<InputSection *, int>> OrderedSections;
+ uint64_t UnorderedSize = 0;
+
+ for (InputSection *IS : ISD->Sections) {
+ auto I = Order.find(IS);
+ if (I == Order.end()) {
+ UnorderedSections.push_back(IS);
+ UnorderedSize += IS->getSize();
+ continue;
+ }
+ OrderedSections.push_back({IS, I->second});
+ }
+ llvm::sort(
+ OrderedSections.begin(), OrderedSections.end(),
+ [&](std::pair<InputSection *, int> A, std::pair<InputSection *, int> B) {
+ return A.second < B.second;
+ });
+
+ // Find an insertion point for the ordered section list in the unordered
+ // section list. On targets with limited-range branches, this is the mid-point
+ // of the unordered section list. This decreases the likelihood that a range
+ // extension thunk will be needed to enter or exit the ordered region. If the
+ // ordered section list is a list of hot functions, we can generally expect
+ // the ordered functions to be called more often than the unordered functions,
+ // making it more likely that any particular call will be within range, and
+ // therefore reducing the number of thunks required.
+ //
+ // For example, imagine that you have 8MB of hot code and 32MB of cold code.
+ // If the layout is:
+ //
+ // 8MB hot
+ // 32MB cold
+ //
+ // only the first 8-16MB of the cold code (depending on which hot function it
+ // is actually calling) can call the hot code without a range extension thunk.
+ // However, if we use this layout:
+ //
+ // 16MB cold
+ // 8MB hot
+ // 16MB cold
+ //
+ // both the last 8-16MB of the first block of cold code and the first 8-16MB
+ // of the second block of cold code can call the hot code without a thunk. So
+ // we effectively double the amount of code that could potentially call into
+ // the hot code without a thunk.
+ size_t InsPt = 0;
+ if (Target->ThunkSectionSpacing && !OrderedSections.empty()) {
+ uint64_t UnorderedPos = 0;
+ for (; InsPt != UnorderedSections.size(); ++InsPt) {
+ UnorderedPos += UnorderedSections[InsPt]->getSize();
+ if (UnorderedPos > UnorderedSize / 2)
+ break;
+ }
+ }
+
+ ISD->Sections.clear();
+ for (InputSection *IS : makeArrayRef(UnorderedSections).slice(0, InsPt))
+ ISD->Sections.push_back(IS);
+ for (std::pair<InputSection *, int> P : OrderedSections)
+ ISD->Sections.push_back(P.first);
+ for (InputSection *IS : makeArrayRef(UnorderedSections).slice(InsPt))
+ ISD->Sections.push_back(IS);
+}
+
+static void sortSection(OutputSection *Sec,
+ const DenseMap<const InputSectionBase *, int> &Order) {
+ StringRef Name = Sec->Name;
// Sort input sections by section name suffixes for
// __attribute__((init_priority(N))).
- if (OutputSection *Sec = findSection(".init_array"))
- Sec->sortInitFini();
- if (OutputSection *Sec = findSection(".fini_array"))
- Sec->sortInitFini();
+ if (Name == ".init_array" || Name == ".fini_array") {
+ if (!Script->HasSectionsCommand)
+ Sec->sortInitFini();
+ return;
+ }
// Sort input sections by the special rule for .ctors and .dtors.
- if (OutputSection *Sec = findSection(".ctors"))
- Sec->sortCtorsDtors();
- if (OutputSection *Sec = findSection(".dtors"))
- Sec->sortCtorsDtors();
+ if (Name == ".ctors" || Name == ".dtors") {
+ if (!Script->HasSectionsCommand)
+ Sec->sortCtorsDtors();
+ return;
+ }
+
+ // Never sort these.
+ if (Name == ".init" || Name == ".fini")
+ return;
+
+ // Sort input sections by priority using the list provided
+ // by --symbol-ordering-file.
+ if (!Order.empty())
+ for (BaseCommand *B : Sec->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(B))
+ sortISDBySectionOrder(ISD, Order);
+}
+
+// If no layout was provided by linker script, we want to apply default
+// sorting for special input sections. This also handles --symbol-ordering-file.
+template <class ELFT> void Writer<ELFT>::sortInputSections() {
+ // Build the order once since it is expensive.
+ DenseMap<const InputSectionBase *, int> Order = buildSectionOrder();
+ for (BaseCommand *Base : Script->SectionCommands)
+ if (auto *Sec = dyn_cast<OutputSection>(Base))
+ sortSection(Sec, Order);
}
template <class ELFT> void Writer<ELFT>::sortSections() {
@@ -1053,22 +1233,29 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
if (Config->Relocatable)
return;
- for (BaseCommand *Base : Script->SectionCommands)
- if (auto *Sec = dyn_cast<OutputSection>(Base))
- Sec->SortRank = getSectionRank(Sec);
+ sortInputSections();
- if (!Script->HasSectionsCommand) {
- sortInputSections();
+ for (BaseCommand *Base : Script->SectionCommands) {
+ auto *OS = dyn_cast<OutputSection>(Base);
+ if (!OS)
+ continue;
+ OS->SortRank = getSectionRank(OS);
+
+ // We want to assign rude approximation values to OutSecOff fields
+ // to know the relative order of the input sections. We use it for
+ // sorting SHF_LINK_ORDER sections. See resolveShfLinkOrder().
+ uint64_t I = 0;
+ for (InputSection *Sec : getInputSections(OS))
+ Sec->OutSecOff = I++;
+ }
+ if (!Script->HasSectionsCommand) {
// We know that all the OutputSections are contiguous in this case.
- auto E = Script->SectionCommands.end();
- auto I = Script->SectionCommands.begin();
auto IsSection = [](BaseCommand *Base) { return isa<OutputSection>(Base); };
- I = std::find_if(I, E, IsSection);
- E = std::find_if(llvm::make_reverse_iterator(E),
- llvm::make_reverse_iterator(I), IsSection)
- .base();
- std::stable_sort(I, E, compareSections);
+ std::stable_sort(
+ llvm::find_if(Script->SectionCommands, IsSection),
+ llvm::find_if(llvm::reverse(Script->SectionCommands), IsSection).base(),
+ compareSections);
return;
}
@@ -1099,7 +1286,7 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
// The way we define an order then is:
// * Sort only the orphan sections. They are in the end right now.
// * Move each orphan section to its preferred position. We try
- // to put each section in the last position where it it can share
+ // to put each section in the last position where it can share
// a PT_LOAD.
//
// There is some ambiguity as to where exactly a new entry should be
@@ -1115,7 +1302,7 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
auto E = Script->SectionCommands.end();
auto NonScriptI = std::find_if(I, E, [](BaseCommand *Base) {
if (auto *Sec = dyn_cast<OutputSection>(Base))
- return Sec->Live && Sec->SectionIndex == INT_MAX;
+ return Sec->SectionIndex == UINT32_MAX;
return false;
});
@@ -1190,8 +1377,7 @@ static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) {
};
// Get the last table Entry from the previous .ARM.exidx section.
- const ExidxEntry &PrevEntry = *reinterpret_cast<const ExidxEntry *>(
- Prev->Data.data() + Prev->getSize() - sizeof(ExidxEntry));
+ const ExidxEntry &PrevEntry = Prev->getDataAs<ExidxEntry>().back();
if (IsExtabRef(PrevEntry.Unwind))
return false;
@@ -1203,14 +1389,7 @@ static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) {
// consecutive identical entries are rare and the effort to check that they
// are identical is high.
- if (isa<SyntheticSection>(Cur))
- // Exidx sentinel section has implicit EXIDX_CANTUNWIND;
- return PrevEntry.Unwind == 0x1;
-
- ArrayRef<const ExidxEntry> Entries(
- reinterpret_cast<const ExidxEntry *>(Cur->Data.data()),
- Cur->getSize() / sizeof(ExidxEntry));
- for (const ExidxEntry &Entry : Entries)
+ for (const ExidxEntry Entry : Cur->getDataAs<ExidxEntry>())
if (IsExtabRef(Entry.Unwind) || Entry.Unwind != PrevEntry.Unwind)
return false;
// All table entries in this .ARM.exidx Section can be merged into the
@@ -1240,13 +1419,12 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
if (!Config->Relocatable && Config->EMachine == EM_ARM &&
Sec->Type == SHT_ARM_EXIDX) {
- if (!Sections.empty() && isa<ARMExidxSentinelSection>(Sections.back())) {
+ if (auto *Sentinel = dyn_cast<ARMExidxSentinelSection>(Sections.back())) {
assert(Sections.size() >= 2 &&
"We should create a sentinel section only if there are "
"alive regular exidx sections.");
// The last executable section is required to fill the sentinel.
// Remember it here so that we don't have to find it again.
- auto *Sentinel = cast<ARMExidxSentinelSection>(Sections.back());
Sentinel->Highest = Sections[Sections.size() - 2]->getLinkOrderDep();
}
@@ -1257,16 +1435,13 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
// previous one. This does not require any rewriting of InputSection
// contents but misses opportunities for fine grained deduplication
// where only a subset of the InputSection contents can be merged.
- int Cur = 1;
- int Prev = 0;
+ size_t Prev = 0;
// The last one is a sentinel entry which should not be removed.
- int N = Sections.size() - 1;
- while (Cur < N) {
- if (isDuplicateArmExidxSec(Sections[Prev], Sections[Cur]))
- Sections[Cur] = nullptr;
+ for (size_t I = 1; I < Sections.size() - 1; ++I) {
+ if (isDuplicateArmExidxSec(Sections[Prev], Sections[I]))
+ Sections[I] = nullptr;
else
- Prev = Cur;
- ++Cur;
+ Prev = I;
}
}
}
@@ -1277,14 +1452,12 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
// Remove the Sections we marked as duplicate earlier.
for (BaseCommand *Base : Sec->SectionCommands)
if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
- ISD->Sections.erase(
- std::remove(ISD->Sections.begin(), ISD->Sections.end(), nullptr),
- ISD->Sections.end());
+ llvm::erase_if(ISD->Sections, [](InputSection *IS) { return !IS; });
}
}
static void applySynthetic(const std::vector<SyntheticSection *> &Sections,
- std::function<void(SyntheticSection *)> Fn) {
+ llvm::function_ref<void(SyntheticSection *)> Fn) {
for (SyntheticSection *SS : Sections)
if (SS && SS->getParent() && !SS->empty())
Fn(SS);
@@ -1311,27 +1484,15 @@ static void removeUnusedSyntheticSections() {
if (!SS)
return;
OutputSection *OS = SS->getParent();
- if (!SS->empty() || !OS)
+ if (!OS || !SS->empty())
continue;
- std::vector<BaseCommand *>::iterator Empty = OS->SectionCommands.end();
- for (auto I = OS->SectionCommands.begin(), E = OS->SectionCommands.end();
- I != E; ++I) {
- BaseCommand *B = *I;
- if (auto *ISD = dyn_cast<InputSectionDescription>(B)) {
+ // If we reach here, then SS is an unused synthetic section and we want to
+ // remove it from corresponding input section description of output section.
+ for (BaseCommand *B : OS->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(B))
llvm::erase_if(ISD->Sections,
[=](InputSection *IS) { return IS == SS; });
- if (ISD->Sections.empty())
- Empty = I;
- }
- }
- if (Empty != OS->SectionCommands.end())
- OS->SectionCommands.erase(Empty);
-
- // If there are no other sections in the output section, remove it from the
- // output.
- if (OS->SectionCommands.empty())
- OS->Live = false;
}
}
@@ -1423,9 +1584,9 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (InX::DynSymTab && Sym->includeInDynsym()) {
InX::DynSymTab->addSymbol(Sym);
- if (auto *SS = dyn_cast<SharedSymbol>(Sym))
- if (cast<SharedFile<ELFT>>(Sym->File)->IsNeeded)
- In<ELFT>::VerNeed->addSymbol(SS);
+ if (auto *File = dyn_cast_or_null<SharedFile<ELFT>>(Sym->File))
+ if (File->IsNeeded && !Sym->isUndefined())
+ In<ELFT>::VerNeed->addSymbol(Sym);
}
}
@@ -1433,10 +1594,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (errorCount())
return;
+ if (InX::MipsGot)
+ InX::MipsGot->build<ELFT>();
+
removeUnusedSyntheticSections();
sortSections();
- Script->removeEmptyCommands();
// Now that we have the final list, create a list of all the
// OutputSections for convenience.
@@ -1444,6 +1607,15 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (auto *Sec = dyn_cast<OutputSection>(Base))
OutputSections.push_back(Sec);
+ // Ensure data sections are not mixed with executable sections when
+ // -execute-only is used.
+ if (Config->ExecuteOnly)
+ for (OutputSection *OS : OutputSections)
+ if (OS->Flags & SHF_EXECINSTR)
+ for (InputSection *IS : getInputSections(OS))
+ if (!(IS->Flags & SHF_EXECINSTR))
+ error("-execute-only does not support intermingling data and code");
+
// Prefer command line supplied address over other constraints.
for (OutputSection *Sec : OutputSections) {
auto I = Config->SectionStartMap.find(Sec->Name);
@@ -1452,7 +1624,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
}
// This is a bit of a hack. A value of 0 means undef, so we set it
- // to 1 t make __ehdr_start defined. The section number is not
+ // to 1 to make __ehdr_start defined. The section number is not
// particularly relevant.
Out::ElfHeader->SectionIndex = 1;
@@ -1478,12 +1650,13 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// Dynamic section must be the last one in this list and dynamic
// symbol table section (DynSymTab) must be the first one.
applySynthetic(
- {InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab,
- InX::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab,
- In<ELFT>::VerDef, InX::DynStrTab, InX::Got, InX::MipsGot,
- InX::IgotPlt, InX::GotPlt, InX::RelaDyn, InX::RelaIplt,
- InX::RelaPlt, InX::Plt, InX::Iplt, InX::EhFrameHdr,
- In<ELFT>::VerSym, In<ELFT>::VerNeed, InX::Dynamic},
+ {InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab,
+ InX::HashTab, InX::SymTab, InX::SymTabShndx, InX::ShStrTab,
+ InX::StrTab, In<ELFT>::VerDef, InX::DynStrTab, InX::Got,
+ InX::MipsGot, InX::IgotPlt, InX::GotPlt, InX::RelaDyn,
+ InX::RelrDyn, InX::RelaIplt, InX::RelaPlt, InX::Plt,
+ InX::Iplt, InX::EhFrameHdr, In<ELFT>::VerSym, In<ELFT>::VerNeed,
+ InX::Dynamic},
[](SyntheticSection *SS) { SS->finalizeContents(); });
if (!Script->HasSectionsCommand && !Config->Relocatable)
@@ -1495,10 +1668,11 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// Some architectures need to generate content that depends on the address
// of InputSections. For example some architectures use small displacements
- // for jump instructions that is is the linker's responsibility for creating
+ // for jump instructions that is the linker's responsibility for creating
// range extension thunks for. As the generation of the content may also
// alter InputSection addresses we must converge to a fixed point.
- if (Target->NeedsThunks || Config->AndroidPackDynRelocs) {
+ if (Target->NeedsThunks || Config->AndroidPackDynRelocs ||
+ Config->RelrPackDynRelocs) {
ThunkCreator TC;
AArch64Err843419Patcher A64P;
bool Changed;
@@ -1515,34 +1689,48 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (InX::MipsGot)
InX::MipsGot->updateAllocSize();
Changed |= InX::RelaDyn->updateAllocSize();
+ if (InX::RelrDyn)
+ Changed |= InX::RelrDyn->updateAllocSize();
} while (Changed);
}
+ // createThunks may have added local symbols to the static symbol table
+ applySynthetic({InX::SymTab},
+ [](SyntheticSection *SS) { SS->postThunkContents(); });
+
// Fill other section headers. The dynamic table is finalized
// at the end because some tags like RELSZ depend on result
// of finalizing other sections.
for (OutputSection *Sec : OutputSections)
Sec->finalize<ELFT>();
-
- // createThunks may have added local symbols to the static symbol table
- applySynthetic({InX::SymTab},
- [](SyntheticSection *SS) { SS->postThunkContents(); });
}
// The linker is expected to define SECNAME_start and SECNAME_end
// symbols for a few sections. This function defines them.
template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
- auto Define = [&](StringRef Start, StringRef End, OutputSection *OS) {
- // These symbols resolve to the image base if the section does not exist.
- // A special value -1 indicates end of the section.
+ // If a section does not exist, there's ambiguity as to how we
+ // define _start and _end symbols for an init/fini section. Since
+ // the loader assume that the symbols are always defined, we need to
+ // always define them. But what value? The loader iterates over all
+ // pointers between _start and _end to run global ctors/dtors, so if
+ // the section is empty, their symbol values don't actually matter
+ // as long as _start and _end point to the same location.
+ //
+ // That said, we don't want to set the symbols to 0 (which is
+ // probably the simplest value) because that could cause some
+ // program to fail to link due to relocation overflow, if their
+ // program text is above 2 GiB. We use the address of the .text
+ // section instead to prevent that failure.
+ OutputSection *Default = findSection(".text");
+ if (!Default)
+ Default = Out::ElfHeader;
+ auto Define = [=](StringRef Start, StringRef End, OutputSection *OS) {
if (OS) {
addOptionalRegular(Start, OS, 0);
addOptionalRegular(End, OS, -1);
} else {
- if (Config->Pic)
- OS = Out::ElfHeader;
- addOptionalRegular(Start, OS, 0);
- addOptionalRegular(End, OS, 0);
+ addOptionalRegular(Start, Default, 0);
+ addOptionalRegular(End, Default, 0);
}
};
@@ -1564,12 +1752,12 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) {
StringRef S = Sec->Name;
if (!isValidCIdentifier(S))
return;
- addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT);
- addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT);
+ addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_PROTECTED);
+ addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_PROTECTED);
}
static bool needsPtLoad(OutputSection *Sec) {
- if (!(Sec->Flags & SHF_ALLOC))
+ if (!(Sec->Flags & SHF_ALLOC) || Sec->Noload)
return false;
// Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is
@@ -1587,6 +1775,8 @@ static bool needsPtLoad(OutputSection *Sec) {
static uint64_t computeFlags(uint64_t Flags) {
if (Config->Omagic)
return PF_R | PF_W | PF_X;
+ if (Config->ExecuteOnly && (Flags & PF_X))
+ return Flags & ~PF_R;
if (Config->SingleRoRx && !(Flags & PF_W))
return Flags | PF_X;
return Flags;
@@ -1626,9 +1816,11 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
// (e.g. executable or writable). There is one phdr for each segment.
// Therefore, we need to create a new phdr when the next section has
// different flags or is loaded at a discontiguous address using AT linker
- // script command.
+ // script command. At the same time, we don't want to create a separate
+ // load segment for the headers, even if the first output section has
+ // an AT attribute.
uint64_t NewFlags = computeFlags(Sec->getPhdrFlags());
- if ((Sec->LMAExpr && Load->ASectionHasLMA) ||
+ if ((Sec->LMAExpr && Load->LastSec != Out::ProgramHeaders) ||
Sec->MemRegion != Load->FirstSec->MemRegion || Flags != NewFlags) {
Load = AddHdr(PT_LOAD, NewFlags);
@@ -1691,11 +1883,9 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
// pages for the stack non-executable. If you really want an executable
// stack, you can pass -z execstack, but that's not recommended for
// security reasons.
- unsigned Perm;
+ unsigned Perm = PF_R | PF_W;
if (Config->ZExecstack)
- Perm = PF_R | PF_W | PF_X;
- else
- Perm = PF_R | PF_W;
+ Perm |= PF_X;
AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize;
// PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable
@@ -1813,6 +2003,12 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
FileSize = alignTo(Off, Config->Wordsize);
}
+static std::string rangeToString(uint64_t Addr, uint64_t Len) {
+ if (Len == 0)
+ return "<empty range at 0x" + utohexstr(Addr) + ">";
+ return "[0x" + utohexstr(Addr) + ", 0x" + utohexstr(Addr + Len - 1) + "]";
+}
+
// Assign file offsets to output sections.
template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
uint64_t Off = 0;
@@ -1837,6 +2033,24 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
SectionHeaderOff = alignTo(Off, Config->Wordsize);
FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr);
+
+ // Our logic assumes that sections have rising VA within the same segment.
+ // With use of linker scripts it is possible to violate this rule and get file
+ // offset overlaps or overflows. That should never happen with a valid script
+ // which does not move the location counter backwards and usually scripts do
+ // not do that. Unfortunately, there are apps in the wild, for example, Linux
+ // kernel, which control segment distribution explicitly and move the counter
+ // backwards, so we have to allow doing that to support linking them. We
+ // perform non-critical checks for overlaps in checkSectionOverlap(), but here
+ // we want to prevent file size overflows because it would crash the linker.
+ for (OutputSection *Sec : OutputSections) {
+ if (Sec->Type == SHT_NOBITS)
+ continue;
+ if ((Sec->Offset > FileSize) || (Sec->Offset + Sec->Size > FileSize))
+ error("unable to place section " + Sec->Name + " at file offset " +
+ rangeToString(Sec->Offset, Sec->Offset + Sec->Size) +
+ "; check your linker script for overflows");
+ }
}
// Finalize the program headers. We call this function after we assign
@@ -1875,6 +2089,97 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() {
}
}
+// A helper struct for checkSectionOverlap.
+namespace {
+struct SectionOffset {
+ OutputSection *Sec;
+ uint64_t Offset;
+};
+} // namespace
+
+// Check whether sections overlap for a specific address range (file offsets,
+// load and virtual adresses).
+static void checkOverlap(StringRef Name, std::vector<SectionOffset> &Sections,
+ bool IsVirtualAddr) {
+ llvm::sort(Sections.begin(), Sections.end(),
+ [=](const SectionOffset &A, const SectionOffset &B) {
+ return A.Offset < B.Offset;
+ });
+
+ // Finding overlap is easy given a vector is sorted by start position.
+ // If an element starts before the end of the previous element, they overlap.
+ for (size_t I = 1, End = Sections.size(); I < End; ++I) {
+ SectionOffset A = Sections[I - 1];
+ SectionOffset B = Sections[I];
+ if (B.Offset >= A.Offset + A.Sec->Size)
+ continue;
+
+ // If both sections are in OVERLAY we allow the overlapping of virtual
+ // addresses, because it is what OVERLAY was designed for.
+ if (IsVirtualAddr && A.Sec->InOverlay && B.Sec->InOverlay)
+ continue;
+
+ errorOrWarn("section " + A.Sec->Name + " " + Name +
+ " range overlaps with " + B.Sec->Name + "\n>>> " + A.Sec->Name +
+ " range is " + rangeToString(A.Offset, A.Sec->Size) + "\n>>> " +
+ B.Sec->Name + " range is " +
+ rangeToString(B.Offset, B.Sec->Size));
+ }
+}
+
+// Check for overlapping sections and address overflows.
+//
+// In this function we check that none of the output sections have overlapping
+// file offsets. For SHF_ALLOC sections we also check that the load address
+// ranges and the virtual address ranges don't overlap
+template <class ELFT> void Writer<ELFT>::checkSections() {
+ // First, check that section's VAs fit in available address space for target.
+ for (OutputSection *OS : OutputSections)
+ if ((OS->Addr + OS->Size < OS->Addr) ||
+ (!ELFT::Is64Bits && OS->Addr + OS->Size > UINT32_MAX))
+ errorOrWarn("section " + OS->Name + " at 0x" + utohexstr(OS->Addr) +
+ " of size 0x" + utohexstr(OS->Size) +
+ " exceeds available address space");
+
+ // Check for overlapping file offsets. In this case we need to skip any
+ // section marked as SHT_NOBITS. These sections don't actually occupy space in
+ // the file so Sec->Offset + Sec->Size can overlap with others. If --oformat
+ // binary is specified only add SHF_ALLOC sections are added to the output
+ // file so we skip any non-allocated sections in that case.
+ std::vector<SectionOffset> FileOffs;
+ for (OutputSection *Sec : OutputSections)
+ if (0 < Sec->Size && Sec->Type != SHT_NOBITS &&
+ (!Config->OFormatBinary || (Sec->Flags & SHF_ALLOC)))
+ FileOffs.push_back({Sec, Sec->Offset});
+ checkOverlap("file", FileOffs, false);
+
+ // When linking with -r there is no need to check for overlapping virtual/load
+ // addresses since those addresses will only be assigned when the final
+ // executable/shared object is created.
+ if (Config->Relocatable)
+ return;
+
+ // Checking for overlapping virtual and load addresses only needs to take
+ // into account SHF_ALLOC sections since others will not be loaded.
+ // Furthermore, we also need to skip SHF_TLS sections since these will be
+ // mapped to other addresses at runtime and can therefore have overlapping
+ // ranges in the file.
+ std::vector<SectionOffset> VMAs;
+ for (OutputSection *Sec : OutputSections)
+ if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
+ VMAs.push_back({Sec, Sec->Addr});
+ checkOverlap("virtual address", VMAs, true);
+
+ // Finally, check that the load addresses don't overlap. This will usually be
+ // the same as the virtual addresses but can be different when using a linker
+ // script with AT().
+ std::vector<SectionOffset> LMAs;
+ for (OutputSection *Sec : OutputSections)
+ if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
+ LMAs.push_back({Sec, Sec->getLMA()});
+ checkOverlap("load address", LMAs, false);
+}
+
// The entry point address is chosen in the following ways.
//
// 1. the '-e' entry command-line option;
@@ -1916,8 +2221,20 @@ static uint16_t getELFType() {
return ET_EXEC;
}
+static uint8_t getAbiVersion() {
+ // MIPS non-PIC executable gets ABI version 1.
+ if (Config->EMachine == EM_MIPS && getELFType() == ET_EXEC &&
+ (Config->EFlags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC)
+ return 1;
+ return 0;
+}
+
template <class ELFT> void Writer<ELFT>::writeHeader() {
uint8_t *Buf = Buffer->getBufferStart();
+ // For executable segments, the trap instructions are written before writing
+ // the header. Setting Elf header bytes to zero ensures that any unused bytes
+ // in header are zero-cleared, instead of having trap instructions.
+ memset(Buf, 0, sizeof(Elf_Ehdr));
memcpy(Buf, "\177ELF", 4);
// Write the ELF header.
@@ -1926,6 +2243,7 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB;
EHdr->e_ident[EI_VERSION] = EV_CURRENT;
EHdr->e_ident[EI_OSABI] = Config->OSABI;
+ EHdr->e_ident[EI_ABIVERSION] = getAbiVersion();
EHdr->e_type = getELFType();
EHdr->e_machine = Config->EMachine;
EHdr->e_version = EV_CURRENT;
@@ -1935,8 +2253,6 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
EHdr->e_ehsize = sizeof(Elf_Ehdr);
EHdr->e_phnum = Phdrs.size();
EHdr->e_shentsize = sizeof(Elf_Shdr);
- EHdr->e_shnum = OutputSections.size() + 1;
- EHdr->e_shstrndx = InX::ShStrTab->getParent()->SectionIndex;
if (!Config->Relocatable) {
EHdr->e_phoff = sizeof(Elf_Ehdr);
@@ -1957,8 +2273,30 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
++HBuf;
}
- // Write the section header table. Note that the first table entry is null.
+ // Write the section header table.
+ //
+ // The ELF header can only store numbers up to SHN_LORESERVE in the e_shnum
+ // and e_shstrndx fields. When the value of one of these fields exceeds
+ // SHN_LORESERVE ELF requires us to put sentinel values in the ELF header and
+ // use fields in the section header at index 0 to store
+ // the value. The sentinel values and fields are:
+ // e_shnum = 0, SHdrs[0].sh_size = number of sections.
+ // e_shstrndx = SHN_XINDEX, SHdrs[0].sh_link = .shstrtab section index.
auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
+ size_t Num = OutputSections.size() + 1;
+ if (Num >= SHN_LORESERVE)
+ SHdrs->sh_size = Num;
+ else
+ EHdr->e_shnum = Num;
+
+ uint32_t StrTabIndex = InX::ShStrTab->getParent()->SectionIndex;
+ if (StrTabIndex >= SHN_LORESERVE) {
+ SHdrs->sh_link = StrTabIndex;
+ EHdr->e_shstrndx = SHN_XINDEX;
+ } else {
+ EHdr->e_shstrndx = StrTabIndex;
+ }
+
for (OutputSection *Sec : OutputSections)
Sec->writeHeaderTo<ELFT>(++SHdrs);
}
@@ -2029,14 +2367,6 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
template <class ELFT> void Writer<ELFT>::writeSections() {
uint8_t *Buf = Buffer->getBufferStart();
- // PPC64 needs to process relocations in the .opd section
- // before processing relocations in code-containing sections.
- if (auto *OpdCmd = findSection(".opd")) {
- Out::Opd = OpdCmd;
- Out::OpdBuf = Buf + Out::Opd->Offset;
- OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset);
- }
-
OutputSection *EhFrameHdr = nullptr;
if (InX::EhFrameHdr && !InX::EhFrameHdr->empty())
EhFrameHdr = InX::EhFrameHdr->getParent();
@@ -2049,8 +2379,7 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
Sec->writeTo<ELFT>(Buf + Sec->Offset);
for (OutputSection *Sec : OutputSections)
- if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL &&
- Sec->Type != SHT_RELA)
+ if (Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA)
Sec->writeTo<ELFT>(Buf + Sec->Offset);
// The .eh_frame_hdr depends on .eh_frame section contents, therefore
diff --git a/contrib/llvm/tools/lld/ELF/Writer.h b/contrib/llvm/tools/lld/ELF/Writer.h
index f48f9d1e01b2..7806f824c58f 100644
--- a/contrib/llvm/tools/lld/ELF/Writer.h
+++ b/contrib/llvm/tools/lld/ELF/Writer.h
@@ -23,7 +23,6 @@ class InputSectionBase;
template <class ELFT> class ObjFile;
class SymbolTable;
template <class ELFT> void writeResult();
-template <class ELFT> void markLive();
// This describes a program header entry.
// Each contains type, access flags and range of output sections that will be
@@ -45,16 +44,11 @@ struct PhdrEntry {
OutputSection *LastSec = nullptr;
bool HasLMA = false;
- // True if one of the sections in this program header has a LMA specified via
- // linker script: AT(addr). We never allow 2 or more sections with LMA in the
- // same program header.
- bool ASectionHasLMA = false;
-
uint64_t LMAOffset = 0;
};
void addReservedSymbols();
-llvm::StringRef getOutputSectionName(InputSectionBase *S);
+llvm::StringRef getOutputSectionName(const InputSectionBase *S);
template <class ELFT> uint32_t calcMipsEFlags();
diff --git a/contrib/llvm/tools/lld/LICENSE.TXT b/contrib/llvm/tools/lld/LICENSE.TXT
index ec97986c86ba..e05e1845766e 100644
--- a/contrib/llvm/tools/lld/LICENSE.TXT
+++ b/contrib/llvm/tools/lld/LICENSE.TXT
@@ -4,7 +4,7 @@ lld License
University of Illinois/NCSA
Open Source License
-Copyright (c) 2011-2016 by the contributors listed in CREDITS.TXT
+Copyright (c) 2011-2018 by the contributors listed in CREDITS.TXT
All rights reserved.
Developed by:
diff --git a/contrib/llvm/tools/lld/docs/AtomLLD.rst b/contrib/llvm/tools/lld/docs/AtomLLD.rst
new file mode 100644
index 000000000000..614e568d1997
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/AtomLLD.rst
@@ -0,0 +1,62 @@
+ATOM-based lld
+==============
+
+Note: this document discuss Mach-O port of LLD. For ELF and COFF,
+see :doc:`index`.
+
+ATOM-based lld is a new set of modular code for creating linker tools.
+Currently it supports Mach-O.
+
+* End-User Features:
+
+ * Compatible with existing linker options
+ * Reads standard Object Files
+ * Writes standard Executable Files
+ * Remove clang's reliance on "the system linker"
+ * Uses the LLVM `"UIUC" BSD-Style license`__.
+
+* Applications:
+
+ * Modular design
+ * Support cross linking
+ * Easy to add new CPU support
+ * Can be built as static tool or library
+
+* Design and Implementation:
+
+ * Extensive unit tests
+ * Internal linker model can be dumped/read to textual format
+ * Additional linking features can be plugged in as "passes"
+ * OS specific and CPU specific code factored out
+
+Why a new linker?
+-----------------
+
+The fact that clang relies on whatever linker tool you happen to have installed
+means that clang has been very conservative adopting features which require a
+recent linker.
+
+In the same way that the MC layer of LLVM has removed clang's reliance on the
+system assembler tool, the lld project will remove clang's reliance on the
+system linker tool.
+
+
+Contents
+--------
+
+.. toctree::
+ :maxdepth: 2
+
+ design
+ getting_started
+ development
+ open_projects
+ sphinx_intro
+
+Indices and tables
+------------------
+
+* :ref:`genindex`
+* :ref:`search`
+
+__ http://llvm.org/docs/DeveloperPolicy.html#license
diff --git a/contrib/llvm/tools/lld/docs/CMakeLists.txt b/contrib/llvm/tools/lld/docs/CMakeLists.txt
new file mode 100644
index 000000000000..112ce35e8cf4
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/CMakeLists.txt
@@ -0,0 +1,8 @@
+if (LLVM_ENABLE_SPHINX)
+ include(AddSphinxTarget)
+ if (SPHINX_FOUND)
+ if (${SPHINX_OUTPUT_HTML})
+ add_sphinx_target(html lld)
+ endif()
+ endif()
+endif()
diff --git a/contrib/llvm/tools/lld/docs/Driver.rst b/contrib/llvm/tools/lld/docs/Driver.rst
new file mode 100644
index 000000000000..4ee6ce0c985f
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/Driver.rst
@@ -0,0 +1,82 @@
+======
+Driver
+======
+
+Note: this document discuss Mach-O port of LLD. For ELF and COFF,
+see :doc:`index`.
+
+.. contents::
+ :local:
+
+Introduction
+============
+
+This document describes the lld driver. The purpose of this document is to
+describe both the motivation and design goals for the driver, as well as details
+of the internal implementation.
+
+Overview
+========
+
+The lld driver is designed to support a number of different command line
+interfaces. The main interfaces we plan to support are binutils' ld, Apple's
+ld, and Microsoft's link.exe.
+
+Flavors
+-------
+
+Each of these different interfaces is referred to as a flavor. There is also an
+extra flavor "core" which is used to exercise the core functionality of the
+linker it the test suite.
+
+* gnu
+* darwin
+* link
+* core
+
+Selecting a Flavor
+^^^^^^^^^^^^^^^^^^
+
+There are two different ways to tell lld which flavor to be. They are checked in
+order, so the second overrides the first. The first is to symlink :program:`lld`
+as :program:`lld-{flavor}` or just :program:`{flavor}`. You can also specify
+it as the first command line argument using ``-flavor``::
+
+ $ lld -flavor gnu
+
+There is a shortcut for ``-flavor core`` as ``-core``.
+
+
+Adding an Option to an existing Flavor
+======================================
+
+#. Add the option to the desired :file:`lib/Driver/{flavor}Options.td`.
+
+#. Add to :cpp:class:`lld::FlavorLinkingContext` a getter and setter method
+ for the option.
+
+#. Modify :cpp:func:`lld::FlavorDriver::parse` in :file:
+ `lib/Driver/{Flavor}Driver.cpp` to call the targetInfo setter
+ for corresponding to the option.
+
+#. Modify {Flavor}Reader and {Flavor}Writer to use the new targtInfo option.
+
+
+Adding a Flavor
+===============
+
+#. Add an entry for the flavor in :file:`include/lld/Common/Driver.h` to
+ :cpp:class:`lld::UniversalDriver::Flavor`.
+
+#. Add an entry in :file:`lib/Driver/UniversalDriver.cpp` to
+ :cpp:func:`lld::Driver::strToFlavor` and
+ :cpp:func:`lld::UniversalDriver::link`.
+ This allows the flavor to be selected via symlink and `-flavor`.
+
+#. Add a tablegen file called :file:`lib/Driver/{flavor}Options.td` that
+ describes the options. If the options are a superset of another driver, that
+ driver's td file can simply be included. The :file:`{flavor}Options.td` file
+ must also be added to :file:`lib/Driver/CMakeLists.txt`.
+
+#. Add a ``{flavor}Driver`` as a subclass of :cpp:class:`lld::Driver`
+ in :file:`lib/Driver/{flavor}Driver.cpp`.
diff --git a/contrib/llvm/tools/lld/docs/NewLLD.rst b/contrib/llvm/tools/lld/docs/NewLLD.rst
new file mode 100644
index 000000000000..afdb41e0a145
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/NewLLD.rst
@@ -0,0 +1,309 @@
+The ELF, COFF and Wasm Linkers
+==============================
+
+The ELF Linker as a Library
+---------------------------
+
+You can embed LLD to your program by linking against it and calling the linker's
+entry point function lld::elf::link.
+
+The current policy is that it is your reponsibility to give trustworthy object
+files. The function is guaranteed to return as long as you do not pass corrupted
+or malicious object files. A corrupted file could cause a fatal error or SEGV.
+That being said, you don't need to worry too much about it if you create object
+files in the usual way and give them to the linker. It is naturally expected to
+work, or otherwise it's a linker's bug.
+
+Design
+======
+
+We will describe the design of the linkers in the rest of the document.
+
+Key Concepts
+------------
+
+Linkers are fairly large pieces of software.
+There are many design choices you have to make to create a complete linker.
+
+This is a list of design choices we've made for ELF and COFF LLD.
+We believe that these high-level design choices achieved a right balance
+between speed, simplicity and extensibility.
+
+* Implement as native linkers
+
+ We implemented the linkers as native linkers for each file format.
+
+ The linkers share the same design but share very little code.
+ Sharing code makes sense if the benefit is worth its cost.
+ In our case, the object formats are different enough that we thought the layer
+ to abstract the differences wouldn't be worth its complexity and run-time
+ cost. Elimination of the abstract layer has greatly simplified the
+ implementation.
+
+* Speed by design
+
+ One of the most important things in archiving high performance is to
+ do less rather than do it efficiently.
+ Therefore, the high-level design matters more than local optimizations.
+ Since we are trying to create a high-performance linker,
+ it is very important to keep the design as efficient as possible.
+
+ Broadly speaking, we do not do anything until we have to do it.
+ For example, we do not read section contents or relocations
+ until we need them to continue linking.
+ When we need to do some costly operation (such as looking up
+ a hash table for each symbol), we do it only once.
+ We obtain a handler (which is typically just a pointer to actual data)
+ on the first operation and use it throughout the process.
+
+* Efficient archive file handling
+
+ LLD's handling of archive files (the files with ".a" file extension) is
+ different from the traditional Unix linkers and similar to Windows linkers.
+ We'll describe how the traditional Unix linker handles archive files, what the
+ problem is, and how LLD approached the problem.
+
+ The traditional Unix linker maintains a set of undefined symbols during
+ linking. The linker visits each file in the order as they appeared in the
+ command line until the set becomes empty. What the linker would do depends on
+ file type.
+
+ - If the linker visits an object file, the linker links object files to the
+ result, and undefined symbols in the object file are added to the set.
+
+ - If the linker visits an archive file, it checks for the archive file's
+ symbol table and extracts all object files that have definitions for any
+ symbols in the set.
+
+ This algorithm sometimes leads to a counter-intuitive behavior. If you give
+ archive files before object files, nothing will happen because when the linker
+ visits archives, there is no undefined symbols in the set. As a result, no
+ files are extracted from the first archive file, and the link is done at that
+ point because the set is empty after it visits one file.
+
+ You can fix the problem by reordering the files,
+ but that cannot fix the issue of mutually-dependent archive files.
+
+ Linking mutually-dependent archive files is tricky. You may specify the same
+ archive file multiple times to let the linker visit it more than once. Or,
+ you may use the special command line options, `--start-group` and
+ `--end-group`, to let the linker loop over the files between the options until
+ no new symbols are added to the set.
+
+ Visiting the same archive files multiple makes the linker slower.
+
+ Here is how LLD approaches the problem. Instead of memorizing only undefined
+ symbols, we program LLD so that it memorizes all symbols. When it sees an
+ undefined symbol that can be resolved by extracting an object file from an
+ archive file it previously visited, it immediately extracts the file and link
+ it. It is doable because LLD does not forget symbols it have seen in archive
+ files.
+
+ We believe that the LLD's way is efficient and easy to justify.
+
+ The semantics of LLD's archive handling is different from the traditional
+ Unix's. You can observe it if you carefully craft archive files to exploit
+ it. However, in reality, we don't know any program that cannot link with our
+ algorithm so far, so it's not going to cause trouble.
+
+Numbers You Want to Know
+------------------------
+
+To give you intuition about what kinds of data the linker is mainly working on,
+I'll give you the list of objects and their numbers LLD has to read and process
+in order to link a very large executable. In order to link Chrome with debug
+info, which is roughly 2 GB in output size, LLD reads
+
+- 17,000 files,
+- 1,800,000 sections,
+- 6,300,000 symbols, and
+- 13,000,000 relocations.
+
+LLD produces the 2 GB executable in 15 seconds.
+
+These numbers vary depending on your program, but in general,
+you have a lot of relocations and symbols for each file.
+If your program is written in C++, symbol names are likely to be
+pretty long because of name mangling.
+
+It is important to not waste time on relocations and symbols.
+
+In the above case, the total amount of symbol strings is 450 MB,
+and inserting all of them to a hash table takes 1.5 seconds.
+Therefore, if you causally add a hash table lookup for each symbol,
+it would slow down the linker by 10%. So, don't do that.
+
+On the other hand, you don't have to pursue efficiency
+when handling files.
+
+Important Data Structures
+-------------------------
+
+We will describe the key data structures in LLD in this section. The linker can
+be understood as the interactions between them. Once you understand their
+functions, the code of the linker should look obvious to you.
+
+* Symbol
+
+ This class represents a symbol.
+ They are created for symbols in object files or archive files.
+ The linker creates linker-defined symbols as well.
+
+ There are basically three types of Symbols: Defined, Undefined, or Lazy.
+
+ - Defined symbols are for all symbols that are considered as "resolved",
+ including real defined symbols, COMDAT symbols, common symbols,
+ absolute symbols, linker-created symbols, etc.
+ - Undefined symbols represent undefined symbols, which need to be replaced by
+ Defined symbols by the resolver until the link is complete.
+ - Lazy symbols represent symbols we found in archive file headers
+ which can turn into Defined if we read archieve members.
+
+ There's only one Symbol instance for each unique symbol name. This uniqueness
+ is guaranteed by the symbol table. As the resolver reads symbols from input
+ files, it replaces an existing Symbol with the "best" Symbol for its symbol
+ name using the placement new.
+
+ The above mechanism allows you to use pointers to Symbols as a very cheap way
+ to access name resolution results. Assume for example that you have a pointer
+ to an undefined symbol before name resolution. If the symbol is resolved to a
+ defined symbol by the resolver, the pointer will "automatically" point to the
+ defined symbol, because the undefined symbol the pointer pointed to will have
+ been replaced by the defined symbol in-place.
+
+* SymbolTable
+
+ SymbolTable is basically a hash table from strings to Symbols
+ with logic to resolve symbol conflicts. It resolves conflicts by symbol type.
+
+ - If we add Defined and Undefined symbols, the symbol table will keep the
+ former.
+ - If we add Defined and Lazy symbols, it will keep the former.
+ - If we add Lazy and Undefined, it will keep the former,
+ but it will also trigger the Lazy symbol to load the archive member
+ to actually resolve the symbol.
+
+* Chunk (COFF specific)
+
+ Chunk represents a chunk of data that will occupy space in an output.
+ Each regular section becomes a chunk.
+ Chunks created for common or BSS symbols are not backed by sections.
+ The linker may create chunks to append additional data to an output as well.
+
+ Chunks know about their size, how to copy their data to mmap'ed outputs,
+ and how to apply relocations to them.
+ Specifically, section-based chunks know how to read relocation tables
+ and how to apply them.
+
+* InputSection (ELF specific)
+
+ Since we have less synthesized data for ELF, we don't abstract slices of
+ input files as Chunks for ELF. Instead, we directly use the input section
+ as an internal data type.
+
+ InputSection knows about their size and how to copy themselves to
+ mmap'ed outputs, just like COFF Chunks.
+
+* OutputSection
+
+ OutputSection is a container of InputSections (ELF) or Chunks (COFF).
+ An InputSection or Chunk belongs to at most one OutputSection.
+
+There are mainly three actors in this linker.
+
+* InputFile
+
+ InputFile is a superclass of file readers.
+ We have a different subclass for each input file type,
+ such as regular object file, archive file, etc.
+ They are responsible for creating and owning Symbols and InputSections/Chunks.
+
+* Writer
+
+ The writer is responsible for writing file headers and InputSections/Chunks to
+ a file. It creates OutputSections, put all InputSections/Chunks into them,
+ assign unique, non-overlapping addresses and file offsets to them, and then
+ write them down to a file.
+
+* Driver
+
+ The linking process is driven by the driver. The driver:
+
+ - processes command line options,
+ - creates a symbol table,
+ - creates an InputFile for each input file and puts all symbols within into
+ the symbol table,
+ - checks if there's no remaining undefined symbols,
+ - creates a writer,
+ - and passes the symbol table to the writer to write the result to a file.
+
+Link-Time Optimization
+----------------------
+
+LTO is implemented by handling LLVM bitcode files as object files.
+The linker resolves symbols in bitcode files normally. If all symbols
+are successfully resolved, it then runs LLVM passes
+with all bitcode files to convert them to one big regular ELF/COFF file.
+Finally, the linker replaces bitcode symbols with ELF/COFF symbols,
+so that they are linked as if they were in the native format from the beginning.
+
+The details are described in this document.
+http://llvm.org/docs/LinkTimeOptimization.html
+
+Glossary
+--------
+
+* RVA (COFF)
+
+ Short for Relative Virtual Address.
+
+ Windows executables or DLLs are not position-independent; they are
+ linked against a fixed address called an image base. RVAs are
+ offsets from an image base.
+
+ Default image bases are 0x140000000 for executables and 0x18000000
+ for DLLs. For example, when we are creating an executable, we assume
+ that the executable will be loaded at address 0x140000000 by the
+ loader, so we apply relocations accordingly. Result texts and data
+ will contain raw absolute addresses.
+
+* VA
+
+ Short for Virtual Address. For COFF, it is equivalent to RVA + image base.
+
+* Base relocations (COFF)
+
+ Relocation information for the loader. If the loader decides to map
+ an executable or a DLL to a different address than their image
+ bases, it fixes up binaries using information contained in the base
+ relocation table. A base relocation table consists of a list of
+ locations containing addresses. The loader adds a difference between
+ RVA and actual load address to all locations listed there.
+
+ Note that this run-time relocation mechanism is much simpler than ELF.
+ There's no PLT or GOT. Images are relocated as a whole just
+ by shifting entire images in memory by some offsets. Although doing
+ this breaks text sharing, I think this mechanism is not actually bad
+ on today's computers.
+
+* ICF
+
+ Short for Identical COMDAT Folding (COFF) or Identical Code Folding (ELF).
+
+ ICF is an optimization to reduce output size by merging read-only sections
+ by not only their names but by their contents. If two read-only sections
+ happen to have the same metadata, actual contents and relocations,
+ they are merged by ICF. It is known as an effective technique,
+ and it usually reduces C++ program's size by a few percent or more.
+
+ Note that this is not an entirely sound optimization. C/C++ require
+ different functions have different addresses. If a program depends on
+ that property, it would fail at runtime.
+
+ On Windows, that's not really an issue because MSVC link.exe enabled
+ the optimization by default. As long as your program works
+ with the linker's default settings, your program should be safe with ICF.
+
+ On Unix, your program is generally not guaranteed to be safe with ICF,
+ although large programs happen to work correctly.
+ LLD works fine with ICF for example.
diff --git a/contrib/llvm/tools/lld/docs/README.txt b/contrib/llvm/tools/lld/docs/README.txt
new file mode 100644
index 000000000000..eb09a2d2b7ea
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/README.txt
@@ -0,0 +1,12 @@
+lld Documentation
+=================
+
+The lld documentation is written using the Sphinx documentation generator. It is
+currently tested with Sphinx 1.1.3.
+
+We currently use the 'nature' theme and a Beaker inspired structure.
+
+To rebuild documents into html:
+
+ [/lld/docs]> make html
+
diff --git a/contrib/llvm/tools/lld/docs/Readers.rst b/contrib/llvm/tools/lld/docs/Readers.rst
new file mode 100644
index 000000000000..b69a0b34fabe
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/Readers.rst
@@ -0,0 +1,174 @@
+.. _Readers:
+
+Developing lld Readers
+======================
+
+Note: this document discuss Mach-O port of LLD. For ELF and COFF,
+see :doc:`index`.
+
+Introduction
+------------
+
+The purpose of a "Reader" is to take an object file in a particular format
+and create an `lld::File`:cpp:class: (which is a graph of Atoms)
+representing the object file. A Reader inherits from
+`lld::Reader`:cpp:class: which lives in
+:file:`include/lld/Core/Reader.h` and
+:file:`lib/Core/Reader.cpp`.
+
+The Reader infrastructure for an object format ``Foo`` requires the
+following pieces in order to fit into lld:
+
+:file:`include/lld/ReaderWriter/ReaderFoo.h`
+
+ .. cpp:class:: ReaderOptionsFoo : public ReaderOptions
+
+ This Options class is the only way to configure how the Reader will
+ parse any file into an `lld::Reader`:cpp:class: object. This class
+ should be declared in the `lld`:cpp:class: namespace.
+
+ .. cpp:function:: Reader *createReaderFoo(ReaderOptionsFoo &reader)
+
+ This factory function configures and create the Reader. This function
+ should be declared in the `lld`:cpp:class: namespace.
+
+:file:`lib/ReaderWriter/Foo/ReaderFoo.cpp`
+
+ .. cpp:class:: ReaderFoo : public Reader
+
+ This is the concrete Reader class which can be called to parse
+ object files. It should be declared in an anonymous namespace or
+ if there is shared code with the `lld::WriterFoo`:cpp:class: you
+ can make a nested namespace (e.g. `lld::foo`:cpp:class:).
+
+You may have noticed that :cpp:class:`ReaderFoo` is not declared in the
+``.h`` file. An important design aspect of lld is that all Readers are
+created *only* through an object-format-specific
+:cpp:func:`createReaderFoo` factory function. The creation of the Reader is
+parametrized through a :cpp:class:`ReaderOptionsFoo` class. This options
+class is the one-and-only way to control how the Reader operates when
+parsing an input file into an Atom graph. For instance, you may want the
+Reader to only accept certain architectures. The options class can be
+instantiated from command line options or be programmatically configured.
+
+Where to start
+--------------
+
+The lld project already has a skeleton of source code for Readers for
+``ELF``, ``PECOFF``, ``MachO``, and lld's native ``YAML`` graph format.
+If your file format is a variant of one of those, you should modify the
+existing Reader to support your variant. This is done by customizing the Options
+class for the Reader and making appropriate changes to the ``.cpp`` file to
+interpret those options and act accordingly.
+
+If your object file format is not a variant of any existing Reader, you'll need
+to create a new Reader subclass with the organization described above.
+
+Readers are factories
+---------------------
+
+The linker will usually only instantiate your Reader once. That one Reader will
+have its loadFile() method called many times with different input files.
+To support multithreaded linking, the Reader may be parsing multiple input
+files in parallel. Therefore, there should be no parsing state in you Reader
+object. Any parsing state should be in ivars of your File subclass or in
+some temporary object.
+
+The key method to implement in a reader is::
+
+ virtual error_code loadFile(LinkerInput &input,
+ std::vector<std::unique_ptr<File>> &result);
+
+It takes a memory buffer (which contains the contents of the object file
+being read) and returns an instantiated lld::File object which is
+a collection of Atoms. The result is a vector of File pointers (instead of
+simple a File pointer) because some file formats allow multiple object
+"files" to be encoded in one file system file.
+
+
+Memory Ownership
+----------------
+
+Atoms are always owned by their File object. During core linking when Atoms
+are coalesced or stripped away, core linking does not delete them.
+Core linking just removes those unused Atoms from its internal list.
+The destructor of a File object is responsible for deleting all Atoms it
+owns, and if ownership of the MemoryBuffer was passed to it, the File
+destructor needs to delete that too.
+
+Making Atoms
+------------
+
+The internal model of lld is purely Atom based. But most object files do not
+have an explicit concept of Atoms, instead most have "sections". The way
+to think of this is that a section is just a list of Atoms with common
+attributes.
+
+The first step in parsing section-based object files is to cleave each
+section into a list of Atoms. The technique may vary by section type. For
+code sections (e.g. .text), there are usually symbols at the start of each
+function. Those symbol addresses are the points at which the section is
+cleaved into discrete Atoms. Some file formats (like ELF) also include the
+length of each symbol in the symbol table. Otherwise, the length of each
+Atom is calculated to run to the start of the next symbol or the end of the
+section.
+
+Other sections types can be implicitly cleaved. For instance c-string literals
+or unwind info (e.g. .eh_frame) can be cleaved by having the Reader look at
+the content of the section. It is important to cleave sections into Atoms
+to remove false dependencies. For instance the .eh_frame section often
+has no symbols, but contains "pointers" to the functions for which it
+has unwind info. If the .eh_frame section was not cleaved (but left as one
+big Atom), there would always be a reference (from the eh_frame Atom) to
+each function. So the linker would be unable to coalesce or dead stripped
+away the function atoms.
+
+The lld Atom model also requires that a reference to an undefined symbol be
+modeled as a Reference to an UndefinedAtom. So the Reader also needs to
+create an UndefinedAtom for each undefined symbol in the object file.
+
+Once all Atoms have been created, the second step is to create References
+(recall that Atoms are "nodes" and References are "edges"). Most References
+are created by looking at the "relocation records" in the object file. If
+a function contains a call to "malloc", there is usually a relocation record
+specifying the address in the section and the symbol table index. Your
+Reader will need to convert the address to an Atom and offset and the symbol
+table index into a target Atom. If "malloc" is not defined in the object file,
+the target Atom of the Reference will be an UndefinedAtom.
+
+
+Performance
+-----------
+Once you have the above working to parse an object file into Atoms and
+References, you'll want to look at performance. Some techniques that can
+help performance are:
+
+* Use llvm::BumpPtrAllocator or pre-allocate one big vector<Reference> and then
+ just have each atom point to its subrange of References in that vector.
+ This can be faster that allocating each Reference as separate object.
+* Pre-scan the symbol table and determine how many atoms are in each section
+ then allocate space for all the Atom objects at once.
+* Don't copy symbol names or section content to each Atom, instead use
+ StringRef and ArrayRef in each Atom to point to its name and content in the
+ MemoryBuffer.
+
+
+Testing
+-------
+
+We are still working on infrastructure to test Readers. The issue is that
+you don't want to check in binary files to the test suite. And the tools
+for creating your object file from assembly source may not be available on
+every OS.
+
+We are investigating a way to use YAML to describe the section, symbols,
+and content of a file. Then have some code which will write out an object
+file from that YAML description.
+
+Once that is in place, you can write test cases that contain section/symbols
+YAML and is run through the linker to produce Atom/References based YAML which
+is then run through FileCheck to verify the Atoms and References are as
+expected.
+
+
+
diff --git a/contrib/llvm/tools/lld/docs/ReleaseNotes.rst b/contrib/llvm/tools/lld/docs/ReleaseNotes.rst
new file mode 100644
index 000000000000..7ac1f9ce565b
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/ReleaseNotes.rst
@@ -0,0 +1,37 @@
+=======================
+LLD 7.0.0 Release Notes
+=======================
+
+.. contents::
+ :local:
+
+.. warning::
+ These are in-progress notes for the upcoming LLVM 7.0.0 release.
+ Release notes for previous releases can be found on
+ `the Download Page <http://releases.llvm.org/download.html>`_.
+
+Introduction
+============
+
+This document contains the release notes for the lld linker, release 7.0.0.
+Here we describe the status of lld, including major improvements
+from the previous release. All lld releases may be downloaded
+from the `LLVM releases web site <http://llvm.org/releases/>`_.
+
+Non-comprehensive list of changes in this release
+=================================================
+
+ELF Improvements
+----------------
+
+* Item 1.
+
+COFF Improvements
+-----------------
+
+* Item 1.
+
+MachO Improvements
+------------------
+
+* Item 1.
diff --git a/contrib/llvm/tools/lld/docs/WebAssembly.rst b/contrib/llvm/tools/lld/docs/WebAssembly.rst
new file mode 100644
index 000000000000..264d221970b1
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/WebAssembly.rst
@@ -0,0 +1,36 @@
+WebAssembly lld port
+====================
+
+Note: The WebAssembly port is still a work in progress and is be lacking
+certain features.
+
+The WebAssembly version of lld takes WebAssembly binaries as inputs and produces
+a WebAssembly binary as its output. For the most part this port tried to mimic
+the behaviour of traditional ELF linkers and specifically the ELF lld port.
+Where possible that command line flags and the semantics should be the same.
+
+
+Object file format
+------------------
+
+The format the input object files that lld expects is specified as part of the
+the WebAssembly tool conventions
+https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md.
+
+This is object format that the llvm will produce when run with the
+``wasm32-unknown-unknown`` target. To build llvm with WebAssembly support
+currently requires enabling the experimental backed using
+``-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly``.
+
+
+Missing features
+----------------
+
+There are several key features that are not yet implement in the WebAssembly
+ports:
+
+- COMDAT support. This means that support for C++ is still very limited.
+- Function stripping. Currently there is no support for ``--gc-sections`` so
+ functions and data from a given object will linked as a unit.
+- Section start/end symbols. The synthetic symbols that mark the start and
+ of data regions are not yet created in the output file.
diff --git a/contrib/llvm/tools/lld/docs/_static/favicon.ico b/contrib/llvm/tools/lld/docs/_static/favicon.ico
new file mode 100644
index 000000000000..724ad6e12dd4
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/_static/favicon.ico
Binary files differ
diff --git a/contrib/llvm/tools/lld/docs/_templates/indexsidebar.html b/contrib/llvm/tools/lld/docs/_templates/indexsidebar.html
new file mode 100644
index 000000000000..588be9309bde
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/_templates/indexsidebar.html
@@ -0,0 +1,4 @@
+<h3>Bugs</h3>
+
+<p>lld bugs should be reported at the
+ LLVM <a href="https://bugs.llvm.org/">Bugzilla</a>.</p>
diff --git a/contrib/llvm/tools/lld/docs/_templates/layout.html b/contrib/llvm/tools/lld/docs/_templates/layout.html
new file mode 100644
index 000000000000..519a24bce63a
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/_templates/layout.html
@@ -0,0 +1,12 @@
+{% extends "!layout.html" %}
+
+{% block extrahead %}
+<style type="text/css">
+ table.right { float: right; margin-left: 20px; }
+ table.right td { border: 1px solid #ccc; }
+</style>
+{% endblock %}
+
+{% block rootrellink %}
+ <li><a href="{{ pathto('index') }}">lld Home</a>&nbsp;|&nbsp;</li>
+{% endblock %}
diff --git a/contrib/llvm/tools/lld/docs/conf.py b/contrib/llvm/tools/lld/docs/conf.py
new file mode 100644
index 000000000000..3598fbf50f0d
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/conf.py
@@ -0,0 +1,255 @@
+# -*- coding: utf-8 -*-
+#
+# lld documentation build configuration file.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+from datetime import date
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'lld'
+copyright = u'2011-%d, LLVM Project' % date.today().year
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short version.
+version = '7'
+# The full version, including alpha/beta/rc tags.
+release = '7'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%Y-%m-%d'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+show_authors = True
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'friendly'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'llvm-theme'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+html_theme_path = ["."]
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# If given, this must be the name of an image file (path relative to the
+# configuration directory) that is the favicon of the docs. Modern browsers use
+# this as icon for tabs, windows and bookmarks. It should be a Windows-style
+# icon file (.ico), which is 16x16 or 32x32 pixels large. Default: None. The
+# image file will be copied to the _static directory of the output HTML, but
+# only if the file does not already exist there.
+html_favicon = '_static/favicon.ico'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%Y-%m-%d'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+html_sidebars = {'index': 'indexsidebar.html'}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+# html_additional_pages = {'index': 'index.html'}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'llddoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('contents', 'lld.tex', u'lld Documentation',
+ u'LLVM project', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('contents', 'lld', u'lld Documentation',
+ [u'LLVM project'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('contents', 'lld', u'lld Documentation',
+ u'LLVM project', 'lld', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+
+# FIXME: Define intersphinx configration.
+intersphinx_mapping = {}
+
+
+# -- Options for extensions ----------------------------------------------------
+
+# Enable this if you want TODOs to show up in the generated documentation.
+todo_include_todos = True
diff --git a/contrib/llvm/tools/lld/docs/design.rst b/contrib/llvm/tools/lld/docs/design.rst
new file mode 100644
index 000000000000..1e111f979bb5
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/design.rst
@@ -0,0 +1,421 @@
+.. _design:
+
+Linker Design
+=============
+
+Note: this document discuss Mach-O port of LLD. For ELF and COFF,
+see :doc:`index`.
+
+Introduction
+------------
+
+lld is a new generation of linker. It is not "section" based like traditional
+linkers which mostly just interlace sections from multiple object files into the
+output file. Instead, lld is based on "Atoms". Traditional section based
+linking work well for simple linking, but their model makes advanced linking
+features difficult to implement. Features like dead code stripping, reordering
+functions for locality, and C++ coalescing require the linker to work at a finer
+grain.
+
+An atom is an indivisible chunk of code or data. An atom has a set of
+attributes, such as: name, scope, content-type, alignment, etc. An atom also
+has a list of References. A Reference contains: a kind, an optional offset, an
+optional addend, and an optional target atom.
+
+The Atom model allows the linker to use standard graph theory models for linking
+data structures. Each atom is a node, and each Reference is an edge. The
+feature of dead code stripping is implemented by following edges to mark all
+live atoms, and then delete the non-live atoms.
+
+
+Atom Model
+----------
+
+An atom is an indivisible chunk of code or data. Typically each user written
+function or global variable is an atom. In addition, the compiler may emit
+other atoms, such as for literal c-strings or floating point constants, or for
+runtime data structures like dwarf unwind info or pointers to initializers.
+
+A simple "hello world" object file would be modeled like this:
+
+.. image:: hello.png
+
+There are three atoms: main, a proxy for printf, and an anonymous atom
+containing the c-string literal "hello world". The Atom "main" has two
+references. One is the call site for the call to printf, and the other is a
+reference for the instruction that loads the address of the c-string literal.
+
+There are only four different types of atoms:
+
+ * DefinedAtom
+ 95% of all atoms. This is a chunk of code or data
+
+ * UndefinedAtom
+ This is a place holder in object files for a reference to some atom
+ outside the translation unit.During core linking it is usually replaced
+ by (coalesced into) another Atom.
+
+ * SharedLibraryAtom
+ If a required symbol name turns out to be defined in a dynamic shared
+ library (and not some object file). A SharedLibraryAtom is the
+ placeholder Atom used to represent that fact.
+
+ It is similar to an UndefinedAtom, but it also tracks information
+ about the associated shared library.
+
+ * AbsoluteAtom
+ This is for embedded support where some stuff is implemented in ROM at
+ some fixed address. This atom has no content. It is just an address
+ that the Writer needs to fix up any references to point to.
+
+
+File Model
+----------
+
+The linker views the input files as basically containers of Atoms and
+References, and just a few attributes of their own. The linker works with three
+kinds of files: object files, static libraries, and dynamic shared libraries.
+Each kind of file has reader object which presents the file in the model
+expected by the linker.
+
+Object File
+~~~~~~~~~~~
+
+An object file is just a container of atoms. When linking an object file, a
+reader is instantiated which parses the object file and instantiates a set of
+atoms representing all content in the .o file. The linker adds all those atoms
+to a master graph.
+
+Static Library (Archive)
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the traditional unix static archive which is just a collection of object
+files with a "table of contents". When linking with a static library, by default
+nothing is added to the master graph of atoms. Instead, if after merging all
+atoms from object files into a master graph, if any "undefined" atoms are left
+remaining in the master graph, the linker reads the table of contents for each
+static library to see if any have the needed definitions. If so, the set of
+atoms from the specified object file in the static library is added to the
+master graph of atoms.
+
+Dynamic Library (Shared Object)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Dynamic libraries are different than object files and static libraries in that
+they don't directly add any content. Their purpose is to check at build time
+that the remaining undefined references can be resolved at runtime, and provide
+a list of dynamic libraries (SO_NEEDED) that will be needed at runtime. The way
+this is modeled in the linker is that a dynamic library contributes no atoms to
+the initial graph of atoms. Instead, (like static libraries) if there are
+"undefined" atoms in the master graph of all atoms, then each dynamic library is
+checked to see if exports the required symbol. If so, a "shared library" atom is
+instantiated by the by the reader which the linker uses to replace the
+"undefined" atom.
+
+Linking Steps
+-------------
+
+Through the use of abstract Atoms, the core of linking is architecture
+independent and file format independent. All command line parsing is factored
+out into a separate "options" abstraction which enables the linker to be driven
+with different command line sets.
+
+The overall steps in linking are:
+
+ #. Command line processing
+
+ #. Parsing input files
+
+ #. Resolving
+
+ #. Passes/Optimizations
+
+ #. Generate output file
+
+The Resolving and Passes steps are done purely on the master graph of atoms, so
+they have no notion of file formats such as mach-o or ELF.
+
+
+Input Files
+~~~~~~~~~~~
+
+Existing developer tools using different file formats for object files.
+A goal of lld is to be file format independent. This is done
+through a plug-in model for reading object files. The lld::Reader is the base
+class for all object file readers. A Reader follows the factory method pattern.
+A Reader instantiates an lld::File object (which is a graph of Atoms) from a
+given object file (on disk or in-memory).
+
+Every Reader subclass defines its own "options" class (for instance the mach-o
+Reader defines the class ReaderOptionsMachO). This options class is the
+one-and-only way to control how the Reader operates when parsing an input file
+into an Atom graph. For instance, you may want the Reader to only accept
+certain architectures. The options class can be instantiated from command
+line options, or it can be subclassed and the ivars programmatically set.
+
+Resolving
+~~~~~~~~~
+
+The resolving step takes all the atoms' graphs from each object file and
+combines them into one master object graph. Unfortunately, it is not as simple
+as appending the atom list from each file into one big list. There are many
+cases where atoms need to be coalesced. That is, two or more atoms need to be
+coalesced into one atom. This is necessary to support: C language "tentative
+definitions", C++ weak symbols for templates and inlines defined in headers,
+replacing undefined atoms with actual definition atoms, and for merging copies
+of constants like c-strings and floating point constants.
+
+The linker support coalescing by-name and by-content. By-name is used for
+tentative definitions and weak symbols. By-content is used for constant data
+that can be merged.
+
+The resolving process maintains some global linking "state", including a "symbol
+table" which is a map from llvm::StringRef to lld::Atom*. With these data
+structures, the linker iterates all atoms in all input files. For each atom, it
+checks if the atom is named and has a global or hidden scope. If so, the atom
+is added to the symbol table map. If there already is a matching atom in that
+table, that means the current atom needs to be coalesced with the found atom, or
+it is a multiple definition error.
+
+When all initial input file atoms have been processed by the resolver, a scan is
+made to see if there are any undefined atoms in the graph. If there are, the
+linker scans all libraries (both static and dynamic) looking for definitions to
+replace the undefined atoms. It is an error if any undefined atoms are left
+remaining.
+
+Dead code stripping (if requested) is done at the end of resolving. The linker
+does a simple mark-and-sweep. It starts with "root" atoms (like "main" in a main
+executable) and follows each references and marks each Atom that it visits as
+"live". When done, all atoms not marked "live" are removed.
+
+The result of the Resolving phase is the creation of an lld::File object. The
+goal is that the lld::File model is **the** internal representation
+throughout the linker. The file readers parse (mach-o, ELF, COFF) into an
+lld::File. The file writers (mach-o, ELF, COFF) taken an lld::File and produce
+their file kind, and every Pass only operates on an lld::File. This is not only
+a simpler, consistent model, but it enables the state of the linker to be dumped
+at any point in the link for testing purposes.
+
+
+Passes
+~~~~~~
+
+The Passes step is an open ended set of routines that each get a change to
+modify or enhance the current lld::File object. Some example Passes are:
+
+ * stub (PLT) generation
+
+ * GOT instantiation
+
+ * order_file optimization
+
+ * branch island generation
+
+ * branch shim generation
+
+ * Objective-C optimizations (Darwin specific)
+
+ * TLV instantiation (Darwin specific)
+
+ * DTrace probe processing (Darwin specific)
+
+ * compact unwind encoding (Darwin specific)
+
+
+Some of these passes are specific to Darwin's runtime environments. But many of
+the passes are applicable to any OS (such as generating branch island for out of
+range branch instructions).
+
+The general structure of a pass is to iterate through the atoms in the current
+lld::File object, inspecting each atom and doing something. For instance, the
+stub pass, looks for call sites to shared library atoms (e.g. call to printf).
+It then instantiates a "stub" atom (PLT entry) and a "lazy pointer" atom for
+each proxy atom needed, and these new atoms are added to the current lld::File
+object. Next, all the noted call sites to shared library atoms have their
+References altered to point to the stub atom instead of the shared library atom.
+
+
+Generate Output File
+~~~~~~~~~~~~~~~~~~~~
+
+Once the passes are done, the output file writer is given current lld::File
+object. The writer's job is to create the executable content file wrapper and
+place the content of the atoms into it.
+
+lld uses a plug-in model for writing output files. All concrete writers (e.g.
+ELF, mach-o, etc) are subclasses of the lld::Writer class.
+
+Unlike the Reader class which has just one method to instantiate an lld::File,
+the Writer class has multiple methods. The crucial method is to generate the
+output file, but there are also methods which allow the Writer to contribute
+Atoms to the resolver and specify passes to run.
+
+An example of contributing
+atoms is that if the Writer knows a main executable is being linked and such
+an executable requires a specially named entry point (e.g. "_main"), the Writer
+can add an UndefinedAtom with that special name to the resolver. This will
+cause the resolver to issue an error if that symbol is not defined.
+
+Sometimes a Writer supports lazily created symbols, such as names for the start
+of sections. To support this, the Writer can create a File object which vends
+no initial atoms, but does lazily supply atoms by name as needed.
+
+Every Writer subclass defines its own "options" class (for instance the mach-o
+Writer defines the class WriterOptionsMachO). This options class is the
+one-and-only way to control how the Writer operates when producing an output
+file from an Atom graph. For instance, you may want the Writer to optimize
+the output for certain OS versions, or strip local symbols, etc. The options
+class can be instantiated from command line options, or it can be subclassed
+and the ivars programmatically set.
+
+
+lld::File representations
+-------------------------
+
+Just as LLVM has three representations of its IR model, lld has two
+representations of its File/Atom/Reference model:
+
+ * In memory, abstract C++ classes (lld::Atom, lld::Reference, and lld::File).
+
+ * textual (in YAML)
+
+
+Textual representations in YAML
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In designing a textual format we want something easy for humans to read and easy
+for the linker to parse. Since an atom has lots of attributes most of which are
+usually just the default, we should define default values for every attribute so
+that those can be omitted from the text representation. Here is the atoms for a
+simple hello world program expressed in YAML::
+
+ target-triple: x86_64-apple-darwin11
+
+ atoms:
+ - name: _main
+ scope: global
+ type: code
+ content: [ 55, 48, 89, e5, 48, 8d, 3d, 00, 00, 00, 00, 30, c0, e8, 00, 00,
+ 00, 00, 31, c0, 5d, c3 ]
+ fixups:
+ - offset: 07
+ kind: pcrel32
+ target: 2
+ - offset: 0E
+ kind: call32
+ target: _fprintf
+
+ - type: c-string
+ content: [ 73, 5A, 00 ]
+
+ ...
+
+The biggest use for the textual format will be writing test cases. Writing test
+cases in C is problematic because the compiler may vary its output over time for
+its own optimization reasons which my inadvertently disable or break the linker
+feature trying to be tested. By writing test cases in the linkers own textual
+format, we can exactly specify every attribute of every atom and thus target
+specific linker logic.
+
+The textual/YAML format follows the ReaderWriter patterns used in lld. The lld
+library comes with the classes: ReaderYAML and WriterYAML.
+
+
+Testing
+-------
+
+The lld project contains a test suite which is being built up as new code is
+added to lld. All new lld functionality should have a tests added to the test
+suite. The test suite is `lit <http://llvm.org/cmds/lit.html/>`_ driven. Each
+test is a text file with comments telling lit how to run the test and check the
+result To facilitate testing, the lld project builds a tool called lld-core.
+This tool reads a YAML file (default from stdin), parses it into one or more
+lld::File objects in memory and then feeds those lld::File objects to the
+resolver phase.
+
+
+Resolver testing
+~~~~~~~~~~~~~~~~
+
+Basic testing is the "core linking" or resolving phase. That is where the
+linker merges object files. All test cases are written in YAML. One feature of
+YAML is that it allows multiple "documents" to be encoding in one YAML stream.
+That means one text file can appear to the linker as multiple .o files - the
+normal case for the linker.
+
+Here is a simple example of a core linking test case. It checks that an
+undefined atom from one file will be replaced by a definition from another
+file::
+
+ # RUN: lld-core %s | FileCheck %s
+
+ #
+ # Test that undefined atoms are replaced with defined atoms.
+ #
+
+ ---
+ atoms:
+ - name: foo
+ definition: undefined
+ ---
+ atoms:
+ - name: foo
+ scope: global
+ type: code
+ ...
+
+ # CHECK: name: foo
+ # CHECK: scope: global
+ # CHECK: type: code
+ # CHECK-NOT: name: foo
+ # CHECK: ...
+
+
+Passes testing
+~~~~~~~~~~~~~~
+
+Since Passes just operate on an lld::File object, the lld-core tool has the
+option to run a particular pass (after resolving). Thus, you can write a YAML
+test case with carefully crafted input to exercise areas of a Pass and the check
+the resulting lld::File object as represented in YAML.
+
+
+Design Issues
+-------------
+
+There are a number of open issues in the design of lld. The plan is to wait and
+make these design decisions when we need to.
+
+
+Debug Info
+~~~~~~~~~~
+
+Currently, the lld model says nothing about debug info. But the most popular
+debug format is DWARF and there is some impedance mismatch with the lld model
+and DWARF. In lld there are just Atoms and only Atoms that need to be in a
+special section at runtime have an associated section. Also, Atoms do not have
+addresses. The way DWARF is spec'ed different parts of DWARF are supposed to go
+into specially named sections and the DWARF references function code by address.
+
+CPU and OS specific functionality
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Currently, lld has an abstract "Platform" that deals with any CPU or OS specific
+differences in linking. We just keep adding virtual methods to the base
+Platform class as we find linking areas that might need customization. At some
+point we'll need to structure this better.
+
+
+File Attributes
+~~~~~~~~~~~~~~~
+
+Currently, lld::File just has a path and a way to iterate its atoms. We will
+need to add more attributes on a File. For example, some equivalent to the
+target triple. There is also a number of cached or computed attributes that
+could make various Passes more efficient. For instance, on Darwin there are a
+number of Objective-C optimizations that can be done by a Pass. But it would
+improve the plain C case if the Objective-C optimization Pass did not have to
+scan all atoms looking for any Objective-C data structures. This could be done
+if the lld::File object had an attribute that said if the file had any
+Objective-C data in it. The Resolving phase would then be required to "merge"
+that attribute as object files are added.
diff --git a/contrib/llvm/tools/lld/docs/development.rst b/contrib/llvm/tools/lld/docs/development.rst
new file mode 100644
index 000000000000..ce91341d665f
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/development.rst
@@ -0,0 +1,45 @@
+.. _development:
+
+Development
+===========
+
+Note: this document discuss Mach-O port of LLD. For ELF and COFF,
+see :doc:`index`.
+
+lld is developed as part of the `LLVM <http://llvm.org>`_ project.
+
+Creating a Reader
+-----------------
+
+See the :ref:`Creating a Reader <Readers>` guide.
+
+
+Modifying the Driver
+--------------------
+
+See :doc:`Driver`.
+
+
+Debugging
+---------
+
+You can run lld with ``-mllvm -debug`` command line options to enable debugging
+printouts. If you want to enable debug information for some specific pass, you
+can run it with ``-mllvm '-debug-only=<pass>'``, where pass is a name used in
+the ``DEBUG_WITH_TYPE()`` macro.
+
+
+
+Documentation
+-------------
+
+The project documentation is written in reStructuredText and generated using the
+`Sphinx <http://sphinx.pocoo.org/>`_ documentation generator. For more
+information on writing documentation for the project, see the
+:ref:`sphinx_intro`.
+
+.. toctree::
+ :hidden:
+
+ Readers
+ Driver
diff --git a/contrib/llvm/tools/lld/docs/getting_started.rst b/contrib/llvm/tools/lld/docs/getting_started.rst
new file mode 100644
index 000000000000..97c3d1bccbda
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/getting_started.rst
@@ -0,0 +1,106 @@
+.. _getting_started:
+
+Getting Started: Building and Running lld
+=========================================
+
+This page gives you the shortest path to checking out and building lld. If you
+run into problems, please file bugs in the `LLVM Bugzilla`__
+
+__ http://llvm.org/bugs/
+
+Building lld
+------------
+
+On Unix-like Systems
+~~~~~~~~~~~~~~~~~~~~
+
+1. Get the required tools.
+
+ * `CMake 2.8`_\+.
+ * make (or any build system CMake supports).
+ * `Clang 3.1`_\+ or GCC 4.7+ (C++11 support is required).
+
+ * If using Clang, you will also need `libc++`_.
+ * `Python 2.4`_\+ (not 3.x) for running tests.
+
+.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html
+.. _Clang 3.1: http://clang.llvm.org/
+.. _libc++: http://libcxx.llvm.org/
+.. _Python 2.4: http://python.org/download/
+
+2. Check out LLVM::
+
+ $ cd path/to/llvm-project
+ $ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
+
+3. Check out lld::
+
+ $ cd llvm/tools
+ $ svn co http://llvm.org/svn/llvm-project/lld/trunk lld
+
+ * lld can also be checked out to ``path/to/llvm-project`` and built as an external
+ project.
+
+4. Build LLVM and lld::
+
+ $ cd path/to/llvm-build/llvm (out of source build required)
+ $ cmake -G "Unix Makefiles" path/to/llvm-project/llvm
+ $ make
+
+ * If you want to build with clang and it is not the default compiler or
+ it is installed in an alternate location, you'll need to tell the cmake tool
+ the location of the C and C++ compiler via CMAKE_C_COMPILER and
+ CMAKE_CXX_COMPILER. For example::
+
+ $ cmake -DCMAKE_CXX_COMPILER=/path/to/clang++ -DCMAKE_C_COMPILER=/path/to/clang ...
+
+5. Test::
+
+ $ make check-lld
+
+Using Visual Studio
+~~~~~~~~~~~~~~~~~~~
+
+#. Get the required tools.
+
+ * `CMake 2.8`_\+.
+ * `Visual Studio 12 (2013) or later`_ (required for C++11 support)
+ * `Python 2.4`_\+ (not 3.x) for running tests.
+
+.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html
+.. _Visual Studio 12 (2013) or later: http://www.microsoft.com/visualstudio/11/en-us
+.. _Python 2.4: http://python.org/download/
+
+#. Check out LLVM::
+
+ $ cd path/to/llvm-project
+ $ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
+
+#. Check out lld::
+
+ $ cd llvm/tools
+ $ svn co http://llvm.org/svn/llvm-project/lld/trunk lld
+
+ * lld can also be checked out to ``path/to/llvm-project`` and built as an external
+ project.
+
+#. Generate Visual Studio project files::
+
+ $ cd path/to/llvm-build/llvm (out of source build required)
+ $ cmake -G "Visual Studio 11" path/to/llvm-project/llvm
+
+#. Build
+
+ * Open LLVM.sln in Visual Studio.
+ * Build the ``ALL_BUILD`` target.
+
+#. Test
+
+ * Build the ``lld-test`` target.
+
+More Information
+~~~~~~~~~~~~~~~~
+
+For more information on using CMake see the `LLVM CMake guide`_.
+
+.. _LLVM CMake guide: http://llvm.org/docs/CMake.html
diff --git a/contrib/llvm/tools/lld/docs/hello.png b/contrib/llvm/tools/lld/docs/hello.png
new file mode 100644
index 000000000000..70df111f1abd
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/hello.png
Binary files differ
diff --git a/contrib/llvm/tools/lld/docs/index.rst b/contrib/llvm/tools/lld/docs/index.rst
new file mode 100644
index 000000000000..2821ce4d214e
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/index.rst
@@ -0,0 +1,178 @@
+LLD - The LLVM Linker
+=====================
+
+LLD is a linker from the LLVM project. That is a drop-in replacement
+for system linkers and runs much faster than them. It also provides
+features that are useful for toolchain developers.
+
+The linker supports ELF (Unix), PE/COFF (Windows), Mach-O (macOS) and
+WebAssembly in descending order of completeness. Internally, LLD consists of
+several different linkers. The ELF port is the one that will be described in
+this document. The PE/COFF port is complete, including
+Windows debug info (PDB) support. The WebAssembly port is still a work in
+progress (See :doc:`WebAssembly`). The Mach-O port is built based on a
+different architecture than the others. For the details about Mach-O, please
+read :doc:`AtomLLD`.
+
+Features
+--------
+
+- LLD is a drop-in replacement for the GNU linkers. That accepts the
+ same command line arguments and linker scripts as GNU.
+
+ We are currently working closely with the FreeBSD project to make
+ LLD default system linker in future versions of the operating
+ system, so we are serious about addressing compatibility issues. As
+ of February 2017, LLD is able to link the entire FreeBSD/amd64 base
+ system including the kernel. With a few work-in-progress patches it
+ can link approximately 95% of the ports collection on AMD64. For the
+ details, see `FreeBSD quarterly status report
+ <https://www.freebsd.org/news/status/report-2016-10-2016-12.html#Using-LLVM%27s-LLD-Linker-as-FreeBSD%27s-System-Linker>`_.
+
+- LLD is very fast. When you link a large program on a multicore
+ machine, you can expect that LLD runs more than twice as fast as GNU
+ gold linker. Your milage may vary, though.
+
+- It supports various CPUs/ABIs including x86-64, x86, x32, AArch64,
+ ARM, MIPS 32/64 big/little-endian, PowerPC, PowerPC 64 and AMDGPU.
+ Among these, x86-64 is the most well-supported target and have
+ reached production quality. AArch64 and MIPS seem decent too. x86
+ should be OK but not well tested yet. ARM support is being developed
+ actively.
+
+- It is always a cross-linker, meaning that it always supports all the
+ above targets however it was built. In fact, we don't provide a
+ build-time option to enable/disable each target. This should make it
+ easy to use our linker as part of a cross-compile toolchain.
+
+- You can embed LLD to your program to eliminate dependency to
+ external linkers. All you have to do is to construct object files
+ and command line arguments just like you would do to invoke an
+ external linker and then call the linker's main function,
+ ``lld::elf::link``, from your code.
+
+- It is small. We are using LLVM libObject library to read from object
+ files, so it is not completely a fair comparison, but as of February
+ 2017, LLD/ELF consists only of 21k lines of C++ code while GNU gold
+ consists of 198k lines of C++ code.
+
+- Link-time optimization (LTO) is supported by default. Essentially,
+ all you have to do to do LTO is to pass the ``-flto`` option to clang.
+ Then clang creates object files not in the native object file format
+ but in LLVM bitcode format. LLD reads bitcode object files, compile
+ them using LLVM and emit an output file. Because in this way LLD can
+ see the entire program, it can do the whole program optimization.
+
+- Some very old features for ancient Unix systems (pre-90s or even
+ before that) have been removed. Some default settings have been
+ tuned for the 21st century. For example, the stack is marked as
+ non-executable by default to tighten security.
+
+Performance
+-----------
+
+This is a link time comparison on a 2-socket 20-core 40-thread Xeon
+E5-2680 2.80 GHz machine with an SSD drive. We ran gold and lld with
+or without multi-threading support. To disable multi-threading, we
+added ``-no-threads`` to the command lines.
+
+============ =========== ============ ==================== ================== =============== =============
+Program Output size GNU ld GNU gold w/o threads GNU gold w/threads lld w/o threads lld w/threads
+ffmpeg dbg 92 MiB 1.72s 1.16s 1.01s 0.60s 0.35s
+mysqld dbg 154 MiB 8.50s 2.96s 2.68s 1.06s 0.68s
+clang dbg 1.67 GiB 104.03s 34.18s 23.49s 14.82s 5.28s
+chromium dbg 1.14 GiB 209.05s [1]_ 64.70s 60.82s 27.60s 16.70s
+============ =========== ============ ==================== ================== =============== =============
+
+As you can see, lld is significantly faster than GNU linkers.
+Note that this is just a benchmark result of our environment.
+Depending on number of available cores, available amount of memory or
+disk latency/throughput, your results may vary.
+
+.. [1] Since GNU ld doesn't support the ``-icf=all`` and
+ ``-gdb-index`` options, we removed them from the command line
+ for GNU ld. GNU ld would have been slower than this if it had
+ these options.
+
+Build
+-----
+
+If you have already checked out LLVM using SVN, you can check out LLD
+under ``tools`` directory just like you probably did for clang. For the
+details, see `Getting Started with the LLVM System
+<http://llvm.org/docs/GettingStarted.html>`_.
+
+If you haven't checkout out LLVM, the easiest way to build LLD is to
+checkout the entire LLVM projects/sub-projects from a git mirror and
+build that tree. You need `cmake` and of course a C++ compiler.
+
+.. code-block:: console
+
+ $ git clone https://github.com/llvm-project/llvm-project-20170507 llvm-project
+ $ mkdir build
+ $ cd build
+ $ cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=lld -DCMAKE_INSTALL_PREFIX=/usr/local ../llvm-project/llvm
+ $ make install
+
+Using LLD
+---------
+
+LLD is installed as ``ld.lld``. On Unix, linkers are invoked by
+compiler drivers, so you are not expected to use that command
+directly. There are a few ways to tell compiler drivers to use ld.lld
+instead of the default linker.
+
+The easiest way to do that is to overwrite the default linker. After
+installing LLD to somewhere on your disk, you can create a symbolic
+link by doing ``ln -s /path/to/ld.lld /usr/bin/ld`` so that
+``/usr/bin/ld`` is resolved to LLD.
+
+If you don't want to change the system setting, you can use clang's
+``-fuse-ld`` option. In this way, you want to set ``-fuse-ld=lld`` to
+LDFLAGS when building your programs.
+
+LLD leaves its name and version number to a ``.comment`` section in an
+output. If you are in doubt whether you are successfully using LLD or
+not, run ``readelf --string-dump .comment <output-file>`` and examine the
+output. If the string "Linker: LLD" is included in the output, you are
+using LLD.
+
+History
+-------
+
+Here is a brief project history of the ELF and COFF ports.
+
+- May 2015: We decided to rewrite the COFF linker and did that.
+ Noticed that the new linker is much faster than the MSVC linker.
+
+- July 2015: The new ELF port was developed based on the COFF linker
+ architecture.
+
+- September 2015: The first patches to support MIPS and AArch64 landed.
+
+- October 2015: Succeeded to self-host the ELF port. We have noticed
+ that the linker was faster than the GNU linkers, but we weren't sure
+ at the time if we would be able to keep the gap as we would add more
+ features to the linker.
+
+- July 2016: Started working on improving the linker script support.
+
+- December 2016: Succeeded to build the entire FreeBSD base system
+ including the kernel. We had widen the performance gap against the
+ GNU linkers.
+
+Internals
+---------
+
+For the internals of the linker, please read :doc:`NewLLD`. It is a bit
+outdated but the fundamental concepts remain valid. We'll update the
+document soon.
+
+.. toctree::
+ :maxdepth: 1
+
+ NewLLD
+ AtomLLD
+ WebAssembly
+ windows_support
+ ReleaseNotes
diff --git a/contrib/llvm/tools/lld/docs/ld.lld.1 b/contrib/llvm/tools/lld/docs/ld.lld.1
new file mode 100644
index 000000000000..92d890f8cadb
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/ld.lld.1
@@ -0,0 +1,570 @@
+.\" This file is distributed under the University of Illinois Open Source
+.\" License. See LICENSE.TXT for details.
+.\"
+.\" This man page documents only lld's ELF linking support, obtained originally
+.\" from FreeBSD.
+.Dd July 30, 2018
+.Dt LD.LLD 1
+.Os
+.Sh NAME
+.Nm ld.lld
+.Nd ELF linker from the LLVM project
+.Sh SYNOPSIS
+.Nm ld.lld
+.Op Ar options
+.Ar objfile ...
+.Sh DESCRIPTION
+A linker takes one or more object, archive, and library files, and combines
+them into an output file (an executable, a shared library, or another object
+file).
+It relocates code and data from the input files and resolves symbol
+references between them.
+.Pp
+.Nm
+is a drop-in replacement for the GNU BFD and gold linkers.
+It accepts most of the same command line arguments and linker scripts
+as GNU linkers.
+.Pp
+Many options have both a single-letter and long form.
+When using the long form options other than those beginning with the
+letter
+.Cm o
+may be specified using either one or two dashes preceding the option name.
+Long options beginning with
+.Cm o
+require two dashes to avoid confusion with the
+.Fl o Ar path
+option.
+.Pp
+These options are available:
+.Bl -tag -width indent
+.It Fl -allow-multiple-definition
+Do not error if a symbol is defined multiple times.
+The first definition will be used.
+.It Fl -apply-dynamic-relocs
+Apply link-time values for dynamic relocations.
+.It Fl -as-needed
+Only set
+.Dv DT_NEEDED
+for shared libraries if used.
+.It Fl -auxiliary Ns = Ns Ar value
+Set the
+.Dv DT_AUXILIARY
+field to the specified name.
+.It Fl -Bdynamic , Fl -dy
+Link against shared libraries.
+.It Fl -Bstatic , Fl -static , Fl -dn
+Do not link against shared libraries.
+.It Fl -Bsymbolic
+Bind defined symbols locally.
+.It Fl -Bsymbolic-functions
+Bind defined function symbols locally.
+.It Fl -build-id Ns = Ns Ar value
+Generate a build ID note.
+.Ar value
+may be one of
+.Cm fast ,
+.Cm md5 ,
+.Cm sha1 ,
+.Cm tree ,
+.Cm uuid ,
+.Cm 0x Ns Ar hex-string ,
+and
+.Cm none .
+.Cm tree
+is an alias for
+.Cm sha1 .
+Build-IDs of type
+.Cm fast ,
+.Cm md5 ,
+.Cm sha1 ,
+and
+.Cm tree
+are calculated from the object contents.
+.Cm fast
+is not intended to be cryptographically secure.
+.It Fl -build-id
+Synonym for
+.Fl -build-id Ns = Ns Cm fast .
+.It Fl -color-diagnostics Ns = Ns Ar value
+Use colors in diagnostics.
+.Ar value
+may be one of
+.Cm always ,
+.Cm auto ,
+and
+.Cm never .
+.Cm auto
+enables color if and only if output is to a terminal.
+.It Fl -color-diagnostics
+Alias for
+.Fl -color-diagnostics Ns = Ns Cm auto .
+.It Fl -compress-debug-sections Ns = Ns Ar value
+Compress DWARF debug sections.
+.Ar value
+may be
+.Cm none
+or
+.Cm zlib .
+.It Fl -cref
+Output cross reference table.
+.It Fl -define-common , Fl d
+Assign space to common symbols.
+.It Fl -defsym Ns = Ns Ar symbol Ns = Ns Ar expression
+Define a symbol alias.
+.Ar expression
+may be another symbol or a linker script expression.
+For example,
+.Ql --defsym=foo=bar
+or
+.Ql --defsym=foo=bar+0x100 .
+.It Fl -demangle
+Demangle symbol names.
+.It Fl -disable-new-dtags
+Disable new dynamic tags.
+.It Fl -discard-all , Fl x
+Delete all local symbols.
+.It Fl -discard-locals , Fl X
+Delete temporary local symbols.
+.It Fl -discard-none
+Keep all symbols in the symbol table.
+.It Fl -dynamic-linker Ns = Ns Ar value
+Specify the dynamic linker to be used for a dynamically linked executable.
+This is recorded in an ELF segment of type
+.Dv PT_INTERP .
+.It Fl -dynamic-list Ns = Ns Ar file
+Read a list of dynamic symbols from
+.Ar file .
+.It Fl -eh-frame-hdr
+Request creation of
+.Li .eh_frame_hdr
+section and
+.Dv PT_GNU_EH_FRAME
+segment header.
+.It Fl -emit-relocs , Fl q
+Generate relocations in the output.
+.It Fl -enable-new-dtags
+Enable new dynamic tags.
+.It Fl -end-lib
+End a grouping of objects that should be treated as if they were together
+in an archive.
+.It Fl -entry Ns = Ns Ar entry
+Name of entry point symbol.
+.It Fl -error-limit Ns = Ns Ar value
+Maximum number of errors to emit before stopping.
+A value of zero indicates that there is no limit.
+.It Fl -error-unresolved-symbols
+Report unresolved symbols as errors.
+.It Fl -exclude-libs Ns = Ns Ar value
+Exclude static libraries from automatic export.
+.It Fl -export-dynamic , Fl E
+Put symbols in the dynamic symbol table.
+.It Fl -export-dynamic-symbol Ns = Ns Ar symbol
+Include
+.Ar symbol
+in the dynamic symbol table.
+.It Fl -fatal-warnings
+Treat warnings as errors.
+.It Fl -filter Ns = Ns Ar value , Fl F Ar value
+Set the
+.Dv DT_FILTER
+field to the specified value.
+.It Fl -fini Ns = Ns Ar symbol
+Specify a finalizer function.
+.It Fl -format Ns = Ns Ar input-format , Fl b Ar input-format
+Specify the format of the inputs following this option.
+.Ar input-format
+may be one of
+.Cm binary ,
+.Cm elf ,
+and
+.Cm default .
+.Cm default
+is a synonym for
+.Cm elf .
+.It Fl -gc-sections
+Enable garbage collection of unused sections.
+.It Fl -gdb-index
+Generate
+.Li .gdb_index
+section.
+.It Fl -hash-style Ns = Ns Ar value
+Specify hash style.
+.Ar value
+may be
+.Cm sysv ,
+.Cm gnu ,
+or
+.Cm both .
+.Cm both
+is the default.
+.It Fl -help
+Print a help message.
+.It Fl -icf Ns = Ns Cm all
+Enable identical code folding.
+.It Fl -icf Ns = Ns Cm safe
+Enable safe identical code folding.
+.It Fl -icf Ns = Ns Cm none
+Disable identical code folding.
+.It Fl -image-base Ns = Ns Ar value
+Set the base address to
+.Ar value .
+.It Fl -init Ns = Ns Ar symbol
+Specify an initializer function.
+.It Fl -keep-unique Ns = Ns Ar symbol
+Do not fold
+.Ar symbol
+during ICF.
+.It Fl l Ar libName, Fl -library Ns = Ns Ar libName
+Root name of library to use.
+.It Fl L Ar dir , Fl -library-path Ns = Ns Ar dir
+Add a directory to the library search path.
+.It Fl -lto-aa-pipeline Ns = Ns Ar value
+AA pipeline to run during LTO.
+Used in conjunction with
+.Fl -lto-newpm-passes .
+.It Fl -lto-newpm-passes Ns = Ns Ar value
+Passes to run during LTO.
+.It Fl -lto-O Ns Ar opt-level
+Optimization level for LTO.
+.It Fl -lto-partitions Ns = Ns Ar value
+Number of LTO codegen partitions.
+.It Fl m Ar value
+Set target emulation.
+.It Fl -Map Ns = Ns Ar file , Fl M Ar file
+Print a link map to
+.Ar file .
+.It Fl -no-as-needed
+Always set
+.Dv DT_NEEDED
+for shared libraries.
+.It Fl -no-color-diagnostics
+Do not use colors in diagnostics.
+.It Fl -no-define-common
+Do not assign space to common symbols.
+.It Fl -no-demangle
+Do not demangle symbol names.
+.It Fl -no-dynamic-linker
+Inhibit output of an
+.Li .interp
+section.
+.It Fl -no-gc-sections
+Disable garbage collection of unused sections.
+.It Fl -no-gnu-unique
+Disable STB_GNU_UNIQUE symbol binding.
+.It Fl -no-rosegment
+Do not put read-only non-executable sections in their own segment.
+.It Fl -no-threads
+Do not run the linker multi-threaded.
+.It Fl -no-undefined-version
+Report version scripts that refer undefined symbols.
+.It Fl -no-undefined
+Report unresolved symbols even if the linker is creating a shared library.
+.It Fl -no-whole-archive
+Restores the default behavior of loading archive members.
+.It Fl -no-pie
+Do not create a position independent executable.
+.It Fl -noinhibit-exec
+Retain the executable output file whenever it is still usable.
+.It Fl -nostdlib
+Only search directories specified on the command line.
+.It Fl o Ar path
+Write the output executable, library, or object to
+.Ar path .
+If not specified,
+.Dv a.out
+is used as a default.
+.It Fl O Ns Ar value
+Optimize output file size.
+.Ar value
+may be:
+.Pp
+.Bl -tag -width 2n -compact
+.It Cm 0
+Disable string merging.
+.It Cm 1
+Enable string merging.
+.It Cm 2
+Enable string tail merging.
+.El
+.Pp
+.Fl O Ns Cm 1
+is the default.
+.It Fl -oformat Ns = Ns Ar format
+Specify the format for the output object file.
+The only supported
+.Ar format
+is
+.Cm binary ,
+which produces output with no ELF header.
+.It Fl -omagic , Fl N
+Set the text and data sections to be readable and writable.
+.It Fl -opt-remarks-filename Ar file
+Write optimization remarks in YAML format to
+.Ar file .
+.It Fl -opt-remarks-with-hotness
+Include hotness information in the optimization remarks file.
+.It Fl -pie
+Create a position independent executable.
+.It Fl -print-gc-sections
+List removed unused sections.
+.It Fl -print-map
+Print a link map to the standard output.
+.It Fl -push-state
+Save the current state of
+.Fl -as-needed ,
+.Fl -static ,
+and
+.Fl -while-archive.
+.It Fl -pop-state
+Undo the effect of
+.Fl -push-state.
+.It Fl -relocatable , Fl r
+Create relocatable object file.
+.It Fl -reproduce Ns = Ns Ar value
+Dump linker invocation and input files for debugging.
+.It Fl -retain-symbols-file Ns = Ns Ar file
+Retain only the symbols listed in the file.
+.It Fl -rpath Ns = Ns Ar value , Fl R Ar value
+Add a
+.Dv DT_RUNPATH
+to the output.
+.It Fl -rsp-quoting Ns = Ns Ar value
+Quoting style for response files.
+The supported values are
+.Cm windows
+and
+.Cm posix .
+.It Fl -script Ns = Ns Ar file , Fl T Ar file
+Read linker script from
+.Ar file .
+.It Fl -section-start Ns = Ns Ar section Ns = Ns Ar address
+Set address of section.
+.It Fl -shared , Fl -Bsharable
+Build a shared object.
+.It Fl -soname Ns = Ns Ar value , Fl h Ar value
+Set
+.Dv DT_SONAME
+to
+.Ar value .
+.It Fl -sort-section Ns = Ns Ar value
+Specifies sections sorting rule when linkerscript is used.
+.It Fl -start-lib
+Start a grouping of objects that should be treated as if they were together
+in an archive.
+.It Fl -strip-all , Fl s
+Strip all symbols.
+.It Fl -strip-debug , Fl S
+Strip debugging information.
+.It Fl -symbol-ordering-file Ns = Ns Ar file
+Lay out sections in the order specified by
+.Ar file .
+.It Fl -sysroot Ns = Ns Ar value
+Set the system root.
+.It Fl -target1-abs
+Interpret
+.Dv R_ARM_TARGET1
+as
+.Dv R_ARM_ABS32 .
+.It Fl -target1-rel
+Interpret
+.Dv R_ARM_TARGET1
+as
+.Dv R_ARM_REL32 .
+.It Fl -target2 Ns = Ns Ar type
+Interpret
+.Dv R_ARM_TARGET2
+as
+.Ar type ,
+where
+.Ar type
+is one of
+.Cm rel ,
+.Cm abs ,
+or
+.Cm got-rel .
+.It Fl -Tbss Ns = Ns Ar value
+Same as
+.Fl -section-start
+with
+.Li .bss
+as the sectionname.
+.It Fl -Tdata Ns = Ns Ar value
+Same as
+.Fl -section-start
+with
+.Li .data
+as the sectionname.
+.It Fl -Ttext Ns = Ns Ar value
+Same as
+.Fl -section-start
+with
+.Li .text
+as the sectionname.
+.It Fl -thinlto-cache-dir Ns = Ns Ar value
+Path to ThinLTO cached object file directory.
+.It Fl -thinlto-cache-policy Ns = Ns Ar value
+Pruning policy for the ThinLTO cache.
+.It Fl -thinlto-jobs Ns = Ns Ar value
+Number of ThinLTO jobs.
+.It Fl -threads
+Run the linker multi-threaded.
+This option is enabled by default.
+.It Fl -trace
+Print the names of the input files.
+.It Fl -trace-symbol Ns = Ns Ar symbol , Fl y Ar symbol
+Trace references to
+.Ar symbol .
+.It Fl -undefined Ns = Ns Ar symbol , Fl u Ar symbol
+Force
+.Ar symbol
+to be an undefined symbol during linking.
+.It Fl -unresolved-symbols Ns = Ns Ar value
+Determine how to handle unresolved symbols.
+.It Fl v
+Display the version number and proceed with linking if object files are
+specified.
+.It Fl V , Fl -version
+Display the version number and exit.
+.It Fl -verbose
+Verbose mode.
+.It Fl -version-script Ns = Ns Ar file
+Read version script from
+.Ar file .
+.It Fl -warn-backrefs
+Warn about reverse or cyclic dependencies to or between static archives.
+This can be used to ensure linker invocation remains compatible with
+traditional Unix-like linkers.
+.It Fl -warn-common
+Warn about duplicate common symbols.
+.It Fl -warn-unresolved-symbols
+Report unresolved symbols as warnings.
+.It Fl -whole-archive
+Force load of all members in a static library.
+.It Fl -wrap Ns = Ns Ar symbol
+Use wrapper functions for symbol.
+.It Fl z Ar option
+Linker option extensions.
+.Bl -tag -width indent
+.It Cm execstack
+Make the main stack executable.
+Stack permissions are recorded in the
+.Dv PT_GNU_STACK
+segment.
+.It Cm initfirst
+Sets the
+.Dv DF_1_INITFIRST
+flag to indicate the module should be initialized first.
+.It Cm muldefs
+Do not error if a symbol is defined multiple times.
+The first definition will be used.
+This is a synonym for
+.Fl -allow-multiple-definition.
+.It Cm nocombreloc
+Disable combining and sorting multiple relocation sections.
+.It Cm nocopyreloc
+Disable the creation of copy relocations.
+.It Cm nodelete
+Set the
+.Dv DF_1_NODELETE
+flag to indicate that the object cannot be unloaded from a process.
+.It Cm nodlopen
+Set the
+.Dv DF_1_NOOPEN
+flag to indcate that the object may not be opened by
+.Xr dlopen 3 .
+.It Cm norelro
+Do not indicate that portions of the object shold be mapped read-only
+after initial relocation processing.
+The object will omit the
+.Dv PT_GNU_RELRO
+segment.
+.It Cm notext
+Allow relocations against read-only segments.
+Sets the
+.Dv DT_TEXTREL flag in the
+.Dv DYNAMIC
+section.
+.It Cm now
+Set the
+.Dv DF_BIND_NOW
+flag to indicate that the run-time loader should perform all relocation
+processing as part of object initialization.
+By default relocations may be performed on demand.
+.It Cm origin
+Set the
+.Dv DF_ORIGIN
+flag to indicate that the object requires
+$ORIGIN
+processing.
+.It Cm retpolineplt
+Emit retpoline format PLT entries as a mitigation for CVE-2017-5715.
+.It Cm rodynamic
+Make the
+.Li .dynamic
+section read-only.
+The
+.Dv DT_DEBUG
+tag will not be emitted.
+.It Cm stack-size Ns = Ns Ar size
+Set the main thread's stack size to
+.Ar size .
+The stack size is recorded as the size of the
+.Ar size .
+.Dv PT_GNU_STACK
+program segment.
+.It Cm text
+Do not allow relocations against read-only segments.
+This is the default.
+.It Cm wxneeded
+Create a
+.Dv PT_OPENBSD_WXNEEDED
+segment.
+.El
+.El
+.Sh IMPLEMENTATION NOTES
+.Nm Ap s
+handing of archive files (those with a
+.Pa .a
+file extension) is different from traditional linkers used on Unix-like
+systems.
+.Pp
+Traditional linkers maintain a set of undefined symbols during linking.
+The linker processes each file in the order in which it appears on the
+command line, until the set of undefined symbols becomes empty.
+An object file is linked into the output object when it is encountered,
+with its undefined symbols added to the set.
+Upon encountering an archive file a traditional linker searches the objects
+contained therein, and processes those that satisfy symbols in the unresolved
+set.
+.Pp
+Handling mutually dependent archives may be awkward when using a traditional
+linker.
+Archive files may have to be specified multiple times, or the special command
+line options
+.Fl -start-group
+and
+.Fl -end-group
+may be used to have the linker loop over the files in the group until no new
+symbols are added to the set.
+.Pp
+.Nm
+records all symbols found in objects and archives as it iterates over
+command line arguments.
+When
+.Nm
+encounters an undefined symbol that can be resolved by an object file
+contained in a previously processed archive file, it immediately extracts
+and links it into the output object.
+.Pp
+With certain archive inputs
+.Nm
+may produce different results compared to traditional linkers.
+In practice, large bodies of third party software have been linked with
+.Nm
+without material issues.
+.Pp
+The
+.Fl -warn-backrefs
+option may be used to identify a linker invocation that may be incompatible
+with traditional Unix-like linker behavior.
diff --git a/contrib/llvm/tools/lld/docs/llvm-theme/layout.html b/contrib/llvm/tools/lld/docs/llvm-theme/layout.html
new file mode 100644
index 000000000000..0cd0918eac2a
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/llvm-theme/layout.html
@@ -0,0 +1,22 @@
+{#
+ sphinxdoc/layout.html
+ ~~~~~~~~~~~~~~~~~~~~~
+
+ Sphinx layout template for the sphinxdoc theme.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+#}
+{% extends "basic/layout.html" %}
+
+{% block relbar1 %}
+<div class="logo">
+<a href="{{ pathto('index') }}"><img src="{{
+pathto("_static/logo.png", 1) }}" alt="LLVM Documentation"/></a>
+</div>
+{{ super() }}
+{% endblock %}
+
+{# put the sidebar before the body #}
+{% block sidebar1 %}{{ sidebar() }}{% endblock %}
+{% block sidebar2 %}{% endblock %}
diff --git a/contrib/llvm/tools/lld/docs/llvm-theme/static/contents.png b/contrib/llvm/tools/lld/docs/llvm-theme/static/contents.png
new file mode 100644
index 000000000000..7fb82154a174
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/llvm-theme/static/contents.png
Binary files differ
diff --git a/contrib/llvm/tools/lld/docs/llvm-theme/static/llvm.css b/contrib/llvm/tools/lld/docs/llvm-theme/static/llvm.css
new file mode 100644
index 000000000000..32802bb6a2d0
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/llvm-theme/static/llvm.css
@@ -0,0 +1,345 @@
+/*
+ * sphinxdoc.css_t
+ * ~~~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- sphinxdoc theme. Originally created by
+ * Armin Ronacher for Werkzeug.
+ *
+ * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+ 'Verdana', sans-serif;
+ font-size: 14px;
+ letter-spacing: -0.01em;
+ line-height: 150%;
+ text-align: center;
+ background-color: #BFD1D4;
+ color: black;
+ padding: 0;
+ border: 1px solid #aaa;
+
+ margin: 0px 80px 0px 80px;
+ min-width: 740px;
+}
+
+div.logo {
+ background-color: white;
+ text-align: left;
+ padding: 10px 10px 15px 15px;
+}
+
+div.document {
+ background-color: white;
+ text-align: left;
+ background-image: url(contents.png);
+ background-repeat: repeat-x;
+}
+
+div.bodywrapper {
+ margin: 0 240px 0 0;
+ border-right: 1px solid #ccc;
+}
+
+div.body {
+ margin: 0;
+ padding: 0.5em 20px 20px 20px;
+}
+
+div.related {
+ font-size: 1em;
+}
+
+div.related ul {
+ background-image: url(navigation.png);
+ height: 2em;
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+}
+
+div.related ul li {
+ margin: 0;
+ padding: 0;
+ height: 2em;
+ float: left;
+}
+
+div.related ul li.right {
+ float: right;
+ margin-right: 5px;
+}
+
+div.related ul li a {
+ margin: 0;
+ padding: 0 5px 0 5px;
+ line-height: 1.75em;
+ color: #EE9816;
+}
+
+div.related ul li a:hover {
+ color: #3CA8E7;
+}
+
+div.sphinxsidebarwrapper {
+ padding: 0;
+}
+
+div.sphinxsidebar {
+ margin: 0;
+ padding: 0.5em 15px 15px 0;
+ width: 210px;
+ float: right;
+ font-size: 1em;
+ text-align: left;
+}
+
+div.sphinxsidebar h3, div.sphinxsidebar h4 {
+ margin: 1em 0 0.5em 0;
+ font-size: 1em;
+ padding: 0.1em 0 0.1em 0.5em;
+ color: white;
+ border: 1px solid #86989B;
+ background-color: #AFC1C4;
+}
+
+div.sphinxsidebar h3 a {
+ color: white;
+}
+
+div.sphinxsidebar ul {
+ padding-left: 1.5em;
+ margin-top: 7px;
+ padding: 0;
+ line-height: 130%;
+}
+
+div.sphinxsidebar ul ul {
+ margin-left: 20px;
+}
+
+div.footer {
+ background-color: #E3EFF1;
+ color: #86989B;
+ padding: 3px 8px 3px 0;
+ clear: both;
+ font-size: 0.8em;
+ text-align: right;
+}
+
+div.footer a {
+ color: #86989B;
+ text-decoration: underline;
+}
+
+/* -- body styles ----------------------------------------------------------- */
+
+p {
+ margin: 0.8em 0 0.5em 0;
+}
+
+a {
+ color: #CA7900;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #2491CF;
+}
+
+div.body a {
+ text-decoration: underline;
+}
+
+h1 {
+ margin: 0;
+ padding: 0.7em 0 0.3em 0;
+ font-size: 1.5em;
+ color: #11557C;
+}
+
+h2 {
+ margin: 1.3em 0 0.2em 0;
+ font-size: 1.35em;
+ padding: 0;
+}
+
+h3 {
+ margin: 1em 0 -0.3em 0;
+ font-size: 1.2em;
+}
+
+div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a {
+ color: black!important;
+}
+
+h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor {
+ display: none;
+ margin: 0 0 0 0.3em;
+ padding: 0 0.2em 0 0.2em;
+ color: #aaa!important;
+}
+
+h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor,
+h5:hover a.anchor, h6:hover a.anchor {
+ display: inline;
+}
+
+h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover,
+h5 a.anchor:hover, h6 a.anchor:hover {
+ color: #777;
+ background-color: #eee;
+}
+
+a.headerlink {
+ color: #c60f0f!important;
+ font-size: 1em;
+ margin-left: 6px;
+ padding: 0 4px 0 4px;
+ text-decoration: none!important;
+}
+
+a.headerlink:hover {
+ background-color: #ccc;
+ color: white!important;
+}
+
+cite, code, tt {
+ font-family: 'Consolas', 'Deja Vu Sans Mono',
+ 'Bitstream Vera Sans Mono', monospace;
+ font-size: 0.95em;
+ letter-spacing: 0.01em;
+}
+
+tt {
+ background-color: #f2f2f2;
+ border-bottom: 1px solid #ddd;
+ color: #333;
+}
+
+tt.descname, tt.descclassname, tt.xref {
+ border: 0;
+}
+
+hr {
+ border: 1px solid #abc;
+ margin: 2em;
+}
+
+a tt {
+ border: 0;
+ color: #CA7900;
+}
+
+a tt:hover {
+ color: #2491CF;
+}
+
+pre {
+ font-family: 'Consolas', 'Deja Vu Sans Mono',
+ 'Bitstream Vera Sans Mono', monospace;
+ font-size: 0.95em;
+ letter-spacing: 0.015em;
+ line-height: 120%;
+ padding: 0.5em;
+ border: 1px solid #ccc;
+ background-color: #f8f8f8;
+}
+
+pre a {
+ color: inherit;
+ text-decoration: underline;
+}
+
+td.linenos pre {
+ padding: 0.5em 0;
+}
+
+div.quotebar {
+ background-color: #f8f8f8;
+ max-width: 250px;
+ float: right;
+ padding: 2px 7px;
+ border: 1px solid #ccc;
+}
+
+div.topic {
+ background-color: #f8f8f8;
+}
+
+table {
+ border-collapse: collapse;
+ margin: 0 -0.5em 0 -0.5em;
+}
+
+table td, table th {
+ padding: 0.2em 0.5em 0.2em 0.5em;
+}
+
+div.admonition, div.warning {
+ font-size: 0.9em;
+ margin: 1em 0 1em 0;
+ border: 1px solid #86989B;
+ background-color: #f7f7f7;
+ padding: 0;
+}
+
+div.admonition p, div.warning p {
+ margin: 0.5em 1em 0.5em 1em;
+ padding: 0;
+}
+
+div.admonition pre, div.warning pre {
+ margin: 0.4em 1em 0.4em 1em;
+}
+
+div.admonition p.admonition-title,
+div.warning p.admonition-title {
+ margin: 0;
+ padding: 0.1em 0 0.1em 0.5em;
+ color: white;
+ border-bottom: 1px solid #86989B;
+ font-weight: bold;
+ background-color: #AFC1C4;
+}
+
+div.warning {
+ border: 1px solid #940000;
+}
+
+div.warning p.admonition-title {
+ background-color: #CF0000;
+ border-bottom-color: #940000;
+}
+
+div.admonition ul, div.admonition ol,
+div.warning ul, div.warning ol {
+ margin: 0.1em 0.5em 0.5em 3em;
+ padding: 0;
+}
+
+div.versioninfo {
+ margin: 1em 0 0 0;
+ border: 1px solid #ccc;
+ background-color: #DDEAF0;
+ padding: 8px;
+ line-height: 1.3em;
+ font-size: 0.9em;
+}
+
+.viewcode-back {
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+ 'Verdana', sans-serif;
+}
+
+div.viewcode-block:target {
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+}
diff --git a/contrib/llvm/tools/lld/docs/llvm-theme/static/logo.png b/contrib/llvm/tools/lld/docs/llvm-theme/static/logo.png
new file mode 100644
index 000000000000..4fc899028dc6
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/llvm-theme/static/logo.png
Binary files differ
diff --git a/contrib/llvm/tools/lld/docs/llvm-theme/static/navigation.png b/contrib/llvm/tools/lld/docs/llvm-theme/static/navigation.png
new file mode 100644
index 000000000000..1081dc1439fb
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/llvm-theme/static/navigation.png
Binary files differ
diff --git a/contrib/llvm/tools/lld/docs/llvm-theme/theme.conf b/contrib/llvm/tools/lld/docs/llvm-theme/theme.conf
new file mode 100644
index 000000000000..330fc92ffa18
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/llvm-theme/theme.conf
@@ -0,0 +1,4 @@
+[theme]
+inherit = basic
+stylesheet = llvm.css
+pygments_style = friendly
diff --git a/contrib/llvm/tools/lld/docs/make.bat b/contrib/llvm/tools/lld/docs/make.bat
new file mode 100644
index 000000000000..8471252d709f
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/make.bat
@@ -0,0 +1,190 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\lld.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\lld.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
diff --git a/contrib/llvm/tools/lld/docs/open_projects.rst b/contrib/llvm/tools/lld/docs/open_projects.rst
new file mode 100644
index 000000000000..eeb9f9f48f34
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/open_projects.rst
@@ -0,0 +1,11 @@
+.. _open_projects:
+
+Open Projects
+=============
+
+.. include:: ../include/lld/Core/TODO.txt
+
+Documentation TODOs
+~~~~~~~~~~~~~~~~~~~
+
+.. todolist::
diff --git a/contrib/llvm/tools/lld/docs/sphinx_intro.rst b/contrib/llvm/tools/lld/docs/sphinx_intro.rst
new file mode 100644
index 000000000000..6bb9816b5ab4
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/sphinx_intro.rst
@@ -0,0 +1,127 @@
+.. _sphinx_intro:
+
+Sphinx Introduction for LLVM Developers
+=======================================
+
+This document is intended as a short and simple introduction to the Sphinx
+documentation generation system for LLVM developers.
+
+Quickstart
+----------
+
+To get started writing documentation, you will need to:
+
+ 1. Have the Sphinx tools :ref:`installed <installing_sphinx>`.
+
+ 2. Understand how to :ref:`build the documentation
+ <building_the_documentation>`.
+
+ 3. Start :ref:`writing documentation <writing_documentation>`!
+
+.. _installing_sphinx:
+
+Installing Sphinx
+~~~~~~~~~~~~~~~~~
+
+You should be able to install Sphinx using the standard Python package
+installation tool ``easy_install``, as follows::
+
+ $ sudo easy_install sphinx
+ Searching for sphinx
+ Reading http://pypi.python.org/simple/sphinx/
+ Reading http://sphinx.pocoo.org/
+ Best match: Sphinx 1.1.3
+ ... more lines here ..
+
+If you do not have root access (or otherwise want to avoid installing Sphinx in
+system directories) see the section on :ref:`installing_sphinx_in_a_venv` .
+
+If you do not have the ``easy_install`` tool on your system, you should be able
+to install it using:
+
+ Linux
+ Use your distribution's standard package management tool to install it,
+ i.e., ``apt-get install easy_install`` or ``yum install easy_install``.
+
+ Mac OS X
+ All modern Mac OS X systems come with ``easy_install`` as part of the base
+ system.
+
+ Windows
+ See the `setuptools <http://pypi.python.org/pypi/setuptools>`_ package web
+ page for instructions.
+
+
+.. _building_the_documentation:
+
+Building the documentation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In order to build the documentation need to add ``-DLLVM_ENABLE_SPHINX=ON`` to
+your ``cmake`` command. Once you do this you can build the docs using
+``docs-lld-html`` build (``ninja`` or ``make``) target.
+
+That build target will invoke ``sphinx-build`` with the appropriate options for
+the project, and generate the HTML documentation in a ``tools/lld/docs/html``
+subdirectory.
+
+.. _writing_documentation:
+
+Writing documentation
+~~~~~~~~~~~~~~~~~~~~~
+
+The documentation itself is written in the reStructuredText (ReST) format, and
+Sphinx defines additional tags to support features like cross-referencing.
+
+The ReST format itself is organized around documents mostly being readable
+plaintext documents. You should generally be able to write new documentation
+easily just by following the style of the existing documentation.
+
+If you want to understand the formatting of the documents more, the best place
+to start is Sphinx's own `ReST Primer <http://sphinx.pocoo.org/rest.html>`_.
+
+
+Learning More
+-------------
+
+If you want to learn more about the Sphinx system, the best place to start is
+the Sphinx documentation itself, available `here
+<http://sphinx.pocoo.org/contents.html>`_.
+
+
+.. _installing_sphinx_in_a_venv:
+
+Installing Sphinx in a Virtual Environment
+------------------------------------------
+
+Most Python developers prefer to work with tools inside a *virtualenv* (virtual
+environment) instance, which functions as an application sandbox. This avoids
+polluting your system installation with different packages used by various
+projects (and ensures that dependencies for different packages don't conflict
+with one another). Of course, you need to first have the virtualenv software
+itself which generally would be installed at the system level::
+
+ $ sudo easy_install virtualenv
+
+but after that you no longer need to install additional packages in the system
+directories.
+
+Once you have the *virtualenv* tool itself installed, you can create a
+virtualenv for Sphinx using::
+
+ $ virtualenv ~/my-sphinx-install
+ New python executable in /Users/dummy/my-sphinx-install/bin/python
+ Installing setuptools............done.
+ Installing pip...............done.
+
+ $ ~/my-sphinx-install/bin/easy_install sphinx
+ ... install messages here ...
+
+and from now on you can "activate" the *virtualenv* using::
+
+ $ source ~/my-sphinx-install/bin/activate
+
+which will change your PATH to ensure the sphinx-build tool from inside the
+virtual environment will be used. See the `virtualenv website
+<http://www.virtualenv.org/en/latest/index.html>`_ for more information on using
+virtual environments.
diff --git a/contrib/llvm/tools/lld/docs/windows_support.rst b/contrib/llvm/tools/lld/docs/windows_support.rst
new file mode 100644
index 000000000000..a0a2c4d9f1bc
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/windows_support.rst
@@ -0,0 +1,97 @@
+.. raw:: html
+
+ <style type="text/css">
+ .none { background-color: #FFCCCC }
+ .partial { background-color: #FFFF99 }
+ .good { background-color: #CCFF99 }
+ </style>
+
+.. role:: none
+.. role:: partial
+.. role:: good
+
+===============
+Windows support
+===============
+
+LLD supports Windows operating system. When invoked as ``lld-link.exe`` or with
+``-flavor link``, the driver for Windows operating system is used to parse
+command line options, and it drives further linking processes. LLD accepts
+almost all command line options that the linker shipped with Microsoft Visual
+C++ (link.exe) supports.
+
+The current status is that LLD can link itself on Windows x86/x64
+using Visual C++ 2013 as the compiler.
+
+Development status
+==================
+
+Driver
+ :good:`Mostly done`. Some exotic command line options that are not usually
+ used for application develompent, such as ``/DRIVER``, are not supported.
+
+Linking against DLL
+ :good:`Done`. LLD can read import libraries needed to link against DLL. Both
+ export-by-name and export-by-ordinal are supported.
+
+Linking against static library
+ :good:`Done`. The format of static library (.lib) on Windows is actually the
+ same as on Unix (.a). LLD can read it.
+
+Creating DLL
+ :good:`Done`. LLD creates a DLL if ``/DLL`` option is given. Exported
+ functions can be specified either via command line (``/EXPORT``) or via
+ module-definition file (.def). Both export-by-name and export-by-ordinal are
+ supported.
+
+Windows resource files support
+ :good:`Done`. If an ``.res`` file is given, LLD converts the file to a COFF
+ file using LLVM's Object library.
+
+Safe Structured Exception Handler (SEH)
+ :good:`Done` for both x86 and x64.
+
+Module-definition file
+ :partial:`Partially done`. LLD currently recognizes these directives:
+ ``EXPORTS``, ``HEAPSIZE``, ``STACKSIZE``, ``NAME``, and ``VERSION``.
+
+Debug info
+ :good:`Done`. LLD can emit PDBs that are at parity with those generated by
+ link.exe. However, LLD does not support /DEBUG:FASTLINK.
+
+
+Downloading LLD
+===============
+
+The Windows version of LLD is included in the `pre-built binaries of LLVM's
+releases <https://releases.llvm.org/download.html>`_ and in the `LLVM Snapshot
+Builds <https://llvm.org/builds/>`_.
+
+Building LLD
+============
+
+Using Visual Studio IDE/MSBuild
+-------------------------------
+
+1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror),
+#. run ``cmake -G "Visual Studio 12" <llvm-source-dir>`` from VS command prompt,
+#. open LLVM.sln with Visual Studio, and
+#. build ``lld`` target in ``lld executables`` folder
+
+Alternatively, you can use msbuild if you don't like to work in an IDE::
+
+ msbuild LLVM.sln /m /target:"lld executables\lld"
+
+MSBuild.exe had been shipped as a component of the .NET framework, but since
+2013 it's part of Visual Studio. You can find it at "C:\\Program Files
+(x86)\\msbuild".
+
+You can build LLD as a 64 bit application. To do that, open VS2013 x64 command
+prompt and run cmake for "Visual Studio 12 Win64" target.
+
+Using Ninja
+-----------
+
+1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror),
+#. run ``cmake -G ninja <llvm-source-dir>`` from VS command prompt,
+#. run ``ninja lld``
diff --git a/contrib/llvm/tools/lld/include/lld/Common/Driver.h b/contrib/llvm/tools/lld/include/lld/Common/Driver.h
index 15ec3cd44cb5..f6d92933af62 100644
--- a/contrib/llvm/tools/lld/include/lld/Common/Driver.h
+++ b/contrib/llvm/tools/lld/include/lld/Common/Driver.h
@@ -30,7 +30,7 @@ bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
}
namespace mach_o {
-bool link(llvm::ArrayRef<const char *> Args,
+bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
llvm::raw_ostream &Diag = llvm::errs());
}
diff --git a/contrib/llvm/tools/lld/include/lld/Common/ErrorHandler.h b/contrib/llvm/tools/lld/include/lld/Common/ErrorHandler.h
index 8ae6f46ac59e..f17f7cc99035 100644
--- a/contrib/llvm/tools/lld/include/lld/Common/ErrorHandler.h
+++ b/contrib/llvm/tools/lld/include/lld/Common/ErrorHandler.h
@@ -7,21 +7,62 @@
//
//===----------------------------------------------------------------------===//
//
-// In LLD, we have three levels of errors: fatal, error or warn.
+// We designed lld's error handlers with the following goals in mind:
//
-// Fatal makes the program exit immediately with an error message.
-// You shouldn't use it except for reporting a corrupted input file.
+// - Errors can occur at any place where we handle user input, but we don't
+// want them to affect the normal execution path too much. Ideally,
+// handling errors should be as simple as reporting them and exit (but
+// without actually doing exit).
//
-// Error prints out an error message and increment a global variable
-// ErrorCount to record the fact that we met an error condition. It does
-// not exit, so it is safe for a lld-as-a-library use case. It is generally
-// useful because it can report more than one error in a single run.
+// In particular, the design to wrap all functions that could fail with
+// ErrorOr<T> is rejected because otherwise we would have to wrap a large
+// number of functions in lld with ErrorOr. With that approach, if some
+// function F can fail, not only F but all functions that transitively call
+// F have to be wrapped with ErrorOr. That seemed too much.
//
-// Warn doesn't do anything but printing out a given message.
+// - Finding only one error at a time is not sufficient. We want to find as
+// many errors as possible with one execution of the linker. That means the
+// linker needs to keep running after a first error and give up at some
+// checkpoint (beyond which it would find cascading, false errors caused by
+// the previous errors).
//
-// It is not recommended to use llvm::outs() or llvm::errs() directly
-// in LLD because they are not thread-safe. The functions declared in
-// this file are mutually excluded, so you want to use them instead.
+// - We want a simple interface to report errors. Unlike Clang, the data we
+// handle is compiled binary, so we don't need an error reporting mechanism
+// that's as sophisticated as the one that Clang has.
+//
+// The current lld's error handling mechanism is simple:
+//
+// - When you find an error, report it using error() and continue as far as
+// you can. An internal error counter is incremented by one every time you
+// call error().
+//
+// A common idiom to handle an error is calling error() and then returning
+// a reasonable default value. For example, if your function handles a
+// user-supplied alignment value, and if you find an invalid alignment
+// (e.g. 17 which is not 2^n), you may report it using error() and continue
+// as if it were alignment 1 (which is the simplest reasonable value).
+//
+// Note that you should not continue with an invalid value; that breaks the
+// internal consistency. You need to maintain all variables have some sane
+// value even after an error occurred. So, when you have to continue with
+// some value, always use a dummy value.
+//
+// - Find a reasonable checkpoint at where you want to stop the linker, and
+// add code to return from the function if errorCount() > 0. In most cases,
+// a checkpoint already exists, so you don't need to do anything for this.
+//
+// This interface satisfies all the goals that we mentioned above.
+//
+// You should never call fatal() except for reporting a corrupted input file.
+// fatal() immediately terminates the linker, so the function is not desirable
+// if you are using lld as a subroutine in other program, and with that you
+// can find only one error at a time.
+//
+// warn() doesn't do anything but printing out a given message.
+//
+// It is not recommended to use llvm::outs() or llvm::errs() directly in lld
+// because they are not thread-safe. The functions declared in this file are
+// thread-safe.
//
//===----------------------------------------------------------------------===//
@@ -34,6 +75,10 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FileOutputBuffer.h"
+namespace llvm {
+class DiagnosticInfo;
+}
+
namespace lld {
class ErrorHandler {
@@ -74,6 +119,9 @@ inline uint64_t errorCount() { return errorHandler().ErrorCount; }
LLVM_ATTRIBUTE_NORETURN void exitLld(int Val);
+void diagnosticHandler(const llvm::DiagnosticInfo &DI);
+void checkError(Error E);
+
// check functions are convenient functions to strip errors
// from error-or-value objects.
template <class T> T check(ErrorOr<T> E) {
diff --git a/contrib/llvm/tools/lld/include/lld/Common/Strings.h b/contrib/llvm/tools/lld/include/lld/Common/Strings.h
index 1a63f75f9ecf..e17b25763781 100644
--- a/contrib/llvm/tools/lld/include/lld/Common/Strings.h
+++ b/contrib/llvm/tools/lld/include/lld/Common/Strings.h
@@ -10,14 +10,40 @@
#ifndef LLD_STRINGS_H
#define LLD_STRINGS_H
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/GlobPattern.h"
#include <string>
+#include <vector>
namespace lld {
// Returns a demangled C++ symbol name. If Name is not a mangled
// name, it returns Optional::None.
llvm::Optional<std::string> demangleItanium(llvm::StringRef Name);
+llvm::Optional<std::string> demangleMSVC(llvm::StringRef S);
+
+std::vector<uint8_t> parseHex(llvm::StringRef S);
+bool isValidCIdentifier(llvm::StringRef S);
+
+// Write the contents of the a buffer to a file
+void saveBuffer(llvm::StringRef Buffer, const llvm::Twine &Path);
+
+// This class represents multiple glob patterns.
+class StringMatcher {
+public:
+ StringMatcher() = default;
+ explicit StringMatcher(llvm::ArrayRef<llvm::StringRef> Pat);
+
+ bool match(llvm::StringRef S) const;
+
+private:
+ std::vector<llvm::GlobPattern> Patterns;
+};
+
+inline llvm::ArrayRef<uint8_t> toArrayRef(llvm::StringRef S) {
+ return {reinterpret_cast<const uint8_t *>(S.data()), S.size()};
}
+} // namespace lld
#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Common/TargetOptionsCommandFlags.h b/contrib/llvm/tools/lld/include/lld/Common/TargetOptionsCommandFlags.h
index 9c4ff7cea3fb..8443b184aa70 100644
--- a/contrib/llvm/tools/lld/include/lld/Common/TargetOptionsCommandFlags.h
+++ b/contrib/llvm/tools/lld/include/lld/Common/TargetOptionsCommandFlags.h
@@ -18,4 +18,5 @@
namespace lld {
llvm::TargetOptions InitTargetOptionsFromCodeGenFlags();
llvm::Optional<llvm::CodeModel::Model> GetCodeModelFromCMModel();
+std::string GetCPUStr();
}
diff --git a/contrib/llvm/tools/lld/include/lld/Common/Timer.h b/contrib/llvm/tools/lld/include/lld/Common/Timer.h
new file mode 100644
index 000000000000..6654af626919
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Common/Timer.h
@@ -0,0 +1,59 @@
+//===- Timer.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COMMON_TIMER_H
+#define LLD_COMMON_TIMER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include <assert.h>
+#include <chrono>
+#include <map>
+#include <memory>
+
+namespace lld {
+
+class Timer;
+
+struct ScopedTimer {
+ explicit ScopedTimer(Timer &T);
+
+ ~ScopedTimer();
+
+ void stop();
+
+ Timer *T = nullptr;
+};
+
+class Timer {
+public:
+ Timer(llvm::StringRef Name, Timer &Parent);
+
+ static Timer &root();
+
+ void start();
+ void stop();
+ void print();
+
+ double millis() const;
+
+private:
+ explicit Timer(llvm::StringRef Name);
+ void print(int Depth, double TotalDuration, bool Recurse = true) const;
+
+ std::chrono::time_point<std::chrono::high_resolution_clock> StartTime;
+ std::chrono::nanoseconds Total;
+ std::vector<Timer *> Children;
+ std::string Name;
+ Timer *Parent;
+};
+
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Common/Version.h b/contrib/llvm/tools/lld/include/lld/Common/Version.h
index 93de77df5804..23a10ed6dbf3 100644
--- a/contrib/llvm/tools/lld/include/lld/Common/Version.h
+++ b/contrib/llvm/tools/lld/include/lld/Common/Version.h
@@ -18,7 +18,7 @@
#include "llvm/ADT/StringRef.h"
namespace lld {
-/// \brief Retrieves a string representing the complete lld version.
+/// Retrieves a string representing the complete lld version.
std::string getLLDVersion();
}
diff --git a/contrib/llvm/tools/lld/include/lld/Core/DefinedAtom.h b/contrib/llvm/tools/lld/include/lld/Core/DefinedAtom.h
index 6229d67e25a5..ba10b45411f1 100644
--- a/contrib/llvm/tools/lld/include/lld/Core/DefinedAtom.h
+++ b/contrib/llvm/tools/lld/include/lld/Core/DefinedAtom.h
@@ -18,7 +18,7 @@
namespace lld {
class File;
-/// \brief The fundamental unit of linking.
+/// The fundamental unit of linking.
///
/// A C function or global variable is an atom. An atom has content and
/// attributes. The content of a function atom is the instructions that
@@ -179,10 +179,10 @@ public:
};
enum DynamicExport {
- /// \brief The linker may or may not export this atom dynamically depending
+ /// The linker may or may not export this atom dynamically depending
/// on the output type and other context of the link.
dynamicExportNormal,
- /// \brief The linker will always export this atom dynamically.
+ /// The linker will always export this atom dynamically.
dynamicExportAlways,
};
@@ -212,26 +212,26 @@ public:
}
};
- /// \brief returns a value for the order of this Atom within its file.
+ /// returns a value for the order of this Atom within its file.
///
/// This is used by the linker to order the layout of Atoms so that the
/// resulting image is stable and reproducible.
virtual uint64_t ordinal() const = 0;
- /// \brief the number of bytes of space this atom's content will occupy in the
+ /// the number of bytes of space this atom's content will occupy in the
/// final linked image.
///
/// For a function atom, it is the number of bytes of code in the function.
virtual uint64_t size() const = 0;
- /// \brief The size of the section from which the atom is instantiated.
+ /// The size of the section from which the atom is instantiated.
///
/// Merge::mergeByLargestSection is defined in terms of section size
/// and not in terms of atom size, so we need this function separate
/// from size().
virtual uint64_t sectionSize() const { return 0; }
- /// \brief The visibility of this atom to other atoms.
+ /// The visibility of this atom to other atoms.
///
/// C static functions have scope scopeTranslationUnit. Regular C functions
/// have scope scopeGlobal. Functions compiled with visibility=hidden have
@@ -239,48 +239,48 @@ public:
/// not by the OS loader.
virtual Scope scope() const = 0;
- /// \brief Whether the linker should use direct or indirect access to this
+ /// Whether the linker should use direct or indirect access to this
/// atom.
virtual Interposable interposable() const = 0;
- /// \brief how the linker should handle if multiple atoms have the same name.
+ /// how the linker should handle if multiple atoms have the same name.
virtual Merge merge() const = 0;
- /// \brief The type of this atom, such as code or data.
+ /// The type of this atom, such as code or data.
virtual ContentType contentType() const = 0;
- /// \brief The alignment constraints on how this atom must be laid out in the
+ /// The alignment constraints on how this atom must be laid out in the
/// final linked image (e.g. 16-byte aligned).
virtual Alignment alignment() const = 0;
- /// \brief Whether this atom must be in a specially named section in the final
+ /// Whether this atom must be in a specially named section in the final
/// linked image, or if the linker can infer the section based on the
/// contentType().
virtual SectionChoice sectionChoice() const = 0;
- /// \brief If sectionChoice() != sectionBasedOnContent, then this return the
+ /// If sectionChoice() != sectionBasedOnContent, then this return the
/// name of the section the atom should be placed into.
virtual StringRef customSectionName() const = 0;
- /// \brief constraints on whether the linker may dead strip away this atom.
+ /// constraints on whether the linker may dead strip away this atom.
virtual DeadStripKind deadStrip() const = 0;
- /// \brief Under which conditions should this atom be dynamically exported.
+ /// Under which conditions should this atom be dynamically exported.
virtual DynamicExport dynamicExport() const {
return dynamicExportNormal;
}
- /// \brief Code model used by the atom.
+ /// Code model used by the atom.
virtual CodeModel codeModel() const { return codeNA; }
- /// \brief Returns the OS memory protections required for this atom's content
+ /// Returns the OS memory protections required for this atom's content
/// at runtime.
///
/// A function atom is R_X, a global variable is RW_, and a read-only constant
/// is R__.
virtual ContentPermissions permissions() const;
- /// \brief returns a reference to the raw (unrelocated) bytes of this Atom's
+ /// returns a reference to the raw (unrelocated) bytes of this Atom's
/// content.
virtual ArrayRef<uint8_t> rawContent() const = 0;
@@ -317,10 +317,10 @@ public:
const void *_it;
};
- /// \brief Returns an iterator to the beginning of this Atom's References.
+ /// Returns an iterator to the beginning of this Atom's References.
virtual reference_iterator begin() const = 0;
- /// \brief Returns an iterator to the end of this Atom's References.
+ /// Returns an iterator to the end of this Atom's References.
virtual reference_iterator end() const = 0;
/// Adds a reference to this atom.
@@ -361,11 +361,11 @@ protected:
~DefinedAtom() override = default;
- /// \brief Returns a pointer to the Reference object that the abstract
+ /// Returns a pointer to the Reference object that the abstract
/// iterator "points" to.
virtual const Reference *derefIterator(const void *iter) const = 0;
- /// \brief Adjusts the abstract iterator to "point" to the next Reference
+ /// Adjusts the abstract iterator to "point" to the next Reference
/// object for this Atom.
virtual void incrementIterator(const void *&iter) const = 0;
};
diff --git a/contrib/llvm/tools/lld/include/lld/Core/File.h b/contrib/llvm/tools/lld/include/lld/Core/File.h
index 20418688dfa0..54f533576a4b 100644
--- a/contrib/llvm/tools/lld/include/lld/Core/File.h
+++ b/contrib/llvm/tools/lld/include/lld/Core/File.h
@@ -43,7 +43,7 @@ class File {
public:
virtual ~File();
- /// \brief Kinds of files that are supported.
+ /// Kinds of files that are supported.
enum Kind {
kindErrorObject, ///< a error object file (.o)
kindNormalizedObject, ///< a normalized file (.o)
@@ -59,7 +59,7 @@ public:
kindArchiveLibrary ///< archive (.a)
};
- /// \brief Returns file kind. Need for dyn_cast<> on File objects.
+ /// Returns file kind. Need for dyn_cast<> on File objects.
Kind kind() const {
return _kind;
}
@@ -114,10 +114,8 @@ public:
AtomRange(AtomVector<T> &v) : _v(v) {}
AtomRange(const AtomVector<T> &v) : _v(const_cast<AtomVector<T> &>(v)) {}
- typedef std::pointer_to_unary_function<const OwningAtomPtr<T>&,
- const T*> ConstDerefFn;
-
- typedef std::pointer_to_unary_function<OwningAtomPtr<T>&, T*> DerefFn;
+ using ConstDerefFn = const T* (*)(const OwningAtomPtr<T>&);
+ using DerefFn = T* (*)(OwningAtomPtr<T>&);
typedef llvm::mapped_iterator<typename AtomVector<T>::const_iterator,
ConstDerefFn> ConstItTy;
@@ -174,19 +172,19 @@ public:
AtomVector<T> &_v;
};
- /// \brief Must be implemented to return the AtomVector object for
+ /// Must be implemented to return the AtomVector object for
/// all DefinedAtoms in this File.
virtual const AtomRange<DefinedAtom> defined() const = 0;
- /// \brief Must be implemented to return the AtomVector object for
+ /// Must be implemented to return the AtomVector object for
/// all UndefinedAtomw in this File.
virtual const AtomRange<UndefinedAtom> undefined() const = 0;
- /// \brief Must be implemented to return the AtomVector object for
+ /// Must be implemented to return the AtomVector object for
/// all SharedLibraryAtoms in this File.
virtual const AtomRange<SharedLibraryAtom> sharedLibrary() const = 0;
- /// \brief Must be implemented to return the AtomVector object for
+ /// Must be implemented to return the AtomVector object for
/// all AbsoluteAtoms in this File.
virtual const AtomRange<AbsoluteAtom> absolute() const = 0;
@@ -196,7 +194,7 @@ public:
/// of a different file. We need to destruct all atoms before any files.
virtual void clearAtoms() = 0;
- /// \brief If a file is parsed using a different method than doParse(),
+ /// If a file is parsed using a different method than doParse(),
/// one must use this method to set the last error status, so that
/// doParse will not be called twice. Only YAML reader uses this
/// (because YAML reader does not read blobs but structured data).
@@ -214,12 +212,12 @@ public:
}
protected:
- /// \brief only subclasses of File can be instantiated
+ /// only subclasses of File can be instantiated
File(StringRef p, Kind kind)
: _path(p), _kind(kind), _ordinal(UINT64_MAX),
_nextAtomOrdinal(0) {}
- /// \brief Subclasses should override this method to parse the
+ /// Subclasses should override this method to parse the
/// memory buffer passed to this file's constructor.
virtual std::error_code doParse() { return std::error_code(); }
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Instrumentation.h b/contrib/llvm/tools/lld/include/lld/Core/Instrumentation.h
index 162375905e17..939d64557587 100644
--- a/contrib/llvm/tools/lld/include/lld/Core/Instrumentation.h
+++ b/contrib/llvm/tools/lld/include/lld/Core/Instrumentation.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief Provide an Instrumentation API that optionally uses VTune interfaces.
+/// Provide an Instrumentation API that optionally uses VTune interfaces.
///
//===----------------------------------------------------------------------===//
@@ -24,7 +24,7 @@
namespace lld {
#ifdef LLD_HAS_VTUNE
-/// \brief A unique global scope for instrumentation data.
+/// A unique global scope for instrumentation data.
///
/// Domains last for the lifetime of the application and cannot be destroyed.
/// Multiple Domains created with the same name represent the same domain.
@@ -38,7 +38,7 @@ public:
__itt_domain *operator->() const { return _domain; }
};
-/// \brief A global reference to a string constant.
+/// A global reference to a string constant.
///
/// These are uniqued by the ITT runtime and cannot be deleted. They are not
/// specific to a domain.
@@ -54,7 +54,7 @@ public:
operator __itt_string_handle *() const { return _handle; }
};
-/// \brief A task on a single thread. Nests within other tasks.
+/// A task on a single thread. Nests within other tasks.
///
/// Each thread has its own task stack and tasks nest recursively on that stack.
/// A task cannot transfer threads.
@@ -68,7 +68,7 @@ class ScopedTask {
ScopedTask &operator=(const ScopedTask &) = delete;
public:
- /// \brief Create a task in Domain \p d named \p s.
+ /// Create a task in Domain \p d named \p s.
ScopedTask(const Domain &d, const StringHandle &s) : _domain(d) {
__itt_task_begin(d, __itt_null, __itt_null, s);
}
@@ -83,7 +83,7 @@ public:
return *this;
}
- /// \brief Prematurely end this task.
+ /// Prematurely end this task.
void end() {
if (_domain)
__itt_task_end(_domain);
@@ -93,7 +93,7 @@ public:
~ScopedTask() { end(); }
};
-/// \brief A specific point in time. Allows metadata to be associated.
+/// A specific point in time. Allows metadata to be associated.
class Marker {
public:
Marker(const Domain &d, const StringHandle &s) {
diff --git a/contrib/llvm/tools/lld/include/lld/Core/LinkingContext.h b/contrib/llvm/tools/lld/include/lld/Core/LinkingContext.h
index eb9510cbd215..52ab1a2480e8 100644
--- a/contrib/llvm/tools/lld/include/lld/Core/LinkingContext.h
+++ b/contrib/llvm/tools/lld/include/lld/Core/LinkingContext.h
@@ -16,7 +16,6 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Error.h"
-#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstdint>
#include <memory>
@@ -31,7 +30,7 @@ class Writer;
class Node;
class SharedLibraryFile;
-/// \brief The LinkingContext class encapsulates "what and how" to link.
+/// The LinkingContext class encapsulates "what and how" to link.
///
/// The base class LinkingContext contains the options needed by core linking.
/// Subclasses of LinkingContext have additional options needed by specific
@@ -167,10 +166,10 @@ public:
/// After all set* methods are called, the Driver calls this method
/// to validate that there are no missing options or invalid combinations
/// of options. If there is a problem, a description of the problem
- /// is written to the supplied stream.
+ /// is written to the global error handler.
///
/// \returns true if there is an error with the current settings.
- bool validate(raw_ostream &diagnostics);
+ bool validate();
/// Formats symbol name for use in error messages.
virtual std::string demangle(StringRef symbolName) const = 0;
@@ -250,7 +249,7 @@ protected:
private:
/// Validate the subclass bits. Only called by validate.
- virtual bool validateImpl(raw_ostream &diagnostics) = 0;
+ virtual bool validateImpl() = 0;
};
} // end namespace lld
diff --git a/contrib/llvm/tools/lld/include/lld/Core/PassManager.h b/contrib/llvm/tools/lld/include/lld/Core/PassManager.h
index 2ea65ae13ace..f2ef10f406f2 100644
--- a/contrib/llvm/tools/lld/include/lld/Core/PassManager.h
+++ b/contrib/llvm/tools/lld/include/lld/Core/PassManager.h
@@ -20,7 +20,7 @@ namespace lld {
class SimpleFile;
class Pass;
-/// \brief Owns and runs a collection of passes.
+/// Owns and runs a collection of passes.
///
/// This class is currently just a container for passes and a way to run them.
///
@@ -40,7 +40,7 @@ public:
}
private:
- /// \brief Passes in the order they should run.
+ /// Passes in the order they should run.
std::vector<std::unique_ptr<Pass>> _passes;
};
} // end namespace lld
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Reader.h b/contrib/llvm/tools/lld/include/lld/Core/Reader.h
index c7baf86af61f..6cf6282ff39c 100644
--- a/contrib/llvm/tools/lld/include/lld/Core/Reader.h
+++ b/contrib/llvm/tools/lld/include/lld/Core/Reader.h
@@ -32,7 +32,7 @@ class File;
class LinkingContext;
class MachOLinkingContext;
-/// \brief An abstract class for reading object files, library files, and
+/// An abstract class for reading object files, library files, and
/// executable files.
///
/// Each file format (e.g. mach-o, etc) has a concrete subclass of Reader.
@@ -46,14 +46,14 @@ public:
/// 2) the whole file content buffer if the above is not enough.
virtual bool canParse(llvm::file_magic magic, MemoryBufferRef mb) const = 0;
- /// \brief Parse a supplied buffer (already filled with the contents of a
+ /// Parse a supplied buffer (already filled with the contents of a
/// file) and create a File object.
/// The resulting File object takes ownership of the MemoryBuffer.
virtual ErrorOr<std::unique_ptr<File>>
loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &) const = 0;
};
-/// \brief An abstract class for handling alternate yaml representations
+/// An abstract class for handling alternate yaml representations
/// of object files.
///
/// The YAML syntax allows "tags" which are used to specify the type of
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Resolver.h b/contrib/llvm/tools/lld/include/lld/Core/Resolver.h
index fb62a779c0a5..5157c9fddc1a 100644
--- a/contrib/llvm/tools/lld/include/lld/Core/Resolver.h
+++ b/contrib/llvm/tools/lld/include/lld/Core/Resolver.h
@@ -28,7 +28,7 @@ namespace lld {
class Atom;
class LinkingContext;
-/// \brief The Resolver is responsible for merging all input object files
+/// The Resolver is responsible for merging all input object files
/// and producing a merged graph.
class Resolver {
public:
@@ -50,7 +50,7 @@ public:
// Handle a shared library file.
llvm::Error handleSharedLibrary(File &);
- /// @brief do work of merging and resolving and return list
+ /// do work of merging and resolving and return list
bool resolve();
std::unique_ptr<SimpleFile> resultFile() { return std::move(_result); }
@@ -61,7 +61,7 @@ private:
bool undefinesAdded(int begin, int end);
File *getFile(int &index);
- /// \brief The main function that iterates over the files to resolve
+ /// The main function that iterates over the files to resolve
bool resolveUndefines();
void updateReferences();
void deadStripOptimize();
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Simple.h b/contrib/llvm/tools/lld/include/lld/Core/Simple.h
index 3aa7abf5d12b..feeed6ae473b 100644
--- a/contrib/llvm/tools/lld/include/lld/Core/Simple.h
+++ b/contrib/llvm/tools/lld/include/lld/Core/Simple.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief Provide simple implementations for Atoms and File.
+/// Provide simple implementations for Atoms and File.
///
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/lld/include/lld/Core/SymbolTable.h b/contrib/llvm/tools/lld/include/lld/Core/SymbolTable.h
index 9c39a6ed507c..156c56eafbf7 100644
--- a/contrib/llvm/tools/lld/include/lld/Core/SymbolTable.h
+++ b/contrib/llvm/tools/lld/include/lld/Core/SymbolTable.h
@@ -12,7 +12,7 @@
#include "lld/Common/LLVM.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/DJB.h"
#include <cstring>
#include <map>
#include <vector>
@@ -27,35 +27,35 @@ class ResolverOptions;
class SharedLibraryAtom;
class UndefinedAtom;
-/// \brief The SymbolTable class is responsible for coalescing atoms.
+/// The SymbolTable class is responsible for coalescing atoms.
///
/// All atoms coalescable by-name or by-content should be added.
/// The method replacement() can be used to find the replacement atom
/// if an atom has been coalesced away.
class SymbolTable {
public:
- /// @brief add atom to symbol table
+ /// add atom to symbol table
bool add(const DefinedAtom &);
- /// @brief add atom to symbol table
+ /// add atom to symbol table
bool add(const UndefinedAtom &);
- /// @brief add atom to symbol table
+ /// add atom to symbol table
bool add(const SharedLibraryAtom &);
- /// @brief add atom to symbol table
+ /// add atom to symbol table
bool add(const AbsoluteAtom &);
- /// @brief returns atom in symbol table for specified name (or nullptr)
+ /// returns atom in symbol table for specified name (or nullptr)
const Atom *findByName(StringRef sym);
- /// @brief returns vector of remaining UndefinedAtoms
+ /// returns vector of remaining UndefinedAtoms
std::vector<const UndefinedAtom *> undefines();
- /// @brief if atom has been coalesced away, return replacement, else return atom
+ /// if atom has been coalesced away, return replacement, else return atom
const Atom *replacement(const Atom *);
- /// @brief if atom has been coalesced away, return true
+ /// if atom has been coalesced away, return true
bool isCoalescedAway(const Atom *);
private:
@@ -65,7 +65,7 @@ private:
static StringRef getEmptyKey() { return StringRef(); }
static StringRef getTombstoneKey() { return StringRef(" ", 1); }
static unsigned getHashValue(StringRef const val) {
- return llvm::HashString(val);
+ return llvm::djbHash(val, 0);
}
static bool isEqual(StringRef const lhs, StringRef const rhs) {
return lhs.equals(rhs);
diff --git a/contrib/llvm/tools/lld/include/lld/Core/TODO.txt b/contrib/llvm/tools/lld/include/lld/Core/TODO.txt
index 8b523045de75..2aa61ff8612d 100644
--- a/contrib/llvm/tools/lld/include/lld/Core/TODO.txt
+++ b/contrib/llvm/tools/lld/include/lld/Core/TODO.txt
@@ -6,9 +6,6 @@ include/lld/Core
abstraction only works for returning low level OS errors. It does not
work for describing formatting issues.
-* We need to design a diagnostics interface. It would be nice to share code
- with Clang_ where possible.
-
* We need to add more attributes to File. In particular, we need cpu
and OS information (like target triples). We should also provide explicit
support for `LLVM IR module flags metadata`__.
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Writer.h b/contrib/llvm/tools/lld/include/lld/Core/Writer.h
index 1f0ca4cda41f..1cdfabefebd7 100644
--- a/contrib/llvm/tools/lld/include/lld/Core/Writer.h
+++ b/contrib/llvm/tools/lld/include/lld/Core/Writer.h
@@ -20,17 +20,17 @@ class File;
class LinkingContext;
class MachOLinkingContext;
-/// \brief The Writer is an abstract class for writing object files, shared
+/// The Writer is an abstract class for writing object files, shared
/// library files, and executable files. Each file format (e.g. mach-o, etc)
/// has a concrete subclass of Writer.
class Writer {
public:
virtual ~Writer();
- /// \brief Write a file from the supplied File object
+ /// Write a file from the supplied File object
virtual llvm::Error writeFile(const File &linkedFile, StringRef path) = 0;
- /// \brief This method is called by Core Linking to give the Writer a chance
+ /// This method is called by Core Linking to give the Writer a chance
/// to add file format specific "files" to set of files to be linked. This is
/// how file format specific atoms can be added to the link.
virtual void createImplicitFiles(std::vector<std::unique_ptr<File>> &) {}
diff --git a/contrib/llvm/tools/lld/include/lld/ReaderWriter/MachOLinkingContext.h b/contrib/llvm/tools/lld/include/lld/ReaderWriter/MachOLinkingContext.h
index 9eefa8c4d944..fde65880c3e3 100644
--- a/contrib/llvm/tools/lld/include/lld/ReaderWriter/MachOLinkingContext.h
+++ b/contrib/llvm/tools/lld/include/lld/ReaderWriter/MachOLinkingContext.h
@@ -89,7 +89,7 @@ public:
bool exportDynamicSymbols);
void addPasses(PassManager &pm) override;
- bool validateImpl(raw_ostream &diagnostics) override;
+ bool validateImpl() override;
std::string demangle(StringRef symbolName) const override;
void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
@@ -201,7 +201,7 @@ public:
uint32_t swiftVersion() const { return _swiftVersion; }
- /// \brief Checks whether a given path on the filesystem exists.
+ /// Checks whether a given path on the filesystem exists.
///
/// When running in -test_file_usage mode, this method consults an
/// internally maintained list of files that exist (provided by -path_exists)
@@ -211,7 +211,7 @@ public:
/// Like pathExists() but only used on files - not directories.
bool fileExists(StringRef path) const;
- /// \brief Adds any library search paths derived from the given base, possibly
+ /// Adds any library search paths derived from the given base, possibly
/// modified by -syslibroots.
///
/// The set of paths added consists of approximately all syslibroot-prepended
@@ -219,7 +219,7 @@ public:
/// for whatever reason. With various edge-cases for compatibility.
void addModifiedSearchDir(StringRef libPath, bool isSystemPath = false);
- /// \brief Determine whether -lFoo can be resolve within the given path, and
+ /// Determine whether -lFoo can be resolve within the given path, and
/// return the filename if so.
///
/// The -lFoo option is documented to search for libFoo.dylib and libFoo.a in
@@ -228,7 +228,7 @@ public:
llvm::Optional<StringRef> searchDirForLibrary(StringRef path,
StringRef libName) const;
- /// \brief Iterates through all search path entries looking for libName (as
+ /// Iterates through all search path entries looking for libName (as
/// specified by -lFoo).
llvm::Optional<StringRef> searchLibrary(StringRef libName) const;
@@ -236,11 +236,11 @@ public:
/// the path with syslibroot.
void addFrameworkSearchDir(StringRef fwPath, bool isSystemPath = false);
- /// \brief Iterates through all framework directories looking for
+ /// Iterates through all framework directories looking for
/// Foo.framework/Foo (when fwName = "Foo").
llvm::Optional<StringRef> findPathForFramework(StringRef fwName) const;
- /// \brief The dylib's binary compatibility version, in the raw uint32 format.
+ /// The dylib's binary compatibility version, in the raw uint32 format.
///
/// When building a dynamic library, this is the compatibility version that
/// gets embedded into the result. Other Mach-O binaries that link against
@@ -249,28 +249,28 @@ public:
/// installed dynamic library.
uint32_t compatibilityVersion() const { return _compatibilityVersion; }
- /// \brief The dylib's current version, in the the raw uint32 format.
+ /// The dylib's current version, in the the raw uint32 format.
///
/// When building a dynamic library, this is the current version that gets
/// embedded into the result. Other Mach-O binaries that link against
/// this library will store the compatibility version in its load command.
uint32_t currentVersion() const { return _currentVersion; }
- /// \brief The dylib's install name.
+ /// The dylib's install name.
///
/// Binaries that link against the dylib will embed this path into the dylib
/// load command. When loading the binaries at runtime, this is the location
/// on disk that the loader will look for the dylib.
StringRef installName() const { return _installName; }
- /// \brief Whether or not the dylib has side effects during initialization.
+ /// Whether or not the dylib has side effects during initialization.
///
/// Dylibs marked as being dead strippable provide the guarantee that loading
/// the dylib has no side effects, allowing the linker to strip out the dylib
/// when linking a binary that does not use any of its symbols.
bool deadStrippableDylib() const { return _deadStrippableDylib; }
- /// \brief Whether or not to use flat namespace.
+ /// Whether or not to use flat namespace.
///
/// MachO usually uses a two-level namespace, where each external symbol
/// referenced by the target is associated with the dylib that will provide
@@ -282,7 +282,7 @@ public:
/// loaded flat_namespace dylibs must be resolvable at build time.
bool useFlatNamespace() const { return _flatNamespace; }
- /// \brief How to handle undefined symbols.
+ /// How to handle undefined symbols.
///
/// Options are:
/// * error: Report an error and terminate linking.
@@ -294,7 +294,7 @@ public:
/// runtime.
UndefinedMode undefinedMode() const { return _undefinedMode; }
- /// \brief The path to the executable that will load the bundle at runtime.
+ /// The path to the executable that will load the bundle at runtime.
///
/// When building a Mach-O bundle, this executable will be examined if there
/// are undefined symbols after the main link phase. It is expected that this
@@ -331,7 +331,7 @@ public:
/// Add section alignment constraint on final layout.
void addSectionAlignment(StringRef seg, StringRef sect, uint16_t align);
- /// \brief Add a section based on a command-line sectcreate option.
+ /// Add a section based on a command-line sectcreate option.
void addSectCreateSection(StringRef seg, StringRef sect,
std::unique_ptr<MemoryBuffer> content);
diff --git a/contrib/llvm/tools/lld/lib/Core/LinkingContext.cpp b/contrib/llvm/tools/lld/lib/Core/LinkingContext.cpp
index 5de863aa7f37..0f225c322122 100644
--- a/contrib/llvm/tools/lld/lib/Core/LinkingContext.cpp
+++ b/contrib/llvm/tools/lld/lib/Core/LinkingContext.cpp
@@ -20,8 +20,8 @@ LinkingContext::LinkingContext() = default;
LinkingContext::~LinkingContext() = default;
-bool LinkingContext::validate(raw_ostream &diagnostics) {
- return validateImpl(diagnostics);
+bool LinkingContext::validate() {
+ return validateImpl();
}
llvm::Error LinkingContext::writeFile(const File &linkedFile) const {
diff --git a/contrib/llvm/tools/lld/lib/Driver/CMakeLists.txt b/contrib/llvm/tools/lld/lib/Driver/CMakeLists.txt
index 097a8177ea1f..ff67c282f47e 100644
--- a/contrib/llvm/tools/lld/lib/Driver/CMakeLists.txt
+++ b/contrib/llvm/tools/lld/lib/Driver/CMakeLists.txt
@@ -13,6 +13,7 @@ add_lld_library(lldDriver
Support
LINK_LIBS
+ lldCommon
lldCore
lldMachO
lldReaderWriter
diff --git a/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp b/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp
index a019e9c32800..ad22845207e1 100644
--- a/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp
+++ b/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp
@@ -13,6 +13,8 @@
///
//===----------------------------------------------------------------------===//
+#include "lld/Common/Args.h"
+#include "lld/Common/ErrorHandler.h"
#include "lld/Common/LLVM.h"
#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/Error.h"
@@ -110,11 +112,11 @@ parseMemberFiles(std::unique_ptr<File> file) {
return members;
}
-std::vector<std::unique_ptr<File>>
-loadFile(MachOLinkingContext &ctx, StringRef path,
- raw_ostream &diag, bool wholeArchive, bool upwardDylib) {
+std::vector<std::unique_ptr<File>> loadFile(MachOLinkingContext &ctx,
+ StringRef path, bool wholeArchive,
+ bool upwardDylib) {
if (ctx.logInputFiles())
- diag << path << "\n";
+ message(path);
ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = ctx.getMemoryBuffer(path);
if (std::error_code ec = mbOrErr.getError())
@@ -155,10 +157,9 @@ static std::string canonicalizePath(StringRef path) {
}
static void addFile(StringRef path, MachOLinkingContext &ctx,
- bool loadWholeArchive,
- bool upwardDylib, raw_ostream &diag) {
+ bool loadWholeArchive, bool upwardDylib) {
std::vector<std::unique_ptr<File>> files =
- loadFile(ctx, path, diag, loadWholeArchive, upwardDylib);
+ loadFile(ctx, path, loadWholeArchive, upwardDylib);
for (std::unique_ptr<File> &file : files)
ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
}
@@ -166,8 +167,7 @@ static void addFile(StringRef path, MachOLinkingContext &ctx,
// Export lists are one symbol per line. Blank lines are ignored.
// Trailing comments start with #.
static std::error_code parseExportsList(StringRef exportFilePath,
- MachOLinkingContext &ctx,
- raw_ostream &diagnostics) {
+ MachOLinkingContext &ctx) {
// Map in export list file.
ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
MemoryBuffer::getFileOrSTDIN(exportFilePath);
@@ -197,8 +197,7 @@ static std::error_code parseExportsList(StringRef exportFilePath,
/// libfrob.a(bar.o):_bar
/// x86_64:_foo64
static std::error_code parseOrderFile(StringRef orderFilePath,
- MachOLinkingContext &ctx,
- raw_ostream &diagnostics) {
+ MachOLinkingContext &ctx) {
// Map in order file.
ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
MemoryBuffer::getFileOrSTDIN(orderFilePath);
@@ -252,8 +251,7 @@ static std::error_code parseOrderFile(StringRef orderFilePath,
// per line. The <dir> prefix is prepended to each partial path.
//
static llvm::Error loadFileList(StringRef fileListPath,
- MachOLinkingContext &ctx, bool forceLoad,
- raw_ostream &diagnostics) {
+ MachOLinkingContext &ctx, bool forceLoad) {
// If there is a comma, split off <dir>.
std::pair<StringRef, StringRef> opt = fileListPath.split(',');
StringRef filePath = opt.first;
@@ -286,9 +284,9 @@ static llvm::Error loadFileList(StringRef fileListPath,
+ "'");
}
if (ctx.testingFileUsage()) {
- diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n';
+ message("Found filelist entry " + canonicalizePath(path));
}
- addFile(path, ctx, forceLoad, false, diagnostics);
+ addFile(path, ctx, forceLoad, false);
buffer = lineAndRest.second;
}
return llvm::Error::success();
@@ -317,8 +315,7 @@ static void parseLLVMOptions(const LinkingContext &ctx) {
namespace lld {
namespace mach_o {
-bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
- raw_ostream &diagnostics) {
+bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx) {
// Parse command line options using DarwinLdOptions.td
DarwinLdOptTable table;
unsigned missingIndex;
@@ -326,17 +323,20 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
llvm::opt::InputArgList parsedArgs =
table.ParseArgs(args.slice(1), missingIndex, missingCount);
if (missingCount) {
- diagnostics << "error: missing arg value for '"
- << parsedArgs.getArgString(missingIndex) << "' expected "
- << missingCount << " argument(s).\n";
+ error("missing arg value for '" +
+ Twine(parsedArgs.getArgString(missingIndex)) + "' expected " +
+ Twine(missingCount) + " argument(s).");
return false;
}
for (auto unknownArg : parsedArgs.filtered(OPT_UNKNOWN)) {
- diagnostics << "warning: ignoring unknown argument: "
- << unknownArg->getAsString(parsedArgs) << "\n";
+ warn("ignoring unknown argument: " +
+ Twine(unknownArg->getAsString(parsedArgs)));
}
+ errorHandler().Verbose = parsedArgs.hasArg(OPT_v);
+ errorHandler().ErrorLimit = args::getInteger(parsedArgs, OPT_error_limit, 20);
+
// Figure out output kind ( -dylib, -r, -bundle, -preload, or -static )
llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE;
bool isStaticExecutable = false;
@@ -367,8 +367,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
if (llvm::opt::Arg *archStr = parsedArgs.getLastArg(OPT_arch)) {
arch = MachOLinkingContext::archFromName(archStr->getValue());
if (arch == MachOLinkingContext::arch_unknown) {
- diagnostics << "error: unknown arch named '" << archStr->getValue()
- << "'\n";
+ error("unknown arch named '" + Twine(archStr->getValue()) + "'");
return false;
}
}
@@ -386,7 +385,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
if (parsedArgs.size() == 0)
table.PrintHelp(llvm::outs(), args[0], "LLVM Linker", false);
else
- diagnostics << "error: -arch not specified and could not be inferred\n";
+ error("-arch not specified and could not be inferred");
return false;
}
}
@@ -402,7 +401,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
os = MachOLinkingContext::OS::macOSX;
if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
minOSVersion)) {
- diagnostics << "error: malformed macosx_version_min value\n";
+ error("malformed macosx_version_min value");
return false;
}
break;
@@ -410,7 +409,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
os = MachOLinkingContext::OS::iOS;
if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
minOSVersion)) {
- diagnostics << "error: malformed ios_version_min value\n";
+ error("malformed ios_version_min value");
return false;
}
break;
@@ -418,7 +417,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
os = MachOLinkingContext::OS::iOS_simulator;
if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
minOSVersion)) {
- diagnostics << "error: malformed ios_simulator_version_min value\n";
+ error("malformed ios_simulator_version_min value");
return false;
}
break;
@@ -452,14 +451,14 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
if (llvm::opt::Arg *imageBase = parsedArgs.getLastArg(OPT_image_base)) {
uint64_t baseAddress;
if (parseNumberBase16(imageBase->getValue(), baseAddress)) {
- diagnostics << "error: image_base expects a hex number\n";
+ error("image_base expects a hex number");
return false;
} else if (baseAddress < ctx.pageZeroSize()) {
- diagnostics << "error: image_base overlaps with __PAGEZERO\n";
+ error("image_base overlaps with __PAGEZERO");
return false;
} else if (baseAddress % ctx.pageSize()) {
- diagnostics << "error: image_base must be a multiple of page size ("
- << "0x" << llvm::utohexstr(ctx.pageSize()) << ")\n";
+ error("image_base must be a multiple of page size (0x" +
+ llvm::utohexstr(ctx.pageSize()) + ")");
return false;
}
@@ -488,13 +487,12 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// Handle -compatibility_version and -current_version
if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_compatibility_version)) {
if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
- diagnostics
- << "error: -compatibility_version can only be used with -dylib\n";
+ error("-compatibility_version can only be used with -dylib");
return false;
}
uint32_t parsedVers;
if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) {
- diagnostics << "error: -compatibility_version value is malformed\n";
+ error("-compatibility_version value is malformed");
return false;
}
ctx.setCompatibilityVersion(parsedVers);
@@ -502,12 +500,12 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_current_version)) {
if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
- diagnostics << "-current_version can only be used with -dylib\n";
+ error("-current_version can only be used with -dylib");
return false;
}
uint32_t parsedVers;
if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) {
- diagnostics << "error: -current_version value is malformed\n";
+ error("-current_version value is malformed");
return false;
}
ctx.setCurrentVersion(parsedVers);
@@ -526,17 +524,19 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
alignStr += 2;
unsigned long long alignValue;
if (llvm::getAsUnsignedInteger(alignStr, 16, alignValue)) {
- diagnostics << "error: -sectalign alignment value '"
- << alignStr << "' not a valid number\n";
+ error("-sectalign alignment value '" + Twine(alignStr) +
+ "' not a valid number");
return false;
}
uint16_t align = 1 << llvm::countTrailingZeros(alignValue);
if (!llvm::isPowerOf2_64(alignValue)) {
- diagnostics << "warning: alignment for '-sectalign "
- << segName << " " << sectName
- << llvm::format(" 0x%llX", alignValue)
- << "' is not a power of two, using "
- << llvm::format("0x%08X", align) << "\n";
+ std::string Msg;
+ llvm::raw_string_ostream OS(Msg);
+ OS << "alignment for '-sectalign " << segName << " " << sectName
+ << llvm::format(" 0x%llX", alignValue)
+ << "' is not a power of two, using " << llvm::format("0x%08X", align);
+ OS.flush();
+ warn(Msg);
}
ctx.addSectionAlignment(segName, sectName, align);
}
@@ -562,18 +562,14 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
if (parsedArgs.getLastArg(OPT_keep_private_externs)) {
ctx.setKeepPrivateExterns(true);
if (ctx.outputMachOType() != llvm::MachO::MH_OBJECT)
- diagnostics << "warning: -keep_private_externs only used in -r mode\n";
+ warn("-keep_private_externs only used in -r mode");
}
// Handle -dependency_info <path> used by Xcode.
- if (llvm::opt::Arg *depInfo = parsedArgs.getLastArg(OPT_dependency_info)) {
- if (std::error_code ec = ctx.createDependencyFile(depInfo->getValue())) {
- diagnostics << "warning: " << ec.message()
- << ", processing '-dependency_info "
- << depInfo->getValue()
- << "'\n";
- }
- }
+ if (llvm::opt::Arg *depInfo = parsedArgs.getLastArg(OPT_dependency_info))
+ if (std::error_code ec = ctx.createDependencyFile(depInfo->getValue()))
+ warn(ec.message() + ", processing '-dependency_info " +
+ depInfo->getValue());
// In -test_file_usage mode, we'll be given an explicit list of paths that
// exist. We'll also be expected to print out information about how we located
@@ -639,31 +635,28 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// Now that we've constructed the final set of search paths, print out those
// search paths in verbose mode.
- if (parsedArgs.getLastArg(OPT_v)) {
- diagnostics << "Library search paths:\n";
+ if (errorHandler().Verbose) {
+ message("Library search paths:");
for (auto path : ctx.searchDirs()) {
- diagnostics << " " << path << '\n';
+ message(" " + path);
}
- diagnostics << "Framework search paths:\n";
+ message("Framework search paths:");
for (auto path : ctx.frameworkDirs()) {
- diagnostics << " " << path << '\n';
+ message(" " + path);
}
}
// Handle -exported_symbols_list <file>
for (auto expFile : parsedArgs.filtered(OPT_exported_symbols_list)) {
if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
- diagnostics << "error: -exported_symbols_list cannot be combined "
- << "with -unexported_symbol[s_list]\n";
- return false;
+ error("-exported_symbols_list cannot be combined with "
+ "-unexported_symbol[s_list]");
+ return false;
}
ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
- if (std::error_code ec = parseExportsList(expFile->getValue(), ctx,
- diagnostics)) {
- diagnostics << "error: " << ec.message()
- << ", processing '-exported_symbols_list "
- << expFile->getValue()
- << "'\n";
+ if (std::error_code ec = parseExportsList(expFile->getValue(), ctx)) {
+ error(ec.message() + ", processing '-exported_symbols_list " +
+ expFile->getValue());
return false;
}
}
@@ -671,9 +664,9 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// Handle -exported_symbol <symbol>
for (auto symbol : parsedArgs.filtered(OPT_exported_symbol)) {
if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
- diagnostics << "error: -exported_symbol cannot be combined "
- << "with -unexported_symbol[s_list]\n";
- return false;
+ error("-exported_symbol cannot be combined with "
+ "-unexported_symbol[s_list]");
+ return false;
}
ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
ctx.addExportSymbol(symbol->getValue());
@@ -682,17 +675,14 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// Handle -unexported_symbols_list <file>
for (auto expFile : parsedArgs.filtered(OPT_unexported_symbols_list)) {
if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
- diagnostics << "error: -unexported_symbols_list cannot be combined "
- << "with -exported_symbol[s_list]\n";
- return false;
+ error("-unexported_symbols_list cannot be combined with "
+ "-exported_symbol[s_list]");
+ return false;
}
ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
- if (std::error_code ec = parseExportsList(expFile->getValue(), ctx,
- diagnostics)) {
- diagnostics << "error: " << ec.message()
- << ", processing '-unexported_symbols_list "
- << expFile->getValue()
- << "'\n";
+ if (std::error_code ec = parseExportsList(expFile->getValue(), ctx)) {
+ error(ec.message() + ", processing '-unexported_symbols_list " +
+ expFile->getValue());
return false;
}
}
@@ -700,9 +690,9 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// Handle -unexported_symbol <symbol>
for (auto symbol : parsedArgs.filtered(OPT_unexported_symbol)) {
if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
- diagnostics << "error: -unexported_symbol cannot be combined "
- << "with -exported_symbol[s_list]\n";
- return false;
+ error("-unexported_symbol cannot be combined with "
+ "-exported_symbol[s_list]");
+ return false;
}
ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
ctx.addExportSymbol(symbol->getValue());
@@ -711,30 +701,26 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// Handle obosolete -multi_module and -single_module
if (llvm::opt::Arg *mod =
parsedArgs.getLastArg(OPT_multi_module, OPT_single_module)) {
- if (mod->getOption().getID() == OPT_multi_module) {
- diagnostics << "warning: -multi_module is obsolete and being ignored\n";
- }
- else {
- if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
- diagnostics << "warning: -single_module being ignored. "
- "It is only for use when producing a dylib\n";
- }
- }
+ if (mod->getOption().getID() == OPT_multi_module)
+ warn("-multi_module is obsolete and being ignored");
+ else if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB)
+ warn("-single_module being ignored. It is only for use when producing a "
+ "dylib");
}
// Handle obsolete ObjC options: -objc_gc_compaction, -objc_gc, -objc_gc_only
if (parsedArgs.getLastArg(OPT_objc_gc_compaction)) {
- diagnostics << "error: -objc_gc_compaction is not supported\n";
+ error("-objc_gc_compaction is not supported");
return false;
}
if (parsedArgs.getLastArg(OPT_objc_gc)) {
- diagnostics << "error: -objc_gc is not supported\n";
+ error("-objc_gc is not supported");
return false;
}
if (parsedArgs.getLastArg(OPT_objc_gc_only)) {
- diagnostics << "error: -objc_gc_only is not supported\n";
+ error("-objc_gc_only is not supported");
return false;
}
@@ -746,22 +732,20 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
case MachOLinkingContext::OS::macOSX:
if ((minOSVersion < 0x000A0500) &&
(pie->getOption().getID() == OPT_pie)) {
- diagnostics << "-pie can only be used when targeting "
- "Mac OS X 10.5 or later\n";
+ error("-pie can only be used when targeting Mac OS X 10.5 or later");
return false;
}
break;
case MachOLinkingContext::OS::iOS:
if ((minOSVersion < 0x00040200) &&
(pie->getOption().getID() == OPT_pie)) {
- diagnostics << "-pie can only be used when targeting "
- "iOS 4.2 or later\n";
+ error("-pie can only be used when targeting iOS 4.2 or later");
return false;
}
break;
case MachOLinkingContext::OS::iOS_simulator:
if (pie->getOption().getID() == OPT_no_pie) {
- diagnostics << "iOS simulator programs must be built PIE\n";
+ error("iOS simulator programs must be built PIE");
return false;
}
break;
@@ -774,12 +758,12 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
break;
case llvm::MachO::MH_DYLIB:
case llvm::MachO::MH_BUNDLE:
- diagnostics << "warning: " << pie->getSpelling() << " being ignored. "
- << "It is only used when linking main executables\n";
+ warn(pie->getSpelling() +
+ " being ignored. It is only used when linking main executables");
break;
default:
- diagnostics << pie->getSpelling()
- << " can only used when linking main executables\n";
+ error(pie->getSpelling() +
+ " can only used when linking main executables");
return false;
}
}
@@ -934,7 +918,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
uint32_t sdkVersion = 0;
if (MachOLinkingContext::parsePackedVersion(arg->getValue(),
sdkVersion)) {
- diagnostics << "error: malformed sdkVersion value\n";
+ error("malformed sdkVersion value");
return false;
}
ctx.setSdkVersion(sdkVersion);
@@ -943,9 +927,8 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// with min_version, then we need to give an warning as we have no sdk
// version to put in that command.
// FIXME: We need to decide whether to make this an error.
- diagnostics << "warning: -sdk_version is required when emitting "
- "min version load command. "
- "Setting sdk version to match provided min version\n";
+ warn("-sdk_version is required when emitting min version load command. "
+ "Setting sdk version to match provided min version");
ctx.setSdkVersion(ctx.osMinVersion());
}
@@ -954,7 +937,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
uint64_t version = 0;
if (MachOLinkingContext::parsePackedVersion(arg->getValue(),
version)) {
- diagnostics << "error: malformed source_version value\n";
+ error("malformed source_version value");
return false;
}
ctx.setSourceVersion(version);
@@ -964,12 +947,12 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
if (llvm::opt::Arg *stackSize = parsedArgs.getLastArg(OPT_stack_size)) {
uint64_t stackSizeVal;
if (parseNumberBase16(stackSize->getValue(), stackSizeVal)) {
- diagnostics << "error: stack_size expects a hex number\n";
+ error("stack_size expects a hex number");
return false;
}
if ((stackSizeVal % ctx.pageSize()) != 0) {
- diagnostics << "error: stack_size must be a multiple of page size ("
- << "0x" << llvm::utohexstr(ctx.pageSize()) << ")\n";
+ error("stack_size must be a multiple of page size (0x" +
+ llvm::utohexstr(ctx.pageSize()) + ")");
return false;
}
@@ -982,12 +965,9 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// Handle -order_file <file>
for (auto orderFile : parsedArgs.filtered(OPT_order_file)) {
- if (std::error_code ec = parseOrderFile(orderFile->getValue(), ctx,
- diagnostics)) {
- diagnostics << "error: " << ec.message()
- << ", processing '-order_file "
- << orderFile->getValue()
- << "'\n";
+ if (std::error_code ec = parseOrderFile(orderFile->getValue(), ctx)) {
+ error(ec.message() + ", processing '-order_file " + orderFile->getValue()
+ + "'");
return false;
}
}
@@ -1011,8 +991,8 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
else if (StringRef(undef->getValue()).equals("dynamic_lookup"))
UndefMode = MachOLinkingContext::UndefinedMode::dynamicLookup;
else {
- diagnostics << "error: invalid option to -undefined "
- "[ warning | error | suppress | dynamic_lookup ]\n";
+ error("invalid option to -undefined [ warning | error | suppress | "
+ "dynamic_lookup ]");
return false;
}
@@ -1026,8 +1006,8 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
// illegal. Emit a diagnostic if they've been (mis)used.
if (UndefMode == MachOLinkingContext::UndefinedMode::warning ||
UndefMode == MachOLinkingContext::UndefinedMode::suppress) {
- diagnostics << "error: can't use -undefined warning or suppress with "
- "-twolevel_namespace\n";
+ error("can't use -undefined warning or suppress with "
+ "-twolevel_namespace");
return false;
}
}
@@ -1046,19 +1026,16 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
case llvm::MachO::MH_DYLIB:
case llvm::MachO::MH_BUNDLE:
if (!ctx.minOS("10.5", "2.0")) {
- if (ctx.os() == MachOLinkingContext::OS::macOSX) {
- diagnostics << "error: -rpath can only be used when targeting "
- "OS X 10.5 or later\n";
- } else {
- diagnostics << "error: -rpath can only be used when targeting "
- "iOS 2.0 or later\n";
- }
+ if (ctx.os() == MachOLinkingContext::OS::macOSX)
+ error("-rpath can only be used when targeting OS X 10.5 or later");
+ else
+ error("-rpath can only be used when targeting iOS 2.0 or later");
return false;
}
break;
default:
- diagnostics << "error: -rpath can only be used when creating "
- "a dynamic final linked image\n";
+ error("-rpath can only be used when creating a dynamic final linked "
+ "image");
return false;
}
@@ -1068,7 +1045,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
}
// Parse the LLVM options before we process files in case the file handling
- // makes use of things like DEBUG().
+ // makes use of things like LLVM_DEBUG().
parseLLVMOptions(ctx);
// Handle input files and sectcreate.
@@ -1079,52 +1056,46 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
default:
continue;
case OPT_INPUT:
- addFile(arg->getValue(), ctx, globalWholeArchive, false, diagnostics);
+ addFile(arg->getValue(), ctx, globalWholeArchive, false);
break;
case OPT_upward_library:
- addFile(arg->getValue(), ctx, false, true, diagnostics);
+ addFile(arg->getValue(), ctx, false, true);
break;
case OPT_force_load:
- addFile(arg->getValue(), ctx, true, false, diagnostics);
+ addFile(arg->getValue(), ctx, true, false);
break;
case OPT_l:
case OPT_upward_l:
upward = (arg->getOption().getID() == OPT_upward_l);
resolvedPath = ctx.searchLibrary(arg->getValue());
if (!resolvedPath) {
- diagnostics << "Unable to find library for " << arg->getSpelling()
- << arg->getValue() << "\n";
+ error("Unable to find library for " + arg->getSpelling() +
+ arg->getValue());
return false;
} else if (ctx.testingFileUsage()) {
- diagnostics << "Found " << (upward ? "upward " : " ") << "library "
- << canonicalizePath(resolvedPath.getValue()) << '\n';
+ message(Twine("Found ") + (upward ? "upward " : " ") + "library " +
+ canonicalizePath(resolvedPath.getValue()));
}
- addFile(resolvedPath.getValue(), ctx, globalWholeArchive,
- upward, diagnostics);
+ addFile(resolvedPath.getValue(), ctx, globalWholeArchive, upward);
break;
case OPT_framework:
case OPT_upward_framework:
upward = (arg->getOption().getID() == OPT_upward_framework);
resolvedPath = ctx.findPathForFramework(arg->getValue());
if (!resolvedPath) {
- diagnostics << "Unable to find framework for "
- << arg->getSpelling() << " " << arg->getValue() << "\n";
+ error("Unable to find framework for " + arg->getSpelling() + " " +
+ arg->getValue());
return false;
} else if (ctx.testingFileUsage()) {
- diagnostics << "Found " << (upward ? "upward " : " ") << "framework "
- << canonicalizePath(resolvedPath.getValue()) << '\n';
+ message(Twine("Found ") + (upward ? "upward " : " ") + "framework " +
+ canonicalizePath(resolvedPath.getValue()));
}
- addFile(resolvedPath.getValue(), ctx, globalWholeArchive,
- upward, diagnostics);
+ addFile(resolvedPath.getValue(), ctx, globalWholeArchive, upward);
break;
case OPT_filelist:
- if (auto ec = loadFileList(arg->getValue(),
- ctx, globalWholeArchive,
- diagnostics)) {
+ if (auto ec = loadFileList(arg->getValue(), ctx, globalWholeArchive)) {
handleAllErrors(std::move(ec), [&](const llvm::ErrorInfoBase &EI) {
- diagnostics << "error: ";
- EI.log(diagnostics);
- diagnostics << ", processing '-filelist " << arg->getValue() << "'\n";
+ error(EI.message() + ", processing '-filelist " + arg->getValue());
});
return false;
}
@@ -1138,7 +1109,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
MemoryBuffer::getFile(fileName);
if (!contentOrErr) {
- diagnostics << "error: can't open -sectcreate file " << fileName << "\n";
+ error("can't open -sectcreate file " + Twine(fileName));
return false;
}
@@ -1149,12 +1120,12 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
}
if (ctx.getNodes().empty()) {
- diagnostics << "No input files\n";
+ error("No input files");
return false;
}
// Validate the combination of options used.
- return ctx.validate(diagnostics);
+ return ctx.validate();
}
static void createFiles(MachOLinkingContext &ctx, bool Implicit) {
@@ -1170,9 +1141,18 @@ static void createFiles(MachOLinkingContext &ctx, bool Implicit) {
}
/// This is where the link is actually performed.
-bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) {
+bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly,
+ raw_ostream &Error) {
+ errorHandler().LogName = llvm::sys::path::filename(args[0]);
+ errorHandler().ErrorLimitExceededMsg =
+ "too many errors emitted, stopping now (use "
+ "'-error-limit 0' to see all errors)";
+ errorHandler().ErrorOS = &Error;
+ errorHandler().ExitEarly = CanExitEarly;
+ errorHandler().ColorDiagnostics = Error.has_colors();
+
MachOLinkingContext ctx;
- if (!parse(args, ctx, diagnostics))
+ if (!parse(args, ctx))
return false;
if (ctx.doNothing())
return true;
@@ -1214,9 +1194,10 @@ bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) {
if (auto ec = pm.runOnFile(*merged)) {
// FIXME: This should be passed to logAllUnhandledErrors but it needs
// to be passed a Twine instead of a string.
- diagnostics << "Failed to run passes on file '" << ctx.outputPath()
- << "': ";
- logAllUnhandledErrors(std::move(ec), diagnostics, std::string());
+ *errorHandler().ErrorOS << "Failed to run passes on file '"
+ << ctx.outputPath() << "': ";
+ logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS,
+ std::string());
return false;
}
@@ -1227,11 +1208,18 @@ bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) {
if (auto ec = ctx.writeFile(*merged)) {
// FIXME: This should be passed to logAllUnhandledErrors but it needs
// to be passed a Twine instead of a string.
- diagnostics << "Failed to write file '" << ctx.outputPath() << "': ";
- logAllUnhandledErrors(std::move(ec), diagnostics, std::string());
+ *errorHandler().ErrorOS << "Failed to write file '" << ctx.outputPath()
+ << "': ";
+ logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS,
+ std::string());
return false;
}
+ // Call exit() if we can to avoid calling destructors.
+ if (CanExitEarly)
+ exitLld(errorCount() ? 1 : 0);
+
+
return true;
}
diff --git a/contrib/llvm/tools/lld/lib/Driver/DarwinLdOptions.td b/contrib/llvm/tools/lld/lib/Driver/DarwinLdOptions.td
index fa07f33646e7..3bbde8bf1c1c 100644
--- a/contrib/llvm/tools/lld/lib/Driver/DarwinLdOptions.td
+++ b/contrib/llvm/tools/lld/lib/Driver/DarwinLdOptions.td
@@ -227,6 +227,14 @@ def t : Flag<["-"], "t">,
HelpText<"Print the names of the input files as ld processes them">;
def v : Flag<["-"], "v">,
HelpText<"Print linker information">;
+def error_limit : Separate<["-", "--"], "error-limit">,
+ MetaVarName<"<number>">,
+ HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">;
+
+// Ignored options
+def lto_library : Separate<["-"], "lto_library">,
+ MetaVarName<"<path>">,
+ HelpText<"Ignored for compatibility with other linkers">;
// Obsolete options
def grp_obsolete : OptionGroup<"obsolete">, HelpText<"OBSOLETE OPTIONS">;
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp
index 04c0bee76989..2f52d9d34312 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp
@@ -38,7 +38,7 @@ namespace lld {
namespace {
-/// \brief The FileArchive class represents an Archive Library file
+/// The FileArchive class represents an Archive Library file
class FileArchive : public lld::ArchiveLibraryFile {
public:
FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
@@ -46,7 +46,7 @@ public:
: ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())),
_registry(reg), _logLoading(logLoading) {}
- /// \brief Check if any member of the archive contains an Atom with the
+ /// Check if any member of the archive contains an Atom with the
/// specified name and return the File object for that member, or nullptr.
File *find(StringRef name) override {
auto member = _symbolMemberMap.find(name);
@@ -77,7 +77,7 @@ public:
return file;
}
- /// \brief parse each member
+ /// parse each member
std::error_code
parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
if (std::error_code ec = parse())
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
index aee9959ca6b8..8cb6710857e3 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
@@ -674,7 +674,7 @@ void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
*loc32 = ref.addend() + inAtomAddress - fixupAddress;
return;
case delta32Anon:
- // The value we write here should be the the delta to the target
+ // The value we write here should be the delta to the target
// after taking in to account the difference from the fixup back to the
// last defined label
// ie, if we have:
@@ -690,7 +690,7 @@ void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
*loc64 = ref.addend() + inAtomAddress - fixupAddress;
return;
case delta64Anon:
- // The value we write here should be the the delta to the target
+ // The value we write here should be the delta to the target
// after taking in to account the difference from the fixup back to the
// last defined label
// ie, if we have:
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CMakeLists.txt b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CMakeLists.txt
index f2fc34772496..37d1de432c0f 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CMakeLists.txt
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CMakeLists.txt
@@ -26,6 +26,7 @@ add_lld_library(lldMachO
Support
LINK_LIBS
+ lldCommon
lldCore
lldYAML
${LLVM_PTHREAD_LIB}
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
index 1e210409237f..fa0aaa103eeb 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
@@ -282,7 +282,7 @@ public:
private:
llvm::Error perform(SimpleFile &mergedFile) override {
- DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n");
+ LLVM_DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n");
std::map<const Atom *, CompactUnwindEntry> unwindLocs;
std::map<const Atom *, const Atom *> dwarfFrames;
@@ -319,7 +319,7 @@ private:
// Finally, we can start creating pages based on these entries.
- DEBUG(llvm::dbgs() << " Splitting entries into pages\n");
+ LLVM_DEBUG(llvm::dbgs() << " Splitting entries into pages\n");
// FIXME: we split the entries into pages naively: lots of 4k pages followed
// by a small one. ld64 tried to minimize space and align them to real 4k
// boundaries. That might be worth doing, or perhaps we could perform some
@@ -336,11 +336,13 @@ private:
pages.back().entries = remainingInfos.slice(0, entriesInPage);
remainingInfos = remainingInfos.slice(entriesInPage);
- DEBUG(llvm::dbgs()
- << " Page from " << pages.back().entries[0].rangeStart->name()
- << " to " << pages.back().entries.back().rangeStart->name() << " + "
- << llvm::format("0x%x", pages.back().entries.back().rangeLength)
- << " has " << entriesInPage << " entries\n");
+ LLVM_DEBUG(llvm::dbgs()
+ << " Page from "
+ << pages.back().entries[0].rangeStart->name() << " to "
+ << pages.back().entries.back().rangeStart->name() << " + "
+ << llvm::format("0x%x",
+ pages.back().entries.back().rangeLength)
+ << " has " << entriesInPage << " entries\n");
} while (!remainingInfos.empty());
auto *unwind = new (_file.allocator())
@@ -360,7 +362,7 @@ private:
const SimpleFile &mergedFile,
std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
std::vector<const Atom *> &personalities, uint32_t &numLSDAs) {
- DEBUG(llvm::dbgs() << " Collecting __compact_unwind entries\n");
+ LLVM_DEBUG(llvm::dbgs() << " Collecting __compact_unwind entries\n");
for (const DefinedAtom *atom : mergedFile.defined()) {
if (atom->contentType() != DefinedAtom::typeCompactUnwindInfo)
@@ -369,14 +371,15 @@ private:
auto unwindEntry = extractCompactUnwindEntry(atom);
unwindLocs.insert(std::make_pair(unwindEntry.rangeStart, unwindEntry));
- DEBUG(llvm::dbgs() << " Entry for " << unwindEntry.rangeStart->name()
- << ", encoding="
- << llvm::format("0x%08x", unwindEntry.encoding));
+ LLVM_DEBUG(llvm::dbgs() << " Entry for "
+ << unwindEntry.rangeStart->name() << ", encoding="
+ << llvm::format("0x%08x", unwindEntry.encoding));
if (unwindEntry.personalityFunction)
- DEBUG(llvm::dbgs() << ", personality="
- << unwindEntry.personalityFunction->name()
- << ", lsdaLoc=" << unwindEntry.lsdaLocation->name());
- DEBUG(llvm::dbgs() << '\n');
+ LLVM_DEBUG(llvm::dbgs()
+ << ", personality="
+ << unwindEntry.personalityFunction->name()
+ << ", lsdaLoc=" << unwindEntry.lsdaLocation->name());
+ LLVM_DEBUG(llvm::dbgs() << '\n');
// Count number of LSDAs we see, since we need to know how big the index
// will be while laying out the section.
@@ -454,7 +457,7 @@ private:
const std::map<const Atom *, const Atom *> &dwarfFrames) {
std::vector<CompactUnwindEntry> unwindInfos;
- DEBUG(llvm::dbgs() << " Creating __unwind_info entries\n");
+ LLVM_DEBUG(llvm::dbgs() << " Creating __unwind_info entries\n");
// The final order in the __unwind_info section must be derived from the
// order of typeCode atoms, since that's how they'll be put into the object
// file eventually (yuck!).
@@ -465,10 +468,10 @@ private:
unwindInfos.push_back(finalizeUnwindInfoEntryForAtom(
atom, unwindLocs, personalities, dwarfFrames));
- DEBUG(llvm::dbgs() << " Entry for " << atom->name()
- << ", final encoding="
- << llvm::format("0x%08x", unwindInfos.back().encoding)
- << '\n');
+ LLVM_DEBUG(llvm::dbgs()
+ << " Entry for " << atom->name() << ", final encoding="
+ << llvm::format("0x%08x", unwindInfos.back().encoding)
+ << '\n');
}
return unwindInfos;
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.cpp
index 7bca07eb16d6..9058e4f562e2 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.cpp
@@ -191,7 +191,7 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc,
// Sort atoms by their ordinal overrides only if they fall in the same
// chain.
if (leftRoot == rightRoot) {
- DEBUG(reason = formatReason("override", lc._override, rc._override));
+ LLVM_DEBUG(reason = formatReason("override", lc._override, rc._override));
return lc._override < rc._override;
}
@@ -200,8 +200,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc,
DefinedAtom::ContentPermissions rightPerms = rightRoot->permissions();
if (leftPerms != rightPerms) {
- DEBUG(reason =
- formatReason("contentPerms", (int)leftPerms, (int)rightPerms));
+ LLVM_DEBUG(
+ reason = formatReason("contentPerms", (int)leftPerms, (int)rightPerms));
return leftPerms < rightPerms;
}
@@ -210,7 +210,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc,
DefinedAtom::ContentType rightType = rightRoot->contentType();
if (leftType != rightType) {
- DEBUG(reason = formatReason("contentType", (int)leftType, (int)rightType));
+ LLVM_DEBUG(reason =
+ formatReason("contentType", (int)leftType, (int)rightType));
return leftType < rightType;
}
@@ -226,8 +227,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc,
const File *rightFile = &rightRoot->file();
if (leftFile != rightFile) {
- DEBUG(reason = formatReason(".o order", (int)leftFile->ordinal(),
- (int)rightFile->ordinal()));
+ LLVM_DEBUG(reason = formatReason(".o order", (int)leftFile->ordinal(),
+ (int)rightFile->ordinal()));
return leftFile->ordinal() < rightFile->ordinal();
}
@@ -236,8 +237,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc,
uint64_t rightOrdinal = rightRoot->ordinal();
if (leftOrdinal != rightOrdinal) {
- DEBUG(reason = formatReason("ordinal", (int)leftRoot->ordinal(),
- (int)rightRoot->ordinal()));
+ LLVM_DEBUG(reason = formatReason("ordinal", (int)leftRoot->ordinal(),
+ (int)rightRoot->ordinal()));
return leftOrdinal < rightOrdinal;
}
@@ -251,7 +252,7 @@ static bool compareAtoms(const LayoutPass::SortKey &lc,
LayoutPass::SortOverride customSorter) {
std::string reason;
bool result = compareAtomsSub(lc, rc, customSorter, reason);
- DEBUG({
+ LLVM_DEBUG({
StringRef comp = result ? "<" : ">=";
llvm::dbgs() << "Layout: '" << lc._atom.get()->name()
<< "' " << comp << " '"
@@ -441,7 +442,7 @@ void LayoutPass::undecorate(File::AtomRange<DefinedAtom> &atomRange,
/// Perform the actual pass
llvm::Error LayoutPass::perform(SimpleFile &mergedFile) {
- DEBUG(llvm::dbgs() << "******** Laying out atoms:\n");
+ LLVM_DEBUG(llvm::dbgs() << "******** Laying out atoms:\n");
// sort the atoms
ScopedTask task(getDefaultDomain(), "LayoutPass");
File::AtomRange<DefinedAtom> atomRange = mergedFile.defined();
@@ -450,12 +451,12 @@ llvm::Error LayoutPass::perform(SimpleFile &mergedFile) {
buildFollowOnTable(atomRange);
// Check the structure of followon graph if running in debug mode.
- DEBUG(checkFollowonChain(atomRange));
+ LLVM_DEBUG(checkFollowonChain(atomRange));
// Build override maps
buildOrdinalOverrideMap(atomRange);
- DEBUG({
+ LLVM_DEBUG({
llvm::dbgs() << "unsorted atoms:\n";
printDefinedAtoms(atomRange);
});
@@ -465,15 +466,15 @@ llvm::Error LayoutPass::perform(SimpleFile &mergedFile) {
[&](const LayoutPass::SortKey &l, const LayoutPass::SortKey &r) -> bool {
return compareAtoms(l, r, _customSorter);
});
- DEBUG(checkTransitivity(vec, _customSorter));
+ LLVM_DEBUG(checkTransitivity(vec, _customSorter));
undecorate(atomRange, vec);
- DEBUG({
+ LLVM_DEBUG({
llvm::dbgs() << "sorted atoms:\n";
printDefinedAtoms(atomRange);
});
- DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n");
+ LLVM_DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n");
return llvm::Error::success();
}
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
index 4ef7a62a8297..ce423d03aae3 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "lld/Common/ErrorHandler.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
#include "ArchHandler.h"
#include "File.h"
@@ -579,29 +580,26 @@ MachOLinkingContext::findPathForFramework(StringRef fwName) const{
return llvm::None;
}
-bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
+bool MachOLinkingContext::validateImpl() {
// TODO: if -arch not specified, look at arch of first .o file.
if (_currentVersion && _outputMachOType != MH_DYLIB) {
- diagnostics << "error: -current_version can only be used with dylibs\n";
+ error("-current_version can only be used with dylibs");
return false;
}
if (_compatibilityVersion && _outputMachOType != MH_DYLIB) {
- diagnostics
- << "error: -compatibility_version can only be used with dylibs\n";
+ error("-compatibility_version can only be used with dylibs");
return false;
}
if (_deadStrippableDylib && _outputMachOType != MH_DYLIB) {
- diagnostics
- << "error: -mark_dead_strippable_dylib can only be used with dylibs.\n";
+ error("-mark_dead_strippable_dylib can only be used with dylibs");
return false;
}
if (!_bundleLoader.empty() && outputMachOType() != MH_BUNDLE) {
- diagnostics
- << "error: -bundle_loader can only be used with Mach-O bundles\n";
+ error("-bundle_loader can only be used with Mach-O bundles");
return false;
}
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
index 3b07a40f9bf2..473de894894e 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
@@ -906,7 +906,7 @@ readCompUnit(const NormalizedFile &normalizedFile,
abbrevData.getU8(&abbrevOffset);
uint32_t name;
llvm::dwarf::Form form;
- llvm::DWARFFormParams formParams = {version, addrSize, Format};
+ llvm::dwarf::FormParams formParams = {version, addrSize, Format};
TranslationUnitSource tu;
while ((name = abbrevData.getULEB128(&abbrevOffset)) |
(form = static_cast<llvm::dwarf::Form>(
@@ -1431,8 +1431,8 @@ llvm::Error
normalizedObjectToAtoms(MachOFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs) {
- DEBUG(llvm::dbgs() << "******** Normalizing file to atoms: "
- << file->path() << "\n");
+ LLVM_DEBUG(llvm::dbgs() << "******** Normalizing file to atoms: "
+ << file->path() << "\n");
bool scatterable = ((normalizedFile.flags & MH_SUBSECTIONS_VIA_SYMBOLS) != 0);
// Create atoms from each section.
diff --git a/contrib/llvm/tools/lld/tools/lld/lld.cpp b/contrib/llvm/tools/lld/tools/lld/lld.cpp
index fa4bf6f64328..65a9a800ec7a 100644
--- a/contrib/llvm/tools/lld/tools/lld/lld.cpp
+++ b/contrib/llvm/tools/lld/tools/lld/lld.cpp
@@ -7,12 +7,22 @@
//
//===----------------------------------------------------------------------===//
//
-// This is the entry point to the lld driver. This is a thin wrapper which
-// dispatches to the given platform specific driver.
+// This file contains the main function of the lld executable. The main
+// function is a thin wrapper which dispatches to the platform specific
+// driver.
//
-// If there is -flavor option, it is dispatched according to the arguments.
-// If the flavor parameter is not present, then it is dispatched according
-// to argv[0].
+// lld is a single executable that contains four different linkers for ELF,
+// COFF, WebAssembly and Mach-O. The main function dispatches according to
+// argv[0] (i.e. command name). The most common name for each target is shown
+// below:
+//
+// - ld.lld: ELF (Unix)
+// - ld64: Mach-O (macOS)
+// - lld-link: COFF (Windows)
+// - ld-wasm: WebAssembly
+//
+// lld can be invoked as "lld" along with "-flavor" option. This is for
+// backward compatibility and not recommended.
//
//===----------------------------------------------------------------------===//
@@ -20,10 +30,9 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Signals.h"
+#include <cstdlib>
using namespace lld;
using namespace llvm;
@@ -102,13 +111,18 @@ static Flavor parseFlavor(std::vector<const char *> &V) {
return parseProgname(Arg0);
}
+// If this function returns true, lld calls _exit() so that it quickly
+// exits without invoking destructors of globally allocated objects.
+//
+// We don't want to do that if we are running tests though, because
+// doing that breaks leak sanitizer. So, lit sets this environment variable,
+// and we use it to detect whether we are running tests or not.
+static bool canExitEarly() { return StringRef(getenv("LLD_IN_TEST")) != "1"; }
+
/// Universal linker main(). This linker emulates the gnu, darwin, or
/// windows linker based on the argv[0] or -flavor option.
int main(int Argc, const char **Argv) {
- // Standard set up, so program fails gracefully.
- sys::PrintStackTraceOnErrorSignal(Argv[0]);
- PrettyStackTraceProgram StackPrinter(Argc, Argv);
- llvm_shutdown_obj Shutdown;
+ InitLLVM X(Argc, Argv);
std::vector<const char *> Args(Argv, Argv + Argc);
#ifdef __FreeBSD__
@@ -118,16 +132,17 @@ int main(int Argc, const char **Argv) {
case Gnu:
if (isPETarget(Args))
return !mingw::link(Args);
- return !elf::link(Args, true);
+ return !elf::link(Args, canExitEarly());
case WinLink:
- return !coff::link(Args, true);
+ return !coff::link(Args, canExitEarly());
case Darwin:
- return !mach_o::link(Args);
+ return !mach_o::link(Args, canExitEarly());
case Wasm:
- return !wasm::link(Args, true);
+ return !wasm::link(Args, canExitEarly());
default:
die("lld is a generic driver.\n"
- "Invoke ld.lld (Unix), ld (macOS) or lld-link (Windows) instead.");
+ "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-lld"
+ " (WebAssembly) instead");
}
#endif
}