diff --git a/lld/MachO/OutputSegment.h b/lld/MachO/OutputSegment.h --- a/lld/MachO/OutputSegment.h +++ b/lld/MachO/OutputSegment.h @@ -42,10 +42,7 @@ const OutputSection *lastSection() const { return sections.back(); } void addOutputSection(OutputSection *os); - void sortOutputSections( - llvm::function_ref comparator) { - llvm::sort(sections, comparator); - } + void sortOutputSections(); const std::vector &getSections() const { return sections; } size_t numNonHiddenSections() const; @@ -65,6 +62,8 @@ extern std::vector outputSegments; +void sortOutputSegments(); + OutputSegment *getOrCreateOutputSegment(StringRef name); } // namespace macho diff --git a/lld/MachO/OutputSegment.cpp b/lld/MachO/OutputSegment.cpp --- a/lld/MachO/OutputSegment.cpp +++ b/lld/MachO/OutputSegment.cpp @@ -13,6 +13,7 @@ #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/BinaryFormat/MachO.h" using namespace llvm; @@ -60,6 +61,87 @@ osec->align = sectAlign.align; } +template static auto compareByOrder(F ord) { + return [=](T a, T b) { return ord(a) < ord(b); }; +} + +static int segmentOrder(OutputSegment *seg) { + return StringSwitch(seg->name) + .Case(segment_names::pageZero, -4) + .Case(segment_names::text, -3) + .Case(segment_names::dataConst, -2) + .Case(segment_names::data, -1) + .Case(segment_names::llvm, std::numeric_limits::max() - 1) + // Make sure __LINKEDIT is the last segment (i.e. all its hidden + // sections must be ordered after other sections). + .Case(segment_names::linkEdit, std::numeric_limits::max()) + .Default(seg->inputOrder); +} + +static int sectionOrder(OutputSection *osec) { + StringRef segname = osec->parent->name; + // Sections are uniquely identified by their segment + section name. + if (segname == segment_names::text) { + return StringSwitch(osec->name) + .Case(section_names::header, -4) + .Case(section_names::text, -3) + .Case(section_names::stubs, -2) + .Case(section_names::stubHelper, -1) + .Case(section_names::unwindInfo, std::numeric_limits::max() - 1) + .Case(section_names::ehFrame, std::numeric_limits::max()) + .Default(osec->inputOrder); + } else if (segname == segment_names::data || + segname == segment_names::dataConst) { + // For each thread spawned, dyld will initialize its TLVs by copying the + // address range from the start of the first thread-local data section to + // the end of the last one. We therefore arrange these sections contiguously + // to minimize the amount of memory used. Additionally, since zerofill + // sections must be at the end of their segments, and since TLV data + // sections can be zerofills, we end up putting all TLV data sections at the + // end of the segment. + switch (sectionType(osec->flags)) { + case S_THREAD_LOCAL_REGULAR: + return std::numeric_limits::max() - 2; + case S_THREAD_LOCAL_ZEROFILL: + return std::numeric_limits::max() - 1; + case S_ZEROFILL: + return std::numeric_limits::max(); + default: + return StringSwitch(osec->name) + .Case(section_names::got, -3) + .Case(section_names::lazySymbolPtr, -2) + .Case(section_names::const_, -1) + .Default(osec->inputOrder); + } + } else if (segname == segment_names::linkEdit) { + return StringSwitch(osec->name) + .Case(section_names::rebase, -9) + .Case(section_names::binding, -8) + .Case(section_names::weakBinding, -7) + .Case(section_names::lazyBinding, -6) + .Case(section_names::export_, -5) + .Case(section_names::functionStarts, -4) + .Case(section_names::symbolTable, -3) + .Case(section_names::indirectSymbolTable, -2) + .Case(section_names::stringTable, -1) + .Case(section_names::codeSignature, std::numeric_limits::max()) + .Default(osec->inputOrder); + } + // ZeroFill sections must always be the at the end of their segments, + // otherwise subsequent sections may get overwritten with zeroes at runtime. + if (sectionType(osec->flags) == S_ZEROFILL) + return std::numeric_limits::max(); + return osec->inputOrder; +} + +void OutputSegment::sortOutputSections() { + llvm::sort(sections, compareByOrder(sectionOrder)); +} + +void macho::sortOutputSegments() { + llvm::sort(outputSegments, compareByOrder(segmentOrder)); +} + static DenseMap nameToOutputSegment; std::vector macho::outputSegments; diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -755,94 +755,19 @@ return sectionPriorities; } -static int segmentOrder(OutputSegment *seg) { - return StringSwitch(seg->name) - .Case(segment_names::pageZero, -4) - .Case(segment_names::text, -3) - .Case(segment_names::dataConst, -2) - .Case(segment_names::data, -1) - .Case(segment_names::llvm, std::numeric_limits::max() - 1) - // Make sure __LINKEDIT is the last segment (i.e. all its hidden - // sections must be ordered after other sections). - .Case(segment_names::linkEdit, std::numeric_limits::max()) - .Default(seg->inputOrder); -} - -static int sectionOrder(OutputSection *osec) { - StringRef segname = osec->parent->name; - // Sections are uniquely identified by their segment + section name. - if (segname == segment_names::text) { - return StringSwitch(osec->name) - .Case(section_names::header, -4) - .Case(section_names::text, -3) - .Case(section_names::stubs, -2) - .Case(section_names::stubHelper, -1) - .Case(section_names::unwindInfo, std::numeric_limits::max() - 1) - .Case(section_names::ehFrame, std::numeric_limits::max()) - .Default(osec->inputOrder); - } else if (segname == segment_names::data || - segname == segment_names::dataConst) { - // For each thread spawned, dyld will initialize its TLVs by copying the - // address range from the start of the first thread-local data section to - // the end of the last one. We therefore arrange these sections contiguously - // to minimize the amount of memory used. Additionally, since zerofill - // sections must be at the end of their segments, and since TLV data - // sections can be zerofills, we end up putting all TLV data sections at the - // end of the segment. - switch (sectionType(osec->flags)) { - case S_THREAD_LOCAL_REGULAR: - return std::numeric_limits::max() - 2; - case S_THREAD_LOCAL_ZEROFILL: - return std::numeric_limits::max() - 1; - case S_ZEROFILL: - return std::numeric_limits::max(); - default: - return StringSwitch(osec->name) - .Case(section_names::got, -3) - .Case(section_names::lazySymbolPtr, -2) - .Case(section_names::const_, -1) - .Default(osec->inputOrder); - } - } else if (segname == segment_names::linkEdit) { - return StringSwitch(osec->name) - .Case(section_names::rebase, -9) - .Case(section_names::binding, -8) - .Case(section_names::weakBinding, -7) - .Case(section_names::lazyBinding, -6) - .Case(section_names::export_, -5) - .Case(section_names::functionStarts, -4) - .Case(section_names::symbolTable, -3) - .Case(section_names::indirectSymbolTable, -2) - .Case(section_names::stringTable, -1) - .Case(section_names::codeSignature, std::numeric_limits::max()) - .Default(osec->inputOrder); - } - // ZeroFill sections must always be the at the end of their segments, - // otherwise subsequent sections may get overwritten with zeroes at runtime. - if (sectionType(osec->flags) == S_ZEROFILL) - return std::numeric_limits::max(); - return osec->inputOrder; -} - -template -static std::function compareByOrder(F ord) { - return [=](T a, T b) { return ord(a) < ord(b); }; -} - // Sorting only can happen once all outputs have been collected. Here we sort // segments, output sections within each segment, and input sections within each // output segment. static void sortSegmentsAndSections() { TimeTraceScope timeScope("Sort segments and sections"); - - llvm::sort(outputSegments, compareByOrder(segmentOrder)); + sortOutputSegments(); DenseMap isecPriorities = buildInputSectionPriorities(); uint32_t sectionIndex = 0; for (OutputSegment *seg : outputSegments) { - seg->sortOutputSections(compareByOrder(sectionOrder)); + seg->sortOutputSections(); for (OutputSection *osec : seg->getSections()) { // Now that the output sections are sorted, assign the final // output section indices.