Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -256,6 +256,8 @@ bool isDefined(StringRef S); std::vector *OutputSections; + void fabricateDefaultCommands(std::vector &Phdrs, + unsigned PageSize, bool AllocateHeader); void addOrphanSections(OutputSectionFactory &Factory); void removeEmptyCommands(); void adjustSectionsBeforeSorting(); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -408,6 +408,60 @@ CurOutSec = nullptr; } +void LinkerScript::fabricateDefaultCommands(std::vector &Phdrs, + unsigned MaxPageSize, + 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); + } + Expr E = [=]() { return StartAddr; }; + auto *StartCmd = make(".", E, ""); + Commands.push_back(StartCmd); + + // 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()) { + Expr E = [=]() { return I->second; }; + auto *DotCmd = make(".", E, ""); + Commands.push_back(DotCmd); + } + + auto *OSCmd = make(Sec->Name); + OSCmd->Sec = Sec; + if (Sec->PageAlign) + OSCmd->AddrExpr = [=]() { + return alignTo(Script->getDot(), 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) Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -58,7 +58,6 @@ std::vector createPhdrs(); void removeEmptyPTLoad(); void addPtArmExid(std::vector &Phdrs); - void assignAddresses(); void assignFileOffsets(); void assignFileOffsetsBinary(); void setPhdrs(); @@ -250,13 +249,12 @@ if (Config->Relocatable) { assignFileOffsets(); } else { - if (Script->Opt.HasSections) { - Script->assignAddresses(Phdrs); - } else { + if (!Script->Opt.HasSections) { fixSectionAlignments(); - assignAddresses(); - Script->processNonSectionCommands(); + Script->fabricateDefaultCommands(Phdrs, Config->MaxPageSize, + AllocateHeader); } + 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 @@ -1467,37 +1465,6 @@ 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 Index: test/ELF/tls-offset.s =================================================================== --- test/ELF/tls-offset.s +++ 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 @@ // 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