From d0f0453b7cebfbd9da84610e4f10c6f7910cd1f6 Mon Sep 17 00:00:00 2001 From: Fangrui Song 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 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 void elf::markLive(Ctx &ctx) { MarkLive(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(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 ">, + MetaVarName<"">; 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 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=`` prints garbage collection section listing to a file. + (`#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 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 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: