[lld] [lld][ELF] Introduce an option to keep data section prefix. (PR #148985)

Mingming Liu via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 20 22:54:55 PDT 2025


https://github.com/mingmingl-llvm updated https://github.com/llvm/llvm-project/pull/148985

>From 24c1c62b584fb42fcd91b9343bbe61e521038dd0 Mon Sep 17 00:00:00 2001
From: mingmingl <mingmingl at google.com>
Date: Sun, 30 Mar 2025 23:32:41 +0000
Subject: [PATCH 1/2] 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<N>.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 <mingmingl at google.com>
Date: Sun, 20 Jul 2025 18:22:20 -0700
Subject: [PATCH 2/2] 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<N>.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<N>.hot.` for constant
+        // pool or  `rodata.str<N>.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;
 



More information about the llvm-commits mailing list