Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -420,7 +420,7 @@ // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = getHeaderSize(); - uintX_t MinVA = std::numeric_limits::max(); + uintX_t HeaderVA = std::numeric_limits::max(); uintX_t ThreadBssOffset = 0; for (const std::unique_ptr &Base : Opt.Commands) { @@ -462,21 +462,21 @@ Dot = alignTo(Dot, Sec->getAlignment()); Sec->setVA(Dot); assignOffsets(Cmd, Sec); - MinVA = std::min(MinVA, Dot); + HeaderVA = std::min(HeaderVA, Dot); Dot += Sec->getSize(); } } uintX_t HeaderSize = Out::ElfHeader->getSize() + Out::ProgramHeaders->getSize(); - if (HeaderSize > MinVA) + if (HeaderSize > HeaderVA && !hasPhdrsCommands()) fatal("Not enough space for ELF and program headers"); - // ELF and Program headers need to be right before the first section in - // memory. Set their addresses accordingly. - MinVA = alignDown(MinVA - HeaderSize, Target->PageSize); - Out::ElfHeader->setVA(MinVA); - Out::ProgramHeaders->setVA(Out::ElfHeader->getSize() + MinVA); + HeaderVA = HeaderSize > HeaderVA + ? alignTo(Dot, Target->PageSize) + : alignDown(HeaderVA - HeaderSize, Target->PageSize); + Out::ElfHeader->setVA(HeaderVA); + Out::ProgramHeaders->setVA(Out::ElfHeader->getSize() + HeaderVA); } // Creates program headers as instructed by PHDRS linker script command. Index: test/ELF/linkerscript/phdrs.s =================================================================== --- test/ELF/linkerscript/phdrs.s +++ test/ELF/linkerscript/phdrs.s @@ -19,6 +19,16 @@ # RUN: ld.lld -o %t1 --script %t.script %t # RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=AT %s +## Check PHDR VA. +# RUN: echo "PHDRS { header PT_PHDR PHDRS; other PT_LOAD; } \ +# RUN: SECTIONS { \ +# RUN: . = 0; \ +# RUN: .text : {*(.text*)} : other \ +# RUN: .foo : {*(.foo.*)} : other \ +# RUN: .data : {*(.data.*)} : other }" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=PHDR %s + # CHECK: ProgramHeaders [ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD (0x1) @@ -47,6 +57,35 @@ # AT-NEXT: PF_X (0x1) # AT-NEXT: ] +# PHDR: ProgramHeaders [ +# PHDR-NEXT: ProgramHeader { +# PHDR-NEXT: Type: PT_PHDR (0x6) +# PHDR-NEXT: Offset: 0x40 +# PHDR-NEXT: VirtualAddress: 0x1040 +# PHDR-NEXT: PhysicalAddress: 0x1040 +# PHDR-NEXT: FileSize: 112 +# PHDR-NEXT: MemSize: 112 +# PHDR-NEXT: Flags [ (0x4) +# PHDR-NEXT: PF_R (0x4) +# PHDR-NEXT: ] +# PHDR-NEXT: Alignment: 8 +# PHDR-NEXT: } +# PHDR-NEXT: ProgramHeader { +# PHDR-NEXT: Type: PT_LOAD (0x1) +# PHDR-NEXT: Offset: 0x1000 +# PHDR-NEXT: VirtualAddress: 0x0 +# PHDR-NEXT: PhysicalAddress: 0x0 +# PHDR-NEXT: FileSize: 9 +# PHDR-NEXT: MemSize: 9 +# PHDR-NEXT: Flags [ (0x7) +# PHDR-NEXT: PF_R (0x4) +# PHDR-NEXT: PF_W (0x2) +# PHDR-NEXT: PF_X (0x1) +# PHDR-NEXT: ] +# PHDR-NEXT: Alignment: 4096 +# PHDR-NEXT: } +# PHDR-NEXT: ] + .global _start _start: nop