Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -218,6 +218,8 @@ std::vector *> createInputSectionList(OutputSectionCommand &Cmd); + bool canAdjustPhdrFlags(unsigned PhdrId); + // "ScriptConfig" is a bit too long, so define a short name for it. ScriptConfiguration &Opt = *ScriptConfig; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -622,6 +622,12 @@ Out::ProgramHeaders->setVA(Out::ElfHeader->getSize() + MinVA); } +template +bool LinkerScript::canAdjustPhdrFlags(unsigned PhdrId) { + return Opt.PhdrsCommands.size() > PhdrId && + Opt.PhdrsCommands[PhdrId].Flags == UINT_MAX; +} + // Creates program headers as instructed by PHDRS linker script command. template std::vector> LinkerScript::createPhdrs() { @@ -645,8 +651,7 @@ } // Add output sections to program headers. - PhdrEntry *Load = nullptr; - uintX_t Flags = PF_R; + unsigned LoadId = UINT_MAX; for (OutputSectionBase *Sec : *OutputSections) { if (!(Sec->getFlags() & SHF_ALLOC)) break; @@ -658,16 +663,23 @@ Ret[Id].add(Sec); if (Opt.PhdrsCommands[Id].Flags == UINT_MAX) Ret[Id].H.p_flags |= Sec->getPhdrFlags(); + if (Ret[Id].H.p_type == PT_LOAD) + LoadId = Id; } } else { - // If we have no load segment or flags've changed then we want new load - // segment. - uintX_t NewFlags = Sec->getPhdrFlags(); - if (Load == nullptr || Flags != NewFlags) { - Load = &*Ret.emplace(Ret.end(), PT_LOAD, NewFlags); - Flags = NewFlags; + uintX_t Flags = Sec->getPhdrFlags(); + // Try to put section to previously created segment. + // We can do this in the following cases: + // a) Previous segment flags and section flags are identical. + // b) Previous segment is listed in PHDRS block with no flag + // specification. In such case we're ORing the segment flags. + if (LoadId == UINT_MAX || + ((Flags != Ret[LoadId].H.p_flags) && !canAdjustPhdrFlags(LoadId))) { + Ret.emplace_back(PT_LOAD, 0); + LoadId = Ret.size() - 1; } - Load->add(Sec); + Ret[LoadId].add(Sec); + Ret[LoadId].H.p_flags |= Flags; } } return Ret; Index: test/ELF/linkerscript/phdrs-flags.s =================================================================== --- test/ELF/linkerscript/phdrs-flags.s +++ test/ELF/linkerscript/phdrs-flags.s @@ -6,9 +6,18 @@ # RUN: .text : {*(.text*)} :all \ # RUN: .foo : {*(.foo.*)} :all \ # RUN: .data : {*(.data.*)} :all}" > %t.script - # RUN: ld.lld -o %t1 --script %t.script %t # RUN: llvm-readobj -program-headers %t1 | FileCheck %s + +# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS FLAGS (0x1);} \ +# RUN: SECTIONS { \ +# RUN: . = 0x10000200; \ +# RUN: .text : {*(.text*)} :all \ +# RUN: .foo : {*(.foo.*)} \ +# RUN: .data : {*(.data.*)} }" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=DEFHDR %s + # CHECK: ProgramHeaders [ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD (0x1) @@ -22,6 +31,34 @@ # CHECK-NEXT: PF_X (0x1) # CHECK-NEXT: ] +# DEFHDR: ProgramHeaders [ +# DEFHDR-NEXT: ProgramHeader { +# DEFHDR-NEXT: Type: PT_LOAD (0x1) +# DEFHDR-NEXT: Offset: 0x0 +# DEFHDR-NEXT: VirtualAddress: 0x10000000 +# DEFHDR-NEXT: PhysicalAddress: 0x10000000 +# DEFHDR-NEXT: FileSize: 513 +# DEFHDR-NEXT: MemSize: 513 +# DEFHDR-NEXT: Flags [ (0x1) +# DEFHDR-NEXT: PF_X (0x1) +# DEFHDR-NEXT: ] +# DEFHDR-NEXT: Alignment: 4096 +# DEFHDR-NEXT: } +# DEFHDR-NEXT: ProgramHeader { +# DEFHDR-NEXT: Type: PT_LOAD (0x1) +# DEFHDR-NEXT: Offset: 0x201 +# DEFHDR-NEXT: VirtualAddress: 0x10000201 +# DEFHDR-NEXT: PhysicalAddress: 0x10000201 +# DEFHDR-NEXT: FileSize: 8 +# DEFHDR-NEXT: MemSize: 8 +# DEFHDR-NEXT: Flags [ (0x6) +# DEFHDR-NEXT: PF_R (0x4) +# DEFHDR-NEXT: PF_W (0x2) +# DEFHDR-NEXT: ] +# DEFHDR-NEXT: Alignment: 4096 +# DEFHDR-NEXT: } +# DEFHDR-NEXT: ] + .global _start _start: nop Index: test/ELF/linkerscript/phdrs.s =================================================================== --- test/ELF/linkerscript/phdrs.s +++ test/ELF/linkerscript/phdrs.s @@ -19,6 +19,15 @@ # RUN: ld.lld -o %t1 --script %t.script %t # RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=AT %s +# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS ;} \ +# RUN: SECTIONS { \ +# RUN: . = 0x10000200; \ +# RUN: .text : {*(.text*)} :all \ +# RUN: .foo : {*(.foo.*)} \ +# RUN: .data : {*(.data.*)} }" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=DEFHDR %s + # CHECK: ProgramHeaders [ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD (0x1) @@ -47,6 +56,20 @@ # AT-NEXT: PF_X (0x1) # AT-NEXT: ] +# DEFHDR: ProgramHeaders [ +# DEFHDR-NEXT: ProgramHeader { +# DEFHDR-NEXT: Type: PT_LOAD (0x1) +# DEFHDR-NEXT: Offset: 0x0 +# DEFHDR-NEXT: VirtualAddress: 0x10000000 +# DEFHDR-NEXT: PhysicalAddress: 0x10000000 +# DEFHDR-NEXT: FileSize: 521 +# DEFHDR-NEXT: MemSize: 521 +# DEFHDR-NEXT: Flags [ (0x7) +# DEFHDR-NEXT: PF_R (0x4) +# DEFHDR-NEXT: PF_W (0x2) +# DEFHDR-NEXT: PF_X (0x1) +# DEFHDR-NEXT: ] + .global _start _start: nop