diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp index f5c4e82c5b4c33..8be29eb5b9da14 100644 --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1666,7 +1666,9 @@ bool macho::link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, 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.cpp b/lld/MachO/ICF.cpp index 34ffd059a40163..d06fbc6db84093 100644 --- a/lld/MachO/ICF.cpp +++ b/lld/MachO/ICF.cpp @@ -395,7 +395,7 @@ void macho::markAddrSigSymbols() { } } -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 @@ -416,6 +416,7 @@ void macho::foldIdenticalSections() { 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/ICF.h b/lld/MachO/ICF.h index a287692d7ffa08..b7e695d81d343a 100644 --- a/lld/MachO/ICF.h +++ b/lld/MachO/ICF.h @@ -19,7 +19,7 @@ class Symbol; void markAddrSigSymbols(); void markSymAsAddrSig(Symbol *s); -void foldIdenticalSections(); +void foldIdenticalSections(bool onlyCfStrings); } // namespace macho } // namespace lld diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp index 1abbc303c5bdb6..93cde5f5deb2c5 100644 --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -263,11 +263,15 @@ static Optional getRecordSize(StringRef segname, StringRef name) { 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 index 73aa50fa98b043..6457c18833e3d6 100644 --- a/lld/test/MachO/cfstring-dedup.s +++ b/lld/test/MachO/cfstring-dedup.s @@ -3,7 +3,9 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo1.s -o %t/foo1.o # 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: llvm-objdump --macho --rebase --bind --syms -d %t/foo | FileCheck %s --check-prefixes=CHECK,LITERALS +# 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 # CHECK: (__TEXT,__text) section # CHECK-NEXT: _foo1: @@ -22,18 +24,18 @@ # CHECK-DAG: [[#FOO]] g F __TEXT,__text _foo2 ## Make sure we don't emit redundant bind / rebase opcodes for folded sections. -# CHECK: Rebase table: -# CHECK-NEXT: segment section address type -# CHECK-NEXT: __DATA_CONST __cfstring {{.*}} pointer -# CHECK-NEXT: __DATA_CONST __cfstring {{.*}} pointer -# CHECK-NEXT: __DATA_CONST __cfstring {{.*}} pointer -# CHECK-EMPTY: -# CHECK-NEXT: Bind table: -# CHECK-NEXT: segment section address type addend dylib symbol -# CHECK-NEXT: __DATA_CONST __cfstring {{.*}} pointer 0 CoreFoundation ___CFConstantStringClassReference -# CHECK-NEXT: __DATA_CONST __cfstring {{.*}} pointer 0 CoreFoundation ___CFConstantStringClassReference -# CHECK-NEXT: __DATA_CONST __cfstring {{.*}} pointer 0 CoreFoundation ___CFConstantStringClassReference -# CHECK-EMPTY: +# LITERALS: Rebase table: +# LITERALS-NEXT: segment section address type +# LITERALS-NEXT: __DATA_CONST __cfstring {{.*}} pointer +# LITERALS-NEXT: __DATA_CONST __cfstring {{.*}} pointer +# LITERALS-NEXT: __DATA_CONST __cfstring {{.*}} pointer +# LITERALS-EMPTY: +# LITERALS-NEXT: Bind table: +# LITERALS-NEXT: segment section address type addend dylib symbol +# LITERALS-NEXT: __DATA_CONST __cfstring {{.*}} pointer 0 CoreFoundation ___CFConstantStringClassReference +# LITERALS-NEXT: __DATA_CONST __cfstring {{.*}} pointer 0 CoreFoundation ___CFConstantStringClassReference +# LITERALS-NEXT: __DATA_CONST __cfstring {{.*}} pointer 0 CoreFoundation ___CFConstantStringClassReference +# LITERALS-EMPTY: #--- foo1.s .cstring