[llvm-branch-commits] [ELF] Place .lbss/.lrodata/.ldata after .bss (PR #81224)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Feb 8 20:14:12 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld-elf

@llvm/pr-subscribers-lld

Author: Fangrui Song (MaskRay)

<details>
<summary>Changes</summary>

https://reviews.llvm.org/D150510 places .lrodata before .rodata to
minimize the number of permission transitions in the memory image.
However, this layout is not ideal for -fno-pic code (which is still
important).

Small code model -fno-pic code has R_X86_64_32S relocations with a range
of [0,2**31) (if we ignore the negative area). Placing `.lrodata`
earlier exerts relocation pressure on such code. Non-x86 64-bit
architectures generally have a similar [0,2**31) limitation if they
don't use PC-relative relocations.

If we place .lrodata later, two layouts are appealing:

* .bss/.lbss/.lrodata/.ldata (GNU ld)
* .bss/.ldata/.lbss/.lrodata

The GNU ld style has the nice property that there is only one BSS
(except .tbss/.relro_padding). Let's match GNU ld. While here, also
place `_edata` at a location similar to GNU ld.


---
Full diff: https://github.com/llvm/llvm-project/pull/81224.diff


3 Files Affected:

- (modified) lld/ELF/Writer.cpp (+20-13) 
- (modified) lld/test/ELF/lto/codemodel.ll (+4-4) 
- (modified) lld/test/ELF/x86-64-section-layout.s (+44-35) 


``````````diff
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 53ca70b59076fd..47e15ba869d4f4 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -911,11 +911,11 @@ enum RankFlags {
   RF_NOT_ALLOC = 1 << 26,
   RF_PARTITION = 1 << 18, // Partition number (8 bits)
   RF_NOT_SPECIAL = 1 << 17,
-  RF_WRITE = 1 << 16,
-  RF_EXEC_WRITE = 1 << 15,
-  RF_EXEC = 1 << 14,
-  RF_RODATA = 1 << 13,
-  RF_LARGE = 1 << 12,
+  RF_LARGE = 1 << 14,
+  RF_WRITE = 1 << 13,
+  RF_EXEC_WRITE = 1 << 12,
+  RF_EXEC = 1 << 11,
+  RF_RODATA = 1 << 10,
   RF_NOT_RELRO = 1 << 9,
   RF_NOT_TLS = 1 << 8,
   RF_BSS = 1 << 7,
@@ -973,8 +973,11 @@ static unsigned getSectionRank(OutputSection &osec) {
     // .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))
+    // Place .lrodata after .lbss like GNU ld. An alternative layout is to place
+    // .lrodata before .rodata (one fewer PT_LOAD), but does not alleviate
+    // relocation overflow pressure for absolute relocations referencing small
+    // data from -fno-pic relocatable files.
+    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;
@@ -988,10 +991,10 @@ static unsigned getSectionRank(OutputSection &osec) {
       osec.relro = true;
     else
       rank |= RF_NOT_RELRO;
-    // Place .ldata and .lbss after .bss. Making .bss closer to .text alleviates
-    // relocation overflow pressure.
+    // Place .lbss/.lrodata/.ldata after .bss. .bss/.lbss being adjacent reuses
+    // the NOBITS size optimization.
     if (osec.flags & SHF_X86_64_LARGE && config->emachine == EM_X86_64)
-      rank |= RF_LARGE;
+      rank |= osec.type == SHT_NOBITS ? 1 : RF_LARGE;
   }
 
   // Within TLS sections, or within other RelRo sections, or within non-RelRo
@@ -1124,11 +1127,15 @@ template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
   }
 
   if (last) {
-    // _edata points to the end of the last mapped initialized section.
+    // _edata points to the end of the last mapped initialized section before
+    // the first regular NOBITS section (except .tbss and .relro_padding). In
+    // the presence of large data sections, .ldata may be after _edata.
     OutputSection *edata = nullptr;
     for (OutputSection *os : outputSections) {
-      if (os->type != SHT_NOBITS)
-        edata = os;
+      if (os->type == SHT_NOBITS && !(os->flags & SHF_TLS) &&
+          (!in.relroPadding || in.relroPadding->getParent() != os))
+        break;
+      edata = os;
       if (os == last->lastSec)
         break;
     }
diff --git a/lld/test/ELF/lto/codemodel.ll b/lld/test/ELF/lto/codemodel.ll
index a35f87729411d7..cf7d0e409ec4b1 100644
--- a/lld/test/ELF/lto/codemodel.ll
+++ b/lld/test/ELF/lto/codemodel.ll
@@ -2,8 +2,8 @@
 ; RUN: llvm-as %s -o %t.o
 ; RUN: ld.lld %t.o -o %ts -mllvm -code-model=small
 ; RUN: ld.lld %t.o -o %tl -mllvm -code-model=large
-; RUN: llvm-objdump --no-print-imm-hex -d %ts | FileCheck %s --check-prefix=CHECK-SMALL
-; RUN: llvm-objdump --no-print-imm-hex -d %tl | FileCheck %s --check-prefix=CHECK-LARGE
+; RUN: llvm-objdump -d %ts | FileCheck %s --check-prefix=CHECK-SMALL
+; RUN: llvm-objdump -d %tl | FileCheck %s --check-prefix=CHECK-LARGE
 
 target triple = "x86_64-unknown-linux-gnu"
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
@@ -13,8 +13,8 @@ target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16
 define ptr @_start() nounwind readonly {
 entry:
 ; CHECK-SMALL-LABEL:  <_start>:
-; CHECK-SMALL: movl    $2097440, %eax
+; CHECK-SMALL: movl    ${{.*}}, %eax
 ; CHECK-LARGE-LABEL: <_start>:
-; CHECK-LARGE: movabsq $2097440, %rax
+; CHECK-LARGE: movabsq ${{.*}}, %rax
     ret ptr @data
 }
diff --git a/lld/test/ELF/x86-64-section-layout.s b/lld/test/ELF/x86-64-section-layout.s
index 37201279fa0a5d..1e1f36ed64009d 100644
--- a/lld/test/ELF/x86-64-section-layout.s
+++ b/lld/test/ELF/x86-64-section-layout.s
@@ -6,7 +6,7 @@
 
 # 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 -l a | FileCheck %s
+# RUN: llvm-readelf -S -l -sX 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
@@ -15,63 +15,72 @@
 # RUN: ld.lld -T b.lds -z norelro a.o -o b
 # RUN: llvm-readelf -S -l 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:  .relro_padding NOBITS      0000000000202306 000306 000cfa 00  WA  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
+# 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:  .rodata           PROGBITS        0000000000200301 000301 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:  .relro_padding    NOBITS          0000000000202306 000306 000cfa 00  WA  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) + size(.lbss)) % MAXPAGESIZE bytes.
+# CHECK-NEXT:  .lbss             NOBITS          0000000000204b07 000307 001201 00 WAl  0   0  1
+# CHECK-NEXT:  .lrodata          PROGBITS        0000000000206d08 000d08 000002 00  Al  0   0  1
+# CHECK-NEXT:  .ldata            PROGBITS        0000000000207d0a 000d0a 000002 00 WAl  0   0  1
+# CHECK-NEXT:  .ldata2           PROGBITS        0000000000207d0c 000d0c 000001 00 WAl  0   0  1
+# CHECK-NEXT:  .comment          PROGBITS        0000000000000000 000d0d {{.*}} 01  MS  0   0  1
 
 # CHECK:       Program Headers:
 # CHECK-NEXT:    Type  Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
 # CHECK-NEXT:    PHDR  0x000040 0x0000000000200040 0x0000000000200040 {{.*}}   {{.*}}   R   0x8
-# CHECK-NEXT:    LOAD  0x000000 0x0000000000200000 0x0000000000200000 0x000304 0x000304 R   0x1000
+# CHECK-NEXT:    LOAD  0x000000 0x0000000000200000 0x0000000000200000 0x000302 0x000302 R   0x1000
 # CHECK-NEXT:    LOAD  0x000304 0x0000000000201304 0x0000000000201304 0x000001 0x000001 R E 0x1000
 # CHECK-NEXT:    LOAD  0x000305 0x0000000000202305 0x0000000000202305 0x000001 0x000cfb RW  0x1000
-# CHECK-NEXT:    LOAD  0x000306 0x0000000000203306 0x0000000000203306 0x000001 0x001801 RW  0x1000
-# CHECK-NEXT:    LOAD  0x000b07 0x0000000000205b07 0x0000000000205b07 0x000003 0x000005 RW  0x1000
+# CHECK-NEXT:    LOAD  0x000306 0x0000000000203306 0x0000000000203306 0x000001 0x002a02 RW  0x1000
+# CHECK-NEXT:    LOAD  0x000d08 0x0000000000206d08 0x0000000000206d08 0x000002 0x000002 R   0x1000
+# CHECK-NEXT:    LOAD  0x000d0a 0x0000000000207d0a 0x0000000000207d0a 0x000003 0x000003 RW  0x1000
+# CHECK-NEXT:    TLS   0x000305 0x0000000000202305 0x0000000000202305 0x000001 0x000003 R   0x1
+
+# CHECK:       0000000000201304     0 NOTYPE  GLOBAL DEFAULT [[#]] (.text)  _start
+# CHECK-NEXT:  0000000000203307     0 NOTYPE  GLOBAL DEFAULT [[#]] (.data)  _edata
+# CHECK-NEXT:  0000000000207d0d     0 NOTYPE  GLOBAL DEFAULT [[#]] (.ldata2) _end
 
 # 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
+# CHECK1-NEXT: .lrodata   PROGBITS        0000000000204307 000307 000002 00  Al  0   0  1
+# CHECK1-NEXT: .ldata     PROGBITS        0000000000205309 000309 000002 00 WAl  0   0  1
+# CHECK1-NEXT: .ldata2    PROGBITS        000000000020530b 00030b 000001 00 WAl  0   0  1
+# CHECK1-NEXT: .comment   PROGBITS        0000000000000000 00030c {{.*}} 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: .rodata    PROGBITS        0000000000200301 000301 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 001b07 000002 00 WAl  0   0  1
-# CHECK2-NEXT: .ldata2    PROGBITS        0000000000201b09 001b09 000001 00 WAl  0   0  1
-# CHECK2-NEXT: .lbss      NOBITS          0000000000201b0a 001b0a 000002 00 WAl  0   0  1
-# CHECK2-NEXT: .comment   PROGBITS        0000000000000000 001b0a {{.*}} 01  MS  0   0  1
+## With a SECTIONS command, we suppress the default rule placing .lrodata.* into .lrodata.
+# CHECK2-NEXT: .lrodata   PROGBITS        0000000000201b07 000b07 000001 00  Al  0   0  1
+# CHECK2-NEXT: .lrodata.1 PROGBITS        0000000000201b08 000b08 000001 00  Al  0   0  1
+# CHECK2-NEXT: .ldata     PROGBITS        0000000000201b09 000b09 000002 00 WAl  0   0  1
+# CHECK2-NEXT: .ldata2    PROGBITS        0000000000201b0b 000b0b 000001 00 WAl  0   0  1
+# CHECK2-NEXT: .lbss      NOBITS          0000000000201b0c 000b0c 001201 00 WAl  0   0  1
+# CHECK2-NEXT: .comment   PROGBITS        0000000000000000 000b0c {{.*}} 01  MS  0   0  1
 
 # CHECK2:      Program Headers:
 # CHECK2-NEXT:   Type  Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
 # CHECK2-NEXT:   PHDR  0x000040 0x0000000000200040 0x0000000000200040 {{.*}}   {{.*}}   R   0x8
-# CHECK2-NEXT:   LOAD  0x000000 0x0000000000200000 0x0000000000200000 0x000304 0x000304 R   0x1000
+# CHECK2-NEXT:   LOAD  0x000000 0x0000000000200000 0x0000000000200000 0x000302 0x000302 R   0x1000
 # CHECK2-NEXT:   LOAD  0x000304 0x0000000000200304 0x0000000000200304 0x000001 0x000001 R E 0x1000
-# CHECK2-NEXT:   LOAD  0x000305 0x0000000000200305 0x0000000000200305 0x001805 0x001807 RW  0x1000
+# CHECK2-NEXT:   LOAD  0x000305 0x0000000000200305 0x0000000000200305 0x000002 0x001802 RW  0x1000
+# CHECK2-NEXT:   LOAD  0x000b07 0x0000000000201b07 0x0000000000201b07 0x000002 0x000002 R   0x1000
+# CHECK2-NEXT:   LOAD  0x000b09 0x0000000000201b09 0x0000000000201b09 0x000003 0x001204 RW  0x1000
 # CHECK2-NEXT:   TLS   0x000305 0x0000000000200305 0x0000000000200305 0x000001 0x000003 R   0x1
 
 #--- a.s
-.globl _start
+.globl _start, _edata, _end
 _start:
   ret
 
@@ -92,7 +101,7 @@ _start:
 ## Input .ldata.rel.ro sections are placed in the output .ldata section.
 .section .ldata.rel.ro,"awl"; .space 1
 .ifdef BSS
-.section .lbss,"awl", at nobits; .space 1
+.section .lbss,"awl", at nobits; .space 0x1200
 ## Input .lbss.rel.ro sections are placed in the output .lbss section.
 .section .lbss.rel.ro,"awl", at nobits; .space 1
 .endif

``````````

</details>


https://github.com/llvm/llvm-project/pull/81224


More information about the llvm-branch-commits mailing list