diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h index d41ca5382c692..f8dcc84e4ee1b 100644 --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -143,6 +143,7 @@ struct Configuration { bool timeTraceEnabled = false; bool dataConst = false; bool dedupStrings = true; + bool dedupSymbolStrings = true; bool deadStripDuplicates = false; bool omitDebugInfo = false; bool warnDylibInstallName = false; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp index 31630ba7d69de..4f6c9b4ddc798 100644 --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1806,6 +1806,7 @@ bool link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, config->keepICFStabs = args.hasArg(OPT_keep_icf_stabs); config->dedupStrings = args.hasFlag(OPT_deduplicate_strings, OPT_no_deduplicate_strings, true); + config->dedupSymbolStrings = !args.hasArg(OPT_no_deduplicate_symbol_strings); config->deadStripDuplicates = args.hasArg(OPT_dead_strip_duplicates); config->warnDylibInstallName = args.hasFlag( OPT_warn_dylib_install_name, OPT_no_warn_dylib_install_name, false); diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td index 4c89f96c3ebaa..9001e85582c12 100644 --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -1476,3 +1476,8 @@ def no_warn_duplicate_libraries : Flag<["-"], "no_warn_duplicate_libraries">, HelpText<"Do not warn if the input contains duplicate library options.">, Flags<[HelpHidden]>, Group; + +// Add this with the other flags in the rare options group +def no_deduplicate_symbol_strings : Flag<["-"], "no-deduplicate-symbol-strings">, + HelpText<"Do not deduplicate strings in the symbol string table. Might result in larger binaries but slightly faster link times.">, + Group; diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp index 417b7cf93efa7..99a46bc150833 100644 --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -1541,7 +1541,14 @@ StringTableSection::StringTableSection() uint32_t StringTableSection::addString(StringRef str) { uint32_t strx = size; - strings.push_back(str); // TODO: consider deduplicating strings + if (config->dedupSymbolStrings) { + llvm::CachedHashStringRef hashedStr(str); + auto [it, inserted] = stringMap.try_emplace(hashedStr, strx); + if (!inserted) + return it->second; + } + + strings.push_back(str); size += str.size() + 1; // account for null terminator return strx; } diff --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h index af99f22788d6e..5796b0790c83a 100644 --- a/lld/MachO/SyntheticSections.h +++ b/lld/MachO/SyntheticSections.h @@ -447,6 +447,7 @@ class StringTableSection final : public LinkEditSection { // match its behavior here since some tools depend on it. // Consequently, the empty string will be at index 1, not zero. std::vector strings{" "}; + llvm::DenseMap stringMap; size_t size = 2; }; diff --git a/lld/test/MachO/cfstring-dedup.s b/lld/test/MachO/cfstring-dedup.s index fb121cde3e958..4f490ba4380e1 100644 --- a/lld/test/MachO/cfstring-dedup.s +++ b/lld/test/MachO/cfstring-dedup.s @@ -7,6 +7,17 @@ # RUN: %lld -dylib -framework CoreFoundation %t/foo1.o %t/foo2.o -o %t/foo # RUN: llvm-objdump --no-print-imm-hex --macho --rebase --bind --syms -d %t/foo | FileCheck %s --check-prefix=LITERALS +# Check that string deduplication for symbol names is working +# RUN: %lld -dylib -framework CoreFoundation %t/foo1.o %t/foo2.o -o %t/foo_no_dedup -no-deduplicate-symbol-strings +# RUN: llvm-strings %t/foo | FileCheck %s --check-prefix=CHECK-DEDUP +# RUN: llvm-strings %t/foo_no_dedup | FileCheck %s --check-prefix=CHECK-NO-DEDUP +# CHECK-DEDUP: _named_cfstring +# CHECK-DEDUP-NOT: _named_cfstring +# CHECK-NO-DEDUP: _named_cfstring +# CHECK-NO-DEDUP: _named_cfstring +# CHECK-NO-DEDUP-NOT: _named_cfstring + + # CHECK: (__TEXT,__text) section # CHECK-NEXT: _foo1: # CHECK-NEXT: _foo2: