[lld] [ELF] Add --print-gc-sections=<file> (PR #159706)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 19 09:15:01 PDT 2025


https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/159706

>From d0f0453b7cebfbd9da84610e4f10c6f7910cd1f6 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Thu, 18 Sep 2025 23:02:54 -0700
Subject: [PATCH 1/3] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
 =?UTF-8?q?itial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.5-bogner
---
 lld/ELF/Config.h                 |  2 +-
 lld/ELF/Driver.cpp               | 10 ++++++++--
 lld/ELF/MarkLive.cpp             | 16 ++++++++++++----
 lld/ELF/Options.td               |  3 +++
 lld/test/ELF/gc-sections-print.s |  7 ++++++-
 5 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index a83a4c1176f6f..fd57967a1d21f 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -358,7 +358,7 @@ struct Config {
   bool optRemarksWithHotness;
   bool picThunk;
   bool pie;
-  bool printGcSections;
+  llvm::StringRef printGcSections;
   bool printIcfSections;
   bool printMemoryUsage;
   std::optional<uint64_t> randomizeSectionPadding;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 6c2f318ffe469..1beab8d33f4ba 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1510,8 +1510,14 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
   ctx.arg.pie = args.hasFlag(OPT_pie, OPT_no_pie, false);
   ctx.arg.printIcfSections =
       args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false);
-  ctx.arg.printGcSections =
-      args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
+  if (auto *arg =
+          args.getLastArg(OPT_print_gc_sections, OPT_no_print_gc_sections,
+                          OPT_print_gc_sections_eq)) {
+    if (arg->getOption().matches(OPT_print_gc_sections))
+      ctx.arg.printGcSections = "-";
+    else if (arg->getOption().matches(OPT_print_gc_sections_eq))
+      ctx.arg.printGcSections = arg->getValue();
+  }
   ctx.arg.printMemoryUsage = args.hasArg(OPT_print_memory_usage);
   ctx.arg.printArchiveStats = args.getLastArgValue(OPT_print_archive_stats);
   ctx.arg.printSymbolOrder = args.getLastArgValue(OPT_print_symbol_order);
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 8dd341b79c8fc..464df98285e38 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -528,10 +528,18 @@ template <class ELFT> void elf::markLive(Ctx &ctx) {
     MarkLive<ELFT, false>(ctx, 1).moveToMain();
 
   // Report garbage-collected sections.
-  if (ctx.arg.printGcSections)
-    for (InputSectionBase *sec : ctx.inputSections)
-      if (!sec->isLive())
-        Msg(ctx) << "removing unused section " << sec;
+  if (ctx.arg.printGcSections.empty())
+    return;
+  std::error_code ec;
+  raw_fd_ostream os = ctx.openAuxiliaryFile(ctx.arg.printGcSections, ec);
+  if (ec) {
+    ErrAlways(ctx) << "--print-gc-sections=: cannot open "
+                   << ctx.arg.printGcSections << ": " << ec.message();
+    return;
+  }
+  for (InputSectionBase *sec : ctx.inputSections)
+    if (!sec->isLive())
+      os << "removing unused section " << toStr(ctx, sec) << '\n';
 }
 
 template void elf::markLive<ELF32LE>(Ctx &);
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index cc91680550b4b..f0523185a0a31 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -388,6 +388,9 @@ defm pie: B<"pie",
 defm print_gc_sections: B<"print-gc-sections",
     "List removed unused sections",
     "Do not list removed unused sections (default)">;
+def print_gc_sections_eq: JJ<"print-gc-sections=">,
+  HelpText<"List removed unused sections to <file>">,
+  MetaVarName<"<file>">;
 
 defm print_icf_sections: B<"print-icf-sections",
     "List identical folded sections",
diff --git a/lld/test/ELF/gc-sections-print.s b/lld/test/ELF/gc-sections-print.s
index a822e9ef34793..191af74de3aaa 100644
--- a/lld/test/ELF/gc-sections-print.s
+++ b/lld/test/ELF/gc-sections-print.s
@@ -1,11 +1,16 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
 # RUN: ld.lld %t --gc-sections --print-gc-sections -o %t2 2>&1 | FileCheck -check-prefix=PRINT %s
+# RUN: ld.lld %t --gc-sections --print-gc-sections=- -o %t2 2>&1 | FileCheck -check-prefix=PRINT %s
+# RUN: ld.lld %t --gc-sections --print-gc-sections=%t.txt
+# RUN: FileCheck --check-prefix=PRINT %s --input-file=%t.txt
 
 # PRINT:      removing unused section {{.*}}:(.text.x)
 # PRINT-NEXT: removing unused section {{.*}}:(.text.y)
 
-# RUN: ld.lld %t --gc-sections --print-gc-sections --no-print-gc-sections -o %t2 >& %t.log
+# RUN: rm %t.txt
+# RUN: ld.lld %t --gc-sections --print-gc-sections --print-gc-sections=%t.txt --no-print-gc-sections -o %t2 >& %t.log
+# RUN: not ls %t.txt
 # RUN: echo >> %t.log
 # RUN: FileCheck -check-prefix=NOPRINT %s < %t.log
 

>From c551a07dcafd95b38da7679047491ada130df7aa Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Thu, 18 Sep 2025 23:12:49 -0700
Subject: [PATCH 2/3] .

Created using spr 1.3.5-bogner
---
 lld/docs/ReleaseNotes.rst | 3 +++
 lld/docs/ld.lld.1         | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst
index cc1628f48bb0e..6ea1ea0fd6c2f 100644
--- a/lld/docs/ReleaseNotes.rst
+++ b/lld/docs/ReleaseNotes.rst
@@ -29,6 +29,9 @@ Non-comprehensive list of changes in this release
 ELF Improvements
 ----------------
 
+* ``--print-gc-sections=<file>`` prints garbage collection section listing to a file.
+  (`#159706 <https://github.com/llvm/llvm-project/pull/159706>`_)
+
 Breaking changes
 ----------------
 
diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1
index 1835879b671e8..bb1a53ad1112a 100644
--- a/lld/docs/ld.lld.1
+++ b/lld/docs/ld.lld.1
@@ -522,6 +522,8 @@ Don't use.
 
 .It Fl -print-gc-sections
 List removed unused sections.
+.It Fl -print-gc-sections Ns = Ns Ar file
+List removed unused sections to the specified file.
 .It Fl -print-icf-sections
 List identical folded sections.
 .It Fl -print-map

>From 05b7b6ac6fc13b707f49071ff778e753214d1d2a Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Fri, 19 Sep 2025 09:14:50 -0700
Subject: [PATCH 3/3] Test error

Created using spr 1.3.5-bogner
---
 lld/ELF/MarkLive.cpp             | 4 ++--
 lld/test/ELF/gc-sections-print.s | 4 ++++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 464df98285e38..83ae9fb7689e0 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -533,8 +533,8 @@ template <class ELFT> void elf::markLive(Ctx &ctx) {
   std::error_code ec;
   raw_fd_ostream os = ctx.openAuxiliaryFile(ctx.arg.printGcSections, ec);
   if (ec) {
-    ErrAlways(ctx) << "--print-gc-sections=: cannot open "
-                   << ctx.arg.printGcSections << ": " << ec.message();
+    Err(ctx) << "cannot open --print-gc-sections= file "
+             << ctx.arg.printGcSections << ": " << ec.message();
     return;
   }
   for (InputSectionBase *sec : ctx.inputSections)
diff --git a/lld/test/ELF/gc-sections-print.s b/lld/test/ELF/gc-sections-print.s
index 191af74de3aaa..f105dc10c2471 100644
--- a/lld/test/ELF/gc-sections-print.s
+++ b/lld/test/ELF/gc-sections-print.s
@@ -16,6 +16,10 @@
 
 # NOPRINT-NOT: removing
 
+# RUN: not ld.lld %t --gc-sections --print-gc-sections=/ -o %t2 2>&1 | FileCheck --check-prefix=ERR %s
+
+# ERR: error: cannot open --print-gc-sections= file /: {{.*}}
+
 .globl _start
 .protected a, x, y
 _start:



More information about the llvm-commits mailing list