Vendor import of lld trunk r300890:
https://llvm.org/svn/llvm-project/lld/trunk@300890
This commit is contained in:
parent
d2d3ebb819
commit
be08ec9606
@ -509,7 +509,7 @@ filterBitcodeFiles(StringRef Path, std::vector<std::string> &TemporaryFiles) {
|
||||
|
||||
// Create response file contents and invoke the MSVC linker.
|
||||
void LinkerDriver::invokeMSVC(opt::InputArgList &Args) {
|
||||
std::string Rsp = "/nologo ";
|
||||
std::string Rsp = "/nologo\n";
|
||||
std::vector<std::string> Temps;
|
||||
|
||||
for (auto *Arg : Args) {
|
||||
@ -528,14 +528,14 @@ void LinkerDriver::invokeMSVC(opt::InputArgList &Args) {
|
||||
case OPT_INPUT: {
|
||||
if (Optional<StringRef> Path = doFindFile(Arg->getValue())) {
|
||||
if (Optional<std::string> S = filterBitcodeFiles(*Path, Temps))
|
||||
Rsp += quote(*S) + " ";
|
||||
Rsp += quote(*S) + "\n";
|
||||
continue;
|
||||
}
|
||||
Rsp += quote(Arg->getValue()) + " ";
|
||||
Rsp += quote(Arg->getValue()) + "\n";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Rsp += toString(Arg) + " ";
|
||||
Rsp += toString(Arg) + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -634,7 +634,7 @@ void runMSVCLinker(std::string Rsp, ArrayRef<StringRef> Objects) {
|
||||
std::vector<TemporaryFile> Temps;
|
||||
for (StringRef S : Objects) {
|
||||
Temps.emplace_back("lto", "obj", S);
|
||||
Rsp += quote(Temps.back().Path) + " ";
|
||||
Rsp += quote(Temps.back().Path) + "\n";
|
||||
}
|
||||
|
||||
log("link.exe " + Rsp);
|
||||
|
@ -104,6 +104,7 @@ struct Configuration {
|
||||
bool Bsymbolic;
|
||||
bool BsymbolicFunctions;
|
||||
bool ColorDiagnostics = false;
|
||||
bool CompressDebugSections;
|
||||
bool DefineCommon;
|
||||
bool Demangle = true;
|
||||
bool DisableVerify;
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Object/Decompressor.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Compression.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/TarWriter.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
@ -564,12 +565,24 @@ static std::vector<StringRef> getLines(MemoryBufferRef MB) {
|
||||
return Ret;
|
||||
}
|
||||
|
||||
static bool getCompressDebugSections(opt::InputArgList &Args) {
|
||||
if (auto *Arg = Args.getLastArg(OPT_compress_debug_sections)) {
|
||||
StringRef S = Arg->getValue();
|
||||
if (S == "zlib")
|
||||
return zlib::isAvailable();
|
||||
if (S != "none")
|
||||
error("unknown --compress-debug-sections value: " + S);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initializes Config members by the command line options.
|
||||
void LinkerDriver::readConfigs(opt::InputArgList &Args) {
|
||||
Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
|
||||
Config->AuxiliaryList = getArgs(Args, OPT_auxiliary);
|
||||
Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
|
||||
Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
|
||||
Config->CompressDebugSections = getCompressDebugSections(Args);
|
||||
Config->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common,
|
||||
!Args.hasArg(OPT_relocatable));
|
||||
Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true);
|
||||
|
@ -413,6 +413,56 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) {
|
||||
CurOutSec = nullptr;
|
||||
}
|
||||
|
||||
void LinkerScript::fabricateDefaultCommands(bool AllocateHeader) {
|
||||
std::vector<BaseCommand *> Commands;
|
||||
|
||||
// Define start address
|
||||
uint64_t StartAddr = Config->ImageBase;
|
||||
if (AllocateHeader)
|
||||
StartAddr += elf::getHeaderSize();
|
||||
|
||||
// The Sections with -T<section> are sorted in order of ascending address
|
||||
// we must use this if it is lower than StartAddr as calls to setDot() must
|
||||
// be monotonically increasing
|
||||
if (!Config->SectionStartMap.empty()) {
|
||||
uint64_t LowestSecStart = Config->SectionStartMap.begin()->second;
|
||||
StartAddr = std::min(StartAddr, LowestSecStart);
|
||||
}
|
||||
Commands.push_back(
|
||||
make<SymbolAssignment>(".", [=] { return StartAddr; }, ""));
|
||||
|
||||
// For each OutputSection that needs a VA fabricate an OutputSectionCommand
|
||||
// with an InputSectionDescription describing the InputSections
|
||||
for (OutputSection *Sec : *OutputSections) {
|
||||
if (!(Sec->Flags & SHF_ALLOC))
|
||||
continue;
|
||||
|
||||
auto I = Config->SectionStartMap.find(Sec->Name);
|
||||
if (I != Config->SectionStartMap.end())
|
||||
Commands.push_back(
|
||||
make<SymbolAssignment>(".", [=] { return I->second; }, ""));
|
||||
|
||||
auto *OSCmd = make<OutputSectionCommand>(Sec->Name);
|
||||
OSCmd->Sec = Sec;
|
||||
if (Sec->PageAlign)
|
||||
OSCmd->AddrExpr = [=] {
|
||||
return alignTo(Script->getDot(), Config->MaxPageSize);
|
||||
};
|
||||
Commands.push_back(OSCmd);
|
||||
if (Sec->Sections.size()) {
|
||||
auto *ISD = make<InputSectionDescription>("");
|
||||
OSCmd->Commands.push_back(ISD);
|
||||
for (InputSection *ISec : Sec->Sections) {
|
||||
ISD->Sections.push_back(ISec);
|
||||
ISec->Assigned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// SECTIONS commands run before other non SECTIONS commands
|
||||
Commands.insert(Commands.end(), Opt.Commands.begin(), Opt.Commands.end());
|
||||
Opt.Commands = std::move(Commands);
|
||||
}
|
||||
|
||||
// Add sections that didn't match any sections command.
|
||||
void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
|
||||
for (InputSectionBase *S : InputSections)
|
||||
|
@ -256,6 +256,7 @@ class LinkerScript {
|
||||
bool isDefined(StringRef S);
|
||||
|
||||
std::vector<OutputSection *> *OutputSections;
|
||||
void fabricateDefaultCommands(bool AllocateHeader);
|
||||
void addOrphanSections(OutputSectionFactory &Factory);
|
||||
void removeEmptyCommands();
|
||||
void adjustSectionsBeforeSorting();
|
||||
|
@ -22,6 +22,9 @@ def build_id: F<"build-id">, HelpText<"Generate build ID note">;
|
||||
|
||||
def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">;
|
||||
|
||||
def compress_debug_sections : J<"compress-debug-sections=">,
|
||||
HelpText<"Compress DWARF debug sections">;
|
||||
|
||||
def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
|
||||
HelpText<"Add a directory to the library search path">;
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "SyntheticSections.h"
|
||||
#include "Target.h"
|
||||
#include "Threads.h"
|
||||
#include "llvm/Support/Compression.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include "llvm/Support/MD5.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
@ -83,6 +84,33 @@ static bool compareByFilePosition(InputSection *A, InputSection *B) {
|
||||
return LA->OutSecOff < LB->OutSecOff;
|
||||
}
|
||||
|
||||
// Compress section contents if this section contains debug info.
|
||||
template <class ELFT> void OutputSection::maybeCompress() {
|
||||
typedef typename ELFT::Chdr Elf_Chdr;
|
||||
|
||||
// Compress only DWARF debug sections.
|
||||
if (!Config->CompressDebugSections || (Flags & SHF_ALLOC) ||
|
||||
!Name.startswith(".debug_"))
|
||||
return;
|
||||
|
||||
// Create a section header.
|
||||
ZDebugHeader.resize(sizeof(Elf_Chdr));
|
||||
auto *Hdr = reinterpret_cast<Elf_Chdr *>(ZDebugHeader.data());
|
||||
Hdr->ch_type = ELFCOMPRESS_ZLIB;
|
||||
Hdr->ch_size = Size;
|
||||
Hdr->ch_addralign = Alignment;
|
||||
|
||||
// Write section contents to a temporary buffer and compress it.
|
||||
std::vector<uint8_t> Buf(Size);
|
||||
writeTo<ELFT>(Buf.data());
|
||||
if (Error E = zlib::compress(toStringRef(Buf), CompressedData))
|
||||
fatal("compress failed: " + llvm::toString(std::move(E)));
|
||||
|
||||
// Update section headers.
|
||||
Size = sizeof(Elf_Chdr) + CompressedData.size();
|
||||
Flags |= SHF_COMPRESSED;
|
||||
}
|
||||
|
||||
template <class ELFT> void OutputSection::finalize() {
|
||||
if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) {
|
||||
std::sort(Sections.begin(), Sections.end(), compareByFilePosition);
|
||||
@ -245,6 +273,15 @@ uint32_t OutputSection::getFiller() {
|
||||
template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
|
||||
Loc = Buf;
|
||||
|
||||
// We may have already rendered compressed content when using
|
||||
// -compress-debug-sections option. Write it together with header.
|
||||
if (!CompressedData.empty()) {
|
||||
memcpy(Buf, ZDebugHeader.data(), ZDebugHeader.size());
|
||||
memcpy(Buf + ZDebugHeader.size(), CompressedData.data(),
|
||||
CompressedData.size());
|
||||
return;
|
||||
}
|
||||
|
||||
// Write leading padding.
|
||||
uint32_t Filler = getFiller();
|
||||
if (Filler)
|
||||
@ -422,6 +459,11 @@ template void OutputSection::finalize<ELF32BE>();
|
||||
template void OutputSection::finalize<ELF64LE>();
|
||||
template void OutputSection::finalize<ELF64BE>();
|
||||
|
||||
template void OutputSection::maybeCompress<ELF32LE>();
|
||||
template void OutputSection::maybeCompress<ELF32BE>();
|
||||
template void OutputSection::maybeCompress<ELF64LE>();
|
||||
template void OutputSection::maybeCompress<ELF64BE>();
|
||||
|
||||
template void OutputSection::writeTo<ELF32LE>(uint8_t *Buf);
|
||||
template void OutputSection::writeTo<ELF32BE>(uint8_t *Buf);
|
||||
template void OutputSection::writeTo<ELF64LE>(uint8_t *Buf);
|
||||
|
@ -84,9 +84,14 @@ class OutputSection final : public SectionBase {
|
||||
uint32_t getFiller();
|
||||
template <class ELFT> void writeTo(uint8_t *Buf);
|
||||
template <class ELFT> void finalize();
|
||||
template <class ELFT> void maybeCompress();
|
||||
void assignOffsets();
|
||||
std::vector<InputSection *> Sections;
|
||||
|
||||
// Used for implementation of --compress-debug-sections option.
|
||||
std::vector<uint8_t> ZDebugHeader;
|
||||
llvm::SmallVector<char, 1> CompressedData;
|
||||
|
||||
// Location in the output buffer.
|
||||
uint8_t *Loc = nullptr;
|
||||
};
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "SymbolTable.h"
|
||||
#include "SyntheticSections.h"
|
||||
#include "Target.h"
|
||||
#include "Threads.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/FileOutputBuffer.h"
|
||||
@ -58,7 +59,6 @@ template <class ELFT> class Writer {
|
||||
std::vector<PhdrEntry> createPhdrs();
|
||||
void removeEmptyPTLoad();
|
||||
void addPtArmExid(std::vector<PhdrEntry> &Phdrs);
|
||||
void assignAddresses();
|
||||
void assignFileOffsets();
|
||||
void assignFileOffsetsBinary();
|
||||
void setPhdrs();
|
||||
@ -250,13 +250,11 @@ template <class ELFT> void Writer<ELFT>::run() {
|
||||
if (Config->Relocatable) {
|
||||
assignFileOffsets();
|
||||
} else {
|
||||
if (Script->Opt.HasSections) {
|
||||
Script->assignAddresses(Phdrs);
|
||||
} else {
|
||||
if (!Script->Opt.HasSections) {
|
||||
fixSectionAlignments();
|
||||
assignAddresses();
|
||||
Script->processNonSectionCommands();
|
||||
Script->fabricateDefaultCommands(Config->MaxPageSize);
|
||||
}
|
||||
Script->assignAddresses(Phdrs);
|
||||
|
||||
// Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
|
||||
// 0 sized region. This has to be done late since only after assignAddresses
|
||||
@ -1216,6 +1214,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||
for (OutputSection *Sec : OutputSections)
|
||||
Sec->finalize<ELFT>();
|
||||
|
||||
// If -compressed-debug-sections is specified, we need to compress
|
||||
// .debug_* sections. Do it right now because it changes the size of
|
||||
// output sections.
|
||||
parallelForEach(OutputSections.begin(), OutputSections.end(),
|
||||
[](OutputSection *S) { S->maybeCompress<ELFT>(); });
|
||||
|
||||
// createThunks may have added local symbols to the static symbol table
|
||||
applySynthetic({In<ELFT>::SymTab, In<ELFT>::ShStrTab, In<ELFT>::StrTab},
|
||||
[](SyntheticSection *SS) { SS->postThunkContents(); });
|
||||
@ -1502,37 +1506,6 @@ template <class ELFT> void Writer<ELFT>::fixHeaders() {
|
||||
AllocateHeader = allocateHeaders(Phdrs, OutputSections, Min);
|
||||
}
|
||||
|
||||
// Assign VAs (addresses at run-time) to output sections.
|
||||
template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
||||
uint64_t VA = Config->ImageBase;
|
||||
uint64_t ThreadBssOffset = 0;
|
||||
|
||||
if (AllocateHeader)
|
||||
VA += getHeaderSize();
|
||||
|
||||
for (OutputSection *Sec : OutputSections) {
|
||||
uint32_t Alignment = Sec->Alignment;
|
||||
if (Sec->PageAlign)
|
||||
Alignment = std::max<uint32_t>(Alignment, Config->MaxPageSize);
|
||||
|
||||
auto I = Config->SectionStartMap.find(Sec->Name);
|
||||
if (I != Config->SectionStartMap.end())
|
||||
VA = I->second;
|
||||
|
||||
// We only assign VAs to allocated sections.
|
||||
if (needsPtLoad(Sec)) {
|
||||
VA = alignTo(VA, Alignment);
|
||||
Sec->Addr = VA;
|
||||
VA += Sec->Size;
|
||||
} else if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS) {
|
||||
uint64_t TVA = VA + ThreadBssOffset;
|
||||
TVA = alignTo(TVA, Alignment);
|
||||
Sec->Addr = TVA;
|
||||
ThreadBssOffset = TVA - VA + Sec->Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adjusts the file alignment for a given output section and returns
|
||||
// its new file offset. The file offset must be the same with its
|
||||
// virtual address (modulo the page size) so that the loader can load
|
||||
|
@ -5,7 +5,8 @@
|
||||
; RUN: /entry:main /verbose > %t.log || true
|
||||
; RUN: FileCheck %s < %t.log
|
||||
|
||||
; CHECK: /opt:icf /entry:main /verbose
|
||||
; CHECK: /opt:icf /entry:main
|
||||
; CHECK: /verbose
|
||||
|
||||
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-windows-msvc"
|
||||
|
32
test/ELF/compress-debug-sections.s
Normal file
32
test/ELF/compress-debug-sections.s
Normal file
@ -0,0 +1,32 @@
|
||||
# REQUIRES: x86, zlib
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
|
||||
# RUN: ld.lld %t.o -o %t1 --compress-debug-sections=zlib
|
||||
|
||||
# RUN: llvm-objdump -s %t1 | FileCheck %s --check-prefix=ZLIBCONTENT
|
||||
# ZLIBCONTENT: Contents of section .debug_str:
|
||||
# ZLIBCONTENT-NOT: AAAAAAAAA
|
||||
|
||||
# RUN: llvm-readobj -s %t1 | FileCheck %s --check-prefix=ZLIBFLAGS
|
||||
# ZLIBFLAGS: Section {
|
||||
# ZLIBFLAGS: Index:
|
||||
# ZLIBFLAGS: Name: .debug_str
|
||||
# ZLIBFLAGS-NEXT: Type: SHT_PROGBITS
|
||||
# ZLIBFLAGS-NEXT: Flags [
|
||||
# ZLIBFLAGS-NEXT: SHF_COMPRESSED
|
||||
|
||||
# RUN: llvm-dwarfdump %t1 -debug-dump=str | \
|
||||
# RUN: FileCheck %s --check-prefix=DEBUGSTR
|
||||
# DEBUGSTR: .debug_str contents:
|
||||
# DEBUGSTR-NEXT: AAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
# DEBUGSTR-NEXT: BBBBBBBBBBBBBBBBBBBBBBBBBBB
|
||||
|
||||
# RUN: not ld.lld %t.o -o %t1 --compress-debug-sections=zlib-gabi 2>&1 | \
|
||||
# RUN: FileCheck -check-prefix=ERR %s
|
||||
# ERR: unknown --compress-debug-sections value: zlib-gabi
|
||||
|
||||
.section .debug_str,"MS",@progbits,1
|
||||
.Linfo_string0:
|
||||
.asciz "AAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
.Linfo_string1:
|
||||
.asciz "BBBBBBBBBBBBBBBBBBBBBBBBBBB"
|
@ -2,7 +2,17 @@
|
||||
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
|
||||
// RUN: ld.lld %t -o %tout
|
||||
// RUN: llvm-readobj -s %tout | FileCheck %s
|
||||
|
||||
// RUN: echo "SECTIONS { \
|
||||
// RUN: . = 0x201000; \
|
||||
// RUN: .text : { *(.text) } \
|
||||
// RUN: . = 0x202000; \
|
||||
// RUN: .tdata : { *(.tdata) } \
|
||||
// RUN: .tbss : { *(.tbss) } \
|
||||
// RUN: .data.rel.ro : { *(.data.rel.ro) } \
|
||||
// RUN: }" > %t.script
|
||||
// RUN: ld.lld -T %t.script %t -o %tout2
|
||||
// RUN: echo SCRIPT
|
||||
// RUN: llvm-readobj -s %tout2 | FileCheck %s
|
||||
.global _start
|
||||
_start:
|
||||
retq
|
||||
@ -51,6 +61,6 @@ _start:
|
||||
// CHECK-NEXT: SHF_ALLOC
|
||||
// CHECK-NEXT: SHF_WRITE
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Address: 0x202004
|
||||
// CHECK-NEXT: Offset: 0x2004
|
||||
// CHECK-NEXT: Address: 0x202010
|
||||
// CHECK-NEXT: Offset: 0x2010
|
||||
// CHECK-NEXT: Size: 4
|
||||
|
Loading…
Reference in New Issue
Block a user