[lld] 46085d8 - [lld/ELF][x86-64] Place large executable sections at the edges of binary (#70358)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 12 11:41:19 PDT 2025
Author: Arthur Eubanks
Date: 2025-06-12T11:41:16-07:00
New Revision: 46085d8f83623f6ea2921459de9f731d7df762d4
URL: https://github.com/llvm/llvm-project/commit/46085d8f83623f6ea2921459de9f731d7df762d4
DIFF: https://github.com/llvm/llvm-project/commit/46085d8f83623f6ea2921459de9f731d7df762d4.diff
LOG: [lld/ELF][x86-64] Place large executable sections at the edges of binary (#70358)
So that when mixing small and large text, large text stays out of the
way of the rest of the binary.
Place large RX sections at the beginning rather than at the end so that
with `--no-rosegment`, the large text and rodata share a single PT_LOAD
segment. Place large RWX sections at the end to keep writable and
readonly sections separate.
Clang started emitting the large section flag for `.ltext` sections in
#73037.
Added:
Modified:
lld/ELF/Writer.cpp
lld/test/ELF/x86-64-section-layout.s
Removed:
################################################################################
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 10dc688160d1e..3d9888f576f05 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -653,15 +653,17 @@ enum RankFlags {
RF_NOT_ADDR_SET = 1 << 27,
RF_NOT_ALLOC = 1 << 26,
RF_PARTITION = 1 << 18, // Partition number (8 bits)
+ RF_LARGE_EXEC_WRITE = 1 << 16,
RF_LARGE_ALT = 1 << 15,
RF_WRITE = 1 << 14,
RF_EXEC_WRITE = 1 << 13,
RF_EXEC = 1 << 12,
RF_RODATA = 1 << 11,
- RF_LARGE = 1 << 10,
- RF_NOT_RELRO = 1 << 9,
- RF_NOT_TLS = 1 << 8,
- RF_BSS = 1 << 7,
+ RF_LARGE_EXEC = 1 << 10,
+ RF_LARGE = 1 << 9,
+ RF_NOT_RELRO = 1 << 8,
+ RF_NOT_TLS = 1 << 7,
+ RF_BSS = 1 << 6,
};
unsigned elf::getSectionRank(Ctx &ctx, OutputSection &osec) {
@@ -691,6 +693,7 @@ unsigned elf::getSectionRank(Ctx &ctx, OutputSection &osec) {
// places.
bool isExec = osec.flags & SHF_EXECINSTR;
bool isWrite = osec.flags & SHF_WRITE;
+ bool isLarge = osec.flags & SHF_X86_64_LARGE && ctx.arg.emachine == EM_X86_64;
if (!isWrite && !isExec) {
// Among PROGBITS sections, place .lrodata further from .text.
@@ -698,7 +701,7 @@ unsigned elf::getSectionRank(Ctx &ctx, OutputSection &osec) {
// layout has one extra PT_LOAD, but alleviates relocation overflow
// pressure for absolute relocations referencing small data from -fno-pic
// relocatable files.
- if (osec.flags & SHF_X86_64_LARGE && ctx.arg.emachine == EM_X86_64)
+ if (isLarge)
rank |= ctx.arg.zLrodataAfterBss ? RF_LARGE_ALT : 0;
else
rank |= ctx.arg.zLrodataAfterBss ? 0 : RF_LARGE;
@@ -722,7 +725,13 @@ unsigned elf::getSectionRank(Ctx &ctx, OutputSection &osec) {
else
rank |= RF_RODATA;
} else if (isExec) {
- rank |= isWrite ? RF_EXEC_WRITE : RF_EXEC;
+ // Place readonly .ltext before .lrodata and writable .ltext after .lbss to
+ // keep writable and readonly segments separate.
+ if (isLarge) {
+ rank |= isWrite ? RF_LARGE_EXEC_WRITE : RF_LARGE_EXEC;
+ } else {
+ rank |= isWrite ? RF_EXEC_WRITE : RF_EXEC;
+ }
} else {
rank |= RF_WRITE;
// The TLS initialization block needs to be a single contiguous block. Place
@@ -737,7 +746,7 @@ unsigned elf::getSectionRank(Ctx &ctx, OutputSection &osec) {
// alleviates relocation overflow pressure.
// For -z lrodata-after-bss, place .lbss/.lrodata/.ldata after .bss.
// .bss/.lbss being adjacent reuses the NOBITS size optimization.
- if (osec.flags & SHF_X86_64_LARGE && ctx.arg.emachine == EM_X86_64) {
+ if (isLarge) {
rank |= ctx.arg.zLrodataAfterBss
? (osec.type == SHT_NOBITS ? 1 : RF_LARGE_ALT)
: RF_LARGE;
diff --git a/lld/test/ELF/x86-64-section-layout.s b/lld/test/ELF/x86-64-section-layout.s
index b03d3e6c2b999..1432271b885a8 100644
--- a/lld/test/ELF/x86-64-section-layout.s
+++ b/lld/test/ELF/x86-64-section-layout.s
@@ -18,6 +18,10 @@
# RUN: ld.lld --section-start=.note=0x200300 a.o -z lrodata-after-bss -o a3
# RUN: llvm-readelf -S -l -sX a3 | FileCheck %s --check-prefix=CHECK3
+# RUN: llvm-mc -filetype=obj -triple=x86_64 c.s -o c.o
+# RUN: ld.lld c.o -o c
+# RUN: llvm-readelf -S -l c | FileCheck %s --check-prefix=CHECK4
+
# 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
@@ -116,6 +120,18 @@
# CHECK3-NEXT: 0000000000203307 0 NOTYPE GLOBAL DEFAULT [[#]] (.data) _edata
# CHECK3-NEXT: 0000000000207d0d 0 NOTYPE GLOBAL DEFAULT [[#]] (.ldata2) _end
+# CHECK4: .note NOTE
+# CHECK4-NEXT: .ltext PROGBITS
+# CHECK4-NEXT: .lrodata PROGBITS
+# CHECK4-NEXT: .rodata PROGBITS
+# CHECK4-NEXT: .text PROGBITS
+# CHECK4-NEXT: .data PROGBITS
+# CHECK4-NEXT: .bss NOBITS
+# CHECK4-NEXT: .ldata PROGBITS
+# CHECK4-NEXT: .lbss NOBITS
+# CHECK4-NEXT: .ltext_w PROGBITS
+# CHECK4-NEXT: .comment PROGBITS
+
#--- a.s
.globl _start, _etext, _edata, _end
_start:
@@ -155,3 +171,28 @@ SECTIONS {
.ldata2 : {}
.lbss : { *(.lbss .lbss.*) }
}
+
+#--- c.s
+## Test .ltext layout
+.section .ltext,"axl", at progbits
+.globl f
+f:
+ ret
+
+.section .ltext_w,"awxl", at progbits
+.globl g
+g:
+ ret
+
+.section .text,"ax", at progbits
+.globl h
+h:
+ ret
+
+.section .note,"a", at note; .space 1
+.section .rodata,"a", at progbits; .space 1
+.section .data,"aw", at progbits; .space 1
+.section .bss,"aw", at nobits; .space 1
+.section .lrodata,"al"; .space 1
+.section .ldata,"awl"; .space 1
+.section .lbss,"awl", at nobits; .space 1
More information about the llvm-commits
mailing list