Index: include/lld/Passes/LayoutPass.h =================================================================== --- include/lld/Passes/LayoutPass.h +++ include/lld/Passes/LayoutPass.h @@ -37,10 +37,7 @@ uint64_t _override; }; - typedef std::function SortOverride; - - LayoutPass(const Registry ®istry, SortOverride sorter=nullptr); + LayoutPass(const Registry ®istry); /// Sorts atoms in mergedFile by content type then by command line order. void perform(std::unique_ptr &mergedFile) override; @@ -60,7 +57,6 @@ void buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range); const Registry &_registry; - SortOverride _customSorter; typedef llvm::DenseMap AtomToAtomT; typedef llvm::DenseMap AtomToOrdinalT; Index: include/lld/ReaderWriter/MachOLinkingContext.h =================================================================== --- include/lld/ReaderWriter/MachOLinkingContext.h +++ include/lld/ReaderWriter/MachOLinkingContext.h @@ -63,6 +63,11 @@ noDebugMap // -S option }; + struct OrderFileNode { + StringRef fileFilter; + unsigned order; + }; + /// Initializes the context to sane default values given the specified output /// file type, arch, os, and minimum os version. This should be called before /// other setXXX() methods. @@ -253,6 +258,10 @@ /// Used to keep track of direct and indirect dylibs. void registerDylib(mach_o::MachODylibFile *dylib, bool upward) const; + const llvm::StringMap> &getOrderFiles() const { + return _orderFiles; + } + // Reads a file from disk to memory. Returns only a needed chunk // if a fat binary. ErrorOr> getMemoryBuffer(StringRef path); @@ -314,14 +323,6 @@ uint8_t align2; }; - struct OrderFileNode { - StringRef fileFilter; - unsigned order; - }; - - static bool findOrderOrdinal(const std::vector &nodes, - const DefinedAtom *atom, unsigned &ordinal); - static ArchInfo _s_archInfos[]; std::set _existingPaths; // For testing only. Index: lib/Passes/LayoutPass.cpp =================================================================== --- lib/Passes/LayoutPass.cpp +++ lib/Passes/LayoutPass.cpp @@ -20,8 +20,7 @@ #define DEBUG_TYPE "LayoutPass" static bool compareAtoms(const LayoutPass::SortKey &, - const LayoutPass::SortKey &, - LayoutPass::SortOverride customSorter=nullptr); + const LayoutPass::SortKey &); #ifndef NDEBUG // Return "reason (leftval, rightval)" @@ -163,12 +162,10 @@ /// b) Sorts atoms by their ordinal overrides (layout-after/ingroup) /// c) Sorts atoms by their permissions /// d) Sorts atoms by their content -/// e) If custom sorter provided, let it sort /// f) Sorts atoms on how they appear using File Ordinality /// g) Sorts atoms on how they appear within the File static bool compareAtomsSub(const LayoutPass::SortKey &lc, const LayoutPass::SortKey &rc, - LayoutPass::SortOverride customSorter, std::string &reason) { const DefinedAtom *left = lc._atom; const DefinedAtom *right = rc._atom; @@ -220,13 +217,6 @@ return leftType < rightType; } - // Use custom sorter if supplied. - if (customSorter) { - bool leftBeforeRight; - if (customSorter(leftRoot, rightRoot, leftBeforeRight)) - return leftBeforeRight; - } - // Sort by .o order. const File *leftFile = &leftRoot->file(); const File *rightFile = &rightRoot->file(); @@ -253,10 +243,9 @@ } static bool compareAtoms(const LayoutPass::SortKey &lc, - const LayoutPass::SortKey &rc, - LayoutPass::SortOverride customSorter) { + const LayoutPass::SortKey &rc) { std::string reason; - bool result = compareAtomsSub(lc, rc, customSorter, reason); + bool result = compareAtomsSub(lc, rc, reason); DEBUG({ StringRef comp = result ? "<" : ">="; llvm::dbgs() << "Layout: '" << lc._atom->name() << "' " << comp << " '" @@ -265,8 +254,7 @@ return result; } -LayoutPass::LayoutPass(const Registry ®istry, SortOverride sorter) - : _registry(registry), _customSorter(sorter) {} +LayoutPass::LayoutPass(const Registry ®istry) : _registry(registry) {} // Returns the atom immediately followed by the given atom in the followon // chain. @@ -535,10 +523,7 @@ }); std::vector vec = decorate(atomRange); - parallel_sort(vec.begin(), vec.end(), - [&](const LayoutPass::SortKey &l, const LayoutPass::SortKey &r) -> bool { - return compareAtoms(l, r, _customSorter); - }); + parallel_sort(vec.begin(), vec.end(), compareAtoms); DEBUG(checkTransitivity(vec)); undecorate(atomRange, vec); Index: lib/ReaderWriter/MachO/CMakeLists.txt =================================================================== --- lib/ReaderWriter/MachO/CMakeLists.txt +++ lib/ReaderWriter/MachO/CMakeLists.txt @@ -12,6 +12,7 @@ MachONormalizedFileFromAtoms.cpp MachONormalizedFileToAtoms.cpp MachONormalizedFileYAML.cpp + OrderPass.cpp ShimPass.cpp StubsPass.cpp WriterMachO.cpp Index: lib/ReaderWriter/MachO/MachOLinkingContext.cpp =================================================================== --- lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -583,12 +583,8 @@ } void MachOLinkingContext::addPasses(PassManager &pm) { - pm.add(std::unique_ptr(new LayoutPass( - registry(), [&](const DefinedAtom * left, const DefinedAtom * right, - bool & leftBeforeRight) - ->bool { - return customAtomOrderer(left, right, leftBeforeRight); - }))); + pm.add(std::unique_ptr(new LayoutPass(registry()))); + mach_o::addOrderPass(pm, *this); if (needsStubsPass()) mach_o::addStubsPass(pm, *this); if (needsCompactUnwindPass()) @@ -881,71 +877,6 @@ _orderFiles[symbol].push_back(info); } -bool -MachOLinkingContext::findOrderOrdinal(const std::vector &nodes, - const DefinedAtom *atom, - unsigned &ordinal) { - const File *objFile = &atom->file(); - assert(objFile); - StringRef objName = objFile->path(); - std::pair dirAndLeaf = objName.rsplit('/'); - if (!dirAndLeaf.second.empty()) - objName = dirAndLeaf.second; - for (const OrderFileNode &info : nodes) { - if (info.fileFilter.empty()) { - // Have unprefixed symbol name in order file that matches this atom. - ordinal = info.order; - return true; - } - if (info.fileFilter.equals(objName)) { - // Have prefixed symbol name in order file that matches atom's path. - ordinal = info.order; - return true; - } - } - return false; -} - -bool MachOLinkingContext::customAtomOrderer(const DefinedAtom *left, - const DefinedAtom *right, - bool &leftBeforeRight) { - // No custom sorting if no order file entries. - if (!_orderFileEntries) - return false; - - // Order files can only order named atoms. - StringRef leftName = left->name(); - StringRef rightName = right->name(); - if (leftName.empty() || rightName.empty()) - return false; - - // If neither is in order file list, no custom sorter. - auto leftPos = _orderFiles.find(leftName); - auto rightPos = _orderFiles.find(rightName); - bool leftIsOrdered = (leftPos != _orderFiles.end()); - bool rightIsOrdered = (rightPos != _orderFiles.end()); - if (!leftIsOrdered && !rightIsOrdered) - return false; - - // There could be multiple symbols with same name but different file prefixes. - unsigned leftOrder; - unsigned rightOrder; - bool foundLeft = - leftIsOrdered && findOrderOrdinal(leftPos->getValue(), left, leftOrder); - bool foundRight = rightIsOrdered && - findOrderOrdinal(rightPos->getValue(), right, rightOrder); - if (!foundLeft && !foundRight) - return false; - - // If only one is in order file list, ordered one goes first. - if (foundLeft != foundRight) - leftBeforeRight = foundLeft; - else - leftBeforeRight = (leftOrder < rightOrder); - - return true; -} - static bool isLibrary(const std::unique_ptr &elem) { if (FileNode *node = dyn_cast(const_cast(elem.get()))) { File *file = node->getFile(); Index: lib/ReaderWriter/MachO/MachOPasses.h =================================================================== --- lib/ReaderWriter/MachO/MachOPasses.h +++ lib/ReaderWriter/MachO/MachOPasses.h @@ -16,6 +16,7 @@ namespace lld { namespace mach_o { +void addOrderPass(PassManager &pm, const MachOLinkingContext &ctx); void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx); void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx); void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx); Index: lib/ReaderWriter/MachO/OrderPass.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/MachO/OrderPass.cpp @@ -0,0 +1,111 @@ +//===- lib/ReaderWriter/MachO/OrderPass.cpp ------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// This is a pass to reorder atoms as specified by the custom order file +/// given with -order_file. +/// +//===----------------------------------------------------------------------===// + +#include "MachOPasses.h" +#include "lld/Core/File.h" +#include "lld/Core/Pass.h" +#include "lld/ReaderWriter/MachOLinkingContext.h" +#include +#include + +namespace lld { +namespace mach_o { + +typedef MachOLinkingContext::OrderFileNode OrderFileNode; +typedef llvm::StringMap> OrderFiles; + +static bool findOrderOrdinal(const std::vector &nodes, + const DefinedAtom *atom, + unsigned &ordinal) { + const File *objFile = &atom->file(); + assert(objFile); + StringRef objName = objFile->path(); + std::pair dirAndLeaf = objName.rsplit('/'); + if (!dirAndLeaf.second.empty()) + objName = dirAndLeaf.second; + for (const OrderFileNode &info : nodes) { + if (info.fileFilter.empty()) { + // Have unprefixed symbol name in order file that matches this atom. + ordinal = info.order; + return true; + } + if (info.fileFilter.equals(objName)) { + // Have prefixed symbol name in order file that matches atom's path. + ordinal = info.order; + return true; + } + } + return false; +} + +static bool compare(const OrderFiles &orderFiles, const DefinedAtom *lhs, + const DefinedAtom *rhs) { + // Order files can only order named atoms. + StringRef lhsName = lhs->name(); + StringRef rhsName = rhs->name(); + if (lhsName.empty() || rhsName.empty()) + return false; + + // If neither is in order file list, no custom sorter. + auto lhsPos = orderFiles.find(lhsName); + auto rhsPos = orderFiles.find(rhsName); + bool lhsIsOrdered = (lhsPos != orderFiles.end()); + bool rhsIsOrdered = (rhsPos != orderFiles.end()); + if (!lhsIsOrdered && !rhsIsOrdered) + return false; + + // There could be multiple symbols with same name but different file prefixes. + unsigned lhsOrder; + unsigned rhsOrder; + bool foundLhs = + lhsIsOrdered && findOrderOrdinal(lhsPos->getValue(), lhs, lhsOrder); + bool foundRhs = + rhsIsOrdered && findOrderOrdinal(rhsPos->getValue(), rhs, rhsOrder); + if (!foundLhs && !foundRhs) + return false; + + // If only one is in order file list, ordered one goes first. + if (foundLhs != foundRhs) + return foundLhs; + return lhsOrder < rhsOrder; +} + +class OrderPass : public lld::Pass { +public: + OrderPass(const MachOLinkingContext &ctx) : _ctx(ctx) {} + + void perform(std::unique_ptr &file) override { + const OrderFiles &orderFiles = _ctx.getOrderFiles(); + + // No custom sorting if no order file entries. + if (orderFiles.begin() == orderFiles.end()) + return; + + MutableFile::DefinedAtomRange defined = file->definedAtoms(); + std::stable_sort(defined.begin(), defined.end(), + [&](const DefinedAtom *lhs, const DefinedAtom *rhs) { + return compare(orderFiles, lhs, rhs); + }); + } + +private: + const MachOLinkingContext &_ctx; +}; + +void addOrderPass(PassManager &pm, const MachOLinkingContext &ctx) { + pm.add(std::unique_ptr(new OrderPass(ctx))); +} + +} // namespace mach_o +} // namespace lld