diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1014,9 +1014,13 @@ isec->parent = osec; inputSections.push_back(isec); } else if (auto *isec = dyn_cast(entry.isec)) { - if (in.cStringSection->inputOrder == UnspecifiedInputOrder) - in.cStringSection->inputOrder = inputOrder++; - in.cStringSection->addInput(isec); + // Unlike word literals, we cannot merge cstrings across sections, so + // we must create an output section per input cstring section type. + CStringSection *cStringSec = + CStringSection::getOrCreateForInput(isec); + if (cStringSec->inputOrder == UnspecifiedInputOrder) + cStringSec->inputOrder = inputOrder++; + cStringSec->addInput(isec); } else if (auto *isec = dyn_cast(entry.isec)) { if (in.wordLiteralSection->inputOrder == UnspecifiedInputOrder) in.wordLiteralSection->inputOrder = inputOrder++; @@ -1031,10 +1035,11 @@ } static void foldIdenticalLiterals() { - // We always create a cStringSection, regardless of whether dedupLiterals is + // We always create CStringSections, regardless of whether dedupLiterals is // true. If it isn't, we simply create a non-deduplicating CStringSection. - // Either way, we must unconditionally finalize it here. - in.cStringSection->finalizeContents(); + // Either way, we must unconditionally finalize them here. + for (const auto &p : CStringSection::instanceMap) + p.second->finalizeContents(); if (in.wordLiteralSection) in.wordLiteralSection->finalizeContents(); } diff --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h --- a/lld/MachO/SyntheticSections.h +++ b/lld/MachO/SyntheticSections.h @@ -41,7 +41,7 @@ class SyntheticSection : public OutputSection { public: - SyntheticSection(const char *segname, const char *name); + SyntheticSection(StringRef segname, StringRef name); virtual ~SyntheticSection() = default; static bool classof(const OutputSection *sec) { @@ -510,13 +510,17 @@ class CStringSection : public SyntheticSection { public: - CStringSection(); + CStringSection(StringRef segname, StringRef name); void addInput(CStringInputSection *); uint64_t getSize() const override { return size; } virtual void finalizeContents(); bool isNeeded() const override { return !inputs.empty(); } void writeTo(uint8_t *buf) const override; + static llvm::DenseMap instanceMap; + // Returns either a CStringSection or a DeduplicatedCStringSection. + static CStringSection *getOrCreateForInput(const CStringInputSection *); + std::vector inputs; private: @@ -525,7 +529,7 @@ class DeduplicatedCStringSection final : public CStringSection { public: - DeduplicatedCStringSection(); + DeduplicatedCStringSection(StringRef segname, StringRef name); uint64_t getSize() const override { return builder.getSize(); } void finalizeContents() override; void writeTo(uint8_t *buf) const override { builder.write(buf); } @@ -590,7 +594,6 @@ struct InStruct { MachHeaderSection *header = nullptr; - CStringSection *cStringSection = nullptr; WordLiteralSection *wordLiteralSection = nullptr; RebaseSection *rebase = nullptr; BindingSection *binding = nullptr; diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -47,7 +47,7 @@ InStruct macho::in; std::vector macho::syntheticSections; -SyntheticSection::SyntheticSection(const char *segname, const char *name) +SyntheticSection::SyntheticSection(StringRef segname, StringRef name) : OutputSection(SyntheticKind, name) { std::tie(this->segname, this->name) = maybeRenameSection({segname, name}); isec = make(segname, name); @@ -1301,8 +1301,8 @@ remove(xarPath); } -CStringSection::CStringSection() - : SyntheticSection(segment_names::text, section_names::cString) { +CStringSection::CStringSection(StringRef segname, StringRef name) + : SyntheticSection(segname, name) { flags = S_CSTRING_LITERALS; } @@ -1340,6 +1340,22 @@ } size = offset; } + +DenseMap CStringSection::instanceMap; + +CStringSection * +CStringSection::getOrCreateForInput(const CStringInputSection *isec) { + NamePair names = maybeRenameSection({isec->getSegName(), isec->getName()}); + CStringSection *&osec = instanceMap[names]; + if (!osec) { + if (config->dedupLiterals) + osec = make(names.first, names.second); + else + osec = make(names.first, names.second); + } + return osec; +} + // Mergeable cstring literals are found under the __TEXT,__cstring section. In // contrast to ELF, which puts strings that need different alignments into // different sections, clang's Mach-O backend puts them all in one section. @@ -1364,8 +1380,10 @@ // deduplication of differently-aligned strings. Finally, the overhead is not // huge: using 16-byte alignment (vs no alignment) is only a 0.5% size overhead // when linking chromium_framework on x86_64. -DeduplicatedCStringSection::DeduplicatedCStringSection() - : builder(StringTableBuilder::RAW, /*Alignment=*/16) {} +DeduplicatedCStringSection::DeduplicatedCStringSection(StringRef segname, + StringRef name) + : CStringSection(segname, name), + builder(StringTableBuilder::RAW, /*Alignment=*/16) {} void DeduplicatedCStringSection::finalizeContents() { // Add all string pieces to the string table builder to create section diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -1141,11 +1141,6 @@ void macho::createSyntheticSections() { in.header = make(); - if (config->dedupLiterals) { - in.cStringSection = make(); - } else { - in.cStringSection = make(); - } in.wordLiteralSection = config->dedupLiterals ? make() : nullptr; in.rebase = make(); diff --git a/lld/test/MachO/cstring-dedup.s b/lld/test/MachO/cstring-dedup.s --- a/lld/test/MachO/cstring-dedup.s +++ b/lld/test/MachO/cstring-dedup.s @@ -2,12 +2,23 @@ # RUN: rm -rf %t; split-file %s %t # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/more-foo.s -o %t/more-foo.o -# RUN: %lld -dylib --deduplicate-literals %t/test.o %t/more-foo.o -o %t/test +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/name-collision.s -o %t/name-collision.o +# RUN: %lld -dylib --deduplicate-literals \ +# RUN: -rename_section __TEXT more_cstrings __TEXT renamed \ +# RUN: %t/test.o %t/more-foo.o -o %t/test # RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test | \ # RUN: FileCheck %s --check-prefix=STR --implicit-check-not foo --implicit-check-not bar +# RUN: llvm-objdump --macho --section="__TEXT,renamed" %t/test | \ +# RUN: FileCheck %s --check-prefix=MORE-STR --implicit-check-not foo --implicit-check-not bar # RUN: llvm-objdump --macho --section="__DATA,ptrs" --syms %t/test | FileCheck %s # RUN: llvm-readobj --section-headers %t/test | FileCheck %s --check-prefix=HEADER +# RUN: not %lld -dylib --deduplicate-literals \ +# RUN: -rename_section __TEXT more_cstrings __TEXT renamed \ +# RUN: %t/test.o %t/more-foo.o %t/name-collision.o -o /dev/null 2>&1 | \ +# RUN: FileCheck %s --check-prefix=CONFLICT +# CONFLICT: section from {{.*}}name-collision.o conflicts with synthetic section __TEXT,renamed + ## Make sure we only have 3 deduplicated strings in __cstring, and that they ## are 16-byte-aligned. # STR: Contents of (__TEXT,__cstring) section @@ -15,6 +26,13 @@ # STR: {{.*}}0 barbaz # STR: {{.*}}0 {{$}} +## Make sure strings get deduplicated within each section, but not across +## sections. +# MORE-STR: Contents of (__TEXT,renamed) section +# MORE-STR: foo +# MORE-STR: barbaz +# MORE-STR: {{$}} + ## Make sure both symbol and section relocations point to the right thing. # CHECK: Contents of (__DATA,ptrs) section # CHECK-NEXT: __TEXT:__cstring:foo @@ -71,6 +89,9 @@ _bar1: .ascii "bar" +## NOTE: ld64 doesn't actually support having symbols point to the middle of a +## cstring. It crashes with a "more atoms allocated than expected" error. We +## can remove LLD's support for this "feature" if necessary. _baz1: .asciz "baz" _bar2: @@ -83,6 +104,12 @@ _zero2: .asciz "" +.section __TEXT,more_cstrings,cstring_literals +.p2align 2 +.asciz "foo" +.asciz "foo" +.asciz "barbaz" + .section __DATA,ptrs,literal_pointers .quad L_.foo1 .quad L_.foo2 @@ -105,3 +132,7 @@ .asciz "foo" _globl_foo2: .asciz "foo" + +#--- name-collision.s +.section __TEXT,renamed +.space 1 diff --git a/lld/test/MachO/literal-dedup.s b/lld/test/MachO/literal-dedup.s --- a/lld/test/MachO/literal-dedup.s +++ b/lld/test/MachO/literal-dedup.s @@ -3,9 +3,17 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/qux.s -o %t/qux.o # RUN: %lld -dylib --deduplicate-literals %t/test.o %t/qux.o -o %t/test +# RUN: llvm-objdump --macho --section-headers %t/test | FileCheck %s --check-prefix=SECTIONS # RUN: llvm-objdump --macho --section="__TEXT,__literals" --section="__DATA,ptrs" --syms %t/test | FileCheck %s # RUN: llvm-readobj --section-headers %t/test | FileCheck %s --check-prefix=HEADER +## Check that all literal input sections are folded into `__literals`, +## regardless of their original names +# SECTIONS: 0 __text +# SECTIONS-NEXT: 1 __literals +# SECTIONS-NEXT: 2 ptrs +# SECTIONS-EMPTY: + # CHECK: Contents of (__TEXT,__literals) section # CHECK-NEXT: [[#%.16x,DEADBEEF16:]] ef be ad de ef be ad de ef be ad de ef be ad de # CHECK-NEXT: [[#%.16x,FEEDFACE16:]] ce fa ed fe ce fa ed fe ce fa ed fe ce fa ed fe @@ -24,6 +32,7 @@ # CHECK-NEXT: 0000000000001048 0x[[#%x,DEADBEEF4]] # CHECK-NEXT: 0000000000001050 0x[[#%x,DEADBEEF4 + 4]] # CHECK-NEXT: 0000000000001058 0x[[#%x,DEADBEEF4]] +# CHECK-EMPTY: ## Make sure the symbol addresses are correct too. # CHECK: SYMBOL TABLE: @@ -57,6 +66,9 @@ L._baz4: .long 0xfeedface +.section __TEXT,more_lit4,4byte_literals + .long 0xdeadbeef + .literal8 L._foo8: .quad 0xdeadbeefdeadbeef