Index: lld/trunk/ELF/Config.h =================================================================== --- lld/trunk/ELF/Config.h +++ lld/trunk/ELF/Config.h @@ -58,6 +58,7 @@ bool Mips64EL = false; bool NoInhibitExec; bool NoUndefined; + bool PrintGcSections; bool Shared; bool Static = false; bool StripAll; Index: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/ELF/Driver.cpp @@ -163,6 +163,7 @@ Config->GcSections = Args.hasArg(OPT_gc_sections); Config->NoInhibitExec = Args.hasArg(OPT_noinhibit_exec); Config->NoUndefined = Args.hasArg(OPT_no_undefined); + Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections); Config->Shared = Args.hasArg(OPT_shared); Config->StripAll = Args.hasArg(OPT_strip_all); Config->Verbose = Args.hasArg(OPT_verbose); Index: lld/trunk/ELF/Options.td =================================================================== --- lld/trunk/ELF/Options.td +++ lld/trunk/ELF/Options.td @@ -79,6 +79,9 @@ def o : Separate<["-"], "o">, MetaVarName<"">, HelpText<"Path to file to write output">; +def print_gc_sections: Flag<["--"], "print-gc-sections">, + HelpText<"List removed unused sections">; + def rpath : Separate<["-"], "rpath">, HelpText<"Add a DT_RUNPATH to the output">; Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -16,6 +16,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/StringSaver.h" using namespace llvm; @@ -532,6 +533,15 @@ } template +void reportDiscarded(InputSectionBase *IS, + const std::unique_ptr> &File) { + if (!Config->PrintGcSections || !IS || IS->isLive()) + return; + llvm::errs() << "removing unused section from '" << IS->getSectionName() + << "' in file '" << File->getName() << "'\n"; +} + +template bool Writer::isDiscarded(InputSectionBase *IS) const { if (!IS || !IS->isLive() || IS == &InputSection::Discarded) return true; @@ -564,8 +574,10 @@ for (const std::unique_ptr> &F : Symtab.getObjectFiles()) { for (InputSectionBase *C : F->getSections()) { - if (isDiscarded(C)) + if (isDiscarded(C)) { + reportDiscarded(C, F); continue; + } const Elf_Shdr *H = C->getSectionHdr(); uintX_t OutFlags = H->sh_flags & ~SHF_GROUP; // For SHF_MERGE we create different output sections for each sh_entsize. Index: lld/trunk/test/ELF/gc-sections-print.s =================================================================== --- lld/trunk/test/ELF/gc-sections-print.s +++ lld/trunk/test/ELF/gc-sections-print.s @@ -0,0 +1,23 @@ +# 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 + +# PRINT: removing unused section from '.text.x' in file +# PRINT-NEXT: removing unused section from '.text.y' in file + +.globl _start +.protected a, x, y +_start: + call a + +.section .text.a,"ax",@progbits +a: + nop + +.section .text.x,"ax",@progbits +x: + nop + +.section .text.y,"ax",@progbits +y: + nop