diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -2624,22 +2624,34 @@ if (p->p_type == PT_LOAD && (p->p_flags & PF_X)) lastRX = p; - // Layout SHF_ALLOC sections before non-SHF_ALLOC sections. A non-SHF_ALLOC - // will not occupy file offsets contained by a PT_LOAD. - for (OutputSection *sec : outputSections) { - if (!(sec->flags & SHF_ALLOC)) - continue; - off = setFileOffset(sec, off); - - // If this is a last section of the last executable segment and that - // segment is the last loadable segment, align the offset of the - // following section to avoid loading non-segments parts of the file. - if (config->zSeparate != SeparateSegmentKind::None && lastRX && - lastRX->lastSec == sec) - off = alignTo(off, config->commonPageSize); + // Place output sections which are part of load segments first. This means + // that section order does not need to match segment order which can happen + // when using a link script. + for (Partition &part : partitions) { + for (PhdrEntry *p : part.phdrs) { + if (p->p_type != PT_LOAD) + continue; + for (OutputSection *sec : outputSections) { + if (sec->ptLoad != p) + continue; + off = setFileOffset(sec, off); + + // If this is a last section of the last executable segment and that + // segment is the last loadable segment, align the offset of the + // following section to avoid loading non-segments parts of the file. + if (config->zSeparate != SeparateSegmentKind::None && lastRX && + lastRX->lastSec == sec) + off = alignTo(off, config->commonPageSize); + + // If a section is assigned to a load segment it must be allocated + assert(sec->flags & SHF_ALLOC); + } + } } + + // Then place remaining sections for (OutputSection *sec : outputSections) - if (!(sec->flags & SHF_ALLOC)) + if (!sec->ptLoad) off = setFileOffset(sec, off); sectionHeaderOff = alignTo(off, config->wordsize); diff --git a/lld/test/ELF/linkerscript/at8.test b/lld/test/ELF/linkerscript/at8.test --- a/lld/test/ELF/linkerscript/at8.test +++ b/lld/test/ELF/linkerscript/at8.test @@ -20,7 +20,7 @@ # PT_LOAD header. # CHECK: Name Type Address Off -# CHECK: .text PROGBITS 0000000008000000 000158 +# CHECK: .text PROGBITS 0000000008000000 001018 # CHECK: .sec1 PROGBITS 0000000020000000 001000 # CHECK: .sec2 PROGBITS 0000000020000008 001008 # CHECK: .sec3 PROGBITS 0000000020000010 001010 diff --git a/lld/test/ELF/linkerscript/empty-sections-expressions.test b/lld/test/ELF/linkerscript/empty-sections-expressions.test --- a/lld/test/ELF/linkerscript/empty-sections-expressions.test +++ b/lld/test/ELF/linkerscript/empty-sections-expressions.test @@ -9,7 +9,7 @@ # CHECK: Name Type Address Off Size # CHECK-NEXT: NULL 0000000000000000 000000 000000 -# CHECK-NEXT: .empty PROGBITS 0000000000080000 000158 000000 +# CHECK-NEXT: .empty PROGBITS 0000000000080000 001002 000000 # CHECK-NEXT: .text PROGBITS 0000000000080000 001000 000001 # CHECK-NEXT: .data PROGBITS 0000000000080001 001001 000001 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,7 +7,7 @@ # RUN: llvm-readelf -l %t1 | FileCheck %s # CHECK: Segment Sections... -# CHECK-NEXT: 00 .dynsym .hash .dynstr .foo .text .dynamic +# CHECK-NEXT: 00 .dynsym .hash .dynstr .text .dynamic # CHECK-NEXT: 01 .foo # CHECK-NEXT: 02 .foo diff --git a/lld/test/ELF/linkerscript/nobits-offset.s b/lld/test/ELF/linkerscript/nobits-offset.s --- a/lld/test/ELF/linkerscript/nobits-offset.s +++ b/lld/test/ELF/linkerscript/nobits-offset.s @@ -14,8 +14,8 @@ # CHECK: Name Type Address Off Size # CHECK-NEXT: NULL 0000000000000000 000000 000000 -# CHECK-NEXT: .text PROGBITS 0000000000000000 000158 000000 -# CHECK-NEXT: .sec1 NOBITS 0000000000000000 000158 000001 +# CHECK-NEXT: .text PROGBITS 0000000000000000 000400 000000 +# CHECK-NEXT: .sec1 NOBITS 0000000000000000 000400 000001 # CHECK-NEXT: .bss NOBITS 0000000000000400 000400 000001 # CHECK: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align diff --git a/lld/test/ELF/linkerscript/out-of-order-sections.s b/lld/test/ELF/linkerscript/out-of-order-sections.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/linkerscript/out-of-order-sections.s @@ -0,0 +1,49 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "PHDRS { \ +# RUN: ph1 PT_LOAD; \ +# RUN: ph2 PT_LOAD; } \ +# RUN: SECTIONS { \ +# RUN: .text 0 : {*(.text*)} :ph1 \ +# RUN: .foo 0x4000 : {*(.foo*)} :ph2 \ +# RUN: .bar 0x1000 : {*(.bar*)} :ph1 }" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-readobj -l %t1 | FileCheck %s + +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x0 +# CHECK-NEXT: PhysicalAddress: 0x0 +# CHECK-NEXT: FileSize: 4097 +# CHECK-NEXT: MemSize: 4097 +# CHECK-NEXT: Flags [ (0x5) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_X (0x1) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x3000 +# CHECK-NEXT: VirtualAddress: 0x4000 +# CHECK-NEXT: PhysicalAddress: 0x4000 +# CHECK-NEXT: FileSize: 1 +# CHECK-NEXT: MemSize: 1 +# CHECK-NEXT: Flags [ (0x4) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.global _start +_start: + nop + +.section .foo, "a" + .byte 0 + +.section .bar, "a" + .byte 0 diff --git a/lld/test/ELF/linkerscript/tbss.s b/lld/test/ELF/linkerscript/tbss.s --- a/lld/test/ELF/linkerscript/tbss.s +++ b/lld/test/ELF/linkerscript/tbss.s @@ -19,7 +19,7 @@ # CHECK-NEXT: SHF_WRITE # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x[[ADDR:.*]] -# CHECK-NEXT: Offset: 0x[[ADDR]] +# CHECK-NEXT: Offset: # CHECK-NEXT: Size: 4 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 diff --git a/lld/test/ELF/partition-notes.s b/lld/test/ELF/partition-notes.s --- a/lld/test/ELF/partition-notes.s +++ b/lld/test/ELF/partition-notes.s @@ -37,7 +37,7 @@ // CHECK-NEXT: Owner: GNU // CHECK-NEXT: Data size: // CHECK-NEXT: Type: NT_GNU_BUILD_ID (unique build ID bitstring) -// CHECK-NEXT: Build ID: 08b93eab87177a2356d1b0d1148339463f98dac2 +// CHECK-NEXT: Build ID: 406d8bb708edff0eccaa111b8d74fabe63d40534 // CHECK-NEXT: } // CHECK-NEXT: } // CHECK-NEXT: ] diff --git a/lld/test/ELF/partition-synthetic-sections.s b/lld/test/ELF/partition-synthetic-sections.s --- a/lld/test/ELF/partition-synthetic-sections.s +++ b/lld/test/ELF/partition-synthetic-sections.s @@ -190,9 +190,9 @@ // FILL-NEXT: * // FILL-NEXT: 002000 -// FILL: 004010 cccc cccc cccc cccc cccc cccc cccc cccc +// FILL: 005010 cccc cccc cccc cccc cccc cccc cccc cccc // FILL-NEXT: * -// FILL-NEXT: 005000 +// FILL-NEXT: 006000 .section .llvm_sympart,"",@llvm_sympart .asciz "part1" diff --git a/lld/test/ELF/tls-offset.s b/lld/test/ELF/tls-offset.s --- a/lld/test/ELF/tls-offset.s +++ b/lld/test/ELF/tls-offset.s @@ -53,9 +53,9 @@ // CHECK-NEXT: SHF_WRITE // CHECK-NEXT: ] // CHECK1-NEXT: Address: 0x2021E0 -// CHECK1-NEXT: Offset: 0x1D4 +// CHECK1-NEXT: Offset: 0x1D8 // CHECK2-NEXT: Address: 0x202010 -// CHECK2-NEXT: Offset: 0x2004 +// CHECK2-NEXT: Offset: 0x2008 // CHECK-NEXT: Size: 16 // CHECK: Name: .data.rel.ro