diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1633,7 +1633,9 @@ if (config->icfLevel != ICFLevel::none) { if (config->icfLevel == ICFLevel::safe) markAddrSigSymbols(); - foldIdenticalSections(); + foldIdenticalSections(/*onlyCfStrings*/ false); + } else if (config->dedupLiterals) { + foldIdenticalSections(/*onlyCfStrings*/ true); } // Write to an output file. diff --git a/lld/MachO/ICF.h b/lld/MachO/ICF.h --- a/lld/MachO/ICF.h +++ b/lld/MachO/ICF.h @@ -19,7 +19,7 @@ void markAddrSigSymbols(); void markSymAsAddrSig(Symbol *s); -void foldIdenticalSections(); +void foldIdenticalSections(bool onlyCfStrings); } // namespace macho } // namespace lld diff --git a/lld/MachO/ICF.cpp b/lld/MachO/ICF.cpp --- a/lld/MachO/ICF.cpp +++ b/lld/MachO/ICF.cpp @@ -400,7 +400,7 @@ } } -void macho::foldIdenticalSections() { +void macho::foldIdenticalSections(bool onlyCfStrings) { TimeTraceScope timeScope("Fold Identical Code Sections"); // The ICF equivalence-class segregation algorithm relies on pre-computed // hashes of InputSection::data for the ConcatOutputSection::inputs and all @@ -421,6 +421,7 @@ for (ConcatInputSection *isec : inputSections) { // FIXME: consider non-code __text sections as hashable? bool isHashable = + (!onlyCfStrings || isCfStringSection(isec)) && (isCodeSection(isec) || isCfStringSection(isec) || isClassRefsSection(isec) || isGccExceptTabSection(isec)) && !isec->keepUnique && !isec->shouldOmitFromOutput() && diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -263,11 +263,15 @@ if (segname == segment_names::ld) return target->wordSize == 8 ? 32 : 20; } - if (config->icfLevel == ICFLevel::none) + if (!config->dedupLiterals) return {}; if (name == section_names::cfString && segname == segment_names::data) return target->wordSize == 8 ? 32 : 16; + + if (config->icfLevel == ICFLevel::none) + return {}; + if (name == section_names::objcClassRefs && segname == segment_names::data) return target->wordSize; return {}; diff --git a/lld/test/MachO/cfstring-dedup.s b/lld/test/MachO/cfstring-dedup.s --- a/lld/test/MachO/cfstring-dedup.s +++ b/lld/test/MachO/cfstring-dedup.s @@ -4,6 +4,8 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo2.s -o %t/foo2.o # RUN: %lld -dylib --icf=all -framework CoreFoundation %t/foo1.o %t/foo2.o -o %t/foo # RUN: llvm-objdump --macho --rebase --bind --syms -d %t/foo | FileCheck %s +# RUN: %lld -dylib --deduplicate-literals -framework CoreFoundation %t/foo1.o %t/foo2.o -o %t/foo +# RUN: llvm-objdump --macho --rebase --bind --syms -d %t/foo | FileCheck %s --check-prefix=LITERALS-ONLY # CHECK: (__TEXT,__text) section # CHECK-NEXT: _foo1: @@ -35,6 +37,19 @@ # CHECK-NEXT: __DATA_CONST __cfstring {{.*}} pointer 0 CoreFoundation ___CFConstantStringClassReference # CHECK-EMPTY: +# LITERALS-ONLY: Rebase table: +# LITERALS-ONLY-NEXT: segment section address type +# LITERALS-ONLY-NEXT: __DATA_CONST __cfstring {{.*}} pointer +# LITERALS-ONLY-NEXT: __DATA_CONST __cfstring {{.*}} pointer +# LITERALS-ONLY-NEXT: __DATA_CONST __cfstring {{.*}} pointer +# LITERALS-ONLY-EMPTY: +# LITERALS-ONLY-NEXT: Bind table: +# LITERALS-ONLY-NEXT: segment section address type addend dylib symbol +# LITERALS-ONLY-NEXT: __DATA_CONST __cfstring {{.*}} pointer 0 CoreFoundation ___CFConstantStringClassReference +# LITERALS-ONLY-NEXT: __DATA_CONST __cfstring {{.*}} pointer 0 CoreFoundation ___CFConstantStringClassReference +# LITERALS-ONLY-NEXT: __DATA_CONST __cfstring {{.*}} pointer 0 CoreFoundation ___CFConstantStringClassReference +# LITERALS-ONLY-EMPTY: + #--- foo1.s .cstring L_.str.0: