Skip to content

Commit 46085d8

Browse files
authored
[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.
1 parent edf636a commit 46085d8

File tree

2 files changed

+57
-7
lines changed

2 files changed

+57
-7
lines changed

lld/ELF/Writer.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -653,15 +653,17 @@ enum RankFlags {
653653
RF_NOT_ADDR_SET = 1 << 27,
654654
RF_NOT_ALLOC = 1 << 26,
655655
RF_PARTITION = 1 << 18, // Partition number (8 bits)
656+
RF_LARGE_EXEC_WRITE = 1 << 16,
656657
RF_LARGE_ALT = 1 << 15,
657658
RF_WRITE = 1 << 14,
658659
RF_EXEC_WRITE = 1 << 13,
659660
RF_EXEC = 1 << 12,
660661
RF_RODATA = 1 << 11,
661-
RF_LARGE = 1 << 10,
662-
RF_NOT_RELRO = 1 << 9,
663-
RF_NOT_TLS = 1 << 8,
664-
RF_BSS = 1 << 7,
662+
RF_LARGE_EXEC = 1 << 10,
663+
RF_LARGE = 1 << 9,
664+
RF_NOT_RELRO = 1 << 8,
665+
RF_NOT_TLS = 1 << 7,
666+
RF_BSS = 1 << 6,
665667
};
666668

667669
unsigned elf::getSectionRank(Ctx &ctx, OutputSection &osec) {
@@ -691,14 +693,15 @@ unsigned elf::getSectionRank(Ctx &ctx, OutputSection &osec) {
691693
// places.
692694
bool isExec = osec.flags & SHF_EXECINSTR;
693695
bool isWrite = osec.flags & SHF_WRITE;
696+
bool isLarge = osec.flags & SHF_X86_64_LARGE && ctx.arg.emachine == EM_X86_64;
694697

695698
if (!isWrite && !isExec) {
696699
// Among PROGBITS sections, place .lrodata further from .text.
697700
// For -z lrodata-after-bss, place .lrodata after .lbss like GNU ld. This
698701
// layout has one extra PT_LOAD, but alleviates relocation overflow
699702
// pressure for absolute relocations referencing small data from -fno-pic
700703
// relocatable files.
701-
if (osec.flags & SHF_X86_64_LARGE && ctx.arg.emachine == EM_X86_64)
704+
if (isLarge)
702705
rank |= ctx.arg.zLrodataAfterBss ? RF_LARGE_ALT : 0;
703706
else
704707
rank |= ctx.arg.zLrodataAfterBss ? 0 : RF_LARGE;
@@ -722,7 +725,13 @@ unsigned elf::getSectionRank(Ctx &ctx, OutputSection &osec) {
722725
else
723726
rank |= RF_RODATA;
724727
} else if (isExec) {
725-
rank |= isWrite ? RF_EXEC_WRITE : RF_EXEC;
728+
// Place readonly .ltext before .lrodata and writable .ltext after .lbss to
729+
// keep writable and readonly segments separate.
730+
if (isLarge) {
731+
rank |= isWrite ? RF_LARGE_EXEC_WRITE : RF_LARGE_EXEC;
732+
} else {
733+
rank |= isWrite ? RF_EXEC_WRITE : RF_EXEC;
734+
}
726735
} else {
727736
rank |= RF_WRITE;
728737
// The TLS initialization block needs to be a single contiguous block. Place
@@ -737,7 +746,7 @@ unsigned elf::getSectionRank(Ctx &ctx, OutputSection &osec) {
737746
// alleviates relocation overflow pressure.
738747
// For -z lrodata-after-bss, place .lbss/.lrodata/.ldata after .bss.
739748
// .bss/.lbss being adjacent reuses the NOBITS size optimization.
740-
if (osec.flags & SHF_X86_64_LARGE && ctx.arg.emachine == EM_X86_64) {
749+
if (isLarge) {
741750
rank |= ctx.arg.zLrodataAfterBss
742751
? (osec.type == SHT_NOBITS ? 1 : RF_LARGE_ALT)
743752
: RF_LARGE;

lld/test/ELF/x86-64-section-layout.s

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
# RUN: ld.lld --section-start=.note=0x200300 a.o -z lrodata-after-bss -o a3
1919
# RUN: llvm-readelf -S -l -sX a3 | FileCheck %s --check-prefix=CHECK3
2020

21+
# RUN: llvm-mc -filetype=obj -triple=x86_64 c.s -o c.o
22+
# RUN: ld.lld c.o -o c
23+
# RUN: llvm-readelf -S -l c | FileCheck %s --check-prefix=CHECK4
24+
2125
# CHECK: Name Type Address Off Size ES Flg Lk Inf Al
2226
# CHECK-NEXT: NULL 0000000000000000 000000 000000 00 0 0 0
2327
# CHECK-NEXT: .note NOTE 0000000000200300 000300 000001 00 A 0 0 1
@@ -116,6 +120,18 @@
116120
# CHECK3-NEXT: 0000000000203307 0 NOTYPE GLOBAL DEFAULT [[#]] (.data) _edata
117121
# CHECK3-NEXT: 0000000000207d0d 0 NOTYPE GLOBAL DEFAULT [[#]] (.ldata2) _end
118122

123+
# CHECK4: .note NOTE
124+
# CHECK4-NEXT: .ltext PROGBITS
125+
# CHECK4-NEXT: .lrodata PROGBITS
126+
# CHECK4-NEXT: .rodata PROGBITS
127+
# CHECK4-NEXT: .text PROGBITS
128+
# CHECK4-NEXT: .data PROGBITS
129+
# CHECK4-NEXT: .bss NOBITS
130+
# CHECK4-NEXT: .ldata PROGBITS
131+
# CHECK4-NEXT: .lbss NOBITS
132+
# CHECK4-NEXT: .ltext_w PROGBITS
133+
# CHECK4-NEXT: .comment PROGBITS
134+
119135
#--- a.s
120136
.globl _start, _etext, _edata, _end
121137
_start:
@@ -155,3 +171,28 @@ SECTIONS {
155171
.ldata2 : {}
156172
.lbss : { *(.lbss .lbss.*) }
157173
}
174+
175+
#--- c.s
176+
## Test .ltext layout
177+
.section .ltext,"axl",@progbits
178+
.globl f
179+
f:
180+
ret
181+
182+
.section .ltext_w,"awxl",@progbits
183+
.globl g
184+
g:
185+
ret
186+
187+
.section .text,"ax",@progbits
188+
.globl h
189+
h:
190+
ret
191+
192+
.section .note,"a",@note; .space 1
193+
.section .rodata,"a",@progbits; .space 1
194+
.section .data,"aw",@progbits; .space 1
195+
.section .bss,"aw",@nobits; .space 1
196+
.section .lrodata,"al"; .space 1
197+
.section .ldata,"awl"; .space 1
198+
.section .lbss,"awl",@nobits; .space 1

0 commit comments

Comments
 (0)