#define LLD_CORE_PASS_H_
#include "lld/Core/Atom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/range.h"
#include "lld/Core/Reference.h"
#include <vector>
virtual const DefinedAtom *makeGOTEntry(const Atom &target) = 0;
};
-/// Pass for sorting atoms.
-class OrderPass : public Pass {
-public:
- OrderPass() : Pass() {}
-
- /// Sorts atoms in mergedFile by content type then by command line order.
- virtual void perform(MutableFile &mergedFile);
-};
-
-
} // namespace lld
#endif // LLD_CORE_PASS_H_
#define LLD_CORE_REFERENCES_H_
#include "llvm/Support/DataTypes.h"
+#include "llvm/ADT/StringSwitch.h"
namespace lld {
/// Negative kind values are architecture independent.
typedef int32_t Kind;
+ enum {
+ kindInGroup = -3,
+ kindLayoutAfter = -2,
+ kindLayoutBefore = -1,
+ kindTargetLow = 0
+ };
+
// A value to be added to the value of a target
typedef int64_t Addend;
/// hence the reference kind.
virtual void setKind(Kind) = 0;
+ virtual StringRef kindToString() const {
+ switch (kind()) {
+ case kindLayoutBefore:
+ return "layout-before";
+ case kindLayoutAfter:
+ return "layout-after";
+ case kindInGroup:
+ return "in-group";
+ default:
+ return "unknown";
+ }
+ }
+
+ virtual int32_t stringToKind(StringRef kindString) const {
+ if (kindString == "in-group")
+ return kindInGroup;
+ else if (kindString == "layout-before")
+ return kindLayoutBefore;
+ else if (kindString == "layout-after")
+ return kindLayoutAfter;
+ assert(0 && "unknown relocation kind");
+ return -1;
+ }
+
/// If the reference is a fixup in the Atom, then this returns the
/// byte offset into the Atom's content to do the fix up.
virtual uint64_t offsetInAtom() const = 0;
virtual ~Reference() {}
};
-
} // namespace lld
#endif // LLD_CORE_REFERENCES_H_
--- /dev/null
+//===------ Passes/LayoutPass.h - Handles Layout of atoms ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_PASSES_LAYOUT_PASS_H
+#define LLD_PASSES_LAYOUT_PASS_H
+
+#include "lld/Core/Atom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/range.h"
+#include "lld/Core/Reference.h"
+
+#include "llvm/ADT/DenseMap.h"
+
+#include <map>
+#include <vector>
+
+namespace lld {
+class DefinedAtom;
+class MutableFile;
+
+/// This linker pass does the layout of the atoms. The pass is done after the
+/// order their .o files were found on the command line, then by order of the
+/// atoms (address) in the .o file. But some atoms have a prefered location
+/// in their section (such as pinned to the start or end of the section), so
+/// the sort must take that into account too.
+class LayoutPass : public Pass {
+public:
+
+ // Compare and Sort Atoms by their ordinals
+ class CompareAtoms {
+ public:
+ CompareAtoms(const LayoutPass &pass) : _layout(pass) {}
+ bool operator()(const DefinedAtom *left, const DefinedAtom *right);
+ private:
+ const LayoutPass &_layout;
+ };
+
+ LayoutPass() : Pass(), _compareAtoms(*this) {}
+
+ /// Sorts atoms in mergedFile by content type then by command line order.
+ virtual void perform(MutableFile &mergedFile);
+
+ virtual ~LayoutPass() {}
+
+private:
+ // Build the followOn atoms chain as specified by the kindLayoutAfter
+ // reference type
+ void buildFollowOnTable(MutableFile::DefinedAtomRange &range);
+
+ // Build the followOn atoms chain as specified by the kindInGroup
+ // reference type
+ void buildInGroupTable(MutableFile::DefinedAtomRange &range);
+
+ // Build the PrecededBy Table as specified by the kindLayoutBefore
+ // reference type
+ void buildPrecededByTable(MutableFile::DefinedAtomRange &range);
+
+ // Build a map of Atoms to ordinals for sorting the atoms
+ void buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range);
+
+ typedef llvm::DenseMap<const DefinedAtom *, const DefinedAtom *> AtomToAtomT;
+ typedef llvm::DenseMap<const DefinedAtom *, uint64_t> AtomToOrdinalT;
+ AtomToAtomT _followOnNexts;
+ AtomToAtomT _followOnRoots;
+ AtomToOrdinalT _ordinalOverrideMap;
+ CompareAtoms _compareAtoms;
+};
+
+} // namespace lld
+
+#endif // LLD_PASSES_LAYOUT_PASS_H
#define LLD_READER_WRITER_ELF_TARGET_INFO_H
#include "lld/Core/LinkerOptions.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/Pass.h"
#include "lld/Core/TargetInfo.h"
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/Writer.h"
return static_cast<lld::elf::TargetHandler<ELFT> &>(*_targetHandler.get());
}
+ virtual void addPasses(PassManager &pm) const;
+
protected:
std::unique_ptr<TargetHandlerBase> _targetHandler;
mutable std::unique_ptr<Reader> _reader;
add_lld_library(lldPasses
GOTPass.cpp
- OrderPass.cpp
StubsPass.cpp
+ LayoutPass.cpp
)
--- /dev/null
+//===- Passes/LayoutPass.cpp - Layout atoms -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Passes/LayoutPass.h"
+
+using namespace lld;
+
+/// The function compares atoms by sorting atoms in the following order
+/// a) Sorts atoms with the same permissions
+/// b) Sorts atoms with the same content Type
+/// c) Sorts atoms by Section position preference
+/// d) Sorts atoms by how they follow / precede each atom
+/// e) Sorts atoms on how they appear using File Ordinality
+/// f) Sorts atoms on how they appear within the File
+bool LayoutPass::CompareAtoms::operator()(const DefinedAtom *left,
+ const DefinedAtom *right) {
+ if (left == right)
+ return false;
+
+ // Sort same permissions together.
+ DefinedAtom::ContentPermissions leftPerms = left->permissions();
+ DefinedAtom::ContentPermissions rightPerms = right->permissions();
+ if (leftPerms != rightPerms)
+ return leftPerms < rightPerms;
+
+ // Sort same content types together.
+ DefinedAtom::ContentType leftType = left->contentType();
+ DefinedAtom::ContentType rightType = right->contentType();
+ if (leftType != rightType)
+ return leftType < rightType;
+
+ // TO DO: Sort atoms in customs sections together.
+
+ // Sort by section position preference.
+ DefinedAtom::SectionPosition leftPos = left->sectionPosition();
+ DefinedAtom::SectionPosition rightPos = right->sectionPosition();
+ bool leftSpecialPos = (leftPos != DefinedAtom::sectionPositionAny);
+ bool rightSpecialPos = (rightPos != DefinedAtom::sectionPositionAny);
+ if (leftSpecialPos || rightSpecialPos) {
+ if (leftPos != rightPos)
+ return leftPos < rightPos;
+ }
+
+ AtomToOrdinalT::const_iterator lPos = _layout._ordinalOverrideMap.find(left);
+ AtomToOrdinalT::const_iterator rPos = _layout._ordinalOverrideMap.find(right);
+ AtomToOrdinalT::const_iterator end = _layout._ordinalOverrideMap.end();
+ if (lPos != end) {
+ if (rPos != end) {
+ // both left and right are overridden, so compare overridden ordinals
+ return lPos->second < rPos->second;
+ } else {
+ // left is overridden and right is not, so left < right
+ return true;
+ }
+ } else {
+ if (rPos != end) {
+ // right is overridden and left is not, so right < left
+ return false;
+ } else {
+ // neither are overridden,
+ // fall into default sorting below
+ }
+ }
+
+ // Sort by .o order.
+ const File *leftFile = &left->file();
+ const File *rightFile = &right->file();
+ if (leftFile != rightFile)
+ return leftFile->ordinal() < rightFile->ordinal();
+
+ // Sort by atom order with .o file.
+ uint64_t leftOrdinal = left->ordinal();
+ uint64_t rightOrdinal = right->ordinal();
+ if (leftOrdinal != rightOrdinal)
+ return leftOrdinal < rightOrdinal;
+
+ return false;
+}
+
+/// This pass builds the followon tables described by two DenseMaps
+/// followOnRoots and followonNexts.
+/// The followOnRoots map contains a mapping of a DefinedAtom to its root
+/// The followOnNexts map contains a mapping of what DefinedAtom follows the
+/// current Atom
+/// The algorithm follows a very simple approach
+/// a) If the atom is first seen, then make that as the root atom
+/// b) The targetAtom which this Atom contains, has the root thats set to the
+/// root of the current atom
+/// c) If the targetAtom is part of a different tree and the root of the
+/// targetAtom is itself, Chain all the atoms that are contained in the tree
+/// to the current Tree
+/// d) If the targetAtom is part of a different chain and the root of the
+/// targetAtom until the targetAtom has all atoms of size 0, then chain the
+/// targetAtoms and its tree to the current chain
+void LayoutPass::buildFollowOnTable(MutableFile::DefinedAtomRange &range) {
+ for (auto ai : range) {
+ for (const Reference *r : *ai) {
+ if (r->kind() == lld::Reference::kindLayoutAfter) {
+ const DefinedAtom *targetAtom = llvm::dyn_cast<DefinedAtom>(r->target());
+ _followOnNexts[ai] = targetAtom;
+ // If we find a followon for the first time, lets make that
+ // atom as the root atom
+ if (_followOnRoots.count(ai) == 0) {
+ _followOnRoots[ai] = ai;
+ }
+ // If the targetAtom is not a root of any chain, lets make
+ // the root of the targetAtom to the root of the current chain
+ auto iter = _followOnRoots.find(targetAtom);
+ if (iter == _followOnRoots.end()) {
+ _followOnRoots[targetAtom] = _followOnRoots[ai];
+ } else {
+ // The followon is part of another chain
+ if (iter->second == targetAtom) {
+ const DefinedAtom *a = targetAtom;
+ while (true) {
+ _followOnRoots[a] = _followOnRoots[ai];
+ // Set all the follow on's for the targetAtom to be
+ // the current root
+ AtomToAtomT::iterator targetFollowOnAtomsIter =
+ _followOnNexts.find(a);
+
+ if (targetFollowOnAtomsIter != _followOnNexts.end())
+ a = targetFollowOnAtomsIter->second;
+ else
+ break;
+ } // while true
+ } else { // the atom could be part of chain already
+ // Get to the root of the chain
+ const DefinedAtom *a = _followOnRoots[targetAtom];
+ // Lets add to the chain only if the atoms that
+ // appear before the targetAtom in the chain
+ // are of size 0
+ bool foundNonZeroSizeAtom = false;
+ while (true) {
+ // Set all the follow on's for the targetAtom to be
+ // the current root
+ AtomToAtomT::iterator targetFollowOnAtomsIter =
+ _followOnNexts.find(a);
+
+ if (targetFollowOnAtomsIter != _followOnNexts.end())
+ a = targetFollowOnAtomsIter->second;
+ else
+ break;
+
+ if (a->size() != 0) {
+ foundNonZeroSizeAtom = true;
+ break;
+ }
+ if (a == targetAtom)
+ break;
+ } // while true
+ if (foundNonZeroSizeAtom) {
+ // TODO: print warning that an impossible layout
+ // is being desired by the user
+ // Continue to the next atom
+ break;
+ }
+
+ _followOnNexts[ai] = _followOnRoots[targetAtom];
+ // Set the root of all atoms in the
+ a = _followOnRoots[targetAtom];
+ while (true) {
+ _followOnRoots[a] = _followOnRoots[ai];
+ // Set all the follow on's for the targetAtom to be
+ // the current root
+ AtomToAtomT::iterator targetFollowOnAtomsIter =
+ _followOnNexts.find(a);
+ if (targetFollowOnAtomsIter != _followOnNexts.end())
+ a = targetFollowOnAtomsIter->second;
+ else
+ break;
+ } // while true
+ } // end else
+ } // else
+ } // kindLayoutAfter
+ } // Reference
+ } // range
+}
+
+/// This pass builds the followon tables using InGroup relationships
+/// The algorithm follows a very simple approach
+/// a) If the rootAtom is not part of any root, create a new root with the
+/// as the head
+/// b) If the current Atom root is not found, then make the current atoms root
+/// point to the rootAtom
+/// c) If the root of the current Atom is itself a root of some other tree
+/// make all the atoms in the chain point to the ingroup reference
+/// d) Check to see if the current atom is part of the chain from the rootAtom
+/// if not add the atom to the chain, so that the current atom is part of the
+/// the chain where the rootAtom is in
+void LayoutPass::buildInGroupTable(MutableFile::DefinedAtomRange &range) {
+ // This table would convert precededby references to follow on
+ // references so that we have only one table
+ for (auto ai : range) {
+ for (const Reference *r : *ai) {
+ if (r->kind() == lld::Reference::kindInGroup) {
+ const DefinedAtom *rootAtom = llvm::dyn_cast<DefinedAtom>(r->target());
+ // If the root atom is not part of any root
+ // create a new root
+ if (_followOnRoots.count(rootAtom) == 0) {
+ _followOnRoots[rootAtom] = rootAtom;
+ }
+ // If the current Atom has not been seen yet and there is no root
+ // that has been set, set the root of the atom to the targetAtom
+ // as the targetAtom points to the ingroup root
+ auto iter = _followOnRoots.find(ai);
+ if (iter == _followOnRoots.end()) {
+ _followOnRoots[ai] = rootAtom;
+ }
+ else if (iter->second == ai) {
+ if (iter->second != rootAtom) {
+ const DefinedAtom *a = iter->second;
+ // Change all the followon next references to the ingroup reference root
+ while (true) {
+ _followOnRoots[a] = rootAtom;
+ // Set all the follow on's for the targetAtom to be
+ // the current root
+ AtomToAtomT::iterator targetFollowOnAtomsIter =
+ _followOnNexts.find(a);
+ if (targetFollowOnAtomsIter != _followOnNexts.end())
+ a = targetFollowOnAtomsIter->second;
+ else
+ break;
+ } // while true
+ }
+ }
+ else {
+ // TODO : Flag an error that the root of the tree
+ // is different, Here is an example
+ // Say there are atoms
+ // chain 1 : a->b->c
+ // chain 2 : d->e->f
+ // and e,f have their ingroup reference as a
+ // this could happen only if the root of e,f that is d
+ // has root as 'a'
+ continue;
+ }
+
+ // Check if the current atom is part of the chain
+ bool isAtomInChain = false;
+ const DefinedAtom *lastAtom = rootAtom;
+ while (true) {
+ AtomToAtomT::iterator followOnAtomsIter =
+ _followOnNexts.find(lastAtom);
+ if (followOnAtomsIter != _followOnNexts.end()) {
+ lastAtom = followOnAtomsIter->second;
+ if (lastAtom == ai) {
+ isAtomInChain = true;
+ break;
+ }
+ }
+ else
+ break;
+ } // findAtomInChain
+
+ if (!isAtomInChain)
+ _followOnNexts[lastAtom] = ai;
+ }
+ }
+ }
+}
+
+/// This pass builds the followon tables using Preceded By relationships
+/// The algorithm follows a very simple approach
+/// a) If the targetAtom is not part of any root and the current atom is not
+/// part of any root, create a chain with the current atom as root and
+/// the targetAtom as following the current atom
+/// b) Chain the targetAtom to the current Atom if the targetAtom is not part
+/// of any chain and the currentAtom has no followOn's
+/// c) If the targetAtom is part of a different tree and the root of the
+/// targetAtom is itself, and if the current atom is not part of any root
+/// chain all the atoms together
+/// d) If the current atom has no followon and the root of the targetAtom is
+/// not equal to the root of the current atom(the targetAtom is not in the
+/// same chain), chain all the atoms that are lead by the targetAtom into
+/// the current chain
+void LayoutPass::buildPrecededByTable(MutableFile::DefinedAtomRange &range) {
+ // This table would convert precededby references to follow on
+ // references so that we have only one table
+ for (auto ai : range) {
+ for (const Reference *r : *ai) {
+ if (r->kind() == lld::Reference::kindLayoutBefore) {
+ const DefinedAtom *targetAtom = llvm::dyn_cast<DefinedAtom>(r->target());
+ // Is the targetAtom not chained
+ if (_followOnRoots.count(targetAtom) == 0) {
+ // Is the current atom not part of any root ?
+ if (_followOnRoots.count(ai) == 0) {
+ _followOnRoots[ai] = ai;
+ _followOnNexts[ai] = targetAtom;
+ _followOnRoots[targetAtom] = _followOnRoots[ai];
+ } else if (_followOnNexts.count(ai) == 0) {
+ // Chain the targetAtom to the current Atom
+ // if the currentAtom has no followon references
+ _followOnNexts[ai] = targetAtom;
+ _followOnRoots[targetAtom] = _followOnRoots[ai];
+ }
+ } else if (_followOnRoots.find(targetAtom)->second == targetAtom) {
+ // Is the targetAtom in chain with the targetAtom as the root ?
+ bool changeRoots = false;
+ if (_followOnRoots.count(ai) == 0) {
+ _followOnRoots[ai] = ai;
+ _followOnNexts[ai] = targetAtom;
+ _followOnRoots[targetAtom] = _followOnRoots[ai];
+ changeRoots = true;
+ } else if (_followOnNexts.count(ai) == 0) {
+ // Chain the targetAtom to the current Atom
+ // if the currentAtom has no followon references
+ if (_followOnRoots[ai] != _followOnRoots[targetAtom]) {
+ _followOnNexts[ai] = targetAtom;
+ _followOnRoots[targetAtom] = _followOnRoots[ai];
+ changeRoots = true;
+ }
+ }
+ // Change the roots of the targetAtom and its chain to
+ // the current atoms root
+ if (changeRoots) {
+ const DefinedAtom *a = _followOnRoots[targetAtom];
+ while (true) {
+ _followOnRoots[a] = _followOnRoots[ai];
+ // Set all the follow on's for the targetAtom to be
+ // the current root
+ AtomToAtomT::iterator targetFollowOnAtomsIter =
+ _followOnNexts.find(a);
+ if (targetFollowOnAtomsIter != _followOnNexts.end())
+ a = targetFollowOnAtomsIter->second;
+ else
+ break;
+ }
+ } // changeRoots
+ } // Is targetAtom root
+ } // kindLayoutBefore
+ } // Reference
+ } // atom iteration
+} // end function
+
+
+/// Build an ordinal override map by traversing the followon chain, and
+/// assigning ordinals to each atom, if the atoms have their ordinals
+/// already assigned skip the atom and move to the next. This is the
+/// main map thats used to sort the atoms while comparing two atoms together
+void LayoutPass::buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range) {
+ uint64_t index = 0;
+ for (auto ai : range) {
+ const DefinedAtom *atom = ai;
+ AtomToAtomT::iterator start = _followOnRoots.find(atom);
+ if (start != _followOnRoots.end()) {
+ for (const DefinedAtom *nextAtom = start->second; nextAtom != NULL;
+ nextAtom = _followOnNexts[nextAtom]) {
+ AtomToOrdinalT::iterator pos = _ordinalOverrideMap.find(nextAtom);
+ if (pos == _ordinalOverrideMap.end()) {
+ _ordinalOverrideMap[nextAtom] = index++;
+ }
+ }
+ } else {
+ _ordinalOverrideMap[atom] = index;
+ }
+ }
+}
+
+/// Perform the actual pass
+void LayoutPass::perform(MutableFile &mergedFile) {
+
+ MutableFile::DefinedAtomRange atomRange = mergedFile.definedAtoms();
+
+ // Build follow on tables
+ buildFollowOnTable(atomRange);
+
+ // Build Ingroup reference table
+ buildInGroupTable(atomRange);
+
+ // Build preceded by tables
+ buildPrecededByTable(atomRange);
+
+ // Build override maps
+ buildOrdinalOverrideMap(atomRange);
+
+ // sort the atoms
+ std::sort(atomRange.begin(), atomRange.end(), _compareAtoms);
+}
+++ /dev/null
-//===- Passes/OrderPass.cpp - sort atoms ----------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This linker pass sorts atoms. By default atoms are sort first by the
-// order their .o files were found on the command line, then by order of the
-// atoms (address) in the .o file. But some atoms have a prefered location
-// in their section (such as pinned to the start or end of the section), so
-// the sort must take that into account too.
-//
-//===----------------------------------------------------------------------===//
-
-
-#include "lld/Core/DefinedAtom.h"
-#include "lld/Core/File.h"
-#include "lld/Core/LLVM.h"
-#include "lld/Core/Pass.h"
-#include "lld/Core/Reference.h"
-#include "llvm/ADT/DenseMap.h"
-
-
-namespace lld {
-
-static bool compare(const DefinedAtom *left, const DefinedAtom *right) {
- if ( left == right )
- return false;
-
- // Sort same permissions together.
- DefinedAtom::ContentPermissions leftPerms = left->permissions();
- DefinedAtom::ContentPermissions rightPerms = right->permissions();
- if (leftPerms != rightPerms)
- return leftPerms < rightPerms;
-
-
- // Sort same content types together.
- DefinedAtom::ContentType leftType = left->contentType();
- DefinedAtom::ContentType rightType = right->contentType();
- if (leftType != rightType)
- return leftType < rightType;
-
-
- // TO DO: Sort atoms in customs sections together.
-
-
- // Sort by section position preference.
- DefinedAtom::SectionPosition leftPos = left->sectionPosition();
- DefinedAtom::SectionPosition rightPos = right->sectionPosition();
- bool leftSpecialPos = (leftPos != DefinedAtom::sectionPositionAny);
- bool rightSpecialPos = (rightPos != DefinedAtom::sectionPositionAny);
- if (leftSpecialPos || rightSpecialPos) {
- if (leftPos != rightPos)
- return leftPos < rightPos;
- }
-
- // Sort by .o order.
- const File *leftFile = &left->file();
- const File *rightFile = &right->file();
- if ( leftFile != rightFile )
- return leftFile->ordinal() < rightFile->ordinal();
-
- // Sort by atom order with .o file.
- uint64_t leftOrdinal = left->ordinal();
- uint64_t rightOrdinal = right->ordinal();
- if ( leftOrdinal != rightOrdinal )
- return leftOrdinal < rightOrdinal;
-
- return false;
-}
-
-
-
-void OrderPass::perform(MutableFile &mergedFile) {
-
- MutableFile::DefinedAtomRange atomRange = mergedFile.definedAtoms();
-
- std::sort(atomRange.begin(), atomRange.end(), compare);
-}
-
-} // namespace
public:
ELFReference(const Elf_Rela *rela, uint64_t offset, const Atom *target)
- : _target(target)
- , _targetSymbolIndex(rela->getSymbol())
- , _offsetInAtom(offset)
- , _addend(rela->r_addend)
- , _kind(rela->getType()) {}
+ : _target(target), _targetSymbolIndex(rela->getSymbol()),
+ _offsetInAtom(offset), _addend(rela->r_addend),
+ _kind((Kind) rela->getType()) {
+ }
ELFReference(const Elf_Rel *rel, uint64_t offset, const Atom *target)
- : _target(target)
- , _targetSymbolIndex(rel->getSymbol())
- , _offsetInAtom(offset)
- , _addend(0)
- , _kind(rel->getType()) {}
-
- virtual uint64_t offsetInAtom() const {
- return _offsetInAtom;
+ : _target(target), _targetSymbolIndex(rel->getSymbol()),
+ _offsetInAtom(offset), _addend(0), _kind((Kind) rel->getType()) {
}
- virtual Kind kind() const {
- return _kind;
+ ELFReference(Kind kind)
+ : _target(nullptr), _targetSymbolIndex(0), _offsetInAtom(0), _addend(0),
+ _kind(kind) {
}
+ virtual uint64_t offsetInAtom() const { return _offsetInAtom; }
+
+ virtual Kind kind() const { return _kind; }
+
virtual void setKind(Kind kind) {
_kind = kind;
}
_addend = A;
}
- virtual void setTarget(const Atom *newAtom) {
- _target = newAtom;
- }
+ virtual void setTarget(const Atom *newAtom) { _target = newAtom; }
+
private:
- const Atom *_target;
- uint64_t _targetSymbolIndex;
- uint64_t _offsetInAtom;
- Addend _addend;
- Kind _kind;
+ const Atom *_target;
+ uint64_t _targetSymbolIndex;
+ uint64_t _offsetInAtom;
+ Addend _addend;
+ Kind _kind;
};
/// \brief These atoms store symbols that are fixed to a particular address.
return ((_referenceList)[index]);
}
- void incrementIterator(const void*& It) const {
+ void incrementIterator(const void *&It) const {
uintptr_t index = reinterpret_cast<uintptr_t>(It);
++index;
- It = reinterpret_cast<const void*>(index);
+ It = reinterpret_cast<const void *>(index);
+ }
+
+ void addReference(ELFReference<ELFT> *reference) {
+ _referenceList.push_back(reference);
+ _referenceEndIndex = _referenceList.size();
}
private:
lldReaderWriter
lldX86_64ELFTarget
lldX86ELFTarget
+ lldPasses
)
include_directories(.)
#include "Targets.h"
#include "lld/Core/LinkerOptions.h"
+#include "lld/Passes/LayoutPass.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/ELF.h"
llvm_unreachable("Unhandled OutputKind");
}
+void ELFTargetInfo::addPasses(PassManager &pm) const {
+ pm.add(std::unique_ptr<Pass>(new LayoutPass()));
+}
+
uint16_t ELFTargetInfo::getOutputMachine() const {
switch (getTriple().getArch()) {
case llvm::Triple::x86:
content, 0, 0, _references));
}
+ ELFDefinedAtom<ELFT> *previous_atom = nullptr;
+
// i.first is the section the symbol lives in
for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) {
StringRef symbolName;
ArrayRef<uint8_t> symbolData = ArrayRef<uint8_t>(
(uint8_t *)sectionContents.data() + (*si)->st_value, contentSize);
+ // Check to see if we need to add the FollowOn Reference
+ // We dont want to do for symbols that are
+ // a) common symbols
+ // b) the atoms have the merge attribute set
+ // so, lets add a follow-on reference from the previous atom to the
+ // current atom as well as lets add a preceded-by reference from the
+ // current atom to the previous atom, so that the previous atom
+ // is not removed in any case
+ ELFReference<ELFT> *followOn = nullptr;
+ if (!isCommon && previous_atom &&
+ previous_atom->merge() == DefinedAtom::mergeNo) {
+ followOn = new (_readerStorage)
+ ELFReference<ELFT>(lld::Reference::kindLayoutAfter);
+ previous_atom->addReference(followOn);
+ }
+
auto newAtom = createDefinedAtomAndAssignRelocations(
symbolName, sectionName, *si, i.first, symbolData);
+ // If we are inserting a followOn reference, lets add a precededBy
+ // reference too
+ if (followOn) {
+ ELFReference<ELFT> *precededBy = nullptr;
+ followOn->setTarget(newAtom);
+ precededBy = new (_readerStorage)
+ ELFReference<ELFT>(lld::Reference::kindLayoutBefore);
+ precededBy->setTarget(previous_atom);
+ newAtom->addReference(precededBy);
+ }
+
+ previous_atom = newAtom;
+
_definedAtoms._atoms.push_back(newAtom);
_symbolToAtomMapping.insert(std::make_pair((*si), newAtom));
if (anonAtom)
// All the Atoms and References are created. Now update each Reference's
// target with the Atom pointer it refers to.
for (auto &ri : _references) {
- const Elf_Sym *Symbol = _objFile->getElfSymbol(ri->targetSymbolIndex());
- ri->setTarget(findAtom(Symbol));
+ if (ri->kind() >= lld::Reference::kindTargetLow) {
+ const Elf_Sym *Symbol = _objFile->getElfSymbol(ri->targetSymbolIndex());
+ ri->setTarget(findAtom(Symbol));
+ }
}
}
case R_HEX_32:
reloc32(location, relocVAddress, targetVAddress, ref.addend());
break;
- default: {
+ case lld::Reference::kindLayoutAfter:
+ case lld::Reference::kindLayoutBefore:
+ case lld::Reference::kindInGroup:
+ break;
+ default : {
std::string str;
llvm::raw_string_ostream s(str);
auto name = _targetInfo.stringFromRelocKind(ref.kind());
case R_PPC_REL24:
relocB24PCREL(location, relocVAddress, targetVAddress, ref.addend());
break;
- default: {
+
+ case lld::Reference::kindLayoutAfter:
+ case lld::Reference::kindLayoutBefore:
+ case lld::Reference::kindInGroup:
+ break;
+
+ default : {
std::string str;
llvm::raw_string_ostream s(str);
auto name = _targetInfo.stringFromRelocKind(ref.kind());
case R_386_PC32:
relocPC32(location, relocVAddress, targetVAddress, ref.addend());
break;
- default: {
+ case lld::Reference::kindLayoutAfter:
+ case lld::Reference::kindLayoutBefore:
+ case lld::Reference::kindInGroup:
+ break;
+ default : {
std::string str;
llvm::raw_string_ostream s(str);
auto name = _targetInfo.stringFromRelocKind(ref.kind());
// Runtime only relocations. Ignore here.
case R_X86_64_IRELATIVE:
break;
- default: {
+
+ case lld::Reference::kindLayoutAfter:
+ case lld::Reference::kindLayoutBefore:
+ case lld::Reference::kindInGroup:
+ break;
+
+ default : {
std::string str;
llvm::raw_string_ostream s(str);
auto name = _targetInfo.stringFromRelocKind(ref.kind());
#include "lld/Core/LinkerOptions.h"
#include "lld/Core/PassManager.h"
+#include "lld/Passes/LayoutPass.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/MachO.h"
virtual void addPasses(PassManager &pm) const {
pm.add(std::unique_ptr<Pass>(new mach_o::GOTPass));
pm.add(std::unique_ptr<Pass>(new mach_o::StubsPass(*this)));
- pm.add(std::unique_ptr<Pass>(new OrderPass()));
+ pm.add(std::unique_ptr<Pass>(new LayoutPass()));
}
};
ED: ('p_vaddr', 0x00004000)
ED: ('p_paddr', 0x00004000)
ED: ('p_filesz', 0x00000004)
-ED: ('p_memsz', 0x00004005)
+ED: ('p_memsz', 0x00004008)
ED: ('p_align', 0x00001000)
ED: ),
ED: # Program Header 3
RUN: %p/Inputs/rodata-test.hexagon
RUN: llvm-objdump -section-headers %t2 | FileCheck -check-prefix=hexagon %s
-i386: 2 .rodata 00000004
+i386: 1 .rodata 00000004 0000000000001000 DATA
-hexagon: 3 .rodata 00000004
+hexagon: 1 .rodata 00000004 0000000000001000 DATA
OBJDUMP: 2 .data 00000004 0000000000001000 DATA
OBJDUMP: 3 .special 00000004 0000000000001004 DATA
OBJDUMP: 4 .anotherspecial 00000004 0000000000001008 DATA
-OBJDUMP: 5 .bss 00000001 000000000000100c BSS
+OBJDUMP: 5 .bss 00000004 000000000000100c BSS
OBJDUMP: 6 .shstrtab {{[0-9a-f]+}} 0000000000000000
OBJDUMP: 7 .symtab {{[0-9a-f]+}} 0000000000000000
OBJDUMP: 8 .strtab {{[0-9a-f]+}} 0000000000000000
--- /dev/null
+# RUN: lld-core -layout-pass=true %s | FileCheck %s -check-prefix=CHKORDER
+
+---
+defined-atoms:
+ - name: A
+ scope: global
+ references:
+ - kind: layout-after
+ offset: 0
+ target: B
+ - name: B
+ scope: global
+ references:
+ - kind: in-group
+ offset: 0
+ target: A
+ - kind: layout-after
+ offset: 0
+ target: C
+ - name: C
+ scope: global
+ references:
+ - kind: in-group
+ offset: 0
+ target: A
+ - name: E
+ scope: global
+ references:
+ - kind: in-group
+ offset: 0
+ target: E
+ - kind: layout-after
+ offset: 0
+ target: F
+ - name: F
+ scope: global
+ references:
+ - kind: in-group
+ offset: 0
+ target: E
+ - name: D
+ scope: global
+ references:
+ - kind: in-group
+ offset: 0
+ target: A
+ - kind: layout-after
+ offset: 0
+ target: E
+...
+
+# CHKORDER: - name: A
+# CHKORDER: - name: B
+# CHKORDER: - name: C
+# CHKORDER: - name: D
+# CHKORDER: - name: E
+# CHKORDER: - name: F
--- /dev/null
+# RUN: lld-core -layout-pass=true %s | FileCheck %s -check-prefix=CHKORDER
+
+---
+defined-atoms:
+ - name: A
+ scope: global
+ references:
+ - kind: layout-after
+ offset: 0
+ target: E
+ - name: E
+ scope: global
+ references:
+ - kind: in-group
+ offset: 0
+ target: A
+...
+
+# CHKORDER: - name: A
+# CHKORDER: - name: E
--- /dev/null
+# RUN: lld-core -layout-pass=true %s | FileCheck %s -check-prefix=CHKORDER
+
+---
+defined-atoms:
+ - name: A
+ scope: global
+ references:
+ - kind: layout-after
+ offset: 0
+ target: B
+ - name: B
+ scope: global
+ references:
+ - kind: in-group
+ offset: 0
+ target: A
+ - kind: layout-after
+ offset: 0
+ target: E
+ - name: F
+ scope: global
+ references:
+ - kind: in-group
+ offset: 0
+ target: E
+ - kind: layout-after
+ offset: 0
+ target: G
+ - name: G
+ scope: global
+ references:
+ - kind: in-group
+ offset: 0
+ target: E
+ - name: E
+ scope: global
+ references:
+ - kind: in-group
+ offset: 0
+ target: A
+ - kind: layout-after
+ offset: 0
+ target: F
+...
+
+# CHKORDER: - name: A
+# CHKORDER: - name: B
+# CHKORDER: - name: E
+# CHKORDER: - name: F
+# CHKORDER: - name: G
--- /dev/null
+# RUN: lld-core -layout-pass=true %s | FileCheck %s -check-prefix=CHKORDER
+
+---
+defined-atoms:
+ - name: A
+ scope: global
+
+ - name: B
+ scope: global
+ references:
+ - kind: in-group
+ offset: 0
+ target: A
+ - name: F
+ scope: global
+ references:
+ - kind: in-group
+ offset: 0
+ target: E
+ - name: G
+ scope: global
+ references:
+ - kind: in-group
+ offset: 0
+ target: E
+ - name: E
+ scope: global
+ references:
+ - kind: in-group
+ offset: 0
+ target: A
+...
+
+# CHKORDER: - name: A
+# CHKORDER: - name: B
+# CHKORDER: - name: E
+# CHKORDER: - name: F
+# CHKORDER: - name: G
--- /dev/null
+# RUN: lld-core -layout-pass=true %s | FileCheck %s -check-prefix=CHKORDER
+
+---
+defined-atoms:
+ - name: fn
+ scope: global
+ references:
+ - kind: layout-after
+ offset: 0
+ target: fn1
+ - name: fn1
+ scope: global
+ references:
+ - kind: layout-after
+ offset: 0
+ target: fn2
+ - name: fn2
+ scope: global
+ references:
+ - kind: layout-after
+ offset: 0
+ target: fn3
+ - name: fn3
+ scope: global
+...
+
+# CHKORDER: - name: fn
+# CHKORDER: - name: fn1
+# CHKORDER: - name: fn2
+# CHKORDER: - name: fn3
--- /dev/null
+# RUN: lld-core -layout-pass=true %s | FileCheck %s -check-prefix=CHKORDER
+
+---
+defined-atoms:
+ - name: fn
+ scope: global
+
+ - name: fn1
+ scope: global
+ references:
+ - kind: layout-before
+ offset: 0
+ target: fn
+ - name: fn2
+ scope: global
+ references:
+ - kind: layout-before
+ offset: 0
+ target: fn1
+...
+
+
+# CHKORDER: - name: fn2
+# CHKORDER: - name: fn1
+# CHKORDER: - name: fn
-# RUN: lld-core -order-pass=true %s | FileCheck %s -check-prefix=CHKORDER
-# RUN: lld-core -order-pass=false %s | FileCheck %s -check-prefix=CHKUNORD
+# RUN: lld-core -layout-pass=true %s | FileCheck %s -check-prefix=CHKORDER
+# RUN: lld-core -layout-pass=false %s | FileCheck %s -check-prefix=CHKUNORD
#
# Test that atoms with section position requirements are sorted properly.
// Table of fixup kinds in YAML documents used for testing
//
const TestingKindMapping sKinds[] = {
- {"call32", 2, true, false, false},
- {"pcrel32", 3, false, false, false},
- {"gotLoad32", 7, false, true, true},
- {"gotUse32", 9, false, false, true},
- {"lea32wasGot", 8, false, false, false},
- {nullptr, 0, false, false, false}
+ {"in-group", -3, false, false, false},
+ {"layout-after", -2, false, false, false},
+ {"layout-before", -1, false, false, false},
+ {"call32", 2, true, false, false},
+ {"pcrel32", 3, false, false, false},
+ {"gotLoad32", 7, false, true, true},
+ {"gotUse32", 9, false, false, true},
+ {"lea32wasGot", 8, false, false, false},
+ {nullptr, 0, false, false, false}
};
class TestingStubsPass : public StubsPass {
#include "lld/Core/Pass.h"
#include "lld/Core/PassManager.h"
#include "lld/Core/Resolver.h"
+#include "lld/Passes/LayoutPass.h"
#include "lld/ReaderWriter/ELFTargetInfo.h"
#include "lld/ReaderWriter/MachOTargetInfo.h"
#include "lld/ReaderWriter/Reader.h"
llvm::cl::desc("Specify output filename"),
llvm::cl::value_desc("filename"));
-llvm::cl::opt<bool>
-cmdLineDoStubsPass("stubs-pass",
- llvm::cl::desc("Run pass to create stub atoms"));
+llvm::cl::opt<bool> cmdLineDoStubsPass(
+ "stubs-pass", llvm::cl::desc("Run pass to create stub atoms"));
-llvm::cl::opt<bool>
-cmdLineDoGotPass("got-pass",
- llvm::cl::desc("Run pass to create GOT atoms"));
+llvm::cl::opt<bool>
+cmdLineDoGotPass("got-pass", llvm::cl::desc("Run pass to create GOT atoms"));
-llvm::cl::opt<bool>
-cmdLineDoOrderPass("order-pass",
- llvm::cl::desc("Run pass to sort atoms"));
+llvm::cl::opt<bool>
+cmdLineDoLayoutPass("layout-pass", llvm::cl::desc("Run pass to layout atoms"));
-llvm::cl::opt<bool>
-cmdLineUndefinesIsError("undefines-are-errors",
- llvm::cl::desc("Any undefined symbols at end is an error"));
+llvm::cl::opt<bool> cmdLineUndefinesIsError(
+ "undefines-are-errors",
+ llvm::cl::desc("Any undefined symbols at end is an error"));
-llvm::cl::opt<bool>
-cmdLineForceLoad("force-load",
- llvm::cl::desc("force load all members of the archive"));
+llvm::cl::opt<bool> cmdLineForceLoad(
+ "force-load", llvm::cl::desc("force load all members of the archive"));
llvm::cl::opt<bool>
cmdLineCommonsSearchArchives("commons-search-archives",
enum endianChoice {
little, big
};
-llvm::cl::opt<endianChoice>
-endianSelected("endian",
- llvm::cl::desc("Select endianness of ELF output"),
- llvm::cl::values(
- clEnumValN(big, "big",
- "output big endian format"),
- clEnumValN(little, "little",
- "output little endian format"),
- clEnumValEnd));
-
+llvm::cl::opt<endianChoice> endianSelected(
+ "endian", llvm::cl::desc("Select endianness of ELF output"),
+ llvm::cl::values(clEnumValN(big, "big", "output big endian format"),
+ clEnumValN(little, "little",
+ "output little endian format"), clEnumValEnd));
+
class TestingTargetInfo : public TargetInfo {
public:
- TestingTargetInfo(const LinkerOptions &lo, bool stubs, bool got, bool order)
- : TargetInfo(lo), _doStubs(stubs), _doGOT(got), _doOrder(order) {}
+ TestingTargetInfo(const LinkerOptions &lo, bool stubs, bool got, bool layout)
+ : TargetInfo(lo), _doStubs(stubs), _doGOT(got), _doLayout(layout) {
+ }
virtual uint64_t getPageSize() const { return 0x1000; }
pm.add(std::unique_ptr<Pass>(new TestingStubsPass(*this)));
if (_doGOT)
pm.add(std::unique_ptr<Pass>(new TestingGOTPass(*this)));
- if (_doOrder)
- pm.add(std::unique_ptr<Pass>(new OrderPass));
+ if (_doLayout)
+ pm.add(std::unique_ptr<Pass>(new LayoutPass()));
}
virtual ErrorOr<int32_t> relocKindFromString(StringRef str) const {
}
private:
- bool _doStubs;
- bool _doGOT;
- bool _doOrder;
+ bool _doStubs;
+ bool _doGOT;
+ bool _doLayout;
};
int main(int argc, char *argv[]) {
break;
}
- TestingTargetInfo tti(lo, cmdLineDoStubsPass, cmdLineDoGotPass,
- cmdLineDoOrderPass);
+ TestingTargetInfo tti(lo, cmdLineDoStubsPass, cmdLineDoGotPass,
+ cmdLineDoLayoutPass);
std::unique_ptr<ELFTargetInfo> eti = ELFTargetInfo::create(lo);
std::unique_ptr<MachOTargetInfo> mti = MachOTargetInfo::create(lo);