diff options
| -rw-r--r-- | lld/ELF/Config.h | 1 | ||||
| -rw-r--r-- | lld/ELF/Driver.cpp | 1 | ||||
| -rw-r--r-- | lld/ELF/ICF.cpp | 8 | ||||
| -rw-r--r-- | lld/ELF/Options.td | 3 | ||||
| -rw-r--r-- | lld/test/ELF/icf9.s | 13 |
5 files changed, 22 insertions, 4 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 3a6725a1ad2..7ceab51b3ef 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -126,6 +126,7 @@ struct Configuration { bool HasDynamicList = false; bool HasDynSymTab; bool ICF; + bool ICFData; bool MipsN32Abi = false; bool NoGnuUnique; bool NoUndefinedVersion; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 0e7d02e349e..5d6ef6df08a 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -618,6 +618,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->GcSections = Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false); Config->GdbIndex = Args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false); Config->ICF = Args.hasFlag(OPT_icf_all, OPT_icf_none, false); + Config->ICFData = Args.hasArg(OPT_icf_data); Config->Init = Args.getLastArgValue(OPT_init, "_init"); Config->LTOAAPipeline = Args.getLastArgValue(OPT_lto_aa_pipeline); Config->LTONewPmPasses = Args.getLastArgValue(OPT_lto_newpm_passes); diff --git a/lld/ELF/ICF.cpp b/lld/ELF/ICF.cpp index 09dac60c319..b1e12e0590d 100644 --- a/lld/ELF/ICF.cpp +++ b/lld/ELF/ICF.cpp @@ -161,11 +161,15 @@ template <class ELFT> static uint32_t getHash(InputSection *S) { // Returns true if section S is subject of ICF. static bool isEligible(InputSection *S) { + // Don't merge read only data sections unless --icf-data was passed. + if (!(S->Flags & SHF_EXECINSTR) && !Config->ICFData) + return false; + // .init and .fini contains instructions that must be executed to // initialize and finalize the process. They cannot and should not // be merged. - return S->Live && (S->Flags & SHF_ALLOC) && (S->Flags & SHF_EXECINSTR) && - !(S->Flags & SHF_WRITE) && S->Name != ".init" && S->Name != ".fini"; + return S->Live && (S->Flags & SHF_ALLOC) && !(S->Flags & SHF_WRITE) && + S->Name != ".init" && S->Name != ".fini"; } // Split an equivalence class into smaller classes. diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 1a2634760a4..ab7c02f2732 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -143,6 +143,9 @@ def help: F<"help">, HelpText<"Print option help">; def icf_all: F<"icf=all">, HelpText<"Enable identical code folding">; +def icf_data: F<"icf-data">, + HelpText<"Enable ICF to also fold identical read only data">; + def icf_none: F<"icf=none">, HelpText<"Disable identical code folding">; defm image_base : Eq<"image-base">, HelpText<"Set the base address">; diff --git a/lld/test/ELF/icf9.s b/lld/test/ELF/icf9.s index 5da9bd17237..de6db60f968 100644 --- a/lld/test/ELF/icf9.s +++ b/lld/test/ELF/icf9.s @@ -10,14 +10,23 @@ # CHECK-NOT: selected .rodata.d1 # CHECK-NOT: selected .rodata.d2 +# We do merge rodata if passed --icf-data +# RUN: ld.lld %t -o %t2 --icf=all --verbose --icf-data 2>&1 | FileCheck --check-prefix=DATA %s +# RUN: llvm-readelf -S -W %t2 | FileCheck --check-prefix=DATA-SEC %s + +# DATA: selected .rodata.d1 +# DATA: removed .rodata.d2 + +# DATA-SEC: .rodata PROGBITS 0000000000200120 000120 000001 00 A 0 0 1 + .globl _start, d1, d2 _start: ret -.section .rodata.f1, "a" +.section .rodata.d1, "a" d1: .byte 1 -.section .rodata.f2, "a" +.section .rodata.d2, "a" d2: .byte 1 |

