Vendor import of lld trunk r300890:

https://llvm.org/svn/llvm-project/lld/trunk@300890
This commit is contained in:
Dimitry Andric 2017-04-20 21:21:19 +00:00
parent d2d3ebb819
commit be08ec9606
13 changed files with 177 additions and 46 deletions

View File

@ -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";
}
}

View File

@ -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);

View File

@ -104,6 +104,7 @@ struct Configuration {
bool Bsymbolic;
bool BsymbolicFunctions;
bool ColorDiagnostics = false;
bool CompressDebugSections;
bool DefineCommon;
bool Demangle = true;
bool DisableVerify;

View File

@ -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);

View File

@ -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)

View File

@ -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();

View File

@ -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">;

View File

@ -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);

View File

@ -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;
};

View File

@ -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

View File

@ -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"

View 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"

View File

@ -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