Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -693,8 +693,8 @@ // will set the LMA such that the difference between VMA and LMA for the // section is the same as the preceding output section in the same region // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html - if (PhdrEntry *L = Ctx->OutSec->PtLoad) - L->LMAOffset = Ctx->LMAOffset; + if (Ctx->LMAOffset) + Ctx->OutSec->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 @@ -900,6 +900,12 @@ Min = alignDown(Min - HeaderSize, Config->MaxPageSize); Out::ElfHeader->Addr = Min; Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size; + // Avoid creating a gap in the segment + // if the first section has a customized LMA. + if (OutputSection *FirstSec = findFirstSection(FirstPTLoad)) { + Out::ElfHeader->LMAOffset = FirstSec->LMAOffset; + Out::ProgramHeaders->LMAOffset = FirstSec->LMAOffset; + } return; } Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -49,7 +49,7 @@ static bool classof(const BaseCommand *C); - uint64_t getLMA() const { return PtLoad ? Addr + PtLoad->LMAOffset : Addr; } + uint64_t getLMA() const { return Addr + LMAOffset; } template void writeHeaderTo(typename ELFT::Shdr *SHdr); unsigned SectionIndex; @@ -60,9 +60,9 @@ // Pointer to the PT_LOAD segment, which this section resides in. This field // is used to correctly compute file offset of a section. When two sections // share the same load segment, difference between their file offsets should - // be equal to difference between their virtual addresses. To compute some - // section offset we use the following formula: Off = Off_first + VA - - // VA_first, where Off_first and VA_first is file offset and VA of first + // be equal to difference between their load addresses. To compute some + // section offset we use the following formula: Off = Off_first + LA - + // LA_first, where Off_first and LA_first is file offset and LA of first // section in PT_LOAD. PhdrEntry *PtLoad = nullptr; @@ -78,6 +78,7 @@ // The following fields correspond to Elf_Shdr members. uint64_t Offset = 0; + uint64_t LMAOffset = 0; uint64_t Addr = 0; uint32_t ShName = 0; Index: ELF/Writer.h =================================================================== --- ELF/Writer.h +++ ELF/Writer.h @@ -44,8 +44,6 @@ OutputSection *FirstSec = nullptr; OutputSection *LastSec = nullptr; bool HasLMA = false; - - uint64_t LMAOffset = 0; }; void addReservedSymbols(); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -133,7 +133,8 @@ return false; if (!P->FirstSec) return true; - uint64_t Size = P->LastSec->Addr + P->LastSec->Size - P->FirstSec->Addr; + uint64_t Size = + P->LastSec->getLMA() + P->LastSec->Size - P->FirstSec->getLMA(); return Size == 0; }); } @@ -1861,8 +1862,8 @@ return alignTo(Off, Cmd->Alignment); // If two sections share the same PT_LOAD the file offset is calculated - // using this formula: Off2 = Off1 + (VA2 - VA1). - return First->Offset + Cmd->Addr - First->Addr; + // using this formula: Off2 = Off1 + (LMA2 - LMA1). + return First->Offset + Cmd->getLMA() - First->getLMA(); } static uint64_t setOffset(OutputSection *Cmd, uint64_t Off) { @@ -1920,7 +1921,7 @@ P->p_filesz = Last->Offset - First->Offset; if (Last->Type != SHT_NOBITS) P->p_filesz += Last->Size; - P->p_memsz = Last->Addr + Last->Size - First->Addr; + P->p_memsz = Last->getLMA() + Last->Size - First->getLMA(); P->p_offset = First->Offset; P->p_vaddr = First->Addr; if (!P->HasLMA) Index: test/ELF/linkerscript/at5.s =================================================================== --- /dev/null +++ test/ELF/linkerscript/at5.s @@ -0,0 +1,83 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "PHDRS { all PT_LOAD; } \ +# RUN: SECTIONS { \ +# RUN: .aaa 0x1000 : AT(0x3000) { *(.aaa) } : all \ +# RUN: .bbb 0x5000 : AT(0x3000 + SIZEOF(.aaa)) { *(.bbb) } \ +# RUN: .text : { *(.text) } \ +# RUN: }" > %t.script +# RUN: ld.lld %t --script %t.script -o %t2 +# RUN: llvm-readobj -program-headers -sections %t2 | FileCheck %s + +# CHECK: Sections [ +# CHECK: Section { +# CHECK: Index: 1 +# CHECK-NEXT: Name: .aaa +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x1000 +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: .bbb +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x5000 +# CHECK-NEXT: Offset: 0x1008 +# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Name: .text +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x5008 +# CHECK-NEXT: Offset: 0x1010 +# CHECK-NEXT: Size: 1 +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: } +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x1000 +# CHECK-NEXT: PhysicalAddress: 0x3000 +# CHECK-NEXT: FileSize: 17 +# CHECK-NEXT: MemSize: 17 +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: PF_X +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.global _start +_start: + nop + +.section .aaa, "a" +.quad 0 + +.section .bbb, "a" +.quad 0