Index: lld/ELF/Writer.cpp =================================================================== --- lld/ELF/Writer.cpp +++ lld/ELF/Writer.cpp @@ -70,6 +70,7 @@ unsigned pFlags); void assignFileOffsets(); void assignFileOffsetsBinary(); + void reassignPhdrBoundaries(); void setPhdrs(Partition &part); void checkSections(); void fixSectionAlignments(); @@ -551,6 +552,8 @@ else assignFileOffsetsBinary(); + reassignPhdrBoundaries(); + for (Partition &part : partitions) setPhdrs(part); @@ -2554,6 +2557,20 @@ } } +template void Writer::reassignPhdrBoundaries() { + // Based on the offsets, update the program headers to generate the correct + // size fields afterward. If we don't do this update, out-of-order output + // sections can lead to wrong/overflowed size values. + for (OutputSection *sec : outputSections) { + if (PhdrEntry *ptLoad = sec->ptLoad) { + if (OutputSection *first = ptLoad->firstSec) + ptLoad->firstSec = (first->addr > sec->addr) ? sec : first; + if (OutputSection *last = ptLoad->lastSec) + ptLoad->lastSec = (last->addr < sec->addr) ? sec : last; + } + } +} + static std::string rangeToString(uint64_t addr, uint64_t len) { return "[0x" + utohexstr(addr) + ", 0x" + utohexstr(addr + len - 1) + "]"; } Index: lld/test/ELF/out-of-order-sections.s =================================================================== --- /dev/null +++ lld/test/ELF/out-of-order-sections.s @@ -0,0 +1,58 @@ +# REQUIRES: x86 +# RUN: rm -rf %t && split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t/c.s -o %c.o +# RUN: ld.lld --script %t/lda %c.o -o %t/la.o 2>&1 +# RUN: ld.lld --script %t/ldb %c.o -o %t/lb.o 2>&1 +# RUN: llvm-readelf %t/la.o -l 2>&1 | FileCheck --check-prefix=TEST-ORDER-A %s +# RUN: llvm-readelf %t/lb.o -l 2>&1 | FileCheck --check-prefix=TEST-ORDER-B %s + +# TEST-ORDER-A: Elf file type is EXEC (Executable file) +# TEST-ORDER-A: Entry point 0x10000001 +# TEST-ORDER-A: There are 2 program headers, starting at offset 64 +# TEST-ORDER-A: Program Headers: +# TEST-ORDER-A: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# TEST-ORDER-A: LOAD 0x001000 0x0000000010000000 0x0000000010000000 0x000054 0x000054 R E 0x1000 +# TEST-ORDER-A: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0 +# TEST-ORDER-A: Section to Segment mapping: +# TEST-ORDER-A: Segment Sections... +# TEST-ORDER-A: 00 first_section second_section + +# TEST-ORDER-B: Elf file type is EXEC (Executable file) +# TEST-ORDER-B: Entry point 0x10000001 +# TEST-ORDER-B: There are 2 program headers, starting at offset 64 +# TEST-ORDER-B: Program Headers: +# TEST-ORDER-B: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# TEST-ORDER-B: LOAD 0x001000 0x0000000010000000 0x0000000010000000 0x000054 0x000054 R E 0x1000 +# TEST-ORDER-B: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0 +# TEST-ORDER-B: Section to Segment mapping: +# TEST-ORDER-B: Segment Sections... +# TEST-ORDER-B: 00 second_section first_section + + +#--- lda +SECTIONS { + first_section 0x10000000 : { KEEP (*(.first_in_section)); } > mem + second_section (0x10000000 +64) : { KEEP (*(.second_in_section)); } > mem + /DISCARD/ : { KEEP (*(.text, data .comment, .symtab, .strtab)); } +} + +MEMORY { mem (r): org = 0x10000000, len = 0x00100000 } + +#--- ldb +SECTIONS { + second_section (0x10000000 +64) : { KEEP (*(.second_in_section)); } > mem + first_section 0x10000000 : { KEEP (*(.first_in_section)); } > mem + /DISCARD/ : { KEEP (*(.text, data .comment, .symtab, .strtab)); } +} + +MEMORY { mem (r): org = 0x10000000, len = 0x00100000 } + +#--- c.s +.section data,"wa",@nobits +.zero 1 +.section .second_in_section,"ax",@progbits +.zero 20 +.section .first_in_section,"ax",@progbits +.zero 1 +.globl _start +_start: