Index: include/lld/Core/DefinedAtom.h =================================================================== --- include/lld/Core/DefinedAtom.h +++ include/lld/Core/DefinedAtom.h @@ -349,6 +349,10 @@ atomContentType == DefinedAtom::typeGnuLinkOnce); } + // Returns true if lhs should be placed before rhs in the final output. + static bool compareByPosition(const DefinedAtom *lhs, + const DefinedAtom *rhs); + protected: // DefinedAtom is an abstract base class. Only subclasses can access // constructor. Index: lib/Core/DefinedAtom.cpp =================================================================== --- lib/Core/DefinedAtom.cpp +++ lib/Core/DefinedAtom.cpp @@ -9,11 +9,10 @@ #include "llvm/Support/ErrorHandling.h" #include "lld/Core/DefinedAtom.h" - +#include "lld/Core/File.h" namespace lld { - DefinedAtom::ContentPermissions DefinedAtom::permissions() const { // By default base permissions on content type. return permissions(this->contentType()); @@ -82,6 +81,14 @@ llvm_unreachable("unknown content type"); } +bool DefinedAtom::compareByPosition(const DefinedAtom *lhs, + const DefinedAtom *rhs) { + const File *lhsFile = &lhs->file(); + const File *rhsFile = &rhs->file(); + if (lhsFile->ordinal() != rhsFile->ordinal()) + return lhsFile->ordinal() < rhsFile->ordinal(); + assert(lhs->ordinal() != rhs->ordinal()); + return lhs->ordinal() < rhs->ordinal(); +} } // namespace - Index: lib/ReaderWriter/ELF/ArrayOrderPass.h =================================================================== --- lib/ReaderWriter/ELF/ArrayOrderPass.h +++ /dev/null @@ -1,26 +0,0 @@ -//===- lib/ReaderWriter/ELF/ArrayOrderPass.h ------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_ARRAY_ORDER_PASS_H -#define LLD_READER_WRITER_ELF_ARRAY_ORDER_PASS_H - -#include "lld/Core/Pass.h" - -namespace lld { -namespace elf { -/// \brief This pass sorts atoms in .{init,fini}_array. sections. -class ArrayOrderPass : public Pass { -public: - ArrayOrderPass() : Pass() {} - void perform(std::unique_ptr &mergedFile) override; -}; -} -} - -#endif Index: lib/ReaderWriter/ELF/ArrayOrderPass.cpp =================================================================== --- lib/ReaderWriter/ELF/ArrayOrderPass.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//===- lib/ReaderWriter/ELF/ArrayOrderPass.cpp ----------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ArrayOrderPass.h" -#include -#include - -namespace lld { -namespace elf { -void ArrayOrderPass::perform(std::unique_ptr &f) { - auto definedAtoms = f->definedAtoms(); - - // Move sections need to be sorted into the separate continious group. - // That reduces a number of sorting elements and simplifies conditions - // in the sorting predicate. - auto last = std::stable_partition(definedAtoms.begin(), definedAtoms.end(), - [](const DefinedAtom *atom) { - if (atom->sectionChoice() != DefinedAtom::sectionCustomRequired) - return false; - - StringRef name = atom->customSectionName(); - return name.startswith(".init_array") || name.startswith(".fini_array"); - }); - - std::stable_sort(definedAtoms.begin(), last, - [](const DefinedAtom *left, const DefinedAtom *right) { - StringRef leftSec = left->customSectionName(); - StringRef rightSec = right->customSectionName(); - - // Drop the front dot from the section name and get - // an optional section's number starting after the second dot. - StringRef leftNum = leftSec.drop_front().rsplit('.').second; - StringRef rightNum = rightSec.drop_front().rsplit('.').second; - - // Sort {.init_array, .fini_array}[.] sections - // according to their number. Sections without optional - // numer suffix should go last. - - uint32_t leftPriority; - uint32_t rightPriority; - if (leftNum.getAsInteger(10, leftPriority)) - leftPriority = std::numeric_limits::max(); - if (rightNum.getAsInteger(10, rightPriority)) - rightPriority = std::numeric_limits::max(); - - return leftPriority < rightPriority; - }); -} -} // end namespace elf -} // end namespace lld Index: lib/ReaderWriter/ELF/CMakeLists.txt =================================================================== --- lib/ReaderWriter/ELF/CMakeLists.txt +++ lib/ReaderWriter/ELF/CMakeLists.txt @@ -1,5 +1,4 @@ add_llvm_library(lldELF - ArrayOrderPass.cpp ELFLinkingContext.cpp Reader.cpp Writer.cpp Index: lib/ReaderWriter/ELF/ELFLinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -8,12 +8,11 @@ //===----------------------------------------------------------------------===// #include "lld/ReaderWriter/ELFLinkingContext.h" -#include "ArrayOrderPass.h" #include "ELFFile.h" +#include "OrderPass.h" #include "TargetHandler.h" #include "lld/Core/Instrumentation.h" #include "lld/Core/SharedLibraryFile.h" -#include "lld/Passes/LayoutPass.h" #include "lld/Passes/RoundTripYAMLPass.h" #include "llvm/ADT/Triple.h" #include "llvm/Config/config.h" @@ -66,8 +65,7 @@ _finiFunction("_fini"), _sysrootPath("") {} void ELFLinkingContext::addPasses(PassManager &pm) { - pm.add(std::unique_ptr(new LayoutPass(registry()))); - pm.add(std::unique_ptr(new elf::ArrayOrderPass())); + pm.add(std::unique_ptr(new elf::OrderPass())); } uint16_t ELFLinkingContext::getOutputMachine() const { Index: lib/ReaderWriter/ELF/OrderPass.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/OrderPass.h @@ -0,0 +1,70 @@ +//===- lib/ReaderWriter/ELF/OrderPass.h -----------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_ELF_ORDER_PASS_H +#define LLD_READER_WRITER_ELF_ORDER_PASS_H + +#include "lld/Core/Parallel.h" +#include +#include + +namespace lld { +namespace elf { + +/// \brief This pass sorts atoms by file and atom ordinals. +/// .{init,fini}_array. sections are handled specially. +class OrderPass : public Pass { +public: + void perform(std::unique_ptr &file) override { + MutableFile::DefinedAtomRange defined = file->definedAtoms(); + auto last = std::partition(defined.begin(), defined.end(), isInitFini); + parallel_sort(defined.begin(), last, compareInitFini); + parallel_sort(last, defined.end(), DefinedAtom::compareByPosition); + } + +private: + static bool isInitFini(const DefinedAtom *atom) { + if (atom->sectionChoice() != DefinedAtom::sectionCustomRequired) + return false; + StringRef name = atom->customSectionName(); + return name.startswith(".init_array") || name.startswith(".fini_array"); + } + + static bool compareInitFini(const DefinedAtom *lhs, const DefinedAtom *rhs) { + StringRef lhsSec = lhs->customSectionName(); + StringRef rhsSec = rhs->customSectionName(); + + // Drop the front dot from the section name and get + // an optional section's number starting after the second dot. + StringRef lhsNum = lhsSec.drop_front().rsplit('.').second; + StringRef rhsNum = rhsSec.drop_front().rsplit('.').second; + + // Sort {.init_array, .fini_array}[.] sections + // according to their number. Sections without optional + // numer suffix should go last. + + uint32_t lhsPriority; + uint32_t rhsPriority; + if (lhsNum.getAsInteger(10, lhsPriority)) + lhsPriority = std::numeric_limits::max(); + if (rhsNum.getAsInteger(10, rhsPriority)) + rhsPriority = std::numeric_limits::max(); + + if (lhsPriority != rhsPriority) + return lhsPriority < rhsPriority; + + // If both atoms have the same priority, fall back to default. + return DefinedAtom::compareByPosition(lhs, rhs); + } +}; + +} +} + +#endif Index: lib/ReaderWriter/PECOFF/OrderPass.h =================================================================== --- lib/ReaderWriter/PECOFF/OrderPass.h +++ lib/ReaderWriter/PECOFF/OrderPass.h @@ -37,15 +37,6 @@ namespace lld { namespace pecoff { -static bool compareByPosition(const DefinedAtom *lhs, const DefinedAtom *rhs) { - const File *lhsFile = &lhs->file(); - const File *rhsFile = &rhs->file(); - if (lhsFile->ordinal() != rhsFile->ordinal()) - return lhsFile->ordinal() < rhsFile->ordinal(); - assert(lhs->ordinal() != rhs->ordinal()); - return lhs->ordinal() < rhs->ordinal(); -} - static bool compare(const DefinedAtom *lhs, const DefinedAtom *rhs) { bool lhsCustom = (lhs->sectionChoice() == DefinedAtom::sectionCustomRequired); bool rhsCustom = (rhs->sectionChoice() == DefinedAtom::sectionCustomRequired); @@ -53,13 +44,13 @@ int cmp = lhs->customSectionName().compare(rhs->customSectionName()); if (cmp != 0) return cmp < 0; - return compareByPosition(lhs, rhs); + return DefinedAtom::compareByPosition(lhs, rhs); } if (lhsCustom && !rhsCustom) return true; if (!lhsCustom && rhsCustom) return false; - return compareByPosition(lhs, rhs); + return DefinedAtom::compareByPosition(lhs, rhs); } class OrderPass : public lld::Pass {