diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp --- a/lld/MachO/InputSection.cpp +++ b/lld/MachO/InputSection.cpp @@ -157,6 +157,7 @@ fatal(toString(this) + ": string is not null terminated"); size_t size = end + 1; pieces.emplace_back(off, xxHash64(s.substr(0, size))); + // fprintf(stderr, "%llx %s\n", off, s.substr(0, size)); s = s.substr(size); off += size; } diff --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h --- a/lld/MachO/SyntheticSections.h +++ b/lld/MachO/SyntheticSections.h @@ -16,6 +16,7 @@ #include "OutputSegment.h" #include "Target.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SetVector.h" #include "llvm/MC/StringTableBuilder.h" @@ -522,15 +523,16 @@ public: CStringSection(); void addInput(CStringInputSection *); - uint64_t getSize() const override { return builder.getSize(); } + uint64_t getSize() const override { return size; } void finalizeContents(); bool isNeeded() const override { return !inputs.empty(); } - void writeTo(uint8_t *buf) const override { builder.write(buf); } + void writeTo(uint8_t *buf) const override; std::vector inputs; private: - llvm::StringTableBuilder builder; + llvm::DenseMap stringIndexMap; + size_t size = 0; }; class CFStringSection final : public SyntheticSection { diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -1175,40 +1175,56 @@ // Finally, the overhead is not huge: using 16-byte alignment (vs no alignment) // is only a 0.5% size overhead when linking chromium_framework. CStringSection::CStringSection() - : SyntheticSection(segment_names::text, section_names::cString), - builder(StringTableBuilder::RAW, - /*Alignment=*/target->cpuType == CPU_TYPE_X86_64 ? 16 : 1) { - align = target->cpuType == CPU_TYPE_X86_64 ? 16 : 1; + : SyntheticSection(segment_names::text, section_names::cString) { flags = S_CSTRING_LITERALS; } void CStringSection::addInput(CStringInputSection *isec) { isec->parent = this; + align = std::max(align, isec->align); inputs.push_back(isec); } void CStringSection::finalizeContents() { - // Add all string pieces to the string table builder to create section - // contents. - for (const CStringInputSection *isec : inputs) - for (size_t i = 0, e = isec->pieces.size(); i != e; ++i) - if (isec->pieces[i].live) - builder.add(isec->getCachedHashStringRef(i)); - - // Fix the string table content. After this, the contents will never change. - builder.finalizeInOrder(); - - // finalize() fixed tail-optimized strings, so we can now get - // offsets of strings. Get an offset for each string and save it - // to a corresponding SectionPiece for easy access. + llvm::stable_sort(inputs, [](InputSection *a, InputSection *b) { + return a->align > b->align; + }); + for (const CStringInputSection *isec : inputs) { + for (size_t i = 0, e = isec->pieces.size(); i != e; ++i) { + if (isec->pieces[i].live) { + auto s = isec->getCachedHashStringRef(i); + auto it = stringIndexMap.insert(std::make_pair(s, 0)); + if (it.second) { + uint64_t skew = isec->pieces[i].inSecOff % isec->align; + size_t start = alignTo(size, isec->align, skew); + // fprintf(stderr, "%llx %llx %llx %llx %s\n", + // isec->pieces[i].inSecOff, start, skew, isec->align, s.data()); + it.first->second = start; + size = start + s.size(); + } + } + } + } + + // Get an offset for each string and save it to a corresponding SectionPiece + // for easy access. for (CStringInputSection *isec : inputs) { for (size_t i = 0, e = isec->pieces.size(); i != e; ++i) { if (!isec->pieces[i].live) continue; isec->pieces[i].outSecOff = - builder.getOffset(isec->getCachedHashStringRef(i)); - isec->isFinal = true; + stringIndexMap.lookup(isec->getCachedHashStringRef(i)); } + isec->isFinal = true; + } +} + +void CStringSection::writeTo(uint8_t *buf) const { + for (const auto &p : stringIndexMap) { + StringRef data = p.first.val(); + uint64_t off = p.second; + if (!data.empty()) + memcpy(buf + off, data.data(), data.size()); } }