diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -101,9 +101,9 @@ } for (StringRef v : - {".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", - ".gcc_except_table", ".init_array", ".fini_array", ".tbss", ".tdata", - ".ARM.exidx", ".ARM.extab", ".ctors", ".dtors"}) + {".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", ".ldata", + ".lrodata", ".lbss", ".gcc_except_table", ".init_array", ".fini_array", + ".tbss", ".tdata", ".ARM.exidx", ".ARM.extab", ".ctors", ".dtors"}) if (isSectionPrefix(v, s->name)) return v; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -830,10 +830,11 @@ RF_NOT_ALLOC = 1 << 26, RF_PARTITION = 1 << 18, // Partition number (8 bits) RF_NOT_SPECIAL = 1 << 17, - RF_WRITE = 1 << 13, - RF_EXEC_WRITE = 1 << 12, - RF_EXEC = 1 << 11, - RF_RODATA = 1 << 10, + RF_WRITE = 1 << 16, + RF_EXEC_WRITE = 1 << 15, + RF_EXEC = 1 << 14, + RF_RODATA = 1 << 13, + RF_LARGE = 1 << 12, RF_NOT_RELRO = 1 << 9, RF_NOT_TLS = 1 << 8, RF_BSS = 1 << 7, @@ -891,6 +892,9 @@ // .dynstr and .dynsym can be away from .text. if (osec.type == SHT_PROGBITS) rank |= RF_RODATA; + // Among PROGBITS sections, place .lrodata further from .text. + if (!(osec.flags & SHF_X86_64_LARGE && config->emachine == EM_X86_64)) + rank |= RF_LARGE; } else if (isExec) { rank |= isWrite ? RF_EXEC_WRITE : RF_EXEC; } else { @@ -901,6 +905,10 @@ rank |= RF_NOT_TLS; if (!isRelroSection(&osec)) rank |= RF_NOT_RELRO; + // Place .ldata and .lbss after .bss. Making .bss closer to .text alleviates + // relocation overflow pressure. + if (osec.flags & SHF_X86_64_LARGE && config->emachine == EM_X86_64) + rank |= RF_LARGE; } // Within TLS sections, or within other RelRo sections, or within non-RelRo @@ -2321,12 +2329,18 @@ // region using AT or AT> linker script command, respectively. At the same // time, we don't want to create a separate load segment for the headers, // even if the first output section has an AT or AT> attribute. + // + // Create a PT_LOAD when trasiting from NOBITS to non-NOBITS. This ensures + // we don't allocate space for BSS when transiting to a large data section, + // at the cost of one alignment (assignFileOffsets spends no more than + // MAXPAGESIZE bytes). uint64_t newFlags = computeFlags(sec->getPhdrFlags()); bool sameLMARegion = load && !sec->lmaExpr && sec->lmaRegion == load->firstSec->lmaRegion; if (!(load && newFlags == flags && sec != relroEnd && sec->memRegion == load->firstSec->memRegion && - (sameLMARegion || load->lastSec == Out::programHeaders))) { + (sameLMARegion || load->lastSec == Out::programHeaders) && + (sec->type == SHT_NOBITS || load->lastSec->type != SHT_NOBITS))) { load = addHdr(PT_LOAD, newFlags); flags = newFlags; } diff --git a/lld/test/ELF/linkerscript/sections-nonalloc.s b/lld/test/ELF/linkerscript/sections-nonalloc.s --- a/lld/test/ELF/linkerscript/sections-nonalloc.s +++ b/lld/test/ELF/linkerscript/sections-nonalloc.s @@ -26,7 +26,8 @@ # CHECK-NEXT: [11] .text PROGBITS 0000000000000004 001004 000001 00 AX 0 # CHECK: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align -# CHECK-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x000004 0x000004 RW 0x1000 +# CHECK-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x000000 0x000001 RW 0x1000 +# CHECK-NEXT: LOAD 0x001001 0x0000000000000001 0x0000000000000001 0x000003 0x000003 RW 0x1000 # CHECK-NEXT: LOAD 0x001004 0x0000000000000004 0x0000000000000004 0x000001 0x000001 R E 0x1000 # CHECK-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0 diff --git a/lld/test/ELF/linkerscript/sections.s b/lld/test/ELF/linkerscript/sections.s --- a/lld/test/ELF/linkerscript/sections.s +++ b/lld/test/ELF/linkerscript/sections.s @@ -84,7 +84,8 @@ # SEP-BY-NONALLOC: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align # SEP-BY-NONALLOC-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x00000e 0x00000e R E 0x1000 -# SEP-BY-NONALLOC-NEXT: LOAD 0x00100e 0x000000000000000e 0x000000000000000e 0x000025 0x000025 RW 0x1000 +# SEP-BY-NONALLOC-NEXT: LOAD 0x00100e 0x000000000000000e 0x000000000000000e 0x000020 0x000022 RW 0x1000 +# SEP-BY-NONALLOC-NEXT: LOAD 0x001030 0x0000000000000030 0x0000000000000030 0x000003 0x000003 RW 0x1000 # SEP-BY-NONALLOC-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0 # Input section pattern contains additional semicolon. diff --git a/lld/test/ELF/phdr-align.s b/lld/test/ELF/phdr-align.s --- a/lld/test/ELF/phdr-align.s +++ b/lld/test/ELF/phdr-align.s @@ -32,8 +32,8 @@ # CHECK-NEXT: SHF_ALLOC # CHECK-NEXT: SHF_WRITE # CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x158 -# CHECK-NEXT: Offset: 0x158 +# CHECK-NEXT: Address: 0x190 +# CHECK-NEXT: Offset: 0x190 # CHECK-NEXT: Size: 6 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 @@ -48,8 +48,8 @@ # CHECK-NEXT: SHF_ALLOC # CHECK-NEXT: SHF_WRITE # CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x15E -# CHECK-NEXT: Offset: 0x15E +# CHECK-NEXT: Address: 0x196 +# CHECK-NEXT: Offset: 0x196 # CHECK-NEXT: Size: 2 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 @@ -64,8 +64,8 @@ # CHECK-NEXT: SHF_ALLOC # CHECK-NEXT: SHF_EXECINSTR # CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x160 -# CHECK-NEXT: Offset: 0x160 +# CHECK-NEXT: Address: 0x198 +# CHECK-NEXT: Offset: 0x198 # CHECK-NEXT: Size: 1 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 diff --git a/lld/test/ELF/x86-64-section-layout.s b/lld/test/ELF/x86-64-section-layout.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/x86-64-section-layout.s @@ -0,0 +1,93 @@ +# REQUIRES: x86 +## Test the placement of .lrodata, .lbss, .ldata, and their -fdata-sections variants. +## See also section-layout.s. + +# RUN: rm -rf %t && split-file %s %t && cd %t + +# RUN: llvm-mc -filetype=obj -triple=x86_64 --defsym=BSS=1 a.s -o a.o +# RUN: ld.lld --section-start=.note=0x200300 a.o -o a +# RUN: llvm-readelf -S a | FileCheck %s + +# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a1.o +# RUN: ld.lld --section-start=.note=0x200300 a1.o -o a1 +# RUN: llvm-readelf -S a1 | FileCheck %s --check-prefix=CHECK1 + +# RUN: ld.lld -T b.lds a.o -o b +# RUN: llvm-readelf -S b | FileCheck %s --check-prefix=CHECK2 + +# CHECK: Name Type Address Off Size ES Flg Lk Inf Al +# CHECK-NEXT: NULL 0000000000000000 000000 000000 00 0 0 0 +# CHECK-NEXT: .note NOTE 0000000000200300 000300 000001 00 A 0 0 1 +# CHECK-NEXT: .lrodata PROGBITS 0000000000200301 000301 000002 00 Al 0 0 1 +# CHECK-NEXT: .rodata PROGBITS 0000000000200303 000303 000001 00 A 0 0 1 +# CHECK-NEXT: .text PROGBITS 0000000000201304 000304 000001 00 AX 0 0 4 +# CHECK-NEXT: .tdata PROGBITS 0000000000202305 000305 000001 00 WAT 0 0 1 +# CHECK-NEXT: .tbss NOBITS 0000000000202306 000306 000002 00 WAT 0 0 1 +# CHECK-NEXT: .data PROGBITS 0000000000203306 000306 000001 00 WA 0 0 1 +# CHECK-NEXT: .bss NOBITS 0000000000203307 000307 001800 00 WA 0 0 1 +## We spend size(.bss) % MAXPAGESIZE bytes for .bss. +# CHECK-NEXT: .ldata PROGBITS 0000000000205b07 000b07 000002 00 WAl 0 0 1 +# CHECK-NEXT: .ldata2 PROGBITS 0000000000205b09 000b09 000001 00 WAl 0 0 1 +# CHECK-NEXT: .lbss NOBITS 0000000000205b0a 000b0a 000002 00 WAl 0 0 1 +# CHECK-NEXT: .comment PROGBITS 0000000000000000 000b0a {{.*}} 01 MS 0 0 1 + +# CHECK1: .data PROGBITS 0000000000203306 000306 000001 00 WA 0 0 1 +# CHECK1-NEXT: .ldata PROGBITS 0000000000203307 000307 000002 00 WAl 0 0 1 +# CHECK1-NEXT: .ldata2 PROGBITS 0000000000203309 000309 000001 00 WAl 0 0 1 +# CHECK1-NEXT: .comment PROGBITS 0000000000000000 00030a {{.*}} 01 MS 0 0 1 + +# CHECK2: .note NOTE 0000000000200300 000300 000001 00 A 0 0 1 +# CHECK2-NEXT: .lrodata PROGBITS 0000000000200301 000301 000001 00 Al 0 0 1 +## With a SECTIONS command, we suppress the default rule placing .lrodata.* into .lrodata. +# CHECK2-NEXT: .lrodata.1 PROGBITS 0000000000200302 000302 000001 00 Al 0 0 1 +# CHECK2-NEXT: .rodata PROGBITS 0000000000200303 000303 000001 00 A 0 0 1 +# CHECK2-NEXT: .text PROGBITS 0000000000200304 000304 000001 00 AX 0 0 4 +# CHECK2-NEXT: .tdata PROGBITS 0000000000200305 000305 000001 00 WAT 0 0 1 +# CHECK2-NEXT: .tbss NOBITS 0000000000200306 000306 000001 00 WAT 0 0 1 +# CHECK2-NEXT: .tbss.1 NOBITS 0000000000200307 000306 000001 00 WAT 0 0 1 +# CHECK2-NEXT: .data PROGBITS 0000000000200306 000306 000001 00 WA 0 0 1 +# CHECK2-NEXT: .bss NOBITS 0000000000200307 000307 001800 00 WA 0 0 1 +# CHECK2-NEXT: .ldata PROGBITS 0000000000201b07 000b07 000002 00 WAl 0 0 1 +# CHECK2-NEXT: .ldata2 PROGBITS 0000000000201b09 000b09 000001 00 WAl 0 0 1 +# CHECK2-NEXT: .lbss NOBITS 0000000000201b0a 000b0a 000002 00 WAl 0 0 1 +# CHECK2-NEXT: .comment PROGBITS 0000000000000000 000b0a {{.*}} 01 MS 0 0 1 + +#--- a.s +.globl _start +_start: + ret + +.section .note,"a",@note; .space 1 +.section .rodata,"a",@progbits; .space 1 +.section .data,"aw",@progbits; .space 1 +.ifdef BSS +## .bss is large than one MAXPAGESIZE to test file offsets. +.section .bss,"aw",@nobits; .space 0x1800 +.endif +.section .tdata,"awT",@progbits; .space 1 +.section .tbss,"awT",@nobits; .space 1 +.section .tbss.1,"awT",@nobits; .space 1 + +.section .lrodata,"al"; .space 1 +.section .lrodata.1,"al"; .space 1 +.section .ldata,"awl"; .space 1 +## Input .ldata.rel.ro sections are placed in the output .ldata section. +.section .ldata.rel.ro,"awl"; .space 1 +.ifdef BSS +.section .lbss,"awl",@nobits; .space 1 +## Input .lbss.rel.ro sections are placed in the output .lbss section. +.section .lbss.rel.ro,"awl",@nobits; .space 1 +.endif +.section .ldata2,"awl"; .space 1 + +#--- b.lds +SECTIONS { + . = 0x200300; + .rodata : {} + .text : {} + .data : {} + .bss : {} + .ldata : { *(.ldata .ldata.*) } + .ldata2 : {} + .lbss : { *(.lbss .lbss.*) } +}