summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/Config.h1
-rw-r--r--lld/ELF/Driver.cpp1
-rw-r--r--lld/ELF/ICF.cpp8
-rw-r--r--lld/ELF/Options.td3
-rw-r--r--lld/test/ELF/icf9.s13
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
OpenPOWER on IntegriCloud