diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1255,15 +1255,24 @@ }); if (i == e) return e; + auto foundSec = dyn_cast(*i); + if (!foundSec) + return e; // Consider all existing sections with the same proximity. int proximity = getRankProximity(sec, *i); + unsigned sortRank = sec->sortRank; + if (script->hasPhdrsCommands()) + // Prevent the orphan section to be placed before the found section because + // that can result in adding it to a previous segment and changing flags of + // that segment, for example, making a read-only segment writable. + sortRank = std::max(sortRank, foundSec->sortRank); for (; i != e; ++i) { auto *curSec = dyn_cast(*i); if (!curSec || !curSec->hasInputSections) continue; if (getRankProximity(sec, curSec) != proximity || - sec->sortRank < curSec->sortRank) + sortRank < curSec->sortRank) break; } diff --git a/lld/test/ELF/aarch64-thunk-pi.s b/lld/test/ELF/aarch64-thunk-pi.s --- a/lld/test/ELF/aarch64-thunk-pi.s +++ b/lld/test/ELF/aarch64-thunk-pi.s @@ -15,7 +15,7 @@ bl high_target ret // CHECK: : -// CHECK-NEXT: d8: bl 0xec <__AArch64ADRPThunk_high_target> +// CHECK-NEXT: 0: bl 0x14 <__AArch64ADRPThunk_high_target> // CHECK-NEXT: ret .hidden low_target2 @@ -28,23 +28,23 @@ bl .text_high+8 ret // CHECK: : -// CHECK-NEXT: e0: bl 0xf8 <__AArch64ADRPThunk_high_target2> -// CHECK-NEXT: e4: bl 0x104 <__AArch64ADRPThunk_> +// CHECK-NEXT: 8: bl 0x20 <__AArch64ADRPThunk_high_target2> +// CHECK-NEXT: c: bl 0x2c <__AArch64ADRPThunk_> // CHECK-NEXT: ret // Expect range extension thunks for .text_low // adrp calculation is (PC + signed immediate) & (!0xfff) // CHECK: <__AArch64ADRPThunk_high_target>: -// CHECK-NEXT: ec: adrp x16, 0x10000000 +// CHECK-NEXT: 14: adrp x16, 0x10000000 // CHECK-NEXT: add x16, x16, #0x40 // CHECK-NEXT: br x16 // CHECK: <__AArch64ADRPThunk_high_target2>: -// CHECK-NEXT: f8: adrp x16, 0x10000000 +// CHECK-NEXT: 20: adrp x16, 0x10000000 // CHECK-NEXT: add x16, x16, #0x8 // CHECK-NEXT: br x16 /// Identical to the previous one, but for the target .text_high+8. // CHECK: <__AArch64ADRPThunk_>: -// CHECK-NEXT: 104: adrp x16, 0x10000000 +// CHECK-NEXT: 2c: adrp x16, 0x10000000 // CHECK-NEXT: add x16, x16, #0x8 // CHECK-NEXT: br x16 @@ -75,7 +75,7 @@ // CHECK: <__AArch64ADRPThunk_low_target2>: // CHECK-NEXT: 10000010: adrp x16, 0x0 -// CHECK-NEXT: add x16, x16, #0xe0 +// CHECK-NEXT: add x16, x16, #0x8 // CHECK-NEXT: br x16 // CHECK: Disassembly of section .plt: @@ -83,8 +83,8 @@ // CHECK-NEXT: <.plt>: // CHECK-NEXT: 10000020: stp x16, x30, [sp, #-0x10]! // CHECK-NEXT: adrp x16, 0x10000000 -// CHECK-NEXT: ldr x17, [x16, #0x120] -// CHECK-NEXT: add x16, x16, #0x120 +// CHECK-NEXT: ldr x17, [x16, #0x1f8] +// CHECK-NEXT: add x16, x16, #0x1f8 // CHECK-NEXT: br x17 // CHECK-NEXT: nop // CHECK-NEXT: nop @@ -92,14 +92,14 @@ // CHECK-EMPTY: // CHECK-NEXT: : // CHECK-NEXT: 10000040: adrp x16, 0x10000000 -// CHECK-NEXT: ldr x17, [x16, #0x128] -// CHECK-NEXT: add x16, x16, #0x128 +// CHECK-NEXT: ldr x17, [x16, #0x200] +// CHECK-NEXT: add x16, x16, #0x200 // CHECK-NEXT: br x17 // CHECK-EMPTY: // CHECK-NEXT: : // CHECK-NEXT: 10000050: adrp x16, 0x10000000 -// CHECK-NEXT: ldr x17, [x16, #0x130] -// CHECK-NEXT: add x16, x16, #0x130 +// CHECK-NEXT: ldr x17, [x16, #0x208] +// CHECK-NEXT: add x16, x16, #0x208 // CHECK-NEXT: br x17 //--- lds diff --git a/lld/test/ELF/linkerscript/implicit-program-header.test b/lld/test/ELF/linkerscript/implicit-program-header.test --- a/lld/test/ELF/linkerscript/implicit-program-header.test +++ b/lld/test/ELF/linkerscript/implicit-program-header.test @@ -7,9 +7,9 @@ # RUN: llvm-readelf -l %t1 | FileCheck %s # CHECK: Segment Sections... -# CHECK-NEXT: 00 .dynsym .hash .dynstr .text -# CHECK-NEXT: 01 .foo .dynamic -# CHECK-NEXT: 02 .foo .dynamic +# CHECK-NEXT: 00 .text +# CHECK-NEXT: 01 .foo .dynsym .hash .dynstr .dynamic +# CHECK-NEXT: 02 .foo .dynsym .hash .dynstr .dynamic PHDRS { ph_write PT_LOAD FLAGS(2); diff --git a/lld/test/ELF/linkerscript/orphan-phdrs2.test b/lld/test/ELF/linkerscript/orphan-phdrs2.test new file mode 100644 --- /dev/null +++ b/lld/test/ELF/linkerscript/orphan-phdrs2.test @@ -0,0 +1,44 @@ +# 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 its sort rank is lower. +## Adding '.dynamic' to the first segment would make the segment writable. +# CHECK: Program Headers: +# CHECK-NEXT: Type {{.*}} Flg Align +# CHECK-NEXT: LOAD {{.*}} R E 0x +# CHECK-NEXT: LOAD {{.*}} RW 0x +# CHECK-MEXT: LOAD {{.*}} R 0x + +# CHECK: Segment Sections... +# CHECK-NEXT: 00 .text {{$}} +# CHECK-NEXT: 01 .data .dynamic {{$}} +## Check that read-only non-PROGBITS orphan sections are placed after the +## closest-rank section '.rodata' despite their sort ranks are lower. +# CHECK-NEXT: 02 .rodata .dynsym .gnu.hash .hash .dynstr {{$}} + +#--- s + .text + nop + + .data + .quad 0 + + .rodata + .quad 0 + +#--- t +PHDRS { + exec PT_LOAD; + rw PT_LOAD; + ro PT_LOAD; +} +SECTIONS { + .text : { *(.text) } : exec + .data : { *(.data) } : rw + .rodata : { *(.rodata) } : ro +}