Skip to content

Conversation

MaskRay
Copy link
Member

@MaskRay MaskRay commented Sep 19, 2025

Add --print-gc-sections=<file> to redirect garbage collection section
listing to a file, avoiding contamination of stdout with other linker
output. mold has recently added the option.
GNU ld feature request: https://sourceware.org/bugzilla/show_bug.cgi?id=33331

Created using spr 1.3.5-bogner
@llvmbot
Copy link
Member

llvmbot commented Sep 19, 2025

@llvm/pr-subscribers-lld

@llvm/pr-subscribers-lld-elf

Author: Fangrui Song (MaskRay)

Changes

Add --print-gc-sections=&lt;file&gt; to redirect garbage collection section
listing to a file, avoiding contamination of stdout with other linker
output. mold has recently added the option.
GNU ld feature request: https://sourceware.org/bugzilla/show_bug.cgi?id=33331


Full diff: https://github.com/llvm/llvm-project/pull/159706.diff

5 Files Affected:

  • (modified) lld/ELF/Config.h (+1-1)
  • (modified) lld/ELF/Driver.cpp (+8-2)
  • (modified) lld/ELF/MarkLive.cpp (+12-4)
  • (modified) lld/ELF/Options.td (+3)
  • (modified) lld/test/ELF/gc-sections-print.s (+6-1)
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
 

.
Created using spr 1.3.5-bogner
Copy link
Collaborator

@smithp35 smithp35 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Always good to have the flexibility to write to a file.

Above printGCSections, there is printIcfSections. Although not for this patch, would it be useful to apply the same logic to that too?

Created using spr 1.3.5-bogner
@MaskRay
Copy link
Member Author

MaskRay commented Sep 19, 2025

LGTM. Always good to have the flexibility to write to a file.

Above printGCSections, there is printIcfSections. Although not for this patch, would it be useful to apply the same logic to that too?

Thanks for the review! Yes:) Will create a separate patch for --print-icf-sections=

@MaskRay MaskRay enabled auto-merge (squash) September 19, 2025 16:16
@MaskRay MaskRay merged commit cbb60a3 into main Sep 19, 2025
10 checks passed
@MaskRay MaskRay deleted the users/MaskRay/spr/elf-add-print-gc-sectionsfile branch September 19, 2025 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants