diff options
-rw-r--r-- | lld/ELF/Config.h | 1 | ||||
-rw-r--r-- | lld/ELF/Driver.cpp | 1 | ||||
-rw-r--r-- | lld/ELF/Options.td | 3 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 14 | ||||
-rw-r--r-- | lld/test/ELF/gc-sections-print.s | 23 |
5 files changed, 41 insertions, 1 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 4aee5a5cb10..299a0df1858 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -58,6 +58,7 @@ struct Configuration { bool Mips64EL = false; bool NoInhibitExec; bool NoUndefined; + bool PrintGcSections; bool Shared; bool Static = false; bool StripAll; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index b515ddc7bc3..2f1cf9be4df 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -163,6 +163,7 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { 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); diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 6a95e2b92fd..bfa87ac9fbc 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -79,6 +79,9 @@ def no_undefined : Flag<["--"], "no-undefined">, def o : Separate<["-"], "o">, MetaVarName<"<path>">, 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">; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 465dc68a3c0..1a86881c5b4 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/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 @@ StringRef Writer<ELFT>::getOutputSectionName(StringRef S) const { } template <class ELFT> +void reportDiscarded(InputSectionBase<ELFT> *IS, + const std::unique_ptr<ObjectFile<ELFT>> &File) { + if (!Config->PrintGcSections || !IS || IS->isLive()) + return; + llvm::errs() << "removing unused section from '" << IS->getSectionName() + << "' in file '" << File->getName() << "'\n"; +} + +template <class ELFT> bool Writer<ELFT>::isDiscarded(InputSectionBase<ELFT> *IS) const { if (!IS || !IS->isLive() || IS == &InputSection<ELFT>::Discarded) return true; @@ -564,8 +574,10 @@ template <class ELFT> void Writer<ELFT>::createSections() { for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) { for (InputSectionBase<ELFT> *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. diff --git a/lld/test/ELF/gc-sections-print.s b/lld/test/ELF/gc-sections-print.s new file mode 100644 index 00000000000..59177a65367 --- /dev/null +++ b/lld/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 |