Index: lld/ELF/Writer.cpp =================================================================== --- lld/ELF/Writer.cpp +++ lld/ELF/Writer.cpp @@ -1257,6 +1257,15 @@ if (i == e) return e; + // If the orphan section is going to be placed before the found section, + // inherit explicitly specified segments from that section; otherwise, the + // orphan section may be placed in the previous segment. This may change the + // flags of that segment, for example, adding PF_W to a read-only segment. + auto foundSec = dyn_cast(*i); + if (foundSec && sec->sortRank < foundSec->sortRank && + script->hasPhdrsCommands()) + sec->phdrs = foundSec->phdrs; + // Consider all existing sections with the same proximity. int proximity = getRankProximity(sec, *i); for (; i != e; ++i) { Index: lld/test/ELF/linkerscript/orphan-phdrs2.test =================================================================== --- /dev/null +++ lld/test/ELF/linkerscript/orphan-phdrs2.test @@ -0,0 +1,33 @@ +# REQUIRES: x86 + +# RUN: split-file %s %ts +# RUN: llvm-mc -filetype=obj -triple=x86_64 %ts/s -o %t.o +# RUN: ld.lld -pie -o %t -T %ts/t %t.o +# RUN: llvm-readelf -l %t | FileCheck %s + +## Check that an orphan section '.dynamic' is added to the same segment as +## its closest-rank section '.data', even though it is placed before '.data'. +## Adding 'dynamic' to the first segment would make the segment writable. +# CHECK: LOAD {{.*}} R E +# CHECK: LOAD {{.*}} RW + +# CHECK: Segment Sections... +# CHECK-NOT: 00{{.*}} .dynamic +# CHECK: 01 .dynamic .data + +#--- s + .text + nop + + .data + .quad 0 + +#--- t +PHDRS { + exec PT_LOAD; + rw PT_LOAD; +} +SECTIONS { + .text : { *(.text) } : exec + .data : { *(.data) } : rw +}