Index: lld/trunk/ELF/LinkerScript.cpp =================================================================== --- lld/trunk/ELF/LinkerScript.cpp +++ lld/trunk/ELF/LinkerScript.cpp @@ -723,6 +723,17 @@ removeEmptyCommands(); } +// Try to find an address for the file and program headers output sections, +// which were unconditionally added to the first PT_LOAD segment earlier. +// +// When using the default layout, we check if the headers fit below the first +// allocated section. When using a linker script, we also check if the headers +// are covered by the output section. This allows omitting the headers by not +// leaving enough space for them in the linker script; this pattern is common +// in embedded systems. +// +// If there isn't enough space for these sections, we'll remove them from the +// PT_LOAD segment, and we'll also remove the PT_PHDR segment. void LinkerScript::allocateHeaders(std::vector &Phdrs) { uint64_t Min = std::numeric_limits::max(); for (OutputSection *Sec : OutputSections) @@ -736,14 +747,17 @@ PhdrEntry *FirstPTLoad = *It; uint64_t HeaderSize = getHeaderSize(); - if (HeaderSize <= Min || Script->hasPhdrsCommands()) { - Min = alignDown(Min - HeaderSize, Config->MaxPageSize); + // When linker script with SECTIONS is being used, don't output headers + // unless there's a space for them. + uint64_t Base = Opt.HasSections ? alignDown(Min, Config->MaxPageSize) : 0; + if (HeaderSize <= Min - Base || Script->hasPhdrsCommands()) { + Min = Opt.HasSections ? Base + : alignDown(Min - HeaderSize, Config->MaxPageSize); Out::ElfHeader->Addr = Min; Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size; return; } - assert(FirstPTLoad->First == Out::ElfHeader); OutputSection *ActualFirst = nullptr; for (OutputSection *Sec : OutputSections) { if (Sec->FirstInPtLoad == Out::ElfHeader) { Index: lld/trunk/test/ELF/linkerscript/at-addr.s =================================================================== --- lld/trunk/test/ELF/linkerscript/at-addr.s +++ lld/trunk/test/ELF/linkerscript/at-addr.s @@ -9,10 +9,6 @@ # RUN: llvm-readobj -program-headers %t2 | FileCheck %s # CHECK: Type: PT_LOAD -# CHECK-NEXT: Offset: 0x0 -# CHECK-NEXT: VirtualAddress: 0x0 -# CHECK-NEXT: PhysicalAddress: 0x0 -# CHECK: Type: PT_LOAD # CHECK-NEXT: Offset: 0x1000 # CHECK-NEXT: VirtualAddress: 0x1000 # CHECK-NEXT: PhysicalAddress: 0xB00 Index: lld/trunk/test/ELF/linkerscript/at.s =================================================================== --- lld/trunk/test/ELF/linkerscript/at.s +++ lld/trunk/test/ELF/linkerscript/at.s @@ -13,31 +13,6 @@ # CHECK: ProgramHeaders [ # CHECK-NEXT: ProgramHeader { -# CHECK-NEXT: Type: PT_PHDR -# CHECK-NEXT: Offset: 0x40 -# CHECK-NEXT: VirtualAddress: 0x40 -# CHECK-NEXT: PhysicalAddress: 0x40 -# CHECK-NEXT: FileSize: -# CHECK-NEXT: MemSize: -# CHECK-NEXT: Flags [ -# CHECK-NEXT: PF_R -# CHECK-NEXT: ] -# CHECK-NEXT: Alignment: 8 -# CHECK-NEXT: } -# CHECK-NEXT: ProgramHeader { -# CHECK-NEXT: Type: PT_LOAD -# CHECK-NEXT: Offset: 0x0 -# CHECK-NEXT: VirtualAddress: 0x0 -# CHECK-NEXT: PhysicalAddress: 0x0 -# CHECK-NEXT: FileSize: -# CHECK-NEXT: MemSize: -# CHECK-NEXT: Flags [ -# CHECK-NEXT: PF_R -# CHECK-NEXT: PF_X -# CHECK-NEXT: ] -# CHECK-NEXT: Alignment: -# CHECK-NEXT: } -# CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD # CHECK-NEXT: Offset: 0x1000 # CHECK-NEXT: VirtualAddress: 0x1000 Index: lld/trunk/test/ELF/linkerscript/header-addr.s =================================================================== --- lld/trunk/test/ELF/linkerscript/header-addr.s +++ lld/trunk/test/ELF/linkerscript/header-addr.s @@ -2,7 +2,7 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: echo "PHDRS {all PT_LOAD PHDRS;} \ # RUN: SECTIONS { \ -# RUN: . = 0x2000; \ +# RUN: . = 0x2000 + SIZEOF_HEADERS; \ # RUN: .text : {*(.text)} :all \ # RUN: }" > %t.script # RUN: ld.lld -o %t.so --script %t.script %t.o -shared @@ -12,10 +12,10 @@ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD # CHECK-NEXT: Offset: 0x40 -# CHECK-NEXT: VirtualAddress: 0x1040 -# CHECK-NEXT: PhysicalAddress: 0x1040 -# CHECK-NEXT: FileSize: 4176 -# CHECK-NEXT: MemSize: 4176 +# CHECK-NEXT: VirtualAddress: 0x2040 +# CHECK-NEXT: PhysicalAddress: 0x2040 +# CHECK-NEXT: FileSize: 200 +# CHECK-NEXT: MemSize: 200 # CHECK-NEXT: Flags [ # CHECK-NEXT: PF_R (0x4) # CHECK-NEXT: PF_W (0x2) @@ -33,10 +33,10 @@ # MAXPAGE-NEXT: ProgramHeader { # MAXPAGE-NEXT: Type: PT_LOAD # MAXPAGE-NEXT: Offset: 0x40 -# MAXPAGE-NEXT: VirtualAddress: 0x40 -# MAXPAGE-NEXT: PhysicalAddress: 0x40 -# MAXPAGE-NEXT: FileSize: 8272 -# MAXPAGE-NEXT: MemSize: 8272 +# MAXPAGE-NEXT: VirtualAddress: 0x2040 +# MAXPAGE-NEXT: PhysicalAddress: 0x2040 +# MAXPAGE-NEXT: FileSize: 200 +# MAXPAGE-NEXT: MemSize: 200 # MAXPAGE-NEXT: Flags [ # MAXPAGE-NEXT: PF_R # MAXPAGE-NEXT: PF_W Index: lld/trunk/test/ELF/linkerscript/phdr-check.s =================================================================== --- lld/trunk/test/ELF/linkerscript/phdr-check.s +++ lld/trunk/test/ELF/linkerscript/phdr-check.s @@ -1,14 +1,14 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: echo "SECTIONS { . = 0x10000000; .text : {*(.text.*)} }" > %t.script +# RUN: echo "SECTIONS { . = 0x10000000 + SIZEOF_HEADERS; .text : {*(.text.*)} }" > %t.script # RUN: ld.lld -o %t1 --script %t.script %t # RUN: llvm-readobj -program-headers %t1 | FileCheck %s # CHECK: ProgramHeaders [ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_PHDR (0x6) # CHECK-NEXT: Offset: 0x40 -# CHECK-NEXT: VirtualAddress: 0xFFFF040 +# CHECK-NEXT: VirtualAddress: 0x10000040 .global _start _start: Index: lld/trunk/test/ELF/linkerscript/segment-headers.s =================================================================== --- lld/trunk/test/ELF/linkerscript/segment-headers.s +++ lld/trunk/test/ELF/linkerscript/segment-headers.s @@ -0,0 +1,26 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { . = 0x2000; .text : AT(0x100000) { *(.text) } }" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-readobj -l %t | FileCheck %s + +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x2000 +# CHECK-NEXT: PhysicalAddress: 0x100000 +# CHECK-NEXT: FileSize: 1 +# CHECK-NEXT: MemSize: 1 +# CHECK-NEXT: Flags [ (0x5) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_X (0x1) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } + +.section .text +.global _start + +_start: + ret