Skip to content

Commit 7dcd90d

Browse files
[lld][ELF] Allow data.rel.ro.hot and .data.rel.ro.unlikely to be RELRO (#148920)
https://discourse.llvm.org/t/rfc-profile-guided-static-data-partitioning/83744 proposes to partition a static data section (like `.data.rel.ro`) into two sections, one grouping the cold ones and the other grouping the rest. lld requires all relro sections to be contiguous. To place `.data.rel.ro.unlikely` in the middle of all relro sections, this change proposes to add `.data.rel.ro.unlikely` explicitly as RELRO section. --------- Co-authored-by: Sam Elliott <[email protected]>
1 parent dbc63f1 commit 7dcd90d

File tree

4 files changed

+114
-1
lines changed

4 files changed

+114
-1
lines changed

lld/ELF/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ struct Config {
404404
bool zIfuncNoplt;
405405
bool zInitfirst;
406406
bool zInterpose;
407+
bool zKeepDataSectionPrefix;
407408
bool zKeepTextSectionPrefix;
408409
bool zLrodataAfterBss;
409410
bool zNoBtCfi;

lld/ELF/Driver.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,6 +1625,8 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
16251625
ctx.arg.zIfuncNoplt = hasZOption(args, "ifunc-noplt");
16261626
ctx.arg.zInitfirst = hasZOption(args, "initfirst");
16271627
ctx.arg.zInterpose = hasZOption(args, "interpose");
1628+
ctx.arg.zKeepDataSectionPrefix = getZFlag(
1629+
args, "keep-data-section-prefix", "nokeep-data-section-prefix", false);
16281630
ctx.arg.zKeepTextSectionPrefix = getZFlag(
16291631
args, "keep-text-section-prefix", "nokeep-text-section-prefix", false);
16301632
ctx.arg.zLrodataAfterBss =

lld/ELF/Writer.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,27 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
553553
}
554554
}
555555

556+
// Returns true if the section is a data section that's read only and
557+
// relocatable per its section name.
558+
static bool isRelRoDataSection(Ctx &ctx, StringRef secName) {
559+
// The section name should start with ".data.rel.ro".
560+
if (!secName.consume_front(".data.rel.ro"))
561+
return false;
562+
563+
// If the section name is .data.rel.ro, it is a relocatable read-only data
564+
// section.
565+
if (secName.empty())
566+
return true;
567+
// If -z keep-data-section-prefix is given, '.data.rel.ro.hot' and
568+
// '.data.rel.ro.unlikely' are considered a split of '.data.rel.ro' based on
569+
// hotness.
570+
if (ctx.arg.zKeepDataSectionPrefix) {
571+
return secName == ".hot" || secName == ".unlikely";
572+
}
573+
574+
return false;
575+
}
576+
556577
// Today's loaders have a feature to make segments read-only after
557578
// processing dynamic relocations to enhance security. PT_GNU_RELRO
558579
// is defined for that.
@@ -629,7 +650,7 @@ static bool isRelroSection(Ctx &ctx, const OutputSection *sec) {
629650
// magic section names.
630651
StringRef s = sec->name;
631652

632-
bool abiAgnostic = s == ".data.rel.ro" || s == ".bss.rel.ro" ||
653+
bool abiAgnostic = isRelRoDataSection(ctx, s) || s == ".bss.rel.ro" ||
633654
s == ".ctors" || s == ".dtors" || s == ".jcr" ||
634655
s == ".eh_frame" || s == ".fini_array" ||
635656
s == ".init_array" || s == ".preinit_array";
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# REQUIRES: x86
2+
3+
# RUN: rm -rf %t && split-file %s %t && cd %t
4+
5+
# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
6+
7+
# RUN: ld.lld -z keep-data-section-prefix -T x.lds a.o -o out1
8+
# RUN: llvm-readelf -l out1 | FileCheck --check-prefixes=SEG,LS %s
9+
# RUN: llvm-readelf -S out1 | FileCheck %s --check-prefix=CHECK-LS
10+
11+
# RUN: ld.lld -z keep-data-section-prefix a.o -o out2
12+
# RUN: llvm-readelf -l out2 | FileCheck --check-prefixes=SEG,PRE %s
13+
# RUN: llvm-readelf -S out2 | FileCheck %s --check-prefix=CHECK-PRE
14+
15+
# RUN: ld.lld a.o -o out3
16+
# RUN: llvm-readelf -l out3 | FileCheck --check-prefixes=SEG,PRE %s
17+
# RUN: llvm-readelf -S out3 | FileCheck %s --check-prefix=CHECK-PRE
18+
19+
# RUN: not ld.lld -T x.lds a.o 2>&1 | FileCheck %s
20+
# CHECK: error: section: .relro_padding is not contiguous with other relro sections
21+
22+
## The first RW PT_LOAD segment has FileSiz 0x126f (0x1000 + 0x200 + 0x60 + 0xf),
23+
## and its p_offset p_vaddr p_paddr p_filesz should match PT_GNU_RELRO.
24+
# Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
25+
# SEG: LOAD 0x0001c8 0x00000000002011c8 0x00000000002011c8 0x000001 0x000001 R E 0x1000
26+
# SEG-NEXT: LOAD 0x0001c9 0x00000000002021c9 0x00000000002021c9 0x00126f 0x001e37 RW 0x1000
27+
# SEG-NEXT: LOAD 0x001438 0x0000000000204438 0x0000000000204438 0x000001 0x000002 RW 0x1000
28+
# SEG-NEXT: GNU_RELRO 0x0001c9 0x00000000002021c9 0x00000000002021c9 0x00126f 0x001e37 R 0x1
29+
# SEG-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0
30+
31+
## Input to output mapping per linker script
32+
## .data.rel.ro.split -> .data.rel.ro
33+
## .data.rel.ro -> .data.rel.ro
34+
## .data.rel.ro.hot -> .data.rel.ro.hot
35+
## .data.rel.ro.unlikely -> .data.rel.ro.unlikely
36+
# LS: .text
37+
# LS-NEXT: .data.rel.ro.hot .data.rel.ro .data.rel.ro.unlikely .relro_padding
38+
# LS-NEXT: .data .bss
39+
40+
# [Nr] Name Type Address Off Size
41+
# CHECK-LS: .data.rel.ro.hot PROGBITS 00000000002021c9 0001c9 00000f
42+
# CHECK-LS-NEXT: .data.rel.ro PROGBITS 00000000002021d8 0001d8 000260
43+
# CHECK-LS-NEXT: .data.rel.ro.unlikely PROGBITS 0000000000202438 000438 001000
44+
# CHECK-LS-NEXT: .relro_padding NOBITS 0000000000203438 001438 000bc8
45+
# CHECK-LS-NEXT: .data PROGBITS 0000000000204438 001438 000001
46+
# CHECK-LS-NEXT: .bss NOBITS 0000000000204439 001439 000001
47+
48+
## Linker script is not provided to map data sections.
49+
## So all input sections with prefix .data.rel.ro will map to .data.rel.ro in the output.
50+
# PRE: .text
51+
# PRE-NEXT: .data.rel.ro .relro_padding
52+
# PRE-NEXT: .data .bss
53+
54+
# [Nr] Name Type Address Off Size
55+
# CHECK-PRE: .data.rel.ro PROGBITS 00000000002021c9 0001c9 00126f
56+
# CHECK-PRE-NEXT: .relro_padding NOBITS 0000000000203438 001438 000bc8
57+
# CHECK-PRE-NEXT: .data PROGBITS 0000000000204438 001438 000001
58+
# CHECK-PRE-NEXT: .bss NOBITS 0000000000204439 001439 000001
59+
60+
#--- x.lds
61+
SECTIONS {
62+
.data.rel.ro.hot : { *(.data.rel.ro.hot) }
63+
.data.rel.ro : { .data.rel.ro }
64+
.data.rel.ro.unlikely : { *(.data.rel.ro.unlikely) }
65+
} INSERT AFTER .text
66+
67+
68+
#--- a.s
69+
.globl _start
70+
_start:
71+
ret
72+
73+
.section .data.rel.ro.hot, "aw"
74+
.space 15
75+
76+
.section .data.rel.ro, "aw"
77+
.space 96
78+
79+
.section .data.rel.ro.split,"aw"
80+
.space 512
81+
82+
.section .data.rel.ro.unlikely, "aw"
83+
.space 4096
84+
85+
.section .data, "aw"
86+
.space 1
87+
88+
.section .bss, "aw"
89+
.space 1

0 commit comments

Comments
 (0)