From cbfe9e946fd04d57145f35e2289c595a4a498f0b Mon Sep 17 00:00:00 2001 From: Peter Smith Date: Wed, 19 Apr 2017 12:46:32 +0000 Subject: [PATCH] [ELF] Always use Script::assignAddresses() This change fabricates linker script commands for the case where there is no linker script SECTIONS to control address assignment. This permits us to have a single Script->assignAddresses() function. There is a small change in user-visible-behavior with respect to the handling of .tbss SHT_NOBITS, SHF_TLS as the Script->assignAddresses() requires setDot() to be called with monotically increasing addresses. The tls-offset.s test has been updated so that the script and non-script results match. This change should make the non-script behavior of lld closer to an equivalent linker script. Differential Revision: https://reviews.llvm.org/D31888 llvm-svn: 300687 --- lld/ELF/LinkerScript.cpp | 50 +++++++++++++++++++++++++++++++++++++++ lld/ELF/LinkerScript.h | 1 + lld/ELF/Writer.cpp | 40 +++---------------------------- lld/test/ELF/tls-offset.s | 16 ++++++++++--- 4 files changed, 67 insertions(+), 40 deletions(-) diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index ab2ca22e9e17..63eb90456e17 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -413,6 +413,56 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { CurOutSec = nullptr; } +void LinkerScript::fabricateDefaultCommands(bool AllocateHeader) { + std::vector Commands; + + // Define start address + uint64_t StartAddr = Config->ImageBase; + if (AllocateHeader) + StartAddr += elf::getHeaderSize(); + + // The Sections with -T
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(".", [=] { 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(".", [=] { return I->second; }, "")); + + auto *OSCmd = make(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(""); + 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) diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 04a388efb4e9..61942b2db357 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -256,6 +256,7 @@ public: bool isDefined(StringRef S); std::vector *OutputSections; + void fabricateDefaultCommands(bool AllocateHeader); void addOrphanSections(OutputSectionFactory &Factory); void removeEmptyCommands(); void adjustSectionsBeforeSorting(); diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 310b2c086795..e8718c258c77 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -59,7 +59,6 @@ private: std::vector createPhdrs(); void removeEmptyPTLoad(); void addPtArmExid(std::vector &Phdrs); - void assignAddresses(); void assignFileOffsets(); void assignFileOffsetsBinary(); void setPhdrs(); @@ -251,13 +250,11 @@ template void Writer::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 @@ -1509,37 +1506,6 @@ template void Writer::fixHeaders() { AllocateHeader = allocateHeaders(Phdrs, OutputSections, Min); } -// Assign VAs (addresses at run-time) to output sections. -template void Writer::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(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 diff --git a/lld/test/ELF/tls-offset.s b/lld/test/ELF/tls-offset.s index ad921af8eff6..062def4e14fc 100644 --- a/lld/test/ELF/tls-offset.s +++ b/lld/test/ELF/tls-offset.s @@ -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