diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -951,6 +951,7 @@ config->ignoreFunctionAddressEquality = args.hasArg(OPT_ignore_function_address_equality); config->init = args.getLastArgValue(OPT_init, "_init"); + 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); @@ -2111,6 +2112,13 @@ // Split SHF_MERGE and .eh_frame sections into pieces in preparation for garbage collection. splitSections(); + // process section to keep via --keep-sections before garbage collection + for (StringRef secPattern : args::getStrings(args, OPT_keep_section)) { + auto mb = MemoryBuffer::getMemBuffer(secPattern); + MemoryBufferRef mbref = mb->getMemBufferRef(); + make>(std::move(mb)); // take MB ownership + processKeepSections(mbref); + } // Garbage collection and removal of shared symbols from unused shared objects. markLive(); demoteSharedSymbols(); 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/ELF/ScriptParser.h b/lld/ELF/ScriptParser.h --- a/lld/ELF/ScriptParser.h +++ b/lld/ELF/ScriptParser.h @@ -15,6 +15,9 @@ namespace lld { namespace elf { +// Parses the keep sections +void processKeepSections(MemoryBufferRef mb); + // Parses a linker script. Calling this function updates // lld::elf::config and lld::elf::script. void readLinkerScript(MemoryBufferRef mb); diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -58,6 +58,7 @@ } } + void processKeepSections(); void readLinkerScript(); void readVersionScript(); void readDynamicList(); @@ -175,6 +176,12 @@ (a.getValue() | b.getValue()) - a.getSecAddr(), a.loc}; } +void ScriptParser::processKeepSections() { + InputSectionDescription *cmd = + readInputSectionRules(next(), /*withFlags=*/0, /*withoutFlags=*/0); + script->keptSections.push_back(cmd); +} + void ScriptParser::readDynamicList() { expect("{"); std::vector locals; @@ -1634,3 +1641,7 @@ void elf::readDefsym(StringRef name, MemoryBufferRef mb) { ScriptParser(mb).readDefsym(name); } + +void elf::processKeepSections(MemoryBufferRef mb) { + ScriptParser(mb).processKeepSections(); +} 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,37 @@ +# 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 + +## Check that we can parse SORT, the sections are not actually sorted because +## we are not merging them together +# RUN: ld.lld --gc-sections --keep-section="*(SORT_BY_NAME(.keep))" %t.o -o %t3 + +.global _start +_start: + mov temp, %eax + +.section .keep, "a" +keep: + .long 1 + +.section .temp, "a" +temp: + .long 2