From 24c1c62b584fb42fcd91b9343bbe61e521038dd0 Mon Sep 17 00:00:00 2001 From: mingmingl Date: Sun, 30 Mar 2025 23:32:41 +0000 Subject: [PATCH 01/10] lld keep data section prefix --- lld/ELF/Config.h | 1 + lld/ELF/Driver.cpp | 4 +++ lld/ELF/LinkerScript.cpp | 69 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 03b3cd4771f49..0a01eddf20271 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -372,6 +372,7 @@ struct Config { bool zInitfirst; bool zInterpose; bool zKeepTextSectionPrefix; + bool zKeepDataSectionPrefix; bool zLrodataAfterBss; bool zNoBtCfi; bool zNodefaultlib; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 0a220432333cc..32ebd7a1a2ad9 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1566,6 +1566,10 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) { ctx.arg.zInterpose = hasZOption(args, "interpose"); ctx.arg.zKeepTextSectionPrefix = getZFlag( args, "keep-text-section-prefix", "nokeep-text-section-prefix", false); + ctx.arg.zKeepDataSectionPrefix = getZFlag( + args, "keep-data-section-prefix", "nokeep-data-section-prefix", false); + errs() << "ELF/Driver.cpp:1540\t" << ctx.arg.zKeepDataSectionPrefix << "\n"; + ctx.arg.zLrodataAfterBss = getZFlag(args, "lrodata-after-bss", "nolrodata-after-bss", false); ctx.arg.zNoBtCfi = hasZOption(args, "nobtcfi"); diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index e19823f2ea752..17432e65bb1bf 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -48,6 +48,11 @@ static bool isSectionPrefix(StringRef prefix, StringRef name) { return name.consume_front(prefix) && (name.empty() || name[0] == '.'); } +bool hasUnlikelySuffix(StringRef name) { + return name.ends_with(".unlikely") || name.ends_with(".unlikely.") || + name.ends_with("unlikely"); +} + StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const { // This is for --emit-relocs and -r. If .text.foo is emitted as .text.bar, we // want to emit .rela.text.foo as .rela.text.bar for consistency (this is not @@ -105,6 +110,70 @@ StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const { return ".text"; } + if (isSectionPrefix(".data.rel.ro", s->name)) { + // Map input sections' .rodata and rodata.hot into .rodata.hot in the + // output. Map input sections' .rodata.unlikely into .rodata in the output. + if (ctx.arg.zKeepDataSectionPrefix) { + if (isSectionPrefix(".data.rel.ro.unlikely", s->name) || + hasUnlikelySuffix(s->name)) { + return ".data.rel.ro.unlikely"; + } + + return ".data.rel.ro"; + } + return ".data.rel.ro"; + } + + if (isSectionPrefix(".data", s->name)) { + // Map input sections' .rodata and rodata.hot into .rodata.hot in the + // output. Map input sections' .rodata.unlikely into .rodata in the output. + if (ctx.arg.zKeepDataSectionPrefix) { + if (isSectionPrefix(".data.unlikely", s->name) || + hasUnlikelySuffix(s->name)) { + // errs() << "LinkerScript.cpp:100\t" << s->name << "\n"; + return ".data.unlikely"; + } + + return ".data"; + } + return ".data"; + } + + if (isSectionPrefix(".rodata", s->name)) { + // Map input sections' .rodata and rodata.hot into .rodata.hot in the + // output. Map input sections' .rodata.unlikely into .rodata in the output. + if (ctx.arg.zKeepDataSectionPrefix) { + // if (isSectionPrefix(".rodata.cst", s->name)) { + // errs() << "LinkerScript.cpp:100\t" << s->name << "\n"; + //} + // .rodata.cst.unlikely + // .rodata.str4.16.unlikely + if (isSectionPrefix(".rodata.unlikely", s->name) || + hasUnlikelySuffix(s->name)) { + // return ".rodata.unlikely"; + return ".rodata.unlikely"; + } + return ".rodata"; + } + return ".rodata"; + } + + if (isSectionPrefix(".bss.rel.ro", s->name)) { + return ".bss.rel.ro"; + } + + if (isSectionPrefix(".bss", s->name)) { + if (ctx.arg.zKeepDataSectionPrefix) { + if (isSectionPrefix(".bss.unlikely", s->name)) { + // errs() << "LinkerScript.cpp:100\t" << s->name << "\n"; + return ".bss.unlikely"; + } + + return ".bss"; + } + return ".bss"; + } + for (StringRef v : {".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", ".ldata", ".lrodata", ".lbss", ".gcc_except_table", From 6328b71a44ebe50babcf766f9258df1f0dd8bb3d Mon Sep 17 00:00:00 2001 From: mingmingl Date: Sun, 20 Jul 2025 18:22:20 -0700 Subject: [PATCH 02/10] simplify implementation --- lld/ELF/Config.h | 2 +- lld/ELF/Driver.cpp | 5 +- lld/ELF/LinkerScript.cpp | 99 ++++++++++++---------------------------- 3 files changed, 33 insertions(+), 73 deletions(-) diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 0a01eddf20271..d3f6103fde4b7 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -371,8 +371,8 @@ struct Config { bool zIfuncNoplt; bool zInitfirst; bool zInterpose; - bool zKeepTextSectionPrefix; bool zKeepDataSectionPrefix; + bool zKeepTextSectionPrefix; bool zLrodataAfterBss; bool zNoBtCfi; bool zNodefaultlib; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 32ebd7a1a2ad9..cd48f0f64ce29 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1564,11 +1564,10 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) { ctx.arg.zIfuncNoplt = hasZOption(args, "ifunc-noplt"); ctx.arg.zInitfirst = hasZOption(args, "initfirst"); ctx.arg.zInterpose = hasZOption(args, "interpose"); - ctx.arg.zKeepTextSectionPrefix = getZFlag( - args, "keep-text-section-prefix", "nokeep-text-section-prefix", false); ctx.arg.zKeepDataSectionPrefix = getZFlag( args, "keep-data-section-prefix", "nokeep-data-section-prefix", false); - errs() << "ELF/Driver.cpp:1540\t" << ctx.arg.zKeepDataSectionPrefix << "\n"; + ctx.arg.zKeepTextSectionPrefix = getZFlag( + args, "keep-text-section-prefix", "nokeep-text-section-prefix", false); ctx.arg.zLrodataAfterBss = getZFlag(args, "lrodata-after-bss", "nolrodata-after-bss", false); diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 17432e65bb1bf..f1f8f6c776c7a 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -48,9 +48,9 @@ static bool isSectionPrefix(StringRef prefix, StringRef name) { return name.consume_front(prefix) && (name.empty() || name[0] == '.'); } -bool hasUnlikelySuffix(StringRef name) { - return name.ends_with(".unlikely") || name.ends_with(".unlikely.") || - name.ends_with("unlikely"); +static bool isSectionSuffix(StringRef suffix, StringRef name) { + name.consume_back("."); + return name.ends_with(suffix); } StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const { @@ -110,77 +110,38 @@ StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const { return ".text"; } - if (isSectionPrefix(".data.rel.ro", s->name)) { - // Map input sections' .rodata and rodata.hot into .rodata.hot in the - // output. Map input sections' .rodata.unlikely into .rodata in the output. - if (ctx.arg.zKeepDataSectionPrefix) { - if (isSectionPrefix(".data.rel.ro.unlikely", s->name) || - hasUnlikelySuffix(s->name)) { - return ".data.rel.ro.unlikely"; - } - - return ".data.rel.ro"; - } - return ".data.rel.ro"; - } - - if (isSectionPrefix(".data", s->name)) { - // Map input sections' .rodata and rodata.hot into .rodata.hot in the - // output. Map input sections' .rodata.unlikely into .rodata in the output. - if (ctx.arg.zKeepDataSectionPrefix) { - if (isSectionPrefix(".data.unlikely", s->name) || - hasUnlikelySuffix(s->name)) { - // errs() << "LinkerScript.cpp:100\t" << s->name << "\n"; - return ".data.unlikely"; - } - - return ".data"; - } - return ".data"; - } - - if (isSectionPrefix(".rodata", s->name)) { - // Map input sections' .rodata and rodata.hot into .rodata.hot in the - // output. Map input sections' .rodata.unlikely into .rodata in the output. - if (ctx.arg.zKeepDataSectionPrefix) { - // if (isSectionPrefix(".rodata.cst", s->name)) { - // errs() << "LinkerScript.cpp:100\t" << s->name << "\n"; - //} - // .rodata.cst.unlikely - // .rodata.str4.16.unlikely - if (isSectionPrefix(".rodata.unlikely", s->name) || - hasUnlikelySuffix(s->name)) { - // return ".rodata.unlikely"; - return ".rodata.unlikely"; - } - return ".rodata"; - } - return ".rodata"; - } - - if (isSectionPrefix(".bss.rel.ro", s->name)) { - return ".bss.rel.ro"; - } + // When zKeepDataSectionPrefix is true, keep .hot and .unlikely suffixes + // in data sections. + static constexpr StringRef dataSectionPrefixes[] = { + ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", + }; - if (isSectionPrefix(".bss", s->name)) { - if (ctx.arg.zKeepDataSectionPrefix) { - if (isSectionPrefix(".bss.unlikely", s->name)) { - // errs() << "LinkerScript.cpp:100\t" << s->name << "\n"; - return ".bss.unlikely"; + for (auto [index, v] : llvm::enumerate(dataSectionPrefixes)) { + if (isSectionPrefix(v, s->name)) { + if (ctx.arg.zKeepDataSectionPrefix) { + if (isSectionPrefix(".hot", s->name.substr(v.size()))) + return s->name.substr(0, v.size() + 4); + if (isSectionPrefix(".unlikely", s->name.substr(v.size()))) + return s->name.substr(0, v.size() + 9); + // for .rodata, a section could be`.rodata.cst.hot.` for constant + // pool or `rodata.str.hot.` for string literals. + if (index == 2) { + if (isSectionSuffix(".hot", s->name)) { + return ".rodata.hot"; + } + if (isSectionSuffix(".unlikely", s->name)) { + return ".rodata.unlikely"; + } + } } - - return ".bss"; + return v; } - return ".bss"; } - for (StringRef v : {".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", ".sbss", - ".sdata", ".srodata"}) + for (StringRef v : + {".ldata", ".lrodata", ".lbss", ".gcc_except_table", ".init_array", + ".fini_array", ".tbss", ".tdata", ".ARM.exidx", ".ARM.extab", ".ctors", + ".dtors", ".sbss", ".sdata", ".srodata"}) if (isSectionPrefix(v, s->name)) return v; From 25c61499fb130bf5d8827afde108aa8a2f3952b2 Mon Sep 17 00:00:00 2001 From: mingmingl Date: Mon, 21 Jul 2025 13:42:50 -0700 Subject: [PATCH 03/10] update code comment, and add a regression test --- lld/ELF/Driver.cpp | 1 - lld/ELF/LinkerScript.cpp | 7 +- lld/ELF/Writer.cpp | 23 +++++- lld/test/ELF/data-section-prefix.s | 127 +++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 lld/test/ELF/data-section-prefix.s diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index cd48f0f64ce29..b1b55247388a3 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1568,7 +1568,6 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) { args, "keep-data-section-prefix", "nokeep-data-section-prefix", false); ctx.arg.zKeepTextSectionPrefix = getZFlag( args, "keep-text-section-prefix", "nokeep-text-section-prefix", false); - ctx.arg.zLrodataAfterBss = getZFlag(args, "lrodata-after-bss", "nolrodata-after-bss", false); ctx.arg.zNoBtCfi = hasZOption(args, "nobtcfi"); diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index f1f8f6c776c7a..f2b20db7b0521 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -118,12 +118,15 @@ StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const { for (auto [index, v] : llvm::enumerate(dataSectionPrefixes)) { if (isSectionPrefix(v, s->name)) { - if (ctx.arg.zKeepDataSectionPrefix) { + // The .bss.rel.ro section is considered rarely accessed. So this section + // is not partitioned and zKeepDataSectionPrefix is not applied to + // make the executable simpler with fewer elf sections. + if (ctx.arg.zKeepDataSectionPrefix && index != 3) { if (isSectionPrefix(".hot", s->name.substr(v.size()))) return s->name.substr(0, v.size() + 4); if (isSectionPrefix(".unlikely", s->name.substr(v.size()))) return s->name.substr(0, v.size() + 9); - // for .rodata, a section could be`.rodata.cst.hot.` for constant + // For .rodata, a section could be`.rodata.cst.hot.` for constant // pool or `rodata.str.hot.` for string literals. if (index == 2) { if (isSectionSuffix(".hot", s->name)) { diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 2cea6a44b391a..82e5ba6d9e6a8 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -555,6 +555,27 @@ template void Writer::addSectionSymbols() { } } +// Returns true if the section is a data section that's read only and +// relocatable per its section name. +static bool isRelRoDataSection(Ctx &ctx, StringRef secName) { + // The section name should start with ".data.rel.ro". + if (!secName.consume_front(".data.rel.ro")) + return false; + + // If the section name is .data.rel.ro, it is a relocatable read-only data + // section. + if (secName.empty()) + return true; + // If -z keep-data-section-prefix is given, '.data.rel.ro.hot' and + // '.data.rel.ro.unlikely' are considered a split of '.data.rel.ro' based on + // hotness. + if (ctx.arg.zKeepDataSectionPrefix) { + return secName == ".hot" || secName == ".unlikely"; + } + + return false; +} + // Today's loaders have a feature to make segments read-only after // processing dynamic relocations to enhance security. PT_GNU_RELRO // is defined for that. @@ -631,7 +652,7 @@ static bool isRelroSection(Ctx &ctx, const OutputSection *sec) { // magic section names. StringRef s = sec->name; - bool abiAgnostic = s == ".data.rel.ro" || s == ".bss.rel.ro" || + bool abiAgnostic = isRelRoDataSection(ctx, s) || s == ".bss.rel.ro" || s == ".ctors" || s == ".dtors" || s == ".jcr" || s == ".eh_frame" || s == ".fini_array" || s == ".init_array" || s == ".preinit_array"; diff --git a/lld/test/ELF/data-section-prefix.s b/lld/test/ELF/data-section-prefix.s new file mode 100644 index 0000000000000..5012039e438a7 --- /dev/null +++ b/lld/test/ELF/data-section-prefix.s @@ -0,0 +1,127 @@ +# REQUIRES: x86 +## -z keep-data-section-prefix separates static data sections with prefix +## .
.hot, .
.unlikely in the absence of a SECTIONS command. + +# RUN: rm -rf %t && split-file %s %t && cd %t + +# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o + +# RUN: ld.lld a.o -o out1 +# RUN: llvm-readelf -S out1 | FileCheck --check-prefix=BASIC %s +# RUN: ld.lld -z nokeep-text-section-prefix a.o -o out2 +# RUN: cmp out1 out2 + +# RUN: ld.lld -z keep-data-section-prefix a.o -o out3 +# RUN: llvm-readelf -S out3 | FileCheck --check-prefix=KEEP %s + +## With a SECTIONS command, orphan sections are created verbatim. +## No grouping is performed for them. +# RUN: ld.lld -T x.lds -z keep-data-section-prefix a.o -o out4 +# RUN: llvm-readelf -S out4 | FileCheck --check-prefix=SCRIPT %s + +# BASIC: [Nr] Name Type Address Off Size +# BASIC: [ 1] .text +# BASIC-NEXT: [ 2] .data.rel.ro PROGBITS 00000000002021c9 0001c9 00000f +# BASIC-NEXT: [ 3] .bss.rel.ro NOBITS 00000000002021d8 0001d8 000008 +# BASIC-NEXT: [ 4] .relro_padding NOBITS 00000000002021e0 0001d8 000e20 +# BASIC-NEXT: [ 5] .rodata PROGBITS 00000000002031e0 0001e0 000006 +# BASIC-NEXT: [ 6] .data PROGBITS 00000000002031e6 0001e6 000004 +# BASIC-NEXT: [ 7] .bss NOBITS 00000000002031ea 0001ea 000004 + +# KEEP: [Nr] Name Type Address Off Size +# KEEP: [ 1] .text +# KEEP-NEXT: [ 2] .data.rel.ro PROGBITS 00000000002021c9 0001c9 000009 +# KEEP-NEXT: [ 3] .data.rel.ro.hot PROGBITS 00000000002021d2 0001d2 000004 +# KEEP-NEXT: [ 4] .data.rel.ro.unlikely PROGBITS 00000000002021d6 0001d6 000002 +# KEEP-NEXT: [ 5] .bss.rel.ro NOBITS 00000000002021d8 0001d8 000008 +# KEEP-NEXT: [ 6] .relro_padding NOBITS 00000000002021e0 0001d8 000e20 +# KEEP-NEXT: [ 7] .rodata PROGBITS 00000000002031e0 0001e0 000002 +# KEEP-NEXT: [ 8] .rodata.hot PROGBITS 00000000002031e2 0001e2 000002 +# KEEP-NEXT: [ 9] .rodata.unlikely PROGBITS 00000000002031e4 0001e4 000002 +# KEEP-NEXT: [10] .data PROGBITS 00000000002031e6 0001e6 000002 +# KEEP-NEXT: [11] .data.hot PROGBITS 00000000002031e8 0001e8 000001 +# KEEP-NEXT: [12] .data.unlikely PROGBITS 00000000002031e9 0001e9 000001 +# KEEP-NEXT: [13] .bss NOBITS 00000000002031ea 0001ea 000002 +# KEEP-NEXT: [14] .bss.hot NOBITS 00000000002031ec 0001ea 000001 +# KEEP-NEXT: [15] .bss.unlikely NOBITS 00000000002031ed 0001ea 000001 + +# SCRIPT: .text +# SCRIPT-NEXT: .rodata.i +# SCRIPT-NEXT: .rodata.hot.j +# SCRIPT-NEXT: .rodata.unlikely.k +# SCRIPT-NEXT: .rodata.split.l +# SCRIPT-NEXT: .rodata.cst32.hot. +# SCRIPT-NEXT: .rodata.str1.1.unlikely. +# SCRIPT-NEXT: .data.m +# SCRIPT-NEXT: .data.hot.n +# SCRIPT-NEXT: .data.unlikely.o +# SCRIPT-NEXT: .data.split.p +# SCRIPT-NEXT: .data.rel.ro.q +# SCRIPT-NEXT: .data.rel.ro.hot.r +# SCRIPT-NEXT: .data.rel.ro.unlikely.s +# SCRIPT-NEXT: .data.rel.ro.split.t +# SCRIPT-NEXT: .bss.a +# SCRIPT-NEXT: .bss.hot.b +# SCRIPT-NEXT: .bss.unlikely.c +# SCRIPT-NEXT: .bss.split.d +# SCRIPT-NEXT: .bss.rel.ro.e +# SCRIPT-NEXT: .bss.rel.ro.hot.f +# SCRIPT-NEXT: .bss.rel.ro.unlikely.g +# SCRIPT-NEXT: .bss.rel.ro.split.h + +#--- a.s +.globl _start +_start: + ret + +.section .bss.a,"aw" + .byte 0 +.section .bss.hot.b,"aw" + .byte 0 +.section .bss.unlikely.c,"aw" + .byte 0 +.section .bss.split.d,"aw" + .byte 0 + +.section .bss.rel.ro.e, "aw" + .space 2 +.section .bss.rel.ro.hot.f, "aw" + .space 2 +.section .bss.rel.ro.unlikely.g, "aw" + .space 2 +.section .bss.rel.ro.split.h, "aw" + .space 2 + +.section .rodata.i,"aw" + .byte 1 +.section .rodata.hot.j,"aw" + .byte 2 +.section .rodata.unlikely.k,"aw" + .byte 3 +.section .rodata.split.l,"aw" + .byte 4 +.section .rodata.cst32.hot.,"aw" + .byte 5 +.section .rodata.str1.1.unlikely.,"aw" + .byte 6 + +.section .data.m,"aw" + .byte 5 +.section .data.hot.n,"aw" + .byte 6 +.section .data.unlikely.o,"aw" + .byte 7 +.section .data.split.p,"aw" + .byte 8 + +.section .data.rel.ro.q,"aw" + .quad 0 +.section .data.rel.ro.hot.r,"aw" + .long 255 +.section .data.rel.ro.unlikely.s,"aw" + .word 1 +.section .data.rel.ro.split.t,"aw" + .byte 0 + +#--- x.lds +SECTIONS {} From 67e44ed7a9ccd089b142bb6e52cd181ed8ed2cbb Mon Sep 17 00:00:00 2001 From: mingmingl Date: Mon, 21 Jul 2025 22:32:54 -0700 Subject: [PATCH 04/10] resolve comments --- lld/ELF/LinkerScript.cpp | 6 ++++-- lld/test/ELF/data-section-prefix.s | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index f2b20db7b0521..1351e1686c3e2 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -118,10 +118,12 @@ StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const { for (auto [index, v] : llvm::enumerate(dataSectionPrefixes)) { if (isSectionPrefix(v, s->name)) { + if (!ctx.arg.zKeepDataSectionPrefix) + return v; // The .bss.rel.ro section is considered rarely accessed. So this section // is not partitioned and zKeepDataSectionPrefix is not applied to // make the executable simpler with fewer elf sections. - if (ctx.arg.zKeepDataSectionPrefix && index != 3) { + if (isSectionPrefix(".hot", s->name.substr(v.size()))) return s->name.substr(0, v.size() + 4); if (isSectionPrefix(".unlikely", s->name.substr(v.size()))) @@ -136,7 +138,7 @@ StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const { return ".rodata.unlikely"; } } - } + return v; } } diff --git a/lld/test/ELF/data-section-prefix.s b/lld/test/ELF/data-section-prefix.s index 5012039e438a7..a5c347ec275c6 100644 --- a/lld/test/ELF/data-section-prefix.s +++ b/lld/test/ELF/data-section-prefix.s @@ -83,13 +83,13 @@ _start: .section .bss.split.d,"aw" .byte 0 -.section .bss.rel.ro.e, "aw" +.section .bss.rel.ro, "aw" .space 2 -.section .bss.rel.ro.hot.f, "aw" +.section .bss.rel.ro, "aw" .space 2 -.section .bss.rel.ro.unlikely.g, "aw" +.section .bss.rel.ro, "aw" .space 2 -.section .bss.rel.ro.split.h, "aw" +.section .bss.rel.ro, "aw" .space 2 .section .rodata.i,"aw" From ed70327841c951a57b07d1a628e8c9c40d347fe8 Mon Sep 17 00:00:00 2001 From: mingmingl Date: Wed, 23 Jul 2025 11:23:46 -0700 Subject: [PATCH 05/10] resolve comments --- lld/ELF/LinkerScript.cpp | 46 ++++++++-------- ...on-prefix.s => keep-data-section-prefix.s} | 53 +++++++++---------- 2 files changed, 48 insertions(+), 51 deletions(-) rename lld/test/ELF/{data-section-prefix.s => keep-data-section-prefix.s} (51%) diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 1351e1686c3e2..e4274e95241db 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -48,9 +48,10 @@ static bool isSectionPrefix(StringRef prefix, StringRef name) { return name.consume_front(prefix) && (name.empty() || name[0] == '.'); } -static bool isSectionSuffix(StringRef suffix, StringRef name) { - name.consume_back("."); - return name.ends_with(suffix); +// If name starts with prefix, trim the prefix and return true. +// Otherwise, leave the name unchanged and return false. +static bool trimSectionPrefix(StringRef prefix, StringRef &name) { + return name.consume_front(prefix) && (name.empty() || name[0] == '.'); } StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const { @@ -117,28 +118,27 @@ StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const { }; for (auto [index, v] : llvm::enumerate(dataSectionPrefixes)) { - if (isSectionPrefix(v, s->name)) { + StringRef secName = s->name; + if (trimSectionPrefix(v, secName)) { if (!ctx.arg.zKeepDataSectionPrefix) return v; - // The .bss.rel.ro section is considered rarely accessed. So this section - // is not partitioned and zKeepDataSectionPrefix is not applied to - // make the executable simpler with fewer elf sections. - - if (isSectionPrefix(".hot", s->name.substr(v.size()))) - return s->name.substr(0, v.size() + 4); - if (isSectionPrefix(".unlikely", s->name.substr(v.size()))) - return s->name.substr(0, v.size() + 9); - // For .rodata, a section could be`.rodata.cst.hot.` for constant - // pool or `rodata.str.hot.` for string literals. - if (index == 2) { - if (isSectionSuffix(".hot", s->name)) { - return ".rodata.hot"; - } - if (isSectionSuffix(".unlikely", s->name)) { - return ".rodata.unlikely"; - } - } - + if (isSectionPrefix(".hot", secName)) + return s->name.substr(0, v.size() + 4); + if (isSectionPrefix(".unlikely", secName)) + return s->name.substr(0, v.size() + 9); + // For .rodata, a section could be`.rodata.cst.hot.` for constant + // pool or `rodata.str.hot.` for string literals. + if (index == 2) { + // The reason to specialize this path is to spell out .rodata.hot and + // .rodata.unlikely as string literals for StringRef lifetime + // considerations. We cannot use the pattern above to get substr from + // section names. + if (s->name.ends_with(".hot.")) + return ".rodata.hot"; + + if (s->name.ends_with(".unlikely.")) + return ".rodata.unlikely"; + } return v; } } diff --git a/lld/test/ELF/data-section-prefix.s b/lld/test/ELF/keep-data-section-prefix.s similarity index 51% rename from lld/test/ELF/data-section-prefix.s rename to lld/test/ELF/keep-data-section-prefix.s index a5c347ec275c6..a33eb0c2d609f 100644 --- a/lld/test/ELF/data-section-prefix.s +++ b/lld/test/ELF/keep-data-section-prefix.s @@ -19,35 +19,36 @@ # RUN: ld.lld -T x.lds -z keep-data-section-prefix a.o -o out4 # RUN: llvm-readelf -S out4 | FileCheck --check-prefix=SCRIPT %s -# BASIC: [Nr] Name Type Address Off Size +# BASIC: [Nr] Name Type {{.*}} Size # BASIC: [ 1] .text -# BASIC-NEXT: [ 2] .data.rel.ro PROGBITS 00000000002021c9 0001c9 00000f -# BASIC-NEXT: [ 3] .bss.rel.ro NOBITS 00000000002021d8 0001d8 000008 -# BASIC-NEXT: [ 4] .relro_padding NOBITS 00000000002021e0 0001d8 000e20 -# BASIC-NEXT: [ 5] .rodata PROGBITS 00000000002031e0 0001e0 000006 -# BASIC-NEXT: [ 6] .data PROGBITS 00000000002031e6 0001e6 000004 -# BASIC-NEXT: [ 7] .bss NOBITS 00000000002031ea 0001ea 000004 +# BASIC-NEXT: [ 2] .data.rel.ro PROGBITS {{.*}} 00000f +# BASIC-NEXT: [ 3] .bss.rel.ro NOBITS {{.*}} 000008 +# BASIC-NEXT: [ 4] .relro_padding NOBITS {{.*}} 000e20 +# BASIC-NEXT: [ 5] .rodata PROGBITS {{.*}} 000006 +# BASIC-NEXT: [ 6] .data PROGBITS {{.*}} 000004 +# BASIC-NEXT: [ 7] .bss NOBITS {{.*}} 000004 -# KEEP: [Nr] Name Type Address Off Size +# KEEP: [Nr] Name Type {{.*}} Size # KEEP: [ 1] .text -# KEEP-NEXT: [ 2] .data.rel.ro PROGBITS 00000000002021c9 0001c9 000009 -# KEEP-NEXT: [ 3] .data.rel.ro.hot PROGBITS 00000000002021d2 0001d2 000004 -# KEEP-NEXT: [ 4] .data.rel.ro.unlikely PROGBITS 00000000002021d6 0001d6 000002 -# KEEP-NEXT: [ 5] .bss.rel.ro NOBITS 00000000002021d8 0001d8 000008 -# KEEP-NEXT: [ 6] .relro_padding NOBITS 00000000002021e0 0001d8 000e20 -# KEEP-NEXT: [ 7] .rodata PROGBITS 00000000002031e0 0001e0 000002 -# KEEP-NEXT: [ 8] .rodata.hot PROGBITS 00000000002031e2 0001e2 000002 -# KEEP-NEXT: [ 9] .rodata.unlikely PROGBITS 00000000002031e4 0001e4 000002 -# KEEP-NEXT: [10] .data PROGBITS 00000000002031e6 0001e6 000002 -# KEEP-NEXT: [11] .data.hot PROGBITS 00000000002031e8 0001e8 000001 -# KEEP-NEXT: [12] .data.unlikely PROGBITS 00000000002031e9 0001e9 000001 -# KEEP-NEXT: [13] .bss NOBITS 00000000002031ea 0001ea 000002 -# KEEP-NEXT: [14] .bss.hot NOBITS 00000000002031ec 0001ea 000001 -# KEEP-NEXT: [15] .bss.unlikely NOBITS 00000000002031ed 0001ea 000001 +# KEEP-NEXT: [ 2] .data.rel.ro PROGBITS {{.*}} 000009 +# KEEP-NEXT: [ 3] .data.rel.ro.hot PROGBITS {{.*}} 000004 +# KEEP-NEXT: [ 4] .data.rel.ro.unlikely PROGBITS {{.*}} 000002 +# KEEP-NEXT: [ 5] .bss.rel.ro NOBITS {{.*}} 000008 +# KEEP-NEXT: [ 6] .relro_padding NOBITS {{.*}} 000e20 +# KEEP-NEXT: [ 7] .rodata PROGBITS {{.*}} 000002 +# KEEP-NEXT: [ 8] .rodata.hot PROGBITS {{.*}} 000002 +# KEEP-NEXT: [ 9] .rodata.unlikely PROGBITS {{.*}} 000002 +# KEEP-NEXT: [10] .data PROGBITS {{.*}} 000002 +# KEEP-NEXT: [11] .data.hot PROGBITS {{.*}} 000001 +# KEEP-NEXT: [12] .data.unlikely PROGBITS {{.*}} 000001 +# KEEP-NEXT: [13] .bss NOBITS {{.*}} 000002 +# KEEP-NEXT: [14] .bss.hot NOBITS {{.*}} 000001 +# KEEP-NEXT: [15] .bss.unlikely NOBITS {{.*}} 000001 # SCRIPT: .text +# SCRIPT-NEXT: .bss.rel.ro # SCRIPT-NEXT: .rodata.i -# SCRIPT-NEXT: .rodata.hot.j +# SCRIPT-NEXT: .rodata.hot. # SCRIPT-NEXT: .rodata.unlikely.k # SCRIPT-NEXT: .rodata.split.l # SCRIPT-NEXT: .rodata.cst32.hot. @@ -64,10 +65,6 @@ # SCRIPT-NEXT: .bss.hot.b # SCRIPT-NEXT: .bss.unlikely.c # SCRIPT-NEXT: .bss.split.d -# SCRIPT-NEXT: .bss.rel.ro.e -# SCRIPT-NEXT: .bss.rel.ro.hot.f -# SCRIPT-NEXT: .bss.rel.ro.unlikely.g -# SCRIPT-NEXT: .bss.rel.ro.split.h #--- a.s .globl _start @@ -94,7 +91,7 @@ _start: .section .rodata.i,"aw" .byte 1 -.section .rodata.hot.j,"aw" +.section .rodata.hot.,"aw" .byte 2 .section .rodata.unlikely.k,"aw" .byte 3 From b66eceebbf47540539f9aa9b4f4d544b0bfed897 Mon Sep 17 00:00:00 2001 From: mingmingl Date: Wed, 23 Jul 2025 12:27:40 -0700 Subject: [PATCH 06/10] use {{.*}} to omit irrelevant columns in the test case --- lld/test/ELF/keep-data-section-prefix.s | 36 ++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/lld/test/ELF/keep-data-section-prefix.s b/lld/test/ELF/keep-data-section-prefix.s index 0521ff0b7519a..a44be263e821f 100644 --- a/lld/test/ELF/keep-data-section-prefix.s +++ b/lld/test/ELF/keep-data-section-prefix.s @@ -38,12 +38,12 @@ ## The first RW PT_LOAD segment has FileSiz 0x126f (0x1000 + 0x200 + 0x60 + 0xf), ## and its p_offset p_vaddr p_paddr p_filesz should match PT_GNU_RELRO. -# Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align -# SEG: LOAD 0x0001c8 0x00000000002011c8 0x00000000002011c8 0x000001 0x000001 R E 0x1000 -# SEG-NEXT: LOAD 0x0001c9 0x00000000002021c9 0x00000000002021c9 0x00126f 0x001e37 RW 0x1000 -# SEG-NEXT: LOAD 0x001438 0x0000000000204438 0x0000000000204438 0x000001 0x000002 RW 0x1000 -# SEG-NEXT: GNU_RELRO 0x0001c9 0x00000000002021c9 0x00000000002021c9 0x00126f 0x001e37 R 0x1 -# SEG-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0 +# Type {{.*}} FileSiz MemSiz Flg +# SEG: LOAD {{.*}} 0x000001 0x000001 R E +# SEG-NEXT: LOAD {{.*}} 0x00126f 0x001e37 RW +# SEG-NEXT: LOAD {{.*}} 0x000001 0x000002 RW +# SEG-NEXT: GNU_RELRO {{.*}} 0x00126f 0x001e37 R +# SEG-NEXT: GNU_STACK {{.*}} 0x000000 0x000000 RW ## Input to output mapping per linker script ## .data.rel.ro.split -> .data.rel.ro @@ -54,13 +54,13 @@ # LS-NEXT: .data.rel.ro.hot .data.rel.ro .data.rel.ro.unlikely .relro_padding # LS-NEXT: .data .bss -# [Nr] Name Type Address Off Size -# CHECK-LS: .data.rel.ro.hot PROGBITS 00000000002021c9 0001c9 00000f -# CHECK-LS-NEXT: .data.rel.ro PROGBITS 00000000002021d8 0001d8 000260 -# CHECK-LS-NEXT: .data.rel.ro.unlikely PROGBITS 0000000000202438 000438 001000 -# CHECK-LS-NEXT: .relro_padding NOBITS 0000000000203438 001438 000bc8 -# CHECK-LS-NEXT: .data PROGBITS 0000000000204438 001438 000001 -# CHECK-LS-NEXT: .bss NOBITS 0000000000204439 001439 000001 +# [Nr] Name Type {{.*}} Size +# CHECK-LS: .data.rel.ro.hot PROGBITS {{.*}} 00000f +# CHECK-LS-NEXT: .data.rel.ro PROGBITS {{.*}} 000260 +# CHECK-LS-NEXT: .data.rel.ro.unlikely PROGBITS {{.*}} 001000 +# CHECK-LS-NEXT: .relro_padding NOBITS {{.*}} 000bc8 +# CHECK-LS-NEXT: .data PROGBITS {{.*}} 000001 +# CHECK-LS-NEXT: .bss NOBITS {{.*}} 000001 ## Linker script is not provided to map data sections. ## So all input sections with prefix .data.rel.ro will map to .data.rel.ro in the output. @@ -68,11 +68,11 @@ # PRE-NEXT: .data.rel.ro .relro_padding # PRE-NEXT: .data .bss -# [Nr] Name Type Address Off Size -# CHECK-PRE: .data.rel.ro PROGBITS 00000000002021c9 0001c9 00126f -# CHECK-PRE-NEXT: .relro_padding NOBITS 0000000000203438 001438 000bc8 -# CHECK-PRE-NEXT: .data PROGBITS 0000000000204438 001438 000001 -# CHECK-PRE-NEXT: .bss NOBITS 0000000000204439 001439 000001 +# [Nr] Name Type {{.*}} Size +# CHECK-PRE: .data.rel.ro PROGBITS {{.*}} 00126f +# CHECK-PRE-NEXT: .relro_padding NOBITS {{.*}} 000bc8 +# CHECK-PRE-NEXT: .data PROGBITS {{.*}} 000001 +# CHECK-PRE-NEXT: .bss NOBITS {{.*}} 000001 # BASIC: [Nr] Name Type {{.*}} Size # BASIC: [ 1] .text From 5dbe4df4a8cbcfcd5b5d702a54c315ed334743cb Mon Sep 17 00:00:00 2001 From: mingmingl Date: Sat, 26 Jul 2025 19:28:46 -0700 Subject: [PATCH 07/10] resolve comment --- lld/ELF/LinkerScript.cpp | 52 ++++++++++++------------- lld/test/ELF/keep-data-section-prefix.s | 14 ++----- 2 files changed, 30 insertions(+), 36 deletions(-) diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index c0f524eda2c33..2991b03d2ef2b 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -46,12 +46,6 @@ static bool isSectionPrefix(StringRef prefix, StringRef name) { return name.consume_front(prefix) && (name.empty() || name[0] == '.'); } -// If name starts with prefix, trim the prefix and return true. -// Otherwise, leave the name unchanged and return false. -static bool trimSectionPrefix(StringRef prefix, StringRef &name) { - return name.consume_front(prefix) && (name.empty() || name[0] == '.'); -} - StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const { // This is for --emit-relocs and -r. If .text.foo is emitted as .text.bar, we // want to emit .rela.text.foo as .rela.text.bar for consistency (this is not @@ -117,28 +111,34 @@ StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const { for (auto [index, v] : llvm::enumerate(dataSectionPrefixes)) { StringRef secName = s->name; - if (trimSectionPrefix(v, secName)) { - if (!ctx.arg.zKeepDataSectionPrefix) - return v; - if (isSectionPrefix(".hot", secName)) - return s->name.substr(0, v.size() + 4); - if (isSectionPrefix(".unlikely", secName)) - return s->name.substr(0, v.size() + 9); - // For .rodata, a section could be`.rodata.cst.hot.` for constant - // pool or `rodata.str.hot.` for string literals. - if (index == 2) { - // The reason to specialize this path is to spell out .rodata.hot and - // .rodata.unlikely as string literals for StringRef lifetime - // considerations. We cannot use the pattern above to get substr from - // section names. - if (s->name.ends_with(".hot.")) - return ".rodata.hot"; - - if (s->name.ends_with(".unlikely.")) - return ".rodata.unlikely"; - } + if (!secName.consume_front(v)) + continue; + if (!secName.empty() && secName[0] != '.') { + continue; + } + + // The section name starts with 'v', and the remaining string is either + // empty or starts with a '.' character. If keep-data-section-prefix is + // false, map s to output section with name 'v'. + if (!ctx.arg.zKeepDataSectionPrefix) return v; + // Preserve .hot or .unlikely suffixes in data sections with + // keep-data-section-prefix=true. + if (isSectionPrefix(".hot", secName)) + return s->name.substr(0, v.size() + 4); + if (isSectionPrefix(".unlikely", secName)) + return s->name.substr(0, v.size() + 9); + if (index == 2) { + // Place input .rodata.str.hot. or .rodata.cst.hot. into the + // .rodata.hot section. + if (s->name.ends_with(".hot.")) + return ".rodata.hot"; + // Place input .rodata.str.hot. or .rodata.cst.unlikely. into the + // .rodata.unlikely section. + if (s->name.ends_with(".unlikely.")) + return ".rodata.unlikely"; } + return v; } for (StringRef v : diff --git a/lld/test/ELF/keep-data-section-prefix.s b/lld/test/ELF/keep-data-section-prefix.s index a44be263e821f..a539cd66b9205 100644 --- a/lld/test/ELF/keep-data-section-prefix.s +++ b/lld/test/ELF/keep-data-section-prefix.s @@ -77,8 +77,8 @@ # BASIC: [Nr] Name Type {{.*}} Size # BASIC: [ 1] .text # BASIC-NEXT: [ 2] .data.rel.ro PROGBITS {{.*}} 00000f -# BASIC-NEXT: [ 3] .bss.rel.ro NOBITS {{.*}} 000008 -# BASIC-NEXT: [ 4] .relro_padding NOBITS {{.*}} 000e20 +# BASIC-NEXT: [ 3] .bss.rel.ro NOBITS {{.*}} 000002 +# BASIC-NEXT: [ 4] .relro_padding NOBITS {{.*}} 000e26 # BASIC-NEXT: [ 5] .rodata PROGBITS {{.*}} 000006 # BASIC-NEXT: [ 6] .data PROGBITS {{.*}} 000004 # BASIC-NEXT: [ 7] .bss NOBITS {{.*}} 000004 @@ -88,8 +88,8 @@ # KEEP-NEXT: [ 2] .data.rel.ro PROGBITS {{.*}} 000009 # KEEP-NEXT: [ 3] .data.rel.ro.hot PROGBITS {{.*}} 000004 # KEEP-NEXT: [ 4] .data.rel.ro.unlikely PROGBITS {{.*}} 000002 -# KEEP-NEXT: [ 5] .bss.rel.ro NOBITS {{.*}} 000008 -# KEEP-NEXT: [ 6] .relro_padding NOBITS {{.*}} 000e20 +# KEEP-NEXT: [ 5] .bss.rel.ro NOBITS {{.*}} 000002 +# KEEP-NEXT: [ 6] .relro_padding NOBITS {{.*}} 000e26 # KEEP-NEXT: [ 7] .rodata PROGBITS {{.*}} 000002 # KEEP-NEXT: [ 8] .rodata.hot PROGBITS {{.*}} 000002 # KEEP-NEXT: [ 9] .rodata.unlikely PROGBITS {{.*}} 000002 @@ -165,12 +165,6 @@ _start: .section .bss.split.d,"aw" .byte 0 -.section .bss.rel.ro, "aw" - .space 2 -.section .bss.rel.ro, "aw" - .space 2 -.section .bss.rel.ro, "aw" - .space 2 .section .bss.rel.ro, "aw" .space 2 From 28b26f8643454cb891c034dd6385e6eca383b92d Mon Sep 17 00:00:00 2001 From: mingmingl Date: Mon, 4 Aug 2025 14:24:54 -0700 Subject: [PATCH 08/10] drop braces for single-line if --- lld/ELF/LinkerScript.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 2991b03d2ef2b..9652d39f72616 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -113,9 +113,8 @@ StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const { StringRef secName = s->name; if (!secName.consume_front(v)) continue; - if (!secName.empty() && secName[0] != '.') { + if (!secName.empty() && secName[0] != '.') continue; - } // The section name starts with 'v', and the remaining string is either // empty or starts with a '.' character. If keep-data-section-prefix is From a451287170e5e65b8f07c3674e5b492788be6376 Mon Sep 17 00:00:00 2001 From: mingmingl Date: Tue, 5 Aug 2025 16:16:05 -0700 Subject: [PATCH 09/10] incorporate review feedback --- lld/ELF/LinkerScript.cpp | 78 +++++++++++++++---------- lld/test/ELF/keep-data-section-prefix.s | 8 +-- 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 9652d39f72616..b5c7c1c9c2b96 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -109,41 +109,55 @@ StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const { ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", }; - for (auto [index, v] : llvm::enumerate(dataSectionPrefixes)) { - StringRef secName = s->name; - if (!secName.consume_front(v)) - continue; - if (!secName.empty() && secName[0] != '.') - continue; + // If keep-data-section-prefix is enabled, map hot-prefixed data sections + // to a .hot variant in the output and map unlikely-prefixed data sections + // to a .unlikely variant. Mapping for the hot input sections is illustrated + // below, and the same applies for unlikely ones. + // [bar] is a placeholder to represent optional global variable name below + // - .data.rel.ro.hot.[bar] => .data.rel.ro.hot + // - .data.hot.[bar] => .data.hot + // - {.rodata.hot.[bar], .rodata.str.*.hot., .rodata.cst*.hot.} => .rodata.hot + // - .bss.rel.ro => .bss.rel.ro + // - .bss.hot.[bar] => .bss.hot + // Note .bss.rel.ro doesn't have hot / unlikely mapping. It's placed before + // .bss so they get processed before `.bss` prefix is seen, just like + // how `.data.rel.ro` should be processed before seeing the `.data` prefix. + if (ctx.arg.zKeepDataSectionPrefix) + for (auto [index, v] : llvm::enumerate(dataSectionPrefixes)) { + StringRef secName = s->name; + // If v is the prefix, trim it from secName. Otherwise just continue to + // try the next prefix. + if (!secName.consume_front(v)) + continue; - // The section name starts with 'v', and the remaining string is either - // empty or starts with a '.' character. If keep-data-section-prefix is - // false, map s to output section with name 'v'. - if (!ctx.arg.zKeepDataSectionPrefix) - return v; - // Preserve .hot or .unlikely suffixes in data sections with - // keep-data-section-prefix=true. - if (isSectionPrefix(".hot", secName)) - return s->name.substr(0, v.size() + 4); - if (isSectionPrefix(".unlikely", secName)) - return s->name.substr(0, v.size() + 9); - if (index == 2) { - // Place input .rodata.str.hot. or .rodata.cst.hot. into the - // .rodata.hot section. - if (s->name.ends_with(".hot.")) - return ".rodata.hot"; - // Place input .rodata.str.hot. or .rodata.cst.unlikely. into the - // .rodata.unlikely section. - if (s->name.ends_with(".unlikely.")) - return ".rodata.unlikely"; + // Object file writer emits the trailing dot in `.hot.` and `.unlikely.` + // to disambiguate between `.
.` (without trailing + // dot) and `.
.hot.[optional-variable-name]`. We check the same + // (trailing dot required) to not map a C variable named `unlikely` to a + // unlikely variant. + if (secName.starts_with(".hot.")) + return s->name.substr(0, v.size() + 4); + if (secName.starts_with(".unlikely.")) + return s->name.substr(0, v.size() + 9); + if (index == 2) { + // Place input .rodata.str.hot. or .rodata.cst.hot. into the + // .rodata.hot section. + if (s->name.ends_with(".hot.")) + return ".rodata.hot"; + // Place input .rodata.str.hot. or .rodata.cst.unlikely. into + // the .rodata.unlikely section. + if (s->name.ends_with(".unlikely.")) + return ".rodata.unlikely"; + } } - return v; - } - for (StringRef v : - {".ldata", ".lrodata", ".lbss", ".gcc_except_table", ".init_array", - ".fini_array", ".tbss", ".tdata", ".ARM.exidx", ".ARM.extab", ".ctors", - ".dtors", ".sbss", ".sdata", ".srodata"}) + for (StringRef v : {".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", ".sbss", + ".sdata", ".srodata"}) if (isSectionPrefix(v, s->name)) return v; diff --git a/lld/test/ELF/keep-data-section-prefix.s b/lld/test/ELF/keep-data-section-prefix.s index a539cd66b9205..6e15ee6787a0b 100644 --- a/lld/test/ELF/keep-data-section-prefix.s +++ b/lld/test/ELF/keep-data-section-prefix.s @@ -28,14 +28,14 @@ # RUN: ld.lld -z nokeep-text-section-prefix b.o -o out2 # RUN: cmp out1 out2 -# RUN: ld.lld -z keep-data-section-prefix b.o -o out3 -# RUN: llvm-readelf -S out3 | FileCheck --check-prefix=KEEP %s - ## With a SECTIONS command, orphan sections are created verbatim. ## No grouping is performed for them. # RUN: ld.lld -T x2.lds -z keep-data-section-prefix b.o -o out4 # RUN: llvm-readelf -S out4 | FileCheck --check-prefix=SCRIPT %s +# RUN: ld.lld -z keep-data-section-prefix b.o -o out3 +# RUN: llvm-readelf -S out3 | FileCheck --check-prefix=KEEP %s + ## The first RW PT_LOAD segment has FileSiz 0x126f (0x1000 + 0x200 + 0x60 + 0xf), ## and its p_offset p_vaddr p_paddr p_filesz should match PT_GNU_RELRO. # Type {{.*}} FileSiz MemSiz Flg @@ -160,7 +160,7 @@ _start: .byte 0 .section .bss.hot.b,"aw" .byte 0 -.section .bss.unlikely.c,"aw" +.section .bss.unlikely.c.,"aw" .byte 0 .section .bss.split.d,"aw" .byte 0 From ed99ca53e901c24754e86236c20731d1b77406cc Mon Sep 17 00:00:00 2001 From: mingmingl Date: Wed, 6 Aug 2025 17:32:12 -0700 Subject: [PATCH 10/10] undo a test change --- lld/test/ELF/keep-data-section-prefix.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/test/ELF/keep-data-section-prefix.s b/lld/test/ELF/keep-data-section-prefix.s index 6e15ee6787a0b..d180fbfa90cf5 100644 --- a/lld/test/ELF/keep-data-section-prefix.s +++ b/lld/test/ELF/keep-data-section-prefix.s @@ -160,7 +160,7 @@ _start: .byte 0 .section .bss.hot.b,"aw" .byte 0 -.section .bss.unlikely.c.,"aw" +.section .bss.unlikely.c,"aw" .byte 0 .section .bss.split.d,"aw" .byte 0