diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -117,6 +117,7 @@ llvm::StringRef thinLTOCacheDir; llvm::StringRef thinLTOIndexOnlyArg; llvm::StringRef ltoBasicBlockSections; + llvm::StringSet<> keepSections; std::pair thinLTOObjectSuffixReplace; std::pair thinLTOPrefixReplace; std::string rpath; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -46,6 +46,7 @@ #include "lld/Common/Version.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/LTO/LTO.h" #include "llvm/Support/CommandLine.h" @@ -663,6 +664,13 @@ return ICFLevel::All; } +static StringSet<> getKeepSections(opt::InputArgList &args) { + StringSet<> keepSections; + for (StringRef arg : args::getStrings(args, OPT_keep_section)) + keepSections.insert(arg); + return keepSections; +} + static StripPolicy getStrip(opt::InputArgList &args) { if (args.hasArg(OPT_relocatable)) return StripPolicy::None; @@ -951,6 +959,7 @@ config->ignoreFunctionAddressEquality = args.hasArg(OPT_ignore_function_address_equality); config->init = args.getLastArgValue(OPT_init, "_init"); + config->keepSections = getKeepSections(args); config->ltoAAPipeline = args.getLastArgValue(OPT_lto_aa_pipeline); config->ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate); config->ltoCSProfileFile = args.getLastArgValue(OPT_lto_cs_profile_file); diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp --- a/lld/ELF/MarkLive.cpp +++ b/lld/ELF/MarkLive.cpp @@ -30,6 +30,7 @@ #include "lld/Common/Memory.h" #include "lld/Common/Strings.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Object/ELF.h" #include "llvm/Support/TimeProfiler.h" #include @@ -258,7 +259,8 @@ if (sec->flags & SHF_LINK_ORDER) continue; - if (isReserved(sec) || script->shouldKeep(sec)) { + if (isReserved(sec) || script->shouldKeep(sec) || + config->keepSections.count(sec->name)) { enqueue(sec, 0); } else if (isValidCIdentifier(sec->name)) { cNamedSections[saver.save("__start_" + sec->name)].push_back(sec); diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -245,6 +245,9 @@ defm just_symbols: Eq<"just-symbols", "Just link symbols">; +defm keep_section: Eq<"keep-section", + "Do not drop this section during garbage collection">; + defm keep_unique: Eq<"keep-unique", "Do not fold this symbol during ICF">; defm library: Eq<"library", "Root name of library to use">, diff --git a/lld/test/ELF/keep-sections.s b/lld/test/ELF/keep-sections.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/keep-sections.s @@ -0,0 +1,34 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +# Check that the section is removed without --keep-section +# RUN: ld.lld --gc-sections %t.o -o %t1 +# RUN: llvm-objdump --section-headers %t1 | FileCheck -check-prefix=SECGC %s +# SECGC: Sections: +# SECGC-NEXT: Idx Name Size +# SECGC-NEXT: 0 00000000 +# SECGC-NEXT: 1 .temp 00000004 +# SECGC-NEXT: 2 .text 00000007 + +## Now apply --keep-section to preserve the section. +# RUN: ld.lld --gc-sections --keep-section=.keep %t.o -o %t2 +# RUN: llvm-objdump --section-headers %t2 | FileCheck -check-prefix=SECNOGC %s +# SECNOGC: Sections: +# SECNOGC-NEXT: Idx Name Size +# SECNOGC-NEXT: 0 00000000 +# SECNOGC-NEXT: 1 .keep 00000004 +# SECNOGC-NEXT: 2 .temp 00000004 +# SECNOGC-NEXT: 3 .text 00000007 + + +.global _start +_start: + mov temp, %eax + +.section .keep, "a" +keep: + .long 1 + +.section .temp, "a" +temp: + .long 2