Linkloader improvement: mclinker.
Change-Id: I8805e39ccbc2ee204234fb3e71c70c906f3990bb
diff --git a/include/mcld/ADT/BinTree.h b/include/mcld/ADT/BinTree.h
new file mode 100644
index 0000000..0a7fe28
--- /dev/null
+++ b/include/mcld/ADT/BinTree.h
@@ -0,0 +1,481 @@
+//===- BinTree.h ----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_BINARY_TREE_H
+#define MCLD_BINARY_TREE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/ADT/TreeAllocator.h"
+
+#include <iterator>
+#include <memory>
+#include <queue>
+#include <stack>
+
+namespace mcld
+{
+
+template<class DataType>
+class BinaryTree;
+
+class DFSIterator : public TreeIteratorBase
+{
+public:
+ DFSIterator()
+ : TreeIteratorBase()
+ { }
+
+ DFSIterator(NodeBase *X)
+ : TreeIteratorBase(X) {
+ if (hasRightChild())
+ m_Stack.push(m_pNode->right);
+ if (hasLeftChild())
+ m_Stack.push(m_pNode->left);
+ }
+
+ virtual ~DFSIterator()
+ { }
+
+ void advance() {
+ if (m_Stack.empty()) { // reach the end
+ m_pNode = m_pNode->right; // should be root
+ return;
+ }
+ m_pNode = m_Stack.top();
+ m_Stack.pop();
+ if (hasRightChild())
+ m_Stack.push(m_pNode->right);
+ if (hasLeftChild())
+ m_Stack.push(m_pNode->left);
+ }
+
+private:
+ std::stack<NodeBase *> m_Stack;
+};
+
+class BFSIterator : public TreeIteratorBase
+{
+public:
+ BFSIterator()
+ : TreeIteratorBase()
+ { }
+
+ BFSIterator(NodeBase *X)
+ : TreeIteratorBase(X) {
+ if (hasRightChild())
+ m_Queue.push(m_pNode->right);
+ if (hasLeftChild())
+ m_Queue.push(m_pNode->left);
+ }
+
+ virtual ~BFSIterator()
+ { }
+
+ void advance() {
+ if (m_Queue.empty()) { // reach the end
+ m_pNode = m_pNode->right; // should be root
+ return;
+ }
+ m_pNode = m_Queue.front();
+ m_Queue.pop();
+ if (hasRightChild())
+ m_Queue.push(m_pNode->right);
+ if (hasLeftChild())
+ m_Queue.push(m_pNode->left);
+ }
+
+private:
+ std::queue<NodeBase *> m_Queue;
+};
+
+template<class DataType, class Traits, class IteratorType>
+class PolicyIteratorBase : public IteratorType
+{
+public:
+ typedef DataType value_type;
+ typedef Traits traits;
+ typedef typename traits::pointer pointer;
+ typedef typename traits::reference reference;
+
+ typedef PolicyIteratorBase<value_type, Traits, IteratorType> Self;
+ typedef Node<value_type> node_type;
+ typedef typename traits::nonconst_traits nonconst_traits;
+ typedef PolicyIteratorBase<value_type, nonconst_traits, IteratorType> iterator;
+ typedef typename traits::const_traits const_traits;
+ typedef PolicyIteratorBase<value_type, const_traits, IteratorType> const_iterator;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+public:
+ PolicyIteratorBase()
+ : IteratorType() {}
+
+ PolicyIteratorBase(const iterator &X)
+ : IteratorType(X.m_pNode) {}
+
+ explicit PolicyIteratorBase(NodeBase* X)
+ : IteratorType(X) {}
+
+ virtual ~PolicyIteratorBase() {}
+
+ // ----- operators ----- //
+ pointer operator*() const
+ { return static_cast<node_type*>(IteratorType::m_pNode)->data; }
+
+ reference operator->() const
+ { return *static_cast<node_type*>(IteratorType::m_pNode)->data; }
+
+ bool isRoot() const
+ { return (IteratorType::m_pNode->right == IteratorType::m_pNode); }
+
+ bool hasData() const
+ { return (!isRoot() && (0 != static_cast<node_type*>(IteratorType::m_pNode)->data)); }
+
+};
+
+template<class DataType, class Traits, class IteratorType>
+class PolicyIterator : public PolicyIteratorBase<DataType, Traits, IteratorType>
+{
+public:
+ typedef PolicyIterator<DataType, Traits, IteratorType> Self;
+ typedef PolicyIteratorBase<DataType, Traits, IteratorType> Base;
+ typedef PolicyIterator<DataType, typename Traits::nonconst_traits, IteratorType> iterator;
+ typedef PolicyIterator<DataType, typename Traits::const_traits, IteratorType> const_iterator;
+
+public:
+ PolicyIterator()
+ : Base() {}
+
+ PolicyIterator(const iterator &X)
+ : Base(X.m_pNode) {}
+
+ explicit PolicyIterator(NodeBase* X)
+ : Base(X) {}
+
+ virtual ~PolicyIterator() {}
+
+ Self& operator++() {
+ IteratorType::advance();
+ return *this;
+ }
+
+ Self operator++(int) {
+ Self tmp = *this;
+ IteratorType::advance();
+ return tmp;
+ }
+};
+
+template<class DataType>
+class BinaryTree;
+
+/** \class TreeIterator
+ * \brief TreeIterator provides full functions of binary tree's iterator.
+ *
+ * TreeIterator is designed to compatible with STL iterators.
+ * TreeIterator is bi-directional. Incremental direction means to move
+ * rightward, and decremental direction is leftward.
+ *
+ * @see TreeIteratorBase
+ */
+template<class DataType, class Traits>
+struct TreeIterator : public TreeIteratorBase
+{
+public:
+ typedef DataType value_type;
+ typedef Traits traits;
+ typedef typename traits::pointer pointer;
+ typedef typename traits::reference reference;
+
+ typedef TreeIterator<value_type, Traits> Self;
+ typedef Node<value_type> node_type;
+
+ typedef typename traits::nonconst_traits nonconst_traits;
+ typedef TreeIterator<value_type, nonconst_traits> iterator;
+ typedef typename traits::const_traits const_traits;
+ typedef TreeIterator<value_type, const_traits> const_iterator;
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+public:
+ TreeIterator()
+ : TreeIteratorBase() {}
+
+ TreeIterator(const iterator &X)
+ : TreeIteratorBase(X.m_pNode) {}
+
+ ~TreeIterator() {}
+
+ // ----- operators ----- //
+ pointer operator*() const
+ { return static_cast<node_type*>(m_pNode)->data; }
+
+ reference operator->() const
+ { return *static_cast<node_type*>(m_pNode)->data; }
+
+ bool isRoot() const
+ { return (m_pNode->right == m_pNode); }
+
+ bool hasData() const
+ { return (!isRoot() && (0 != static_cast<node_type*>(m_pNode)->data)); }
+
+ Self& operator++() {
+ this->move<TreeIteratorBase::Rightward>();
+ return *this;
+ }
+
+ Self operator++(int) {
+ Self tmp = *this;
+ this->move<TreeIteratorBase::Rightward>();
+ return tmp;
+ }
+
+ Self& operator--() {
+ this->move<TreeIteratorBase::Leftward>();
+ return *this;
+ }
+
+ Self operator--(int) {
+ Self tmp = *this;
+ this->move<TreeIteratorBase::Leftward>();
+ return tmp;
+ }
+
+ explicit TreeIterator(NodeBase* X)
+ : TreeIteratorBase(X) {}
+};
+
+/** \class BinaryTreeBase
+ * \brief BinaryTreeBase gives root node and memory management.
+ *
+ * The memory management of nodes in is hidden by BinaryTreeBase.
+ * BinaryTreeBase also provides the basic functions for merging a tree and
+ * inserton of a node.
+ *
+ * @see BinaryTree
+ */
+template<class DataType>
+class BinaryTreeBase : private Uncopyable
+{
+public:
+ typedef Node<DataType> NodeType;
+protected:
+ /// TreeImpl - TreeImpl records the root node and the number of nodes
+ //
+ // +---> Root(end) <---+
+ // | |left |
+ // | begin |
+ // | / \ |
+ // | Left Right |
+ // +---/ \-----+
+ //
+ class TreeImpl : public NodeFactory<DataType>
+ {
+ typedef typename NodeFactory<DataType>::iterator iterator;
+ typedef typename NodeFactory<DataType>::const_iterator const_iterator;
+
+ public:
+ NodeBase node;
+
+ public:
+ TreeImpl()
+ : NodeFactory<DataType>() {
+ node.left = node.right = &node;
+ }
+
+ ~TreeImpl()
+ { }
+
+ /// summon - change the final edges of pClient to our root
+ void summon(TreeImpl& pClient) {
+ if (this == &pClient)
+ return;
+
+ iterator data;
+ iterator dEnd = pClient.end();
+ for (data = pClient.begin(); data!=dEnd; ++data ) {
+ if ((*data).left == &pClient.node)
+ (*data).left = &node;
+ if ((*data).right == &pClient.node)
+ (*data).right = &node;
+ }
+ }
+ }; // TreeImpl
+
+protected:
+ /// m_Root is a special object who responses:
+ // - the pointer of root
+ // - the simple factory of nodes.
+ TreeImpl m_Root;
+
+protected:
+ NodeType *createNode() {
+ NodeType *result = m_Root.produce();
+ result->left = result->right = &m_Root.node;
+ return result;
+ }
+
+ void destroyNode(NodeType *pNode) {
+ pNode->left = pNode->right = 0;
+ pNode->data = 0;
+ m_Root.deallocate(pNode);
+ }
+
+public:
+ BinaryTreeBase()
+ : m_Root()
+ { }
+
+ virtual ~BinaryTreeBase()
+ { }
+
+ size_t size() const {
+ return m_Root.size();
+ }
+
+ bool empty() const {
+ return m_Root.empty();
+ }
+
+protected:
+ void clear() {
+ m_Root.clear();
+ }
+};
+
+/** \class BinaryTree
+ * \brief An abstract data type of binary tree.
+ *
+ * @see mcld::InputTree
+ */
+template<class DataType>
+class BinaryTree : public BinaryTreeBase<DataType>
+{
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef DataType value_type;
+ typedef value_type* pointer;
+ typedef value_type& reference;
+ typedef const value_type* const_pointer;
+ typedef const value_type& const_reference;
+
+ typedef BinaryTree<DataType> Self;
+ typedef TreeIterator<value_type, NonConstTraits<value_type> > iterator;
+ typedef TreeIterator<value_type, ConstTraits<value_type> > const_iterator;
+
+ typedef PolicyIterator<value_type, NonConstTraits<value_type>, DFSIterator> dfs_iterator;
+ typedef PolicyIterator<value_type, ConstTraits<value_type>, DFSIterator> const_dfs_iterator;
+ typedef PolicyIterator<value_type, NonConstTraits<value_type>, BFSIterator> bfs_iterator;
+ typedef PolicyIterator<value_type, ConstTraits<value_type>, BFSIterator> const_bfs_iterator;
+
+protected:
+ typedef Node<value_type> node_type;
+
+public:
+ // ----- constructors and destructor ----- //
+ BinaryTree()
+ : BinaryTreeBase<DataType>()
+ { }
+
+ ~BinaryTree() {
+ }
+
+ // ----- iterators ----- //
+ bfs_iterator bfs_begin()
+ { return bfs_iterator(BinaryTreeBase<DataType>::m_Root.node.left); }
+
+ bfs_iterator bfs_end()
+ { return bfs_iterator(BinaryTreeBase<DataType>::m_Root.node.right); }
+
+ const_bfs_iterator bfs_begin() const
+ { return const_bfs_iterator(BinaryTreeBase<DataType>::m_Root.node.left); }
+
+ const_bfs_iterator bfs_end() const
+ { return const_bfs_iterator(BinaryTreeBase<DataType>::m_Root.node.right); }
+
+ dfs_iterator dfs_begin()
+ { return dfs_iterator(BinaryTreeBase<DataType>::m_Root.node.left); }
+
+ dfs_iterator dfs_end()
+ { return dfs_iterator(BinaryTreeBase<DataType>::m_Root.node.right); }
+
+ const_dfs_iterator dfs_begin() const
+ { return const_dfs_iterator(BinaryTreeBase<DataType>::m_Root.node.left); }
+
+ const_dfs_iterator dfs_end() const
+ { return const_dfs_iterator(BinaryTreeBase<DataType>::m_Root.node.right); }
+
+ iterator root()
+ { return iterator(&(BinaryTreeBase<DataType>::m_Root.node)); }
+
+ const_iterator root() const
+ { return const_iterator(&(BinaryTreeBase<DataType>::m_Root.node)); }
+
+ iterator begin()
+ { return iterator(BinaryTreeBase<DataType>::m_Root.node.left); }
+
+ iterator end()
+ { return iterator(BinaryTreeBase<DataType>::m_Root.node.right); }
+
+ const_iterator begin() const
+ { return const_iterator(BinaryTreeBase<DataType>::m_Root.node.left); }
+
+ const_iterator end() const
+ { return const_iterator(BinaryTreeBase<DataType>::m_Root.node.right); }
+
+ // ----- modifiers ----- //
+ /// join - create a leaf node and merge it in the tree.
+ // This version of join determines the direction on compilation time.
+ // @param DIRECT the direction of the connecting edge of the parent node.
+ // @param position the parent node
+ // @param value the value being pushed.
+ template<size_t DIRECT, class Pos>
+ BinaryTree& join(Pos position, const DataType& value) {
+ node_type *node = BinaryTreeBase<DataType>::createNode();
+ node->data = const_cast<DataType*>(&value);
+ if (position.isRoot())
+ proxy::hook<TreeIteratorBase::Leftward>(position.m_pNode,
+ const_cast<const node_type*>(node));
+ else
+ proxy::hook<DIRECT>(position.m_pNode,
+ const_cast<const node_type*>(node));
+ return *this;
+ }
+
+ /// merge - merge the tree
+ // @param DIRECT the direction of the connecting edge of the parent node.
+ // @param position the parent node
+ // @param the tree being joined.
+ // @return the joined tree
+ template<size_t DIRECT, class Pos>
+ BinaryTree& merge(Pos position, BinaryTree& pTree) {
+ if (this == &pTree)
+ return *this;
+
+ if (!pTree.empty()) {
+ proxy::hook<DIRECT>(position.m_pNode,
+ const_cast<const NodeBase*>(pTree.m_Root.node.left));
+ BinaryTreeBase<DataType>::m_Root.summon(
+ pTree.BinaryTreeBase<DataType>::m_Root);
+ BinaryTreeBase<DataType>::m_Root.delegate(pTree.m_Root);
+ pTree.m_Root.node.left = pTree.m_Root.node.right = &pTree.m_Root.node;
+ }
+ return *this;
+ }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/HashBase.h b/include/mcld/ADT/HashBase.h
new file mode 100644
index 0000000..76410ab
--- /dev/null
+++ b/include/mcld/ADT/HashBase.h
@@ -0,0 +1,139 @@
+//===- HashBase.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_HASH_BASE_H
+#define MCLD_HASH_BASE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/StringRef.h>
+#include <cstdlib>
+
+namespace mcld {
+
+/** forward declaration **/
+template<typename HashTableImplTy>
+class ChainIteratorBase;
+
+template<typename HashTableImplTy>
+class EntryIteratorBase;
+
+/** \class HashBucket
+ * \brief HashBucket is an entry in the hash table.
+ */
+template<typename HashEntryTy>
+class HashBucket
+{
+public:
+ typedef HashEntryTy entry_type;
+
+public:
+ unsigned int FullHashValue;
+ entry_type *Entry;
+
+public:
+ static entry_type* getEmptyBucket();
+ static entry_type* getTombstone();
+
+};
+
+/** \class HashTableImpl
+ * \brief HashTableImpl is the base class of HashTable.
+ *
+ * HashTableImpl uses open-addressing, linear probing hash table.
+ * linear probing hash table obviously has high performance when the
+ * load factor is less than 0.7.
+ * The drawback is that the number of the stored items can notbe more
+ * than the size of the hash table.
+ *
+ * MCLinker tries to merge every things in the same HashEntry. It can
+ * keep every thing in the same cache line and improve the locality
+ * efficiently. HashTableImpl provides a template argument to change the
+ * definition of HashEntries.
+ *
+ * HashEntryTy must provide getKey() and getKenLength() functions.
+ *
+ * Different environments have different demands of HashFunctions. For
+ * example, on-device linkers needs a more light-weight hash function
+ * than static linkers. HashTableImpl also provides a template argument to
+ * change the hash functions.
+ */
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+class HashTableImpl
+{
+private:
+ static const unsigned int NumOfInitBuckets = 16;
+
+public:
+ typedef size_t size_type;
+ typedef HashFunctionTy hasher;
+ typedef HashEntryTy entry_type;
+ typedef typename HashEntryTy::key_type key_type;
+ typedef HashBucket<HashEntryTy> bucket_type;
+ typedef HashTableImpl<HashEntryTy, HashFunctionTy> Self;
+
+
+public:
+ HashTableImpl();
+ explicit HashTableImpl(unsigned int pInitSize);
+ virtual ~HashTableImpl();
+
+ // ----- observers ----- //
+ bool empty() const;
+
+ size_t numOfBuckets() const
+ { return m_NumOfBuckets; }
+
+ size_t numOfEntries() const
+ { return m_NumOfEntries; }
+
+ hasher& hash()
+ { return m_Hasher; }
+
+ const hasher& hash() const
+ { return m_Hasher; }
+
+protected:
+ /// initialize the hash table.
+ void init(unsigned int pInitSize);
+
+ /// lookUpBucketFor - search the index of bucket whose key is p>ey
+ // @return the index of the found bucket
+ unsigned int lookUpBucketFor(const key_type& pKey);
+
+ /// findKey - finds an element with key pKey
+ // return the index of the element, or -1 when the element does not exist.
+ int findKey(const key_type& pKey) const;
+
+ /// mayRehash - check the load_factor, compute the new size, and then doRehash
+ void mayRehash();
+
+ /// doRehash - re-new the hash table, and rehash all elements into the new buckets
+ void doRehash(unsigned int pNewSize);
+
+friend class ChainIteratorBase<Self>;
+friend class ChainIteratorBase<const Self>;
+friend class EntryIteratorBase<Self>;
+friend class EntryIteratorBase<const Self>;
+protected:
+ // Array of Buckets
+ bucket_type* m_Buckets;
+ unsigned int m_NumOfBuckets;
+ unsigned int m_NumOfEntries;
+ unsigned int m_NumOfTombstones;
+ hasher m_Hasher;
+
+};
+
+#include "HashBase.tcc"
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/HashBase.tcc b/include/mcld/ADT/HashBase.tcc
new file mode 100644
index 0000000..62d92b1
--- /dev/null
+++ b/include/mcld/ADT/HashBase.tcc
@@ -0,0 +1,250 @@
+//===- HashBase.tcc -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===--------------------------------------------------------------------===//
+// internal non-member functions
+inline static unsigned int compute_bucket_count(unsigned int pNumOfBuckets)
+{
+ static const unsigned int bucket_size[] =
+ {
+ 1, 3, 17, 37, 67, 97, 197, 419, 977, 2593, 4099, 8209, 12289,
+ 16411, 20483, 32771, 49157, 65537, 98317, 131101, 196613
+ };
+
+ const unsigned int buckets_count =
+ sizeof(bucket_size) / sizeof(bucket_size[0]);
+ unsigned int idx = 0;
+ do {
+ if (pNumOfBuckets < bucket_size[idx]) {
+ return bucket_size[idx];
+ }
+ ++idx;
+ } while(idx < buckets_count);
+
+ return (pNumOfBuckets+131101); // rare case. increase constantly
+}
+
+//===--------------------------------------------------------------------===//
+// template implementation of HashBucket
+template<typename DataType>
+typename HashBucket<DataType>::entry_type*
+HashBucket<DataType>::getEmptyBucket()
+{
+ static entry_type* empty_bucket = reinterpret_cast<entry_type*>(0x0);
+ return empty_bucket;
+}
+
+template<typename DataType>
+typename HashBucket<DataType>::entry_type*
+HashBucket<DataType>::getTombstone()
+{
+ static entry_type* tombstone = reinterpret_cast<entry_type*>(0x1);
+ return tombstone;
+}
+
+//===--------------------------------------------------------------------===//
+// template implementation of HashTableImpl
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+HashTableImpl<HashEntryTy, HashFunctionTy>::HashTableImpl()
+ : m_Buckets(0),
+ m_NumOfBuckets(0),
+ m_NumOfEntries(0),
+ m_NumOfTombstones(0),
+ m_Hasher() {
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+HashTableImpl<HashEntryTy, HashFunctionTy>::HashTableImpl(
+ unsigned int pInitSize)
+ : m_Hasher() {
+ if (pInitSize) {
+ init(pInitSize);
+ return;
+ }
+
+ m_Buckets = 0;
+ m_NumOfBuckets = 0;
+ m_NumOfEntries = 0;
+ m_NumOfTombstones = 0;
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+HashTableImpl<HashEntryTy, HashFunctionTy>::~HashTableImpl()
+{
+ free(m_Buckets);
+}
+
+/// empty - check if the hash table is empty
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+bool HashTableImpl<HashEntryTy, HashFunctionTy>::empty() const
+{
+ return (0 == m_NumOfEntries);
+}
+
+/// init - initialize the hash table.
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+void HashTableImpl<HashEntryTy, HashFunctionTy>::init(unsigned int pInitSize)
+{
+ m_NumOfBuckets = pInitSize? compute_bucket_count(pInitSize): NumOfInitBuckets;
+
+ m_NumOfEntries = 0;
+ m_NumOfTombstones = 0;
+
+ /** calloc also set bucket.Item = bucket_type::getEmptyStone() **/
+ m_Buckets = (bucket_type*)calloc(m_NumOfBuckets, sizeof(bucket_type));
+}
+
+/// lookUpBucketFor - look up the bucket whose key is pKey
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+unsigned int
+HashTableImpl<HashEntryTy, HashFunctionTy>::lookUpBucketFor(
+ const typename HashTableImpl<HashEntryTy, HashFunctionTy>::key_type& pKey)
+{
+ if (0 == m_NumOfBuckets) {
+ // NumOfBuckets is changed after init(pInitSize)
+ init(NumOfInitBuckets);
+ }
+
+ unsigned int full_hash = m_Hasher(pKey);
+ unsigned int index = full_hash % m_NumOfBuckets;
+
+ const unsigned int probe = 1;
+ int firstTombstone = -1;
+
+ // linear probing
+ while(true) {
+ bucket_type& bucket = m_Buckets[index];
+ // If we found an empty bucket, this key isn't in the table yet, return it.
+ if (bucket_type::getEmptyBucket() == bucket.Entry) {
+ if (-1 != firstTombstone) {
+ m_Buckets[firstTombstone].FullHashValue = full_hash;
+ return firstTombstone;
+ }
+
+ bucket.FullHashValue = full_hash;
+ return index;
+ }
+
+ if (bucket_type::getTombstone() == bucket.Entry) {
+ if (-1 == firstTombstone) {
+ firstTombstone = index;
+ }
+ }
+ else if (bucket.FullHashValue == full_hash) {
+ if (bucket.Entry->compare(pKey)) {
+ return index;
+ }
+ }
+
+ index += probe;
+ if (index == m_NumOfBuckets)
+ index = 0;
+ }
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+int
+HashTableImpl<HashEntryTy, HashFunctionTy>::findKey(
+ const typename HashTableImpl<HashEntryTy, HashFunctionTy>::key_type& pKey) const
+{
+ if (0 == m_NumOfBuckets)
+ return -1;
+
+ unsigned int full_hash = m_Hasher(pKey);
+ unsigned int index = full_hash % m_NumOfBuckets;
+
+ const unsigned int probe = 1;
+ // linear probing
+ while (true) {
+ bucket_type &bucket = m_Buckets[index];
+
+ if (bucket_type::getEmptyBucket() == bucket.Entry)
+ return -1;
+
+ if (bucket_type::getTombstone() == bucket.Entry) {
+ // Ignore tombstones.
+ }
+ else if (full_hash == bucket.FullHashValue) {
+ // get string, compare, if match, return index
+ if (bucket.Entry->compare(pKey))
+ return index;
+ }
+ index += probe;
+ if (index == m_NumOfBuckets)
+ index = 0;
+ }
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+void HashTableImpl<HashEntryTy, HashFunctionTy>::mayRehash()
+{
+
+ unsigned int new_size;
+ // If the hash table is now more than 3/4 full, or if fewer than 1/8 of
+ // the buckets are empty (meaning that many are filled with tombstones),
+ // grow/rehash the table.
+ if ((m_NumOfEntries<<2) > m_NumOfBuckets*3)
+ new_size = compute_bucket_count(m_NumOfBuckets);
+ else if (((m_NumOfBuckets-(m_NumOfEntries+m_NumOfTombstones))<<3) < m_NumOfBuckets)
+ new_size = m_NumOfBuckets;
+ else
+ return;
+
+ doRehash(new_size);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+void HashTableImpl<HashEntryTy, HashFunctionTy>::doRehash(unsigned int pNewSize)
+{
+ bucket_type* new_table = (bucket_type*)calloc(pNewSize, sizeof(bucket_type));
+
+ // Rehash all the items into their new buckets. Luckily :) we already have
+ // the hash values available, so we don't have to recall hash function again.
+ for (bucket_type *IB = m_Buckets, *E = m_Buckets+m_NumOfBuckets; IB != E; ++IB) {
+ if (IB->Entry != bucket_type::getEmptyBucket() &&
+ IB->Entry != bucket_type::getTombstone()) {
+ // Fast case, bucket available.
+ unsigned full_hash = IB->FullHashValue;
+ unsigned new_bucket = full_hash % pNewSize;
+ if (bucket_type::getEmptyBucket() == new_table[new_bucket].Entry) {
+ new_table[new_bucket].Entry = IB->Entry;
+ new_table[new_bucket].FullHashValue = full_hash;
+ continue;
+ }
+
+ // Otherwise probe for a spot.
+ const unsigned int probe = 1;
+ do {
+ new_bucket += probe;
+ if (new_bucket == pNewSize)
+ new_bucket = 0;
+ } while (new_table[new_bucket].Entry != bucket_type::getEmptyBucket());
+
+ // Finally found a slot. Fill it in.
+ new_table[new_bucket].Entry = IB->Entry;
+ new_table[new_bucket].FullHashValue = full_hash;
+ }
+ }
+
+ free(m_Buckets);
+
+ m_Buckets = new_table;
+ m_NumOfBuckets = pNewSize;
+ m_NumOfTombstones = 0;
+}
+
diff --git a/include/mcld/ADT/HashEntry.h b/include/mcld/ADT/HashEntry.h
new file mode 100644
index 0000000..c034783
--- /dev/null
+++ b/include/mcld/ADT/HashEntry.h
@@ -0,0 +1,95 @@
+//===- HashEntry.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_HASH_ENTRY_H
+#define MCLD_HASH_ENTRY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld {
+
+/** forward declaration **/
+template<typename HashEntryTy>
+class EntryFactory;
+
+/** \class HashEntry
+ * \brief HashEntry is the item in the bucket of hash table.
+ *
+ * mcld::HashEntry illustrates the demand from mcld::HashTable.
+ * Since HashTable can change the definition of the HashEntry by changing
+ * the template argument. class mcld::HashEntry here is used to show the
+ * basic interfaces that HashTable requests. You can define your own entry
+ * of the hash table which has no relation to mcld::HashEntry
+ *
+ * Since mcld::HashEntry here is a special class whose size is changing,
+ * derive a new class from it is risky. Make sure you understand what you
+ * are doing when you let a new class inherit from mcld::HashEntry.
+ */
+template <typename KeyType, typename ValueType, typename KeyCompare>
+class HashEntry
+{
+public:
+ typedef KeyType key_type;
+ typedef ValueType value_type;
+ typedef KeyCompare key_compare;
+
+private:
+ typedef HashEntry<KeyType, ValueType, KeyCompare> Self;
+ friend class EntryFactory<Self>;
+
+private:
+ HashEntry(const KeyType& pKey);
+ ~HashEntry();
+
+public:
+ KeyType& key()
+ { return m_Key; }
+
+ const KeyType& key() const
+ { return m_Key; }
+
+ ValueType& value()
+ { return m_Value; }
+
+ const ValueType& value() const
+ { return m_Value; }
+
+ void setValue(const ValueType& pValue)
+ { m_Value = pValue; }
+
+ bool compare(const key_type& pKey);
+
+public:
+ KeyType m_Key;
+ ValueType m_Value;
+};
+
+template <typename HashEntryTy>
+class EntryFactory
+{
+public:
+ typedef HashEntryTy entry_type;
+ typedef typename HashEntryTy::key_type key_type;
+ typedef typename HashEntryTy::value_type value_type;
+
+public:
+ EntryFactory();
+ ~EntryFactory();
+
+ HashEntryTy* produce(const key_type& pKey);
+ void destroy(HashEntryTy* pEntry);
+};
+
+#include "HashEntry.tcc"
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/HashEntry.tcc b/include/mcld/ADT/HashEntry.tcc
new file mode 100644
index 0000000..fdd886b
--- /dev/null
+++ b/include/mcld/ADT/HashEntry.tcc
@@ -0,0 +1,53 @@
+//===- HashEntry.tcc ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===--------------------------------------------------------------------===//
+// template implementation of HashEntry
+template <typename KeyType, typename ValueType, typename KeyCompare>
+HashEntry<KeyType, ValueType, KeyCompare>::HashEntry(const KeyType& pKey)
+ : m_Key(pKey) {
+}
+
+template <typename KeyType, typename ValueType, typename KeyCompare>
+HashEntry<KeyType, ValueType, KeyCompare>::~HashEntry()
+{
+}
+
+template <typename KeyType, typename ValueType, typename KeyCompare>
+bool HashEntry<KeyType, ValueType, KeyCompare>::compare(const KeyType& pKey)
+{
+ static KeyCompare comparator;
+ return comparator(m_Key, pKey);
+}
+
+//===--------------------------------------------------------------------===//
+// template implementation of EntryFactory
+template <typename HashEntryTy>
+EntryFactory<HashEntryTy>::EntryFactory()
+{
+}
+
+template <typename HashEntryTy>
+EntryFactory<HashEntryTy>::~EntryFactory()
+{
+}
+
+template <typename HashEntryTy>
+void EntryFactory<HashEntryTy>::destroy(HashEntryTy* pEntry)
+{
+ delete pEntry;
+}
+
+template <typename HashEntryTy>
+HashEntryTy*
+EntryFactory<HashEntryTy>::produce(const typename EntryFactory<HashEntryTy>::key_type& pKey)
+{
+ return new HashEntryTy(pKey);
+}
+
diff --git a/include/mcld/ADT/HashIterator.h b/include/mcld/ADT/HashIterator.h
new file mode 100644
index 0000000..92ccdc5
--- /dev/null
+++ b/include/mcld/ADT/HashIterator.h
@@ -0,0 +1,323 @@
+//===- HashIterator.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_HASH_ITERATOR_H
+#define MCLD_HASH_ITERATOR_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld {
+
+/** \class ChainIteratorBase
+ * \brief ChaintIteratorBase follows the HashEntryTy with the same hash value.
+ */
+template<typename HashTableImplTy>
+class ChainIteratorBase
+{
+public:
+ typedef HashTableImplTy hash_table;
+ typedef typename HashTableImplTy::key_type key_type;
+ typedef typename HashTableImplTy::entry_type entry_type;
+ typedef typename HashTableImplTy::bucket_type bucket_type;
+
+public:
+ ChainIteratorBase()
+ : m_pHashTable(0), m_HashValue(0), m_Index(0), m_EndIndex(0)
+ { }
+
+ ChainIteratorBase(HashTableImplTy* pTable, const key_type& pKey)
+ : m_pHashTable(pTable)
+ {
+ m_HashValue = pTable->hash()(pKey);
+ m_EndIndex = m_Index = m_HashValue % m_pHashTable->m_NumOfBuckets;
+ const unsigned int probe = 1;
+ while(true) {
+ bucket_type &bucket = m_pHashTable->m_Buckets[m_Index];
+ if (bucket_type::getTombstone() == bucket.Entry) {
+ // Ignore tombstones.
+ }
+ else if (m_HashValue == bucket.FullHashValue) {
+ if (bucket.Entry->compare(pKey)) {
+ m_EndIndex = m_Index;
+ break;
+ }
+ }
+ m_Index += probe;
+ if (m_Index == m_pHashTable->m_NumOfBuckets)
+ m_Index = 0;
+ // doesn't exist
+ if (m_EndIndex == m_Index) {
+ reset();
+ break;
+ }
+ }
+ }
+
+ ChainIteratorBase(const ChainIteratorBase& pCopy)
+ : m_pHashTable(pCopy.m_pHashTable),
+ m_Index(pCopy.m_Index),
+ m_EndIndex(pCopy.m_EndIndex),
+ m_HashValue(pCopy.m_HashValue)
+ { }
+
+ ChainIteratorBase& assign(const ChainIteratorBase& pCopy) {
+ m_pHashTable = pCopy.m_pHashTable;
+ m_Index = pCopy.m_Index;
+ m_EndIndex = pCopy.m_EndIndex;
+ m_HashValue = pCopy.m_HashValue;
+ return *this;
+ }
+
+ inline bucket_type* getBucket() {
+ if (0 == m_pHashTable)
+ return 0;
+ return &(m_pHashTable->m_Buckets[m_Index]);
+ }
+
+ inline const bucket_type* getBucket() const {
+ if (0 == m_pHashTable)
+ return 0;
+ return &(m_pHashTable->m_Buckets[m_Index]);
+ }
+
+ inline entry_type* getEntry() {
+ if (0 == m_pHashTable)
+ return 0;
+ return m_pHashTable->m_Buckets[m_Index].Entry;
+ }
+
+ inline const entry_type* getEntry() const {
+ if (0 == m_pHashTable)
+ return 0;
+ return m_pHashTable->m_Buckets[m_Index].Entry;
+ }
+
+ inline void reset() {
+ m_pHashTable = 0;
+ m_Index = 0;
+ m_EndIndex = 0;
+ m_HashValue = 0;
+ }
+
+ inline void advance() {
+ if (0 == m_pHashTable)
+ return;
+ const unsigned int probe = 1;
+ while(true) {
+ m_Index += probe;
+ if (m_Index == m_pHashTable->m_NumOfBuckets)
+ m_Index = 0;
+ // reach end()
+ if (m_Index == m_EndIndex) {
+ reset();
+ return;
+ }
+
+ bucket_type &bucket = m_pHashTable->m_Buckets[m_Index];
+
+ if (bucket_type::getTombstone() == bucket.Entry ||
+ bucket_type::getEmptyBucket() == bucket.Entry) {
+ // Ignore tombstones.
+ }
+ else if (m_HashValue == bucket.FullHashValue) {
+ return;
+ }
+ }
+ }
+
+ bool operator==(const ChainIteratorBase& pCopy) const {
+ if (m_pHashTable == pCopy.m_pHashTable) {
+ if (0 == m_pHashTable)
+ return true;
+ return ((m_HashValue == pCopy.m_HashValue) &&
+ (m_EndIndex == pCopy.m_EndIndex) &&
+ (m_Index == pCopy.m_Index));
+ }
+ return false;
+ }
+
+ bool operator!=(const ChainIteratorBase& pCopy) const
+ { return !(*this == pCopy); }
+
+private:
+ HashTableImplTy* m_pHashTable;
+ unsigned int m_Index;
+ unsigned int m_HashValue;
+ unsigned int m_EndIndex;
+};
+
+/** \class EntryIteratorBase
+ * \brief EntryIteratorBase walks over hash table by the natural layout of the
+ * buckets
+ */
+template<typename HashTableImplTy>
+class EntryIteratorBase
+{
+public:
+ typedef HashTableImplTy hash_table;
+ typedef typename HashTableImplTy::key_type key_type;
+ typedef typename HashTableImplTy::entry_type entry_type;
+ typedef typename HashTableImplTy::bucket_type bucket_type;
+
+public:
+ EntryIteratorBase()
+ : m_pHashTable(0), m_Index(0)
+ { }
+
+ EntryIteratorBase(HashTableImplTy* pTable,
+ unsigned int pIndex)
+ : m_pHashTable(pTable), m_Index(pIndex)
+ { }
+
+ EntryIteratorBase(const EntryIteratorBase& pCopy)
+ : m_pHashTable(pCopy.m_pHashTable), m_Index(pCopy.m_Index)
+ { }
+
+ EntryIteratorBase& assign(const EntryIteratorBase& pCopy) {
+ m_pHashTable = pCopy.m_pHashTable;
+ m_Index = pCopy.m_Index;
+ return *this;
+ }
+
+ inline bucket_type* getBucket() {
+ if (0 == m_pHashTable)
+ return 0;
+ return &(m_pHashTable->m_Buckets[m_Index]);
+ }
+
+ inline const bucket_type* getBucket() const {
+ if (0 == m_pHashTable)
+ return 0;
+ return &(m_pHashTable->m_Buckets[m_Index]);
+ }
+
+ inline entry_type* getEntry() {
+ if (0 == m_pHashTable)
+ return 0;
+ return m_pHashTable->m_Buckets[m_Index].Entry;
+ }
+
+ inline const entry_type* getEntry() const {
+ if (0 == m_pHashTable)
+ return 0;
+ return m_pHashTable->m_Buckets[m_Index].Entry;
+ }
+
+ inline void reset() {
+ m_pHashTable = 0;
+ m_Index = 0;
+ }
+
+ inline void advance() {
+ if (0 == m_pHashTable)
+ return;
+ do {
+ ++m_Index;
+ if (m_pHashTable->m_NumOfBuckets == m_Index) { // to the end
+ reset();
+ return;
+ }
+ } while(bucket_type::getEmptyBucket() == m_pHashTable->m_Buckets[m_Index].Entry ||
+ bucket_type::getTombstone() == m_pHashTable->m_Buckets[m_Index].Entry);
+ }
+
+ bool operator==(const EntryIteratorBase& pCopy) const
+ { return ((m_pHashTable == pCopy.m_pHashTable) &&
+ (m_Index == pCopy.m_Index)); }
+
+ bool operator!=(const EntryIteratorBase& pCopy) const
+ { return !(*this == pCopy); }
+
+private:
+ HashTableImplTy* m_pHashTable;
+ unsigned int m_Index;
+
+};
+
+/** \class HashIterator
+ * \brief HashIterator provides a policy-based iterator.
+ *
+ * HashTable has two kinds of iterators. One is used to traverse buckets
+ * with the same hash value; the other is used to traverse all entries of the
+ * hash table.
+ *
+ * HashIterator is a template policy-based iterator, which can change its
+ * behavior by change the template argument IteratorBase. HashTable defines
+ * above two iterators by defining HashIterators with different IteratorBase.
+ */
+template<typename IteratorBase,
+ typename Traits>
+class HashIterator : public IteratorBase
+{
+public:
+ typedef Traits traits;
+ typedef typename traits::pointer pointer;
+ typedef typename traits::reference reference;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef IteratorBase Base;
+
+ typedef HashIterator<IteratorBase,
+ Traits> Self;
+
+ typedef typename traits::nonconst_traits nonconst_traits;
+ typedef HashIterator<IteratorBase,
+ nonconst_traits> iterator;
+
+ typedef typename traits::const_traits const_traits;
+ typedef HashIterator<IteratorBase,
+ const_traits> const_iterator;
+ typedef std::forward_iterator_tag iterator_category;
+
+public:
+ HashIterator()
+ : IteratorBase()
+ { }
+
+ /// HashIterator - constructor for EntryIterator
+ HashIterator(typename IteratorBase::hash_table* pTable, unsigned int pIndex)
+ : IteratorBase(pTable, pIndex)
+ { }
+
+ /// HashIterator - constructor for ChainIterator
+ explicit HashIterator(typename IteratorBase::hash_table* pTable,
+ const typename IteratorBase::key_type& pKey,
+ int)
+ : IteratorBase(pTable, pKey)
+ { }
+
+ HashIterator(const HashIterator& pCopy)
+ : IteratorBase(pCopy)
+ { }
+
+ ~HashIterator()
+ { }
+
+ HashIterator& operator=(const HashIterator& pCopy) {
+ IteratorBase::assign(pCopy);
+ return *this;
+ }
+
+ // ----- operators ----- //
+ Self& operator++() {
+ this->Base::advance();
+ return *this;
+ }
+
+ Self operator++(int) {
+ Self tmp = *this;
+ this->Base::advance();
+ return tmp;
+ }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/HashTable.h b/include/mcld/ADT/HashTable.h
new file mode 100644
index 0000000..dfc2f5a
--- /dev/null
+++ b/include/mcld/ADT/HashTable.h
@@ -0,0 +1,126 @@
+//===- HashTable.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_HASH_TABLE_H
+#define MCLD_HASH_TABLE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/HashBase.h"
+#include "mcld/ADT/HashIterator.h"
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/ADT/TypeTraits.h"
+#include "mcld/Support/Allocators.h"
+#include <utility>
+
+namespace mcld
+{
+
+/** \class HashTable
+ * \brief HashTable is a hash table which follows boost::unordered_map, but it
+ * is open addressing and can linear probing.
+ *
+ * mcld::HashTable is a linear probing hash table. It does not allocate
+ * the memory space of the entries by itself. Instead, entries are allocated
+ * outside and then emplaced into the hash table.
+ */
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+class HashTable : public HashTableImpl<HashEntryTy, HashFunctionTy>,
+ private Uncopyable
+{
+private:
+ typedef HashTableImpl<HashEntryTy, HashFunctionTy> BaseTy;
+
+public:
+ typedef size_t size_type;
+ typedef HashFunctionTy hasher;
+ typedef HashEntryTy entry_type;
+ typedef typename BaseTy::bucket_type bucket_type;
+ typedef typename HashEntryTy::key_type key_type;
+
+ typedef HashIterator<ChainIteratorBase<BaseTy>,
+ NonConstTraits<HashEntryTy> > chain_iterator;
+ typedef HashIterator<ChainIteratorBase<const BaseTy>,
+ ConstTraits<HashEntryTy> > const_chain_iterator;
+
+ typedef HashIterator<EntryIteratorBase<BaseTy>,
+ NonConstTraits<HashEntryTy> > entry_iterator;
+ typedef HashIterator<EntryIteratorBase<const BaseTy>,
+ ConstTraits<HashEntryTy> > const_entry_iterator;
+
+ typedef entry_iterator iterator;
+ typedef const_entry_iterator const_iterator;
+
+public:
+ // ----- constructor ----- //
+ explicit HashTable(size_type pSize=3);
+ ~HashTable();
+
+ EntryFactoryTy& getEntryFactory()
+ { return m_EntryFactory; }
+
+ // ----- modifiers ----- //
+ void clear();
+
+ /// insert - insert a new element to the container. The element is
+ // constructed in-place, i.e. no copy or move operations are performed.
+ // If the element already exists, return the element, and set pExist true.
+ entry_type* insert(const key_type& pKey, bool& pExist);
+
+ /// erase - remove the element with the same key
+ size_type erase(const key_type& pKey);
+
+ // ----- lookups ----- //
+ /// find - finds an element with key pKey
+ // If the element does not exist, return end()
+ iterator find(const key_type& pKey);
+
+ /// find - finds an element with key pKey, constant version
+ // If the element does not exist, return end()
+ const_iterator find(const key_type& pKey) const;
+
+ size_type count(const key_type& pKey) const;
+
+ // ----- hash policy ----- //
+ float load_factor() const;
+
+ /// rehash - if the load factor is larger than 75%, or the empty buckets is
+ // less than 12.5%, the rehash the hash table
+ void rehash();
+
+ /// rehash - immediately re-new the hash table to the size pCount, and
+ // rehash all elements.
+ void rehash(size_type pCount);
+
+ // ----- iterators ----- //
+ iterator begin();
+ iterator end();
+
+ const_entry_iterator begin() const;
+ const_entry_iterator end() const;
+
+ chain_iterator begin(const key_type& pKey);
+ chain_iterator end(const key_type& pKey);
+ const_chain_iterator begin(const key_type& pKey) const;
+ const_chain_iterator end(const key_type& pKey) const;
+
+private:
+ EntryFactoryTy m_EntryFactory;
+
+};
+
+#include "HashTable.tcc"
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/HashTable.tcc b/include/mcld/ADT/HashTable.tcc
new file mode 100644
index 0000000..6fb05a3
--- /dev/null
+++ b/include/mcld/ADT/HashTable.tcc
@@ -0,0 +1,268 @@
+//===- HashTable.tcc ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===--------------------------------------------------------------------===//
+// template implementation of HashTable
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::HashTable(size_type pSize)
+ : HashTableImpl<HashEntryTy, HashFunctionTy>(pSize), m_EntryFactory()
+{
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::~HashTable()
+{
+ if (BaseTy::empty())
+ return;
+
+ /** clean up **/
+ for (unsigned int i=0; i < BaseTy::m_NumOfBuckets; ++i) {
+ if (bucket_type::getEmptyBucket() != BaseTy::m_Buckets[i].Entry &&
+ bucket_type::getTombstone() != BaseTy::m_Buckets[i].Entry ) {
+ m_EntryFactory.destroy(BaseTy::m_Buckets[i].Entry);
+ }
+ }
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+void HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::clear()
+{
+ if (BaseTy::empty())
+ return;
+
+ /** clean up **/
+ for (unsigned int i=0; i < BaseTy::m_NumOfBuckets; ++i) {
+ if (bucket_type::getEmptyBucket() != BaseTy::m_Buckets[i].Entry ) {
+ if (bucket_type::getTombstone() != BaseTy::m_Buckets[i].Entry ) {
+ m_EntryFactory.destroy(BaseTy::m_Buckets[i].Entry);
+ }
+ BaseTy::m_Buckets[i].Entry = bucket_type::getEmptyBucket();
+ }
+ }
+ BaseTy::m_NumOfEntries = 0;
+ BaseTy::m_NumOfTombstones = 0;
+}
+
+/// insert - insert a new element to the container. If the element already
+// exist, return the element.
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::entry_type*
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::insert(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey,
+ bool& pExist)
+{
+ unsigned int index = BaseTy::lookUpBucketFor(pKey);
+ bucket_type& bucket = BaseTy::m_Buckets[index];
+ entry_type* entry = bucket.Entry;
+ if (bucket_type::getEmptyBucket() != entry &&
+ bucket_type::getTombstone() != entry) {
+ // Already exist in the table
+ pExist = true;
+ return entry;
+ }
+
+ // find a tombstone
+ if (bucket_type::getTombstone() == entry)
+ --BaseTy::m_NumOfTombstones;
+
+ entry = bucket.Entry = m_EntryFactory.produce(pKey);
+ ++BaseTy::m_NumOfEntries;
+ BaseTy::mayRehash();
+ pExist = false;
+ return entry;
+}
+
+/// erase - remove the elements with the pKey
+// @return the number of removed elements.
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::size_type
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::erase(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey)
+{
+ int index;
+ if (-1 == (index = BaseTy::findKey(pKey)))
+ return 0;
+
+ bucket_type& bucket = BaseTy::m_Buckets[index];
+ m_EntryFactory.destroy(bucket.Entry);
+ bucket.Entry = bucket_type::getTombstone();
+
+ --BaseTy::m_NumOfEntries;
+ ++BaseTy::m_NumOfTombstones;
+ BaseTy::mayRehash();
+ return 1;
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::find(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey)
+{
+ int index;
+ if (-1 == (index = BaseTy::findKey(pKey)))
+ return end();
+ return iterator(this, index);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::const_iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::find(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey) const
+{
+ int index;
+ if (-1 == (index = BaseTy::findKey(pKey)))
+ return end();
+ return const_iterator(this, index);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::size_type
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::count(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey) const
+{
+ const_chain_iterator bucket, bEnd = end(pKey);
+ size_type count = 0;
+ for (bucket = begin(pKey); bucket != bEnd; ++bucket)
+ ++count;
+ return count;
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+float HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::load_factor() const
+{
+ return ((float)BaseTy::m_NumOfEntries/(float)BaseTy::m_NumOfBuckets);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+void
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::rehash()
+{
+ BaseTy::mayRehash();
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+void
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::rehash(
+ typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::size_type pCount)
+{
+ BaseTy::doRehash(pCount);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::begin()
+{
+ if (BaseTy::empty())
+ return iterator(this, 0);
+ unsigned int index = 0;
+ while (bucket_type::getTombstone() == BaseTy::m_Buckets[index].Entry ||
+ bucket_type::getEmptyBucket() == BaseTy::m_Buckets[index].Entry) {
+ ++index;
+ }
+ return iterator(this, index);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::end()
+{
+ return iterator(NULL, 0);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::const_iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::begin() const
+{
+ if (BaseTy::empty())
+ return const_iterator(this, 0);
+ unsigned int index = 0;
+ while (bucket_type::getTombstone() == BaseTy::m_Buckets[index].Entry ||
+ bucket_type::getEmptyBucket() == BaseTy::m_Buckets[index].Entry) {
+ ++index;
+ }
+ return const_iterator(this, index);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::const_iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::end() const
+{
+ return const_iterator(NULL, 0);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::chain_iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::begin(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey)
+{
+ return chain_iterator(this, pKey, 0x0);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::chain_iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::end(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey)
+{
+ return chain_iterator();
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::const_chain_iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::begin(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey) const
+{
+ return const_chain_iterator(this, pKey, 0x0);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::const_chain_iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::end(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey) const
+{
+ return const_chain_iterator();
+}
+
diff --git a/include/mcld/ADT/SizeTraits.h b/include/mcld/ADT/SizeTraits.h
new file mode 100644
index 0000000..8d307bd
--- /dev/null
+++ b/include/mcld/ADT/SizeTraits.h
@@ -0,0 +1,102 @@
+//===- SizeTraits.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SIZE_TRAITS_H
+#define MCLD_SIZE_TRAITS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/DataTypes.h>
+
+namespace mcld
+{
+
+template<size_t SIZE>
+struct SizeTraits;
+
+template<>
+class SizeTraits<32>
+{
+ typedef uint32_t Address;
+ typedef uint32_t Offset;
+ typedef uint32_t Word;
+ typedef int32_t SWord;
+};
+
+template<>
+class SizeTraits<64>
+{
+ typedef uint64_t Address;
+ typedef uint64_t Offset;
+ typedef uint64_t Word;
+ typedef int64_t SWord;
+};
+
+/// alignAddress - helper function to align an address with given alignment
+/// constraint
+///
+/// @param pAddr - the address to be aligned
+/// @param pAlignConstraint - the alignment used to align the given address
+inline void alignAddress(uint64_t& pAddr, uint64_t pAlignConstraint)
+{
+ if (pAlignConstraint != 0)
+ pAddr = (pAddr + pAlignConstraint - 1) &~ (pAlignConstraint - 1);
+}
+
+template<size_t Constraint>
+uint64_t Align(uint64_t pAddress);
+
+template<>
+inline uint64_t Align<32>(uint64_t pAddress)
+{
+ return (pAddress + 0x1F) & (~0x1F);
+}
+
+template<>
+inline uint64_t Align<64>(uint64_t pAddress)
+{
+ return (pAddress + 0x3F) & (~0x3F);
+}
+
+/// bswap16 - byte swap 16-bit version
+/// @ref binary utilities - elfcpp_swap
+inline uint16_t bswap16(uint16_t pData)
+{
+ return ((pData >> 8) & 0xFF) | ((pData & 0xFF) << 8);
+}
+
+/// bswap32 - byte swap 32-bit version
+/// @ref elfcpp_swap
+inline uint32_t bswap32(uint32_t pData)
+{
+ return (((pData & 0xFF000000) >> 24) |
+ ((pData & 0x00FF0000) >> 8) |
+ ((pData & 0x0000FF00) << 8) |
+ ((pData & 0x000000FF) << 24));
+
+}
+
+/// bswap64 - byte swap 64-bit version
+/// @ref binary utilities - elfcpp_swap
+inline uint64_t bswap64(uint64_t pData)
+{
+ return (((pData & 0xFF00000000000000ULL) >> 56) |
+ ((pData & 0x00FF000000000000ULL) >> 40) |
+ ((pData & 0x0000FF0000000000ULL) >> 24) |
+ ((pData & 0x000000FF00000000ULL) >> 8) |
+ ((pData & 0x00000000FF000000ULL) << 8) |
+ ((pData & 0x0000000000FF0000ULL) << 24) |
+ ((pData & 0x000000000000FF00ULL) << 40) |
+ ((pData & 0x00000000000000FFULL) << 56));
+}
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/StringHash.h b/include/mcld/ADT/StringHash.h
new file mode 100644
index 0000000..f100a49
--- /dev/null
+++ b/include/mcld/ADT/StringHash.h
@@ -0,0 +1,289 @@
+//===- StringHash.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_STRING_HASH_FUNCTION_H
+#define MCLD_STRING_HASH_FUNCTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <functional>
+
+namespace mcld
+{
+
+enum StringHashType
+{
+ RS,
+ JS,
+ PJW,
+ ELF,
+ BKDR,
+ SDBM,
+ DJB,
+ DEK,
+ BP,
+ FNV,
+ AP
+};
+
+/** \class template<size_t TYPE> StringHash
+ * \brief the template StringHash class, for specification
+ */
+template<size_t TYPE>
+struct StringHash : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ llvm::report_fatal_error("Undefined StringHash function.\n");
+ }
+};
+
+/** \class StringHash<RSHash>
+ * \brief RS StringHash funciton
+ */
+template<>
+struct StringHash<RS> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ const unsigned int b = 378551;
+ size_t a = 63689;
+ size_t hash_val = 0;
+
+ for(unsigned int i = 0; i < pKey.size(); ++i) {
+ hash_val = hash_val * a + pKey[i];
+ a = a * b;
+ }
+ return hash_val;
+ }
+};
+
+/** \class StringHash<JSHash>
+ * \brief JS hash funciton
+ */
+template<>
+struct StringHash<JS> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ size_t hash_val = 1315423911;
+
+ for(unsigned int i = 0; i < pKey.size(); ++i) {
+ hash_val ^= ((hash_val << 5) + pKey[i] + (hash_val >> 2));
+ }
+ return hash_val;
+ }
+};
+
+/** \class StringHash<PJW>
+ * \brief P.J. Weinberger hash function
+ */
+template<>
+struct StringHash<PJW> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ const unsigned int BitsInUnsignedInt = (unsigned int)(sizeof(unsigned int) * 8);
+ const unsigned int ThreeQuarters = (unsigned int)((BitsInUnsignedInt * 3) / 4);
+ const unsigned int OneEighth = (unsigned int)(BitsInUnsignedInt / 8);
+ const unsigned int HighBits = (unsigned int)(0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth);
+ size_t hash_val = 0;
+ size_t test = 0;
+
+ for(unsigned int i = 0; i < pKey.size(); ++i) {
+ hash_val = (hash_val << OneEighth) + pKey[i];
+
+ if((test = hash_val & HighBits) != 0) {
+ hash_val = (( hash_val ^ (test >> ThreeQuarters)) & (~HighBits));
+ }
+ }
+ return hash_val;
+ }
+};
+
+/** \class StringHash<ELF>
+ * \brief ELF hash function.
+ */
+template<>
+struct StringHash<ELF> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ size_t hash_val = 0;
+ size_t x = 0;
+
+ for (unsigned int i = 0; i < pKey.size(); ++i) {
+ hash_val = (hash_val << 4) + pKey[i];
+ if((x = hash_val & 0xF0000000L) != 0)
+ hash_val ^= (x >> 24);
+ hash_val &= ~x;
+ }
+ return hash_val;
+ }
+};
+
+/** \class StringHash<BKDR>
+ * \brief BKDR hash function
+ */
+template<>
+struct StringHash<BKDR> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ const size_t seed = 131;
+ size_t hash_val = 0;
+
+ for(size_t i = 0; i < pKey.size(); ++i)
+ hash_val = (hash_val * seed) + pKey[i];
+ return hash_val;
+ }
+};
+
+
+/** \class StringHash<SDBM>
+ * \brief SDBM hash function
+ * 0.049s in 100000 test
+ */
+template<>
+struct StringHash<SDBM> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ size_t hash_val = 0;
+
+ for(size_t i = 0; i < pKey.size(); ++i)
+ hash_val = pKey[i] + (hash_val << 6) + (hash_val << 16) - hash_val;
+ return hash_val;
+ }
+};
+
+/** \class StringHash<DJB>
+ * \brief DJB hash function
+ * 0.057s in 100000 test
+ */
+template<>
+struct StringHash<DJB> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ size_t hash_val = 5381;
+
+ for(size_t i = 0; i < pKey.size(); ++i)
+ hash_val = ((hash_val << 5) + hash_val) + pKey[i];
+
+ return hash_val;
+ }
+};
+
+/** \class StringHash<DEK>
+ * \brief DEK hash function
+ * 0.60s
+ */
+template<>
+struct StringHash<DEK> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ size_t hash_val = pKey.size();
+
+ for(size_t i = 0; i < pKey.size(); ++i)
+ hash_val = ((hash_val << 5) ^ (hash_val >> 27)) ^ pKey[i];
+
+ return hash_val;
+ }
+};
+
+/** \class StringHash<BP>
+ * \brief BP hash function
+ * 0.057s
+ */
+template<>
+struct StringHash<BP> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ size_t hash_val = 0;
+ for(size_t i = 0; i < pKey.size(); ++i)
+ hash_val = hash_val << 7 ^ pKey[i];
+
+ return hash_val;
+ }
+};
+
+/** \class StringHash<FNV>
+ * \brief FNV hash function
+ * 0.058s
+ */
+template<>
+struct StringHash<FNV> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ const size_t fnv_prime = 0x811C9DC5;
+ size_t hash_val = 0;
+ for(size_t i = 0; i < pKey.size(); ++i) {
+ hash_val *= fnv_prime;
+ hash_val ^= pKey[i];
+ }
+
+ return hash_val;
+ }
+};
+
+/** \class StringHash<AP>
+ * \brief AP hash function
+ * 0.060s
+ */
+template<>
+struct StringHash<AP> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ unsigned int hash_val = 0xAAAAAAAA;
+
+ for(size_t i = 0; i < pKey.size(); ++i) {
+ hash_val ^= ((i & 1) == 0)?
+ ((hash_val << 7) ^ pKey[i] * (hash_val >> 3)):
+ (~((hash_val << 11) + (pKey[i] ^ (hash_val >> 5))));
+ }
+
+ return hash_val;
+ }
+};
+
+/** \class template<size_t TYPE> StringCompare
+ * \brief the template StringCompare class, for specification
+ */
+template<typename STRING_TYPE>
+struct StringCompare : public std::binary_function<const STRING_TYPE&, const STRING_TYPE&, bool>
+{
+ bool operator()(const STRING_TYPE& X, const STRING_TYPE& Y) const
+ { return X == Y; }
+};
+
+template<>
+struct StringCompare<const char*> : public std::binary_function<const char*, const char*, bool>
+{
+ bool operator()(const char* X, const char* Y) const
+ { return (0 == std::strcmp(X, Y)); }
+};
+
+template<>
+struct StringCompare<char*> : public std::binary_function<const char*, const char*, bool>
+{
+ bool operator()(const char* X, const char* Y) const
+ { return (0 == std::strcmp(X, Y)); }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/TreeAllocator.h b/include/mcld/ADT/TreeAllocator.h
new file mode 100644
index 0000000..899896c
--- /dev/null
+++ b/include/mcld/ADT/TreeAllocator.h
@@ -0,0 +1,98 @@
+//===- TreeAllocator.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TREE_ALLOCATOR_H
+#define MCLD_TREE_ALLOCATOR_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <set>
+#include "mcld/Support/GCFactory.h"
+#include "mcld/ADT/TreeBase.h"
+
+namespace mcld
+{
+
+/** \class NodeFactory
+ * \brief NodeFactory manages the creation and destruction of mcld::Node.
+ *
+ * NodeFactory guarantees all allocated memory are released finally. When
+ * the destructor of NodeFactory is called, all allocated memory are freed.
+ *
+ * NodeFactory provides delegation of memory. Sometimes, we have to merge two
+ * NodeFactories, and NodeFactory::delegate() can move the memory from one
+ * NodeFactories to another.
+ *
+ * @see LinearAllocator
+ */
+template<typename DataType>
+class NodeFactory : public GCFactory<Node<DataType>, 64>
+{
+private:
+ typedef GCFactory<Node<DataType>, 64> Alloc;
+
+public:
+ typedef Node<DataType> NodeType;
+ typedef typename Alloc::iterator iterator;
+ typedef typename Alloc::const_iterator const_iterator;
+
+public:
+ /// produce - produce a node, add it under control
+ NodeType* produce() {
+ NodeType* result = Alloc::allocate();
+ Alloc::construct(result);
+ return result;
+ }
+
+ /// delegate - get the control of chunks owned by the client
+ // after calling delegate(), client will renouce its control
+ // of memory space.
+ void delegate(NodeFactory& pClient) {
+ if (this == &pClient)
+ return;
+
+ if (pClient.empty())
+ return;
+
+ if (Alloc::empty()) {
+ replace(pClient);
+ pClient.renounce();
+ return;
+ }
+
+ // neither me nor client is empty
+ concatenate(pClient);
+ pClient.renounce();
+ }
+
+private:
+ /// renounce - give up the control of all chunks
+ void renounce()
+ { Alloc::reset(); }
+
+ /// replace - be the agent of client.
+ void replace(NodeFactory& pClient) {
+ Alloc::m_pRoot = pClient.Alloc::m_pRoot;
+ Alloc::m_pCurrent = pClient.Alloc::m_pCurrent;
+ Alloc::m_AllocatedNum = pClient.Alloc::m_AllocatedNum;
+ Alloc::m_NumAllocData = pClient.Alloc::m_NumAllocData;
+ }
+
+ /// concatenate - conncet two factories
+ void concatenate(NodeFactory& pClient) {
+ Alloc::m_pCurrent->next = pClient.Alloc::m_pRoot;
+ Alloc::m_pCurrent = pClient.Alloc::m_pCurrent;
+ Alloc::m_AllocatedNum += pClient.Alloc::m_AllocatedNum;
+ Alloc::m_NumAllocData += pClient.Alloc::m_NumAllocData;
+ }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/TreeBase.h b/include/mcld/ADT/TreeBase.h
new file mode 100644
index 0000000..c518975
--- /dev/null
+++ b/include/mcld/ADT/TreeBase.h
@@ -0,0 +1,127 @@
+//===- TreeBase.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TREE_BASE_H
+#define MCLD_TREE_BASE_H
+#include "mcld/ADT/TypeTraits.h"
+
+namespace mcld
+{
+
+class NodeBase
+{
+public:
+ NodeBase *left;
+ NodeBase *right;
+
+public:
+ NodeBase()
+ : left(0), right(0)
+ { }
+};
+
+namespace proxy
+{
+ template<size_t DIRECT>
+ inline void move(NodeBase *&X)
+ { assert(0 && "not allowed"); }
+
+ template<size_t DIRECT>
+ inline void hook(NodeBase *X, const NodeBase *Y)
+ { assert(0 && "not allowed"); }
+
+} // namespace of template proxy
+
+struct TreeIteratorBase
+{
+public:
+ enum Direct {
+ Leftward,
+ Rightward
+ };
+
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef std::bidirectional_iterator_tag iterator_category;
+
+public:
+ NodeBase* m_pNode;
+
+public:
+ TreeIteratorBase()
+ : m_pNode(0)
+ { }
+
+ TreeIteratorBase(NodeBase *X)
+ : m_pNode(X)
+ { }
+
+ virtual ~TreeIteratorBase(){};
+
+ template<size_t DIRECT>
+ inline void move() {
+ proxy::move<DIRECT>(m_pNode);
+ }
+
+ bool hasRightChild() const
+ { return ((m_pNode->right) != (m_pNode->right->right)); }
+
+ bool hasLeftChild() const
+ { return ((m_pNode->left) != (m_pNode->left->right)); }
+
+ bool operator==(const TreeIteratorBase& y) const
+ { return this->m_pNode == y.m_pNode; }
+
+ bool operator!=(const TreeIteratorBase& y) const
+ { return this->m_pNode != y.m_pNode; }
+};
+
+namespace proxy
+{
+ template<>
+ inline void move<TreeIteratorBase::Leftward>(NodeBase *&X)
+ { X = X->left; }
+
+ template<>
+ inline void move<TreeIteratorBase::Rightward>(NodeBase *&X)
+ { X = X->right; }
+
+ template<>
+ inline void hook<TreeIteratorBase::Leftward>(NodeBase *X, const NodeBase *Y)
+ { X->left = const_cast<NodeBase*>(Y); }
+
+ template<>
+ inline void hook<TreeIteratorBase::Rightward>(NodeBase* X, const NodeBase* Y)
+ { X->right = const_cast<NodeBase*>(Y); }
+
+} //namespace of template proxy
+
+template<typename DataType>
+class Node : public NodeBase
+{
+public:
+ typedef DataType value_type;
+
+public:
+ value_type* data;
+
+public:
+ Node()
+ : NodeBase(), data(0)
+ { }
+
+ Node(const value_type& pValue)
+ : NodeBase(), data(&pValue)
+ { }
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/TypeTraits.h b/include/mcld/ADT/TypeTraits.h
new file mode 100644
index 0000000..90b2224
--- /dev/null
+++ b/include/mcld/ADT/TypeTraits.h
@@ -0,0 +1,71 @@
+//===- TypeTraits.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TYPE_TRAITS_H
+#define MCLD_TYPE_TRAITS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <cstdlib>
+
+namespace mcld
+{
+template<typename DataType>
+struct NonConstTraits;
+
+template<typename DataType>
+struct ConstTraits
+{
+ typedef DataType value_type;
+ typedef const DataType* pointer;
+ typedef const DataType& reference;
+ typedef size_t size_type;
+ typedef ConstTraits<DataType> const_traits;
+ typedef NonConstTraits<DataType> nonconst_traits;
+};
+
+template<typename DataType>
+struct NonConstTraits
+{
+ typedef DataType value_type;
+ typedef DataType* pointer;
+ typedef DataType& reference;
+ typedef size_t size_type;
+ typedef ConstTraits<DataType> const_traits;
+ typedef NonConstTraits<DataType> nonconst_traits;
+};
+
+template<typename DataType>
+struct ConstIteratorTraits
+{
+ typedef DataType value_type;
+ typedef const DataType* pointer;
+ typedef const DataType& reference;
+ typedef size_t size_type;
+ typedef ConstTraits<DataType> const_traits;
+ typedef NonConstTraits<DataType> nonconst_traits;
+ typedef typename DataType::const_iterator iterator;
+};
+
+template<typename DataType>
+struct NonConstIteratorTraits
+{
+ typedef DataType value_type;
+ typedef DataType* pointer;
+ typedef DataType& reference;
+ typedef size_t size_type;
+ typedef ConstTraits<DataType> const_traits;
+ typedef NonConstTraits<DataType> nonconst_traits;
+ typedef typename DataType::iterator iterator;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/Uncopyable.h b/include/mcld/ADT/Uncopyable.h
new file mode 100644
index 0000000..7ddfbe3
--- /dev/null
+++ b/include/mcld/ADT/Uncopyable.h
@@ -0,0 +1,36 @@
+//===- Uncopyable.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_UNCOPYABLE_H
+#define MCLD_UNCOPYABLE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+/** \class Uncopyable
+ * \brief Uncopyable provides the base class to forbit copy operations.
+ *
+ */
+class Uncopyable
+{
+protected:
+ Uncopyable() { }
+ ~Uncopyable() { }
+
+private:
+ Uncopyable(const Uncopyable&); /// NOT TO IMPLEMENT
+ Uncopyable& operator=(const Uncopyable&); /// NOT TO IMPLEMENT
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/CodeGen/SectLinker.h b/include/mcld/CodeGen/SectLinker.h
new file mode 100644
index 0000000..31fae4a
--- /dev/null
+++ b/include/mcld/CodeGen/SectLinker.h
@@ -0,0 +1,107 @@
+//===- SectLinker.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//SectLinker is a base class inherited by target specific linker.
+//This class primarily handles common functionality used by all linkers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SECTION_LINKER_H
+#define SECTION_LINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/CodeGen/MachineFunctionPass.h>
+#include <mcld/Support/PositionDependentOption.h>
+#include <vector>
+
+namespace llvm
+{
+ class Module;
+ class MachineFunction;
+} // namespace of llvm
+
+namespace mcld
+{
+ class MCLDFile;
+ class MCLDDriver;
+ class TargetLDBackend;
+ class AttributeFactory;
+ class SectLinkerOption;
+
+ /** \class SectLinker
+ * \brief SectLinker provides a linking pass for standard compilation flow
+ *
+ * SectLinker is responded for
+ * - provide an interface for target-specific SectLinekr
+ * - set up environment for MCLDDriver
+ * - control AsmPrinter, make sure AsmPrinter has already prepared
+ * all MCSectionDatas for linking
+ *
+ * SectLinker resolves the absolue paths of input arguments.
+ *
+ * @see MachineFunctionPass MCLDDriver
+ */
+ class SectLinker : public llvm::MachineFunctionPass
+ {
+ protected:
+ // Constructor. Although SectLinker has only two arguments,
+ // TargetSectLinker should handle
+ // - enabled attributes
+ // - the default attribute
+ // - the default link script
+ // - the standard symbols
+ SectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend);
+
+ public:
+ virtual ~SectLinker();
+
+ /// addTargetOptions - target SectLinker can hook this function to add
+ /// target-specific inputs
+ virtual void addTargetOptions(llvm::Module &pM,
+ SectLinkerOption &pOption)
+ { }
+
+ /// doInitialization - Read all parameters and set up the AsmPrinter.
+ /// If your pass overrides this, it must make sure to explicitly call
+ /// this implementation.
+ virtual bool doInitialization(llvm::Module &pM);
+
+ /// doFinalization - Shut down the AsmPrinter, and do really linking.
+ /// If you override this in your pass, you must make sure to call it
+ /// explicitly.
+ virtual bool doFinalization(llvm::Module &pM);
+
+ /// runOnMachineFunction
+ /// redirect to AsmPrinter
+ virtual bool runOnMachineFunction(llvm::MachineFunction& pMFn);
+
+ protected:
+ void initializeInputTree(const PositionDependentOptions &pOptions) const;
+
+ AttributeFactory* attrFactory()
+ { return m_pAttrFactory; }
+
+ private:
+ SectLinkerOption *m_pOption;
+
+ protected:
+ TargetLDBackend *m_pLDBackend;
+ MCLDDriver *m_pLDDriver;
+ AttributeFactory *m_pAttrFactory;
+
+ private:
+ static char m_ID;
+ };
+
+} // namespace of MC Linker
+
+#endif
+
diff --git a/include/mcld/CodeGen/SectLinkerOption.h b/include/mcld/CodeGen/SectLinkerOption.h
new file mode 100644
index 0000000..b3e3327
--- /dev/null
+++ b/include/mcld/CodeGen/SectLinkerOption.h
@@ -0,0 +1,57 @@
+//===- SectLinkerOption.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SECTLINKERDATA_H
+#define MCLD_SECTLINKERDATA_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/MC/MCLDInfo.h"
+#include "mcld/Support/PositionDependentOption.h"
+
+#include <string>
+
+namespace mcld
+{
+ class PositionDependentOption;
+
+ /** \class SectLinkerOption
+ * \brief This file collects inputs to linker.
+ */
+ class SectLinkerOption
+ {
+ public:
+ // Constructor.
+ SectLinkerOption(MCLDInfo &pLDInfo);
+
+ // ----- Position-dependent Options ----- //
+ inline void appendOption(PositionDependentOption *pOption)
+ { m_PosDepOptions.push_back(pOption); }
+
+ inline void prependOption(PositionDependentOption *pOption)
+ { m_PosDepOptions.insert(m_PosDepOptions.begin(), pOption); }
+
+ inline const PositionDependentOptions &pos_dep_options() const
+ { return m_PosDepOptions; }
+ inline PositionDependentOptions &pos_dep_options()
+ { return m_PosDepOptions; }
+
+ inline const MCLDInfo &info() const { return *m_pLDInfo; }
+ inline MCLDInfo &info() { return *m_pLDInfo; }
+
+ ~SectLinkerOption();
+
+ private:
+ MCLDInfo *m_pLDInfo;
+ PositionDependentOptions m_PosDepOptions;
+ };
+
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Config/Config.h b/include/mcld/Config/Config.h
new file mode 100644
index 0000000..362b076
--- /dev/null
+++ b/include/mcld/Config/Config.h
@@ -0,0 +1,26 @@
+//===- Config.h.in --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Hand-coded for Android build
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_CONFIG_H
+#define MCLD_CONFIG_H
+
+namespace mcld {
+namespace internal {
+
+static const char* version="0.2.10.1-18peaks";
+
+} // namespace of internal
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Config/Config.h.in b/include/mcld/Config/Config.h.in
new file mode 100644
index 0000000..6d428c0
--- /dev/null
+++ b/include/mcld/Config/Config.h.in
@@ -0,0 +1,21 @@
+//===- Config.h.in --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_CONFIG_H
+#define MCLD_CONFIG_H
+
+namespace mcld {
+namespace internal {
+
+static const char* version="@MCLD_VERSION@";
+
+} // namespace of internal
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Config/Linkers.def b/include/mcld/Config/Linkers.def
new file mode 100644
index 0000000..2781461
--- /dev/null
+++ b/include/mcld/Config/Linkers.def
@@ -0,0 +1,33 @@
+//===- llvm/Config/Linkers.def - LLVM Linkers -------------------*- C++ -*-===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file enumerates all of the linkers supported by this build of LLVM.
+// Clients of this file should define the LLVM_LINKER macro to be a function-like
+// macro with a single parameter (the name of the target whose exe/dso can be
+// generated); including this file will then enumerate all of the targets with
+// linkers.
+//
+// The set of targets supported by LLVM is generated at configuration
+// time, at which point this header is generated. Do not modify this
+// header directly.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Hand-coded for Android build
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LINKER
+# error Please define the macro LLVM_LINKER(TargetName)
+#endif
+
+#define LLVM_TARGET LLVM_LINKER
+#include <llvm/Config/Targets.def>
+
+#undef LLVM_LINKER
diff --git a/include/mcld/Config/Linkers.def.in b/include/mcld/Config/Linkers.def.in
new file mode 100644
index 0000000..0e09040
--- /dev/null
+++ b/include/mcld/Config/Linkers.def.in
@@ -0,0 +1,28 @@
+//===- llvm/Config/Linkers.def - LLVM Linkers -------------------*- C++ -*-===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file enumerates all of the linkers supported by this build of LLVM.
+// Clients of this file should define the LLVM_LINKER macro to be a function-like
+// macro with a single parameter (the name of the target whose exe/dso can be
+// generated); including this file will then enumerate all of the targets with
+// linkers.
+//
+// The set of targets supported by LLVM is generated at configuration
+// time, at which point this header is generated. Do not modify this
+// header directly.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LINKER
+# error Please define the macro LLVM_LINKER(TargetName)
+#endif
+
+@LLVM_ENUM_LINKERS@
+
+#undef LLVM_LINKER
diff --git a/include/mcld/Config/Targets.def b/include/mcld/Config/Targets.def
new file mode 100644
index 0000000..a0981d6
--- /dev/null
+++ b/include/mcld/Config/Targets.def
@@ -0,0 +1,32 @@
+/*===- llvm/Config/Targets.def - LLVM Target Architectures ------*- C++ -*-===*\
+|* *|
+|* The MCLinker Project *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* This file enumerates all of the target architectures supported by *|
+|* this build of LLVM. Clients of this file should define the *|
+|* LLVM_TARGET macro to be a function-like macro with a single *|
+|* parameter (the name of the target); including this file will then *|
+|* enumerate all of the targets. *|
+|* *|
+|* The set of targets supported by LLVM is generated at configuration *|
+|* time, at which point this header is generated. Do not modify this *|
+|* header directly. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+
+//===----------------------------------------------------------------------===//
+// Hand-coded for Android build
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TARGET
+# error Please define the macro LLVM_TARGET(TargetName)
+#endif
+
+#include <llvm/Config/Targets.def>
+
+#undef LLVM_TARGET
diff --git a/include/mcld/Config/Targets.def.in b/include/mcld/Config/Targets.def.in
new file mode 100644
index 0000000..a73b9b7
--- /dev/null
+++ b/include/mcld/Config/Targets.def.in
@@ -0,0 +1,28 @@
+/*===- llvm/Config/Targets.def - LLVM Target Architectures ------*- C++ -*-===*\
+|* *|
+|* The MCLinker Project *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* This file enumerates all of the target architectures supported by *|
+|* this build of LLVM. Clients of this file should define the *|
+|* LLVM_TARGET macro to be a function-like macro with a single *|
+|* parameter (the name of the target); including this file will then *|
+|* enumerate all of the targets. *|
+|* *|
+|* The set of targets supported by LLVM is generated at configuration *|
+|* time, at which point this header is generated. Do not modify this *|
+|* header directly. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef LLVM_TARGET
+# error Please define the macro LLVM_TARGET(TargetName)
+#endif
+
+@LLVM_ENUM_TARGETS@
+
+#undef LLVM_TARGET
diff --git a/include/mcld/LD/ArchiveReader.h b/include/mcld/LD/ArchiveReader.h
new file mode 100644
index 0000000..99db0db
--- /dev/null
+++ b/include/mcld/LD/ArchiveReader.h
@@ -0,0 +1,39 @@
+//===- ArchiveReader.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ARCHIVE_READER_INTERFACE_H
+#define MCLD_ARCHIVE_READER_INTERFACE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/LD/LDReader.h"
+
+namespace mcld
+{
+
+class Input;
+class InputTree;
+
+/** \class ArchiveReader
+ * \brief ArchiveReader provides an common interface for all archive readers.
+ *
+ * ArchiveReader also reads the target-independent parts of an archive file.
+ */
+class ArchiveReader : public LDReader
+{
+public:
+ ArchiveReader();
+ virtual ~ArchiveReader();
+
+ virtual InputTree *readArchive(Input &input) = 0;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/BSDArchiveReader.h b/include/mcld/LD/BSDArchiveReader.h
new file mode 100644
index 0000000..a275621
--- /dev/null
+++ b/include/mcld/LD/BSDArchiveReader.h
@@ -0,0 +1,39 @@
+//===- BSDArchiveReader.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_BSD_ARCHIVE_READER_H
+#define MCLD_BSD_ARCHIVE_READER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/LD/ArchiveReader.h"
+
+namespace mcld
+{
+
+class Input;
+class InputTree;
+
+/** \class BSDArchiveReader
+ * \brief BSDArchiveReader reads BSD-variant archive files.
+ *
+ */
+class BSDArchiveReader : public ArchiveReader
+{
+public:
+ BSDArchiveReader();
+ ~BSDArchiveReader();
+
+ InputTree *readArchive(Input &input);
+ bool isMyFormat(Input& pInput) const;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/BranchIsland.h b/include/mcld/LD/BranchIsland.h
new file mode 100644
index 0000000..8e5cf9c
--- /dev/null
+++ b/include/mcld/LD/BranchIsland.h
@@ -0,0 +1,30 @@
+//===- BranchIsland.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef BRANCHISLAND_H
+#define BRANCHISLAND_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+/** \class BranchIsland
+ * \brief BranchIsland is a collection of stubs
+ *
+ */
+class BranchIsland
+{
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/DynObjFileFormat.h b/include/mcld/LD/DynObjFileFormat.h
new file mode 100644
index 0000000..7b1626d
--- /dev/null
+++ b/include/mcld/LD/DynObjFileFormat.h
@@ -0,0 +1,29 @@
+//===- header.h -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef DYNOBJFORMAT_H
+#define DYNOBJFORMAT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+/** \class DynObjFormat
+ * \brief DynObjFormat describes the file format for dynamic objects.
+ */
+class DynObjFormat : public LDFileFormat
+{
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/DynObjReader.h b/include/mcld/LD/DynObjReader.h
new file mode 100644
index 0000000..0900109
--- /dev/null
+++ b/include/mcld/LD/DynObjReader.h
@@ -0,0 +1,45 @@
+//===- DynObjReader.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_DYNAMIC_SHARED_OBJECT_READER_H
+#define MCLD_DYNAMIC_SHARED_OBJECT_READER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/LD/LDReader.h"
+#include <llvm/Support/system_error.h>
+
+namespace mcld
+{
+
+class TargetLDBackend;
+class Input;
+
+/** \class DynObjReader
+ * \brief DynObjReader provides an common interface for different object
+ * formats.
+ */
+class DynObjReader : public LDReader
+{
+protected:
+ DynObjReader()
+ { }
+
+public:
+ virtual ~DynObjReader() { }
+
+ virtual bool readDSO(Input& pFile) = 0;
+
+ virtual bool readSymbols(Input& pFile) = 0;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/DynObjWriter.h b/include/mcld/LD/DynObjWriter.h
new file mode 100644
index 0000000..1c77bd4
--- /dev/null
+++ b/include/mcld/LD/DynObjWriter.h
@@ -0,0 +1,41 @@
+//===- DynObjWriter.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_DYNAMIC_SHARED_OBJECT_WRITER_H
+#define MCLD_DYNAMIC_SHARED_OBJECT_WRITER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/MC/MCLDOutput.h>
+#include <mcld/LD/LDWriter.h>
+#include <llvm/Support/system_error.h>
+
+namespace mcld
+{
+
+/** \class DynObjWriter
+ * \brief DynObjWriter provides an common interface for different object
+ * formats.
+ */
+class DynObjWriter : public LDWriter
+{
+protected:
+ // force to have a TargetLDBackend
+ DynObjWriter(TargetLDBackend& pLDBackend)
+ { }
+
+public:
+ virtual ~DynObjWriter() { }
+
+ virtual llvm::error_code writeDynObj(Output& pOutput) = 0;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFDynObjFileFormat.h b/include/mcld/LD/ELFDynObjFileFormat.h
new file mode 100644
index 0000000..9b77e91
--- /dev/null
+++ b/include/mcld/LD/ELFDynObjFileFormat.h
@@ -0,0 +1,38 @@
+//===- ELFDynObjFileFormat.h ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_DYNAMIC_OBJECT_FILE_FROMAT_H
+#define MCLD_ELF_DYNAMIC_OBJECT_FILE_FROMAT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/LD/ELFFileFormat.h>
+
+namespace mcld
+{
+
+class GNULDBackend;
+class MCLinker;
+
+/** \class ELFDynObjFileFormat
+ * \brief ELFDynObjFileFormat describes the format for ELF dynamic objects.
+ */
+class ELFDynObjFileFormat : public ELFFileFormat
+{
+public:
+ ELFDynObjFileFormat(GNULDBackend& pBackend) : ELFFileFormat(pBackend)
+ {}
+
+ void initObjectType(MCLinker& pLinker);
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFDynObjReader.h b/include/mcld/LD/ELFDynObjReader.h
new file mode 100644
index 0000000..72a3336
--- /dev/null
+++ b/include/mcld/LD/ELFDynObjReader.h
@@ -0,0 +1,51 @@
+//===- ELFDynObjReader.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_DYNAMIC_SHARED_OBJECT_READER_H
+#define MCLD_ELF_DYNAMIC_SHARED_OBJECT_READER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/LD/DynObjReader.h>
+#include <llvm/Support/system_error.h>
+
+namespace mcld
+{
+
+class Input;
+class MCLinker;
+class GNULDBackend;
+class ELFReaderIF;
+
+/** \class ELFDynObjReader
+ * \brief ELFDynObjReader reads ELF dynamic shared objects.
+ *
+ */
+class ELFDynObjReader : public DynObjReader
+{
+public:
+ ELFDynObjReader(GNULDBackend& pBackend, MCLinker& pLinker);
+ ~ELFDynObjReader();
+
+ // ----- observers ----- //
+ bool isMyFormat(Input &pFile) const;
+
+ // ----- readers ----- //
+ bool readDSO(Input& pFile);
+
+ bool readSymbols(Input& pInput);
+
+private:
+ ELFReaderIF *m_pELFReader;
+ MCLinker& m_Linker;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFDynObjWriter.h b/include/mcld/LD/ELFDynObjWriter.h
new file mode 100644
index 0000000..dc0e37b
--- /dev/null
+++ b/include/mcld/LD/ELFDynObjWriter.h
@@ -0,0 +1,53 @@
+//===- ELFDynObjWriter.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_DYNAMIC_SHARED_OBJECT_WRITER_H
+#define MCLD_ELF_DYNAMIC_SHARED_OBJECT_WRITER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/DenseMap.h>
+#include <llvm/Support/ELF.h>
+#include <mcld/LD/DynObjWriter.h>
+#include <mcld/LD/ELFWriter.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/Support/MemoryArea.h>
+#include <vector>
+#include <utility>
+
+
+namespace mcld
+{
+
+class GNULDBackend;
+class MCLinker;
+
+/** \class ELFDynObjWriter
+ * \brief ELFDynObjWriter writes the dynamic sections.
+ */
+class ELFDynObjWriter : public DynObjWriter, private ELFWriter
+{
+public:
+ typedef ELFWriter::FileOffset FileOffset;
+
+public:
+ ELFDynObjWriter(GNULDBackend& pBackend, MCLinker& pLinker);
+ ~ELFDynObjWriter();
+
+ llvm::error_code writeDynObj(Output& pOutput);
+
+private:
+ GNULDBackend& m_Backend;
+ MCLinker& m_Linker;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFExecFileFormat.h b/include/mcld/LD/ELFExecFileFormat.h
new file mode 100644
index 0000000..315300a
--- /dev/null
+++ b/include/mcld/LD/ELFExecFileFormat.h
@@ -0,0 +1,38 @@
+//===- ELFExecFileFormat.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_EXEC_FILE_FORMAT_H
+#define MCLD_ELF_EXEC_FILE_FORMAT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/LD/ELFFileFormat.h>
+
+namespace mcld
+{
+
+class GNULDBackend;
+class MCLinker;
+
+/** \class ELFExecFileFormat
+ * \brief ELFExecFileFormat describes the format for ELF dynamic objects.
+ */
+class ELFExecFileFormat : public ELFFileFormat
+{
+public:
+ ELFExecFileFormat(GNULDBackend& pBackend) : ELFFileFormat(pBackend)
+ {}
+
+ void initObjectType(MCLinker& pLinker)
+ { /** TODO **/ }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFFileFormat.h b/include/mcld/LD/ELFFileFormat.h
new file mode 100644
index 0000000..94d3df3
--- /dev/null
+++ b/include/mcld/LD/ELFFileFormat.h
@@ -0,0 +1,654 @@
+//===- LDFileFormat.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_FILE_FORMAT_H
+#define MCLD_ELF_FILE_FORMAT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/LD/LDSection.h>
+
+namespace mcld
+{
+
+class GNULDBackend;
+class MCLinker;
+
+/** \class ELFFileFormat
+ * \brief ELFFileFormat describes the common file formats in ELF.
+ * LDFileFormats control the formats of the output file.
+ *
+ * @ref "Object Files," Ch. 4, in System V Application Binary Interface,
+ * Fourth Edition.
+ *
+ * @ref "Object Format," Ch. 10, in ISO/IEC 23360 Part 1:2010(E), Linux
+ * Standard Base Core Specification 4.1.
+ */
+class ELFFileFormat : public LDFileFormat
+{
+public:
+ ELFFileFormat(GNULDBackend& pBackend);
+
+ virtual ~ELFFileFormat();
+
+ virtual void initObjectFormat(MCLinker& pLinker);
+
+ virtual void initObjectType(MCLinker& pLinker) = 0;
+
+ // ----- capacity ----- //
+ /// @ref Special Sections, Ch. 4.17, System V ABI, 4th edition.
+ bool hasNULLSection() const
+ { return (NULL != f_pNULLSection) && (0 != f_pNULLSection->size()); }
+
+ bool hasGOT() const
+ { return (NULL != f_pGOT) && (0 != f_pGOT->size()); }
+
+ bool hasPLT() const
+ { return (NULL != f_pPLT) && (0 != f_pPLT->size()); }
+
+ bool hasRelDyn() const
+ { return (NULL != f_pRelDyn) && (0 != f_pRelDyn->size()); }
+
+ bool hasRelPlt() const
+ { return (NULL != f_pRelPlt) && (0 != f_pRelPlt->size()); }
+
+ bool hasRelaDyn() const
+ { return (NULL != f_pRelaDyn) && (0 != f_pRelaDyn->size()); }
+
+ bool hasRelaPlt() const
+ { return (NULL != f_pRelaPlt) && (0 != f_pRelaPlt->size()); }
+
+ /// @ref 10.3.1.1, ISO/IEC 23360, Part 1:2010(E), p. 21.
+ bool hasComment() const
+ { return (NULL != f_pComment) && (0 != f_pComment->size()); }
+
+ bool hasData1() const
+ { return (NULL != f_pData1) && (0 != f_pData1->size()); }
+
+ bool hasDebug() const
+ { return (NULL != f_pDebug) && (0 != f_pDebug->size()); }
+
+ bool hasDynamic() const
+ { return (NULL != f_pDynamic) && (0 != f_pDynamic->size()); }
+
+ bool hasDynStrTab() const
+ { return (NULL != f_pDynStrTab) && (0 != f_pDynStrTab->size()); }
+
+ bool hasDynSymTab() const
+ { return (NULL != f_pDynSymTab) && (0 != f_pDynSymTab->size()); }
+
+ bool hasFini() const
+ { return (NULL != f_pFini) && (0 != f_pFini->size()); }
+
+ bool hasFiniArray() const
+ { return (NULL != f_pFiniArray) && (0 != f_pFiniArray->size()); }
+
+ bool hasHashTab() const
+ { return (NULL != f_pHashTab) && (0 != f_pHashTab->size()); }
+
+ bool hasInit() const
+ { return (NULL != f_pInit) && (0 != f_pInit->size()); }
+
+ bool hasInitArray() const
+ { return (NULL != f_pInitArray) && (0 != f_pInitArray->size()); }
+
+ bool hasInterp() const
+ { return (NULL != f_pInterp) && (0 != f_pInterp->size()); }
+
+ bool hasLine() const
+ { return (NULL != f_pLine) && (0 != f_pLine->size()); }
+
+ bool hasNote() const
+ { return (NULL != f_pNote) && (0 != f_pNote->size()); }
+
+ bool hasPreInitArray() const
+ { return (NULL != f_pPreInitArray) && (0 != f_pPreInitArray->size()); }
+
+ bool hasROData1() const
+ { return (NULL != f_pROData1) && (0 != f_pROData1->size()); }
+
+ bool hasShStrTab() const
+ { return (NULL != f_pShStrTab) && (0 != f_pShStrTab->size()); }
+
+ bool hasStrTab() const
+ { return (NULL != f_pStrTab) && (0 != f_pStrTab->size()); }
+
+ bool hasSymTab() const
+ { return (NULL != f_pSymTab) && (0 != f_pSymTab->size()); }
+
+ bool hasTBSS() const
+ { return (NULL != f_pTBSS) && (0 != f_pTBSS->size()); }
+
+ bool hasTData() const
+ { return (NULL != f_pTData) && (0 != f_pTData->size()); }
+
+ /// @ref 10.3.1.2, ISO/IEC 23360, Part 1:2010(E), p. 24.
+ bool hasCtors() const
+ { return (NULL != f_pCtors) && (0 != f_pCtors->size()); }
+
+ bool hasDataRelRo() const
+ { return (NULL != f_pDataRelRo) && (0 != f_pDataRelRo->size()); }
+
+ bool hasDtors() const
+ { return (NULL != f_pDtors) && (0 != f_pDtors->size()); }
+
+ bool hasEhFrame() const
+ { return (NULL != f_pEhFrame) && (0 != f_pEhFrame->size()); }
+
+ bool hasEhFrameHdr() const
+ { return (NULL != f_pEhFrameHdr) && (0 != f_pEhFrameHdr->size()); }
+
+ bool hasGCCExceptTable() const
+ { return (NULL != f_pGCCExceptTable) && (0 != f_pGCCExceptTable->size()); }
+
+ bool hasGNUVersion() const
+ { return (NULL != f_pGNUVersion) && (0 != f_pGNUVersion->size()); }
+
+ bool hasGNUVersionD() const
+ { return (NULL != f_pGNUVersionD) && (0 != f_pGNUVersionD->size()); }
+
+ bool hasGNUVersionR() const
+ { return (NULL != f_pGNUVersionR) && (0 != f_pGNUVersionR->size()); }
+
+ bool hasGOTPLT() const
+ { return (NULL != f_pGOTPLT) && (0 != f_pGOTPLT->size()); }
+
+ bool hasJCR() const
+ { return (NULL != f_pJCR) && (0 != f_pJCR->size()); }
+
+ bool hasNoteABITag() const
+ { return (NULL != f_pNoteABITag) && (0 != f_pNoteABITag->size()); }
+
+ bool hasStab() const
+ { return (NULL != f_pStab) && (0 != f_pStab->size()); }
+
+ bool hasStabStr() const
+ { return (NULL != f_pStabStr) && (0 != f_pStabStr->size()); }
+
+ // ----- access functions ----- //
+ /// @ref Special Sections, Ch. 4.17, System V ABI, 4th edition.
+ LDSection& getNULLSection() {
+ assert(NULL != f_pNULLSection);
+ return *f_pNULLSection;
+ }
+
+ const LDSection& getNULLSection() const {
+ assert(NULL != f_pNULLSection);
+ return *f_pNULLSection;
+ }
+
+ LDSection& getGOT() {
+ assert(NULL != f_pGOT);
+ return *f_pGOT;
+ }
+
+ const LDSection& getGOT() const {
+ assert(NULL != f_pGOT);
+ return *f_pGOT;
+ }
+
+ LDSection& getPLT() {
+ assert(NULL != f_pPLT);
+ return *f_pPLT;
+ }
+
+ const LDSection& getPLT() const {
+ assert(NULL != f_pPLT);
+ return *f_pPLT;
+ }
+
+ LDSection& getRelDyn() {
+ assert(NULL != f_pRelDyn);
+ return *f_pRelDyn;
+ }
+
+ const LDSection& getRelDyn() const {
+ assert(NULL != f_pRelDyn);
+ return *f_pRelDyn;
+ }
+
+ LDSection& getRelPlt() {
+ assert(NULL != f_pRelPlt);
+ return *f_pRelPlt;
+ }
+
+ const LDSection& getRelPlt() const {
+ assert(NULL != f_pRelPlt);
+ return *f_pRelPlt;
+ }
+
+ LDSection& getRelaDyn() {
+ assert(NULL != f_pRelaDyn);
+ return *f_pRelaDyn;
+ }
+
+ const LDSection& getRelaDyn() const {
+ assert(NULL != f_pRelaDyn);
+ return *f_pRelaDyn;
+ }
+
+ LDSection& getRelaPlt() {
+ assert(NULL != f_pRelaPlt);
+ return *f_pRelaPlt;
+ }
+
+ const LDSection& getRelaPlt() const {
+ assert(NULL != f_pRelaPlt);
+ return *f_pRelaPlt;
+ }
+
+ LDSection& getComment() {
+ assert(NULL != f_pComment);
+ return *f_pComment;
+ }
+
+ /// @ref 10.3.1.1, ISO/IEC 23360, Part 1:2010(E), p. 21.
+ const LDSection& getComment() const {
+ assert(NULL != f_pComment);
+ return *f_pComment;
+ }
+
+ LDSection& getData1() {
+ assert(NULL != f_pData1);
+ return *f_pData1;
+ }
+
+ const LDSection& getData1() const {
+ assert(NULL != f_pData1);
+ return *f_pData1;
+ }
+
+ LDSection& getDebug() {
+ assert(NULL != f_pDebug);
+ return *f_pDebug;
+ }
+
+ const LDSection& getDebug() const {
+ assert(NULL != f_pDebug);
+ return *f_pDebug;
+ }
+
+ LDSection& getDynamic() {
+ assert(NULL != f_pDynamic);
+ return *f_pDynamic;
+ }
+
+ const LDSection& getDynamic() const {
+ assert(NULL != f_pDynamic);
+ return *f_pDynamic;
+ }
+
+ LDSection& getDynStrTab() {
+ assert(NULL != f_pDynStrTab);
+ return *f_pDynStrTab;
+ }
+
+ const LDSection& getDynStrTab() const {
+ assert(NULL != f_pDynStrTab);
+ return *f_pDynStrTab;
+ }
+
+ LDSection& getDynSymTab() {
+ assert(NULL != f_pDynSymTab);
+ return *f_pDynSymTab;
+ }
+
+ const LDSection& getDynSymTab() const {
+ assert(NULL != f_pDynSymTab);
+ return *f_pDynSymTab;
+ }
+
+ LDSection& getFini() {
+ assert(NULL != f_pFini);
+ return *f_pFini;
+ }
+
+ const LDSection& getFini() const {
+ assert(NULL != f_pFini);
+ return *f_pFini;
+ }
+
+ LDSection& getFiniArray() {
+ assert(NULL != f_pFiniArray);
+ return *f_pFiniArray;
+ }
+
+ const LDSection& getFiniArray() const {
+ assert(NULL != f_pFiniArray);
+ return *f_pFiniArray;
+ }
+
+ LDSection& getHashTab() {
+ assert(NULL != f_pHashTab);
+ return *f_pHashTab;
+ }
+
+ const LDSection& getHashTab() const {
+ assert(NULL != f_pHashTab);
+ return *f_pHashTab;
+ }
+
+ LDSection& getInit() {
+ assert(NULL != f_pInit);
+ return *f_pInit;
+ }
+
+ const LDSection& getInit() const {
+ assert(NULL != f_pInit);
+ return *f_pInit;
+ }
+
+ LDSection& getInitArray() {
+ assert(NULL != f_pInitArray);
+ return *f_pInitArray;
+ }
+
+ const LDSection& getInitArray() const {
+ assert(NULL != f_pInitArray);
+ return *f_pInitArray;
+ }
+
+ LDSection& getInterp() {
+ assert(NULL != f_pInterp);
+ return *f_pInterp;
+ }
+
+ const LDSection& getInterp() const {
+ assert(NULL != f_pInterp);
+ return *f_pInterp;
+ }
+
+ LDSection& getLine() {
+ assert(NULL != f_pLine);
+ return *f_pLine;
+ }
+
+ const LDSection& getLine() const {
+ assert(NULL != f_pLine);
+ return *f_pLine;
+ }
+
+ LDSection& getNote() {
+ assert(NULL != f_pNote);
+ return *f_pNote;
+ }
+
+ const LDSection& getNote() const {
+ assert(NULL != f_pNote);
+ return *f_pNote;
+ }
+
+ LDSection& getPreInitArray() {
+ assert(NULL != f_pPreInitArray);
+ return *f_pPreInitArray;
+ }
+
+ const LDSection& getPreInitArray() const {
+ assert(NULL != f_pPreInitArray);
+ return *f_pPreInitArray;
+ }
+
+ LDSection& getROData1() {
+ assert(NULL != f_pROData1);
+ return *f_pROData1;
+ }
+
+ const LDSection& getROData1() const {
+ assert(NULL != f_pROData1);
+ return *f_pROData1;
+ }
+
+ LDSection& getShStrTab() {
+ assert(NULL != f_pShStrTab);
+ return *f_pShStrTab;
+ }
+
+ const LDSection& getShStrTab() const {
+ assert(NULL != f_pShStrTab);
+ return *f_pShStrTab;
+ }
+
+ LDSection& getStrTab() {
+ assert(NULL != f_pStrTab);
+ return *f_pStrTab;
+ }
+
+ const LDSection& getStrTab() const {
+ assert(NULL != f_pStrTab);
+ return *f_pStrTab;
+ }
+
+ LDSection& getSymTab() {
+ assert(NULL != f_pSymTab);
+ return *f_pSymTab;
+ }
+
+ const LDSection& getSymTab() const {
+ assert(NULL != f_pSymTab);
+ return *f_pSymTab;
+ }
+
+ LDSection& getTBSS() {
+ assert(NULL != f_pTBSS);
+ return *f_pTBSS;
+ }
+
+ const LDSection& getTBSS() const {
+ assert(NULL != f_pTBSS);
+ return *f_pTBSS;
+ }
+
+ LDSection& getTData() {
+ assert(NULL != f_pTData);
+ return *f_pTData;
+ }
+
+ const LDSection& getTData() const {
+ assert(NULL != f_pTData);
+ return *f_pTData;
+ }
+
+ /// @ref 10.3.1.2, ISO/IEC 23360, Part 1:2010(E), p. 24.
+ LDSection& getCtors() {
+ assert(NULL != f_pCtors);
+ return *f_pCtors;
+ }
+
+ const LDSection& getCtors() const {
+ assert(NULL != f_pCtors);
+ return *f_pCtors;
+ }
+
+ LDSection& getDataRelRo() {
+ assert(NULL != f_pDataRelRo);
+ return *f_pDataRelRo;
+ }
+
+ const LDSection& getDataRelRo() const {
+ assert(NULL != f_pDataRelRo);
+ return *f_pDataRelRo;
+ }
+
+ LDSection& getDtors() {
+ assert(NULL != f_pDtors);
+ return *f_pDtors;
+ }
+
+ const LDSection& getDtors() const {
+ assert(NULL != f_pDtors);
+ return *f_pDtors;
+ }
+
+ LDSection& getEhFrame() {
+ assert(NULL != f_pEhFrame);
+ return *f_pEhFrame;
+ }
+
+ const LDSection& getEhFrame() const {
+ assert(NULL != f_pEhFrame);
+ return *f_pEhFrame;
+ }
+
+ LDSection& getEhFrameHdr() {
+ assert(NULL != f_pEhFrameHdr);
+ return *f_pEhFrameHdr;
+ }
+
+ const LDSection& getEhFrameHdr() const {
+ assert(NULL != f_pEhFrameHdr);
+ return *f_pEhFrameHdr;
+ }
+
+ LDSection& getGCCExceptTable() {
+ assert(NULL != f_pGCCExceptTable);
+ return *f_pGCCExceptTable;
+ }
+
+ const LDSection& getGCCExceptTable() const {
+ assert(NULL != f_pGCCExceptTable);
+ return *f_pGCCExceptTable;
+ }
+
+ LDSection& getGNUVersion() {
+ assert(NULL != f_pGNUVersion);
+ return *f_pGNUVersion;
+ }
+
+ const LDSection& getGNUVersion() const {
+ assert(NULL != f_pGNUVersion);
+ return *f_pGNUVersion;
+ }
+
+ LDSection& getGNUVersionD() {
+ assert(NULL != f_pGNUVersionD);
+ return *f_pGNUVersionD;
+ }
+
+ const LDSection& getGNUVersionD() const {
+ assert(NULL != f_pGNUVersionD);
+ return *f_pGNUVersionD;
+ }
+
+ LDSection& getGNUVersionR() {
+ assert(NULL != f_pGNUVersionR);
+ return *f_pGNUVersionR;
+ }
+
+ const LDSection& getGNUVersionR() const {
+ assert(NULL != f_pGNUVersionR);
+ return *f_pGNUVersionR;
+ }
+
+ LDSection& getGOTPLT() {
+ assert(NULL != f_pGOTPLT);
+ return *f_pGOTPLT;
+ }
+
+ const LDSection& getGOTPLT() const {
+ assert(NULL != f_pGOTPLT);
+ return *f_pGOTPLT;
+ }
+
+ LDSection& getJCR() {
+ assert(NULL != f_pJCR);
+ return *f_pJCR;
+ }
+
+ const LDSection& getJCR() const {
+ assert(NULL != f_pJCR);
+ return *f_pJCR;
+ }
+
+ LDSection& getNoteABITag() {
+ assert(NULL != f_pNoteABITag);
+ return *f_pNoteABITag;
+ }
+
+ const LDSection& getNoteABITag() const {
+ assert(NULL != f_pNoteABITag);
+ return *f_pNoteABITag;
+ }
+
+ LDSection& getStab() {
+ assert(NULL != f_pStab);
+ return *f_pStab;
+ }
+
+ const LDSection& getStab() const {
+ assert(NULL != f_pStab);
+ return *f_pStab;
+ }
+
+ LDSection& getStabStr() {
+ assert(NULL != f_pStabStr);
+ return *f_pStabStr;
+ }
+
+ const LDSection& getStabStr() const {
+ assert(NULL != f_pStabStr);
+ return *f_pStabStr;
+ }
+
+protected:
+ GNULDBackend& f_Backend;
+
+ // variable name : ELF
+ /// @ref Special Sections, Ch. 4.17, System V ABI, 4th edition.
+ LDSection* f_pNULLSection;
+ LDSection* f_pGOT; // .got
+ LDSection* f_pPLT; // .plt
+ LDSection* f_pRelDyn; // .rel.dyn
+ LDSection* f_pRelPlt; // .rel.plt
+ LDSection* f_pRelaDyn; // .rela.dyn
+ LDSection* f_pRelaPlt; // .rela.plt
+
+ /// @ref 10.3.1.1, ISO/IEC 23360, Part 1:2010(E), p. 21.
+ LDSection* f_pComment; // .comment
+ LDSection* f_pData1; // .data1
+ LDSection* f_pDebug; // .debug
+ LDSection* f_pDynamic; // .dynamic
+ LDSection* f_pDynStrTab; // .dynstr
+ LDSection* f_pDynSymTab; // .dynsym
+ LDSection* f_pFini; // .fini
+ LDSection* f_pFiniArray; // .fini_array
+ LDSection* f_pHashTab; // .hash
+ LDSection* f_pInit; // .init
+ LDSection* f_pInitArray; // .init_array
+ LDSection* f_pInterp; // .interp
+ LDSection* f_pLine; // .line
+ LDSection* f_pNote; // .note
+ LDSection* f_pPreInitArray; // .preinit_array
+ LDSection* f_pROData1; // .rodata1
+ LDSection* f_pShStrTab; // .shstrtab
+ LDSection* f_pStrTab; // .strtab
+ LDSection* f_pSymTab; // .symtab
+ LDSection* f_pTBSS; // .tbss
+ LDSection* f_pTData; // .tdata
+
+ /// @ref 10.3.1.2, ISO/IEC 23360, Part 1:2010(E), p. 24.
+ LDSection* f_pCtors; // .ctors
+ LDSection* f_pDataRelRo; // .data.rel.ro
+ LDSection* f_pDtors; // .dtors
+ LDSection* f_pEhFrame; // .eh_frame
+ LDSection* f_pEhFrameHdr; // .eh_frame_hdr
+ LDSection* f_pGCCExceptTable; // .gcc_except_table
+ LDSection* f_pGNUVersion; // .gnu.version
+ LDSection* f_pGNUVersionD; // .gnu.version_d
+ LDSection* f_pGNUVersionR; // .gnu.version_r
+ LDSection* f_pGOTPLT; // .got.plt
+ LDSection* f_pJCR; // .jcr
+ LDSection* f_pNoteABITag; // .note.ABI-tag
+ LDSection* f_pStab; // .stab
+ LDSection* f_pStabStr; // .stabstr
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFObjectReader.h b/include/mcld/LD/ELFObjectReader.h
new file mode 100644
index 0000000..ac11261
--- /dev/null
+++ b/include/mcld/LD/ELFObjectReader.h
@@ -0,0 +1,59 @@
+//===- ELFObjectReader.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_OBJECT_READER_H
+#define MCLD_ELF_OBJECT_READER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/ObjectReader.h>
+#include <llvm/Support/system_error.h>
+
+namespace mcld
+{
+
+class Input;
+class MCLinker;
+class GNULDBackend;
+class ELFReaderIF;
+
+/** \lclass ELFObjectReader
+ * \brief ELFObjectReader reads target-independent parts of ELF object file
+ */
+class ELFObjectReader : public ObjectReader
+{
+public:
+ ELFObjectReader(GNULDBackend& pBackend, MCLinker& pLinker);
+
+ ~ELFObjectReader();
+
+ // ----- observers ----- //
+ bool isMyFormat(Input &pFile) const;
+
+ // ----- readers ----- //
+ bool readObject(Input& pFile);
+
+ virtual bool readSections(Input& pFile);
+
+ virtual bool readSymbols(Input& pFile);
+
+ /// readRelocations - read relocation sections
+ ///
+ /// This function should be called after symbol resolution.
+ virtual bool readRelocations(Input& pFile);
+
+private:
+ ELFReaderIF* m_pELFReader;
+ MCLinker& m_Linker;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFObjectWriter.h b/include/mcld/LD/ELFObjectWriter.h
new file mode 100644
index 0000000..a6b9a87
--- /dev/null
+++ b/include/mcld/LD/ELFObjectWriter.h
@@ -0,0 +1,47 @@
+//===- ELFObjectWriter.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_OBJECT_WRITER_H
+#define MCLD_ELF_OBJECT_WRITER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/Support/system_error.h>
+#include <mcld/LD/ObjectWriter.h>
+#include <mcld/LD/ELFWriter.h>
+
+namespace mcld
+{
+
+class Input;
+class MCLinker;
+class GNULDBackend;
+
+/** \class ELFObjectWriter
+ * \brief ELFObjectWriter writes the target-independent parts of object files.
+ * ELFObjectWriter reads a MCLDFile and writes into raw_ostream
+ *
+ */
+class ELFObjectWriter : public ObjectWriter, protected ELFWriter
+{
+public:
+ ELFObjectWriter(GNULDBackend& pBackend, MCLinker& pLinker);
+
+ ~ELFObjectWriter();
+
+ llvm::error_code writeObject(Output& pOutput)
+ { return llvm::make_error_code(llvm::errc::not_supported); }
+
+private:
+ MCLinker& m_Linker;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFReader.h b/include/mcld/LD/ELFReader.h
new file mode 100644
index 0000000..cac0175
--- /dev/null
+++ b/include/mcld/LD/ELFReader.h
@@ -0,0 +1,224 @@
+//===- ELFReader.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_READER_INTERFACE_H
+#define MCLD_ELF_READER_INTERFACE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/Host.h>
+#include <llvm/MC/MCAssembler.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/MC/MCRegionFragment.h>
+#include <mcld/LD/ResolveInfo.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/Support/MemoryRegion.h>
+
+namespace mcld
+{
+
+/** \class ELFReaderIF
+ * \brief ELFReaderIF provides common interface for all kind of ELF readers.
+ */
+class ELFReaderIF
+{
+public:
+ ELFReaderIF(GNULDBackend& pBackend)
+ : m_Backend(pBackend)
+ { }
+
+ virtual ~ELFReaderIF() { }
+
+ /// ELFHeaderSize - return the size of the ELFHeader
+ virtual size_t getELFHeaderSize() const = 0;
+
+ /// isELF - is this a ELF file
+ virtual bool isELF(void* pELFHeader) const = 0;
+
+ /// isMyEndian - is this ELF file in the same endian to me?
+ virtual bool isMyEndian(void* pELFHeader) const = 0;
+
+ /// isMyMachine - is this ELF file generated for the same machine.
+ virtual bool isMyMachine(void* pELFHeader) const = 0;
+
+ /// fileType - the file type of this file
+ virtual MCLDFile::Type fileType(void* pELFHeader) const = 0;
+
+ /// target - the target backend
+ GNULDBackend& target()
+ { return m_Backend; }
+
+ /// target - the target backend
+ const GNULDBackend& target() const
+ { return m_Backend; }
+
+ /// readSectionHeaders - read ELF section header table and create LDSections
+ virtual bool readSectionHeaders(Input& pInput,
+ MCLinker& pLinker,
+ void* pELFHeader) const = 0;
+
+ /// readRegularSection - read a regular section and create fragments.
+ virtual bool readRegularSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSectHdr) const = 0;
+
+ /// readRegularSection - read a target section and create fragments.
+ virtual bool readTargetSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSectHdr) = 0;
+
+ /// readSymbols - read ELF symbols and create LDSymbol
+ virtual bool readSymbols(Input& pInput,
+ MCLinker& pLinker,
+ const MemoryRegion& pRegion,
+ const char* StrTab) const = 0;
+
+ /// readSymbol - read a symbol from the given Input and index in symtab
+ virtual ResolveInfo* readSymbol(Input& pInput,
+ LDSection& pSymTab,
+ MCLDInfo& pLDInfo,
+ uint32_t pSymIdx) const = 0;
+
+ /// readRela - read ELF rela and create Relocation
+ virtual bool readRela(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const = 0;
+
+ /// readRel - read ELF rel and create Relocation
+ virtual bool readRel(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const = 0;
+protected:
+ /// LinkInfo - some section needs sh_link and sh_info, remember them.
+ struct LinkInfo {
+ LDSection* section;
+ uint32_t sh_link;
+ uint32_t sh_info;
+ };
+
+ typedef std::vector<LinkInfo> LinkInfoList;
+
+protected:
+ LDFileFormat::Kind getLDSectionKind(uint32_t pType, const char* pName) const;
+
+ ResolveInfo::Desc getSymDesc(uint16_t pShndx, const Input& pInput) const;
+
+ ResolveInfo::Binding getSymBinding(uint8_t pBinding,
+ uint16_t pShndx,
+ uint8_t pVisibility) const;
+
+ uint64_t getSymValue(uint64_t pValue,
+ uint16_t pShndx,
+ const Input& pInput) const;
+
+ MCFragmentRef* getSymFragmentRef(Input& pInput,
+ MCLinker& pLinker,
+ uint16_t pShndx,
+ uint32_t pOffset) const;
+
+ ResolveInfo::Visibility getSymVisibility(uint8_t pVis) const;
+
+private:
+ GNULDBackend& m_Backend;
+};
+
+/** \class ELFReader
+ * \brief ELFReader is a template scaffolding for partial specification.
+ */
+template<size_t BIT, bool LITTLEENDIAN>
+class ELFReader
+{ };
+
+/** \class ELFReader<32, true>
+ * \brief ELFReader<32, true> is a 32-bit, little endian ELFReader.
+ */
+template<>
+class ELFReader<32, true> : public ELFReaderIF
+{
+public:
+ typedef llvm::ELF::Elf32_Ehdr ELFHeader;
+ typedef llvm::ELF::Elf32_Shdr SectionHeader;
+ typedef llvm::ELF::Elf32_Sym Symbol;
+ typedef llvm::ELF::Elf32_Rel Rel;
+ typedef llvm::ELF::Elf32_Rela Rela;
+
+public:
+ inline ELFReader(GNULDBackend& pBackend);
+
+ inline ~ELFReader();
+
+ /// ELFHeaderSize - return the size of the ELFHeader
+ inline size_t getELFHeaderSize() const
+ { return sizeof(ELFHeader); }
+
+ /// isELF - is this a ELF file
+ inline bool isELF(void* pELFHeader) const;
+
+ /// isMyEndian - is this ELF file in the same endian to me?
+ inline bool isMyEndian(void* pELFHeader) const;
+
+ /// isMyMachine - is this ELF file generated for the same machine.
+ inline bool isMyMachine(void* pELFHeader) const;
+
+ /// fileType - the file type of this file
+ inline MCLDFile::Type fileType(void* pELFHeader) const;
+
+ /// readSectionHeaders - read ELF section header table and create LDSections
+ inline bool readSectionHeaders(Input& pInput,
+ MCLinker& pLinker,
+ void* pELFHeader) const;
+
+ /// readRegularSection - read a regular section and create fragments.
+ inline bool readRegularSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr) const;
+
+ /// readRegularSection - read a target section and create fragments.
+ inline bool readTargetSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr);
+
+ /// readSymbols - read ELF symbols and create LDSymbol
+ inline bool readSymbols(Input& pInput,
+ MCLinker& pLinker,
+ const MemoryRegion& pRegion,
+ const char* StrTab) const;
+
+ /// readSymbol - read a symbol from the given Input and index in symtab
+ inline ResolveInfo* readSymbol(Input& pInput,
+ LDSection& pSymTab,
+ MCLDInfo& pLDInfo,
+ uint32_t pSymIdx) const;
+
+ /// readRela - read ELF rela and create Relocation
+ inline bool readRela(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const;
+
+ /// readRel - read ELF rel and create Relocation
+ inline bool readRel(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const;
+};
+
+#include "ELFReader.tcc"
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFReader.tcc b/include/mcld/LD/ELFReader.tcc
new file mode 100644
index 0000000..693a780
--- /dev/null
+++ b/include/mcld/LD/ELFReader.tcc
@@ -0,0 +1,532 @@
+//===- ELFReader.tcc ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is the template implemenation of ELFReaders
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// ELFReader<32, true>
+#include <cstring>
+#include <vector>
+
+/// constructor
+ELFReader<32, true>::ELFReader(GNULDBackend& pBackend)
+ : ELFReaderIF(pBackend) {
+}
+
+/// destructor
+ELFReader<32, true>::~ELFReader()
+{
+}
+
+/// isELF - is this a ELF file
+bool ELFReader<32, true>::isELF(void* pELFHeader) const
+{
+ llvm::ELF::Elf32_Ehdr* hdr =
+ reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(pELFHeader);
+ if (0 == memcmp(llvm::ELF::ElfMagic, hdr, 4))
+ return true;
+ return false;
+}
+
+/// isMyEndian - is this ELF file in the same endian to me?
+bool ELFReader<32, true>::isMyEndian(void* pELFHeader) const
+{
+ llvm::ELF::Elf32_Ehdr* hdr =
+ reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(pELFHeader);
+
+ return (hdr->e_ident[llvm::ELF::EI_DATA] == llvm::ELF::ELFDATA2LSB);
+}
+
+/// isMyMachine - is this ELF file generated for the same machine.
+bool ELFReader<32, true>::isMyMachine(void* pELFHeader) const
+{
+ llvm::ELF::Elf32_Ehdr* hdr =
+ reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(pELFHeader);
+
+ if (llvm::sys::isLittleEndianHost())
+ return (hdr->e_machine == target().machine());
+ return (bswap16(hdr->e_machine) == target().machine());
+}
+
+/// fileType - return the file type
+MCLDFile::Type ELFReader<32, true>::fileType(void* pELFHeader) const
+{
+ llvm::ELF::Elf32_Ehdr* hdr =
+ reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(pELFHeader);
+ uint32_t type = 0x0;
+ if (llvm::sys::isLittleEndianHost())
+ type = hdr->e_type;
+ else
+ type = bswap16(hdr->e_type);
+
+ switch(type) {
+ case llvm::ELF::ET_REL:
+ return MCLDFile::Object;
+ case llvm::ELF::ET_EXEC:
+ return MCLDFile::Exec;
+ case llvm::ELF::ET_DYN:
+ return MCLDFile::DynObj;
+ case llvm::ELF::ET_CORE:
+ return MCLDFile::CoreFile;
+ case llvm::ELF::ET_NONE:
+ default:
+ return MCLDFile::Unknown;
+ }
+}
+
+/// readSectionHeaders - read ELF section header table and create LDSections
+bool ELFReader<32, true>::readSectionHeaders(Input& pInput,
+ MCLinker& pLinker,
+ void* pELFHeader) const
+{
+ llvm::ELF::Elf32_Ehdr* ehdr =
+ reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(pELFHeader);
+
+ uint32_t shoff = 0x0;
+ uint16_t shentsize = 0x0;
+ uint16_t shnum = 0x0;
+ uint16_t shstrtab = 0x0;
+
+ if (llvm::sys::isLittleEndianHost()) {
+ shoff = ehdr->e_shoff;
+ shentsize = ehdr->e_shentsize;
+ shnum = ehdr->e_shnum;
+ shstrtab = ehdr->e_shstrndx;
+ }
+ else {
+ shoff = bswap32(ehdr->e_shoff);
+ shentsize = bswap16(ehdr->e_shentsize);
+ shnum = bswap16(ehdr->e_shnum);
+ shstrtab = bswap16(ehdr->e_shstrndx);
+ }
+
+ // If the file has no section header table, e_shoff holds zero.
+ if (0x0 == shoff)
+ return true;
+
+ MemoryRegion* shdr_region = pInput.memArea()->request(shoff, shnum*shentsize);
+ llvm::ELF::Elf32_Shdr* shdrTab =
+ reinterpret_cast<llvm::ELF::Elf32_Shdr*>(shdr_region->start());
+
+ uint32_t sh_name = 0x0;
+ uint32_t sh_type = 0x0;
+ uint32_t sh_flags = 0x0;
+ uint32_t sh_offset = 0x0;
+ uint32_t sh_size = 0x0;
+ uint32_t sh_link = 0x0;
+ uint32_t sh_info = 0x0;
+ uint32_t sh_addralign = 0x0;
+
+ // get .shstrtab first
+ llvm::ELF::Elf32_Shdr* shdr = &shdrTab[shstrtab];
+ if (llvm::sys::isLittleEndianHost()) {
+ sh_offset = shdr->sh_offset;
+ sh_size = shdr->sh_size;
+ }
+ else {
+ sh_offset = bswap32(shdr->sh_offset);
+ sh_size = bswap32(shdr->sh_size);
+ }
+
+ MemoryRegion* sect_name_region = pInput.memArea()->request(sh_offset, sh_size);
+ const char* sect_name = reinterpret_cast<const char*>(sect_name_region->start());
+
+ LinkInfoList link_info_list;
+
+ // create all LDSections
+ for (size_t idx = 0; idx < shnum; ++idx) {
+ if (llvm::sys::isLittleEndianHost()) {
+ sh_name = shdrTab[idx].sh_name;
+ sh_type = shdrTab[idx].sh_type;
+ sh_flags = shdrTab[idx].sh_flags;
+ sh_offset = shdrTab[idx].sh_offset;
+ sh_size = shdrTab[idx].sh_size;
+ sh_link = shdrTab[idx].sh_link;
+ sh_info = shdrTab[idx].sh_info;
+ sh_addralign = shdrTab[idx].sh_addralign;
+ }
+ else {
+ sh_name = bswap32(shdrTab[idx].sh_name);
+ sh_type = bswap32(shdrTab[idx].sh_type);
+ sh_flags = bswap32(shdrTab[idx].sh_flags);
+ sh_offset = bswap32(shdrTab[idx].sh_offset);
+ sh_size = bswap32(shdrTab[idx].sh_size);
+ sh_link = bswap32(shdrTab[idx].sh_link);
+ sh_info = bswap32(shdrTab[idx].sh_info);
+ sh_addralign = bswap32(shdrTab[idx].sh_addralign);
+ }
+
+ LDFileFormat::Kind kind = getLDSectionKind(sh_type,
+ sect_name+sh_name);
+
+ LDSection& section = pLinker.createSectHdr(sect_name+sh_name,
+ kind,
+ sh_type,
+ sh_flags);
+
+ section.setSize(sh_size);
+ section.setOffset(sh_offset);
+ section.setIndex(pInput.context()->numOfSections());
+ section.setInfo(sh_info);
+ section.setAlign(sh_addralign);
+
+ if (sh_link != 0x0 || sh_info != 0x0) {
+ LinkInfo link_info = { §ion, sh_link, sh_info };
+ link_info_list.push_back(link_info);
+ }
+
+ pInput.context()->getSectionTable().push_back(§ion);
+ } // end of for
+
+ // set up InfoLink
+ LinkInfoList::iterator info, infoEnd = link_info_list.end();
+ for (info = link_info_list.begin(); info != infoEnd; ++info) {
+ if (LDFileFormat::NamePool == info->section->kind() ||
+ LDFileFormat::Group == info->section->kind()) {
+ info->section->setLink(pInput.context()->getSection(info->sh_link));
+ continue;
+ }
+ if (LDFileFormat::Relocation == info->section->kind()) {
+ info->section->setLink(pInput.context()->getSection(info->sh_info));
+ continue;
+ }
+ }
+
+ pInput.memArea()->release(shdr_region);
+ pInput.memArea()->release(sect_name_region);
+
+ return true;
+}
+
+/// readRegularSection - read a regular section and create fragments.
+bool ELFReader<32, true>::readRegularSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr) const
+{
+ LDSection& out_sect = pLinker.getOrCreateOutputSectHdr(pInputSectHdr.name(),
+ pInputSectHdr.kind(),
+ pInputSectHdr.type(),
+ pInputSectHdr.flag());
+
+ MemoryRegion* region = pInput.memArea()->request(pInputSectHdr.offset(),
+ pInputSectHdr.size());
+
+ llvm::MCSectionData& sect_data = pLinker.getOrCreateSectData(pInputSectHdr);
+
+ llvm::MCFragment* frag = NULL;
+ if (NULL == region) {
+ // If the input section's size is zero, we got a NULL region.
+ // use a virtual fill fragment
+ frag = new llvm::MCFillFragment(0x0, 0, 0);
+ }
+ else
+ frag = new MCRegionFragment(*region);
+
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ sect_data,
+ pInputSectHdr.align());
+
+ out_sect.setSize(out_sect.size() + size);
+ return true;
+}
+
+/// readRegularSection - read a target section and create fragments.
+bool ELFReader<32, true>::readTargetSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr)
+{
+ return target().readSection(pInput, pLinker, pInputSectHdr);
+}
+
+/// readSymbols - read ELF symbols and create LDSymbol
+bool ELFReader<32, true>::readSymbols(Input& pInput,
+ MCLinker& pLinker,
+ const MemoryRegion& pRegion,
+ const char* pStrTab) const
+{
+ // get number of symbols
+ size_t entsize = pRegion.size()/sizeof(llvm::ELF::Elf32_Sym);
+ llvm::ELF::Elf32_Sym* symtab =
+ reinterpret_cast<llvm::ELF::Elf32_Sym*>(pRegion.start());
+
+ uint32_t st_name = 0x0;
+ uint32_t st_value = 0x0;
+ uint32_t st_size = 0x0;
+ uint8_t st_info = 0x0;
+ uint8_t st_other = 0x0;
+ uint16_t st_shndx = 0x0;
+ // skip the first NULL symbol
+ pInput.context()->addSymbol(NULL);
+
+ for (size_t idx = 1; idx < entsize; ++idx) {
+ st_info = symtab[idx].st_info;
+ st_other = symtab[idx].st_other;
+
+ if (llvm::sys::isLittleEndianHost()) {
+ st_name = symtab[idx].st_name;
+ st_value = symtab[idx].st_value;
+ st_size = symtab[idx].st_size;
+ st_shndx = symtab[idx].st_shndx;
+ }
+ else {
+ st_name = bswap32(symtab[idx].st_name);
+ st_value = bswap32(symtab[idx].st_value);
+ st_size = bswap32(symtab[idx].st_size);
+ st_shndx = bswap16(symtab[idx].st_shndx);
+ }
+
+ // If the section should not be included, set the st_shndx SHN_UNDEF
+ // - A section in interrelated groups are not included.
+ if (pInput.type() == Input::Object &&
+ st_shndx < llvm::ELF::SHN_LORESERVE &&
+ st_shndx != llvm::ELF::SHN_UNDEF) {
+ if (NULL == pInput.context()->getSection(st_shndx))
+ st_shndx = llvm::ELF::SHN_UNDEF;
+ }
+
+ // get ld_name
+ llvm::StringRef ld_name(pStrTab + st_name);
+
+ // get ld_type
+ ResolveInfo::Type ld_type = static_cast<ResolveInfo::Type>(st_info & 0xF);
+
+ // get ld_desc
+ ResolveInfo::Desc ld_desc = getSymDesc(st_shndx, pInput);
+
+ // get ld_binding
+ ResolveInfo::Binding ld_binding = getSymBinding((st_info >> 4), st_shndx, st_other);
+
+ // get ld_value - ld_value must be section relative.
+ uint64_t ld_value = getSymValue(st_value, st_shndx, pInput);
+
+ // get the input fragment
+ MCFragmentRef* ld_frag_ref = getSymFragmentRef(pInput,
+ pLinker,
+ st_shndx,
+ ld_value);
+
+ // get ld_vis
+ ResolveInfo::Visibility ld_vis = getSymVisibility(st_other);
+
+ // push into MCLinker
+ LDSymbol* input_sym = NULL;
+
+ if (pInput.type() == Input::Object) {
+ input_sym = pLinker.addSymbol<Input::Object>(ld_name,
+ ld_type,
+ ld_desc,
+ ld_binding,
+ st_size,
+ ld_value,
+ ld_frag_ref,
+ ld_vis);
+ // push into the input file
+ pInput.context()->addSymbol(input_sym);
+ continue;
+ }
+ else if (pInput.type() == Input::DynObj) {
+ input_sym = pLinker.addSymbol<Input::DynObj>(ld_name,
+ ld_type,
+ ld_desc,
+ ld_binding,
+ st_size,
+ ld_value,
+ ld_frag_ref,
+ ld_vis);
+ continue;
+ }
+
+ } // end of for loop
+ return true;
+}
+
+/// readSymbol - read a symbol from the given Input and index in symtab
+ResolveInfo* ELFReader<32, true>::readSymbol(Input& pInput,
+ LDSection& pSymTab,
+ MCLDInfo& pLDInfo,
+ uint32_t pSymIdx) const
+{
+ LDSection* symtab = &pSymTab;
+ LDSection* strtab = symtab->getLink();
+ assert(NULL != symtab && NULL != strtab);
+
+ uint32_t offset = symtab->offset() + sizeof(llvm::ELF::Elf32_Sym) * pSymIdx;
+ MemoryRegion* symbol_region =
+ pInput.memArea()->request(offset, sizeof(llvm::ELF::Elf32_Sym));
+ llvm::ELF::Elf32_Sym* entry =
+ reinterpret_cast<llvm::ELF::Elf32_Sym*>(symbol_region->start());
+
+ uint32_t st_name = 0x0;
+ uint32_t st_value = 0x0;
+ uint32_t st_size = 0x0;
+ uint8_t st_info = 0x0;
+ uint8_t st_other = 0x0;
+ uint16_t st_shndx = 0x0;
+ st_info = entry->st_info;
+ st_other = entry->st_other;
+ if (llvm::sys::isLittleEndianHost()) {
+ st_name = entry->st_name;
+ st_value = entry->st_value;
+ st_size = entry->st_size;
+ st_shndx = entry->st_shndx;
+ }
+ else {
+ st_name = bswap32(entry->st_name);
+ st_value = bswap32(entry->st_value);
+ st_size = bswap32(entry->st_size);
+ st_shndx = bswap16(entry->st_shndx);
+ }
+
+ MemoryRegion* strtab_region =
+ pInput.memArea()->request(strtab->offset(), strtab->size());
+
+ // get ld_name
+ llvm::StringRef ld_name(reinterpret_cast<char*>(strtab_region->start() + st_name));
+
+ // get ld_type
+ ResolveInfo::Type ld_type = static_cast<ResolveInfo::Type>(st_info & 0xF);
+
+ // get ld_desc
+ ResolveInfo::Desc ld_desc = getSymDesc(st_shndx, pInput);
+
+ // get ld_binding
+ ResolveInfo::Binding ld_binding = getSymBinding((st_info >> 4), st_shndx, st_other);
+
+ // get ld_vis
+ ResolveInfo::Visibility ld_vis = getSymVisibility(st_other);
+
+ ResolveInfo* result =
+ pLDInfo.getStrSymPool().createSymbol(ld_name,
+ pInput.type() == Input::DynObj,
+ ld_type,
+ ld_desc,
+ ld_binding,
+ st_size,
+ ld_vis);
+ // release regions
+ pInput.memArea()->release(symbol_region);
+ pInput.memArea()->release(strtab_region);
+
+ return result;
+}
+
+/// readRela - read ELF rela and create Relocation
+bool ELFReader<32, true>::readRela(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const
+{
+ // get the number of rela
+ size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf32_Rela);
+ llvm::ELF::Elf32_Rela* relaTab =
+ reinterpret_cast<llvm::ELF::Elf32_Rela*>(pRegion.start());
+
+ for (size_t idx=0; idx < entsize; ++idx) {
+ uint32_t r_offset = 0x0;
+ uint32_t r_info = 0x0;
+ int32_t r_addend = 0;
+ if (llvm::sys::isLittleEndianHost()) {
+ r_offset = relaTab[idx].r_offset;
+ r_info = relaTab[idx].r_info;
+ r_addend = relaTab[idx].r_addend;
+ }
+ else {
+ r_offset = bswap32(relaTab[idx].r_offset);
+ r_info = bswap32(relaTab[idx].r_info);
+ r_addend = bswap32(relaTab[idx].r_addend);
+ }
+
+ uint8_t r_type = static_cast<unsigned char>(r_info);
+ uint32_t r_sym = (r_info >> 8);
+ LDSymbol* symbol = pInput.context()->getSymbol(r_sym);
+ if (NULL == symbol) {
+ llvm::report_fatal_error(llvm::Twine("invalid symbol index :") +
+ llvm::Twine(r_sym) +
+ llvm::Twine(" in file `") +
+ pInput.path().native() +
+ llvm::Twine("'.\n"));
+ }
+
+ ResolveInfo* resolve_info = symbol->resolveInfo();
+
+ MCFragmentRef* frag_ref =
+ pLinker.getLayout().getFragmentRef(*pSection.getLink(), r_offset);
+
+ if (NULL == frag_ref) {
+ llvm::report_fatal_error(llvm::Twine("invalid sh_info: ") +
+ llvm::Twine(pSection.getLink()->index()) +
+ llvm::Twine(" of the relocation section `") +
+ pSection.name() +
+ llvm::Twine("' in file `") +
+ pInput.path().native() +
+ llvm::Twine(".\n"));
+ }
+
+ pLinker.addRelocation(r_type, *symbol, *resolve_info, *frag_ref, r_addend);
+ }
+ return true;
+}
+
+/// readRel - read ELF rel and create Relocation
+bool ELFReader<32, true>::readRel(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const
+{
+ // get the number of rel
+ size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf32_Rel);
+ llvm::ELF::Elf32_Rel* relTab =
+ reinterpret_cast<llvm::ELF::Elf32_Rel*>(pRegion.start());
+
+ for (size_t idx=0; idx < entsize; ++idx) {
+ uint32_t r_offset = 0x0;
+ uint32_t r_info = 0x0;
+ if (llvm::sys::isLittleEndianHost()) {
+ r_offset = relTab[idx].r_offset;
+ r_info = relTab[idx].r_info;
+ }
+ else {
+ r_offset = bswap32(relTab[idx].r_offset);
+ r_info = bswap32(relTab[idx].r_info);
+ }
+
+ uint8_t r_type = static_cast<unsigned char>(r_info);
+ uint32_t r_sym = (r_info >> 8);
+
+ LDSymbol* symbol = pInput.context()->getSymbol(r_sym);
+ if (NULL == symbol) {
+ llvm::report_fatal_error(llvm::Twine("invalid symbol index :") +
+ llvm::Twine(r_sym) +
+ llvm::Twine(" in file `") +
+ pInput.path().native() +
+ llvm::Twine("'.\n"));
+ }
+
+ ResolveInfo* resolve_info = symbol->resolveInfo();
+
+ MCFragmentRef* frag_ref =
+ pLinker.getLayout().getFragmentRef(*pSection.getLink(), r_offset);
+
+ if (NULL == frag_ref) {
+ llvm::report_fatal_error(llvm::Twine("invalid sh_info: ") +
+ llvm::Twine(pSection.getLink()->index()) +
+ llvm::Twine(" of the relocation section `") +
+ pSection.name() +
+ llvm::Twine("' in file `") +
+ pInput.path().native() +
+ llvm::Twine(".\n"));
+ }
+
+ pLinker.addRelocation(r_type, *symbol, *resolve_info, *frag_ref);
+ }
+ return true;
+}
+
diff --git a/include/mcld/LD/ELFSegment.h b/include/mcld/LD/ELFSegment.h
new file mode 100644
index 0000000..24f9458
--- /dev/null
+++ b/include/mcld/LD/ELFSegment.h
@@ -0,0 +1,163 @@
+//===- ELFSegment.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_SEGMENT_H
+#define MCLD_ELF_SEGMENT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/DataTypes.h>
+#include <mcld/LD/LDSection.h>
+#include <cassert>
+#include <vector>
+
+namespace mcld
+{
+
+/** \class ELFSegment
+ * \brief decribe the program header for ELF executable or shared object
+ */
+class ELFSegment
+{
+public:
+ typedef std::vector<LDSection*>::iterator sect_iterator;
+ typedef std::vector<LDSection*>::const_iterator const_sect_iterator;
+public:
+ ELFSegment(uint32_t pType,
+ uint32_t pFlag = llvm::ELF::PF_R,
+ uint64_t pOffset = 0,
+ uint64_t pVaddr = 0,
+ uint64_t pPaddr = 0,
+ uint64_t pFilesz = 0,
+ uint64_t pMemsz = 0,
+ uint64_t pAlign = 0);
+ ~ELFSegment();
+
+ /// ----- iterators ----- ///
+ sect_iterator sectBegin()
+ { return m_SectionList.begin(); }
+
+ sect_iterator sectEnd()
+ { return m_SectionList.end(); }
+
+ const_sect_iterator sectBegin() const
+ { return m_SectionList.begin(); }
+
+ const_sect_iterator sectEnd() const
+ { return m_SectionList.end(); }
+
+ const LDSection* getFirstSection()
+ {
+ if (0 == m_SectionList.size())
+ return NULL;
+ return m_SectionList[0];
+ }
+
+ const LDSection* getLastSection()
+ {
+ size_t size = m_SectionList.size();
+ if (0 == size)
+ return NULL;
+ return m_SectionList[size - 1];
+ }
+
+ const LDSection* getFirstSection() const
+ {
+ if (0 == m_SectionList.size())
+ return NULL;
+ return m_SectionList[0];
+ }
+
+ const LDSection* getLastSection() const
+ {
+ size_t size = m_SectionList.size();
+ if (0 == size)
+ return NULL;
+ return m_SectionList[size - 1];
+ }
+
+ /// ----- observers ----- ///
+ uint32_t type() const
+ { return m_Type; }
+
+ uint64_t offset() const
+ { return m_Offset; }
+
+ uint64_t vaddr() const
+ { return m_Vaddr; }
+
+ uint64_t paddr() const
+ { return m_Paddr; }
+
+ uint64_t filesz() const
+ { return m_Filesz; }
+
+ uint64_t memsz() const
+ { return m_Memsz; }
+
+ uint32_t flag() const
+ { return m_Flag; }
+
+ uint64_t align() const
+ { return m_Align; }
+
+ size_t numOfSections() const
+ { return m_SectionList.size(); }
+
+ /// ----- modifiers ----- ///
+ void setOffset(uint64_t pOffset)
+ { m_Offset = pOffset; }
+
+ void setVaddr(uint64_t pVaddr)
+ { m_Vaddr = pVaddr; }
+
+ void setPaddr(uint64_t pPaddr)
+ { m_Paddr = pPaddr; }
+
+ void setFilesz(uint64_t pFilesz)
+ { m_Filesz = pFilesz; }
+
+ void setMemsz(uint64_t pMemsz)
+ { m_Memsz = pMemsz; }
+
+ void setFlag(uint32_t pFlag)
+ { m_Flag = pFlag; }
+
+ void updateFlag(uint32_t pFlag)
+ {
+ // PT_TLS segment should be PF_R
+ if (llvm::ELF::PT_TLS != m_Type)
+ m_Flag |= pFlag;
+ }
+
+ void setAlign(uint64_t pAlign)
+ { m_Align = pAlign; }
+
+ void addSection(LDSection* pSection)
+ {
+ assert(NULL != pSection);
+ m_SectionList.push_back(pSection);
+ }
+
+private:
+ uint32_t m_Type; // Type of segment
+ uint32_t m_Flag; // Segment flags
+ uint64_t m_Offset; // File offset where segment is located, in bytes
+ uint64_t m_Vaddr; // Virtual address of beginning of segment
+ uint64_t m_Paddr; // Physical address of beginning of segment (OS-specific)
+ uint64_t m_Filesz; // Num. of bytes in file image of segment (may be zero)
+ uint64_t m_Memsz; // Num. of bytes in mem image of segment (may be zero)
+ uint64_t m_Align; // Segment alignment constraint
+ std::vector<LDSection*> m_SectionList;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFSegmentFactory.h b/include/mcld/LD/ELFSegmentFactory.h
new file mode 100644
index 0000000..5dd55cb
--- /dev/null
+++ b/include/mcld/LD/ELFSegmentFactory.h
@@ -0,0 +1,43 @@
+//===- ELFSegmentFactory.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELFSEGMENT_FACTORY_H
+#define MCLD_ELFSEGMENT_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Support/GCFactory.h>
+#include <mcld/LD/ELFSegment.h>
+
+namespace mcld
+{
+
+/** \class ELFSegmentFactory
+ * \brief provide the interface to create and delete an ELFSegment
+ */
+class ELFSegmentFactory : public GCFactory<ELFSegment, 0>
+{
+public:
+ /// ELFSegmentFactory - the factory of ELFSegment
+ /// pNum is the magic number of the ELF segments in the output
+ ELFSegmentFactory(size_t pNum);
+ ~ELFSegmentFactory();
+
+ /// produce - produce an empty ELF segment information.
+ /// this function will create an ELF segment
+ /// @param pType - p_type in ELF program header
+ ELFSegment* produce(uint32_t pType);
+
+ /// destroy - destruct the ELF segment
+ void destroy(ELFSegment*& pSegment);
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFWriter.h b/include/mcld/LD/ELFWriter.h
new file mode 100644
index 0000000..e9db7f5
--- /dev/null
+++ b/include/mcld/LD/ELFWriter.h
@@ -0,0 +1,122 @@
+//===- ELFWriter.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_WRITER_H
+#define MCLD_ELF_WRITER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/ELF.h>
+#include <mcld/MC/MCLDOutput.h>
+
+namespace llvm {
+class MCSectionData;
+}
+
+namespace mcld
+{
+
+class MCLDInfo;
+class Layout;
+class GNULDBackend;
+class Relocation;
+class LDSection;
+
+/** \class ELFWriter
+ * \brief ELFWriter provides basic functions to write ELF sections, symbols,
+ * and so on.
+ */
+class ELFWriter
+{
+public:
+ typedef uint64_t FileOffset;
+
+protected:
+ ELFWriter(GNULDBackend& pBackend)
+ : f_Backend(pBackend) {
+ }
+
+public:
+ virtual ~ELFWriter() { }
+
+ GNULDBackend& target()
+ { return f_Backend; }
+
+ const GNULDBackend& target() const
+ { return f_Backend; }
+
+ virtual void writeELF32Header(const MCLDInfo& pInfo,
+ const Layout& pLayout,
+ const GNULDBackend& pBackend,
+ Output& pOutput) const;
+
+ virtual void writeELF64Header(const MCLDInfo& pInfo,
+ const Layout& pLayout,
+ const GNULDBackend& pBackend,
+ Output& pOutput) const;
+
+ virtual uint64_t getEntryPoint(const MCLDInfo& pInfo,
+ const Layout& pLayout,
+ const GNULDBackend& pBackend,
+ const Output& pOutput) const;
+
+protected:
+ void emitELF32SectionHeader(Output& pOutput, MCLinker& pLinker) const;
+
+ void emitELF64SectionHeader(Output& pOutput, MCLinker& pLinker) const;
+
+ // emitShStrTab - emit .shstrtab
+ void emitELF32ShStrTab(Output& pOutput, MCLinker& pLinker) const;
+
+ void emitELF64ShStrTab(Output& pOutput, MCLinker& pLinker) const;
+
+ void emitSectionData(const Layout& pLayout,
+ const LDSection& pSection,
+ MemoryRegion& pRegion) const;
+
+ void emitRelocation(const Layout& pLayout,
+ const Output& pOutput,
+ const LDSection& pSection,
+ MemoryRegion& pRegion) const;
+
+ void emitRel(const Layout& pLayout,
+ const Output& pOutput,
+ const llvm::MCSectionData& pSectionData,
+ MemoryRegion& pRegion) const;
+
+ void emitRela(const Layout& pLayout,
+ const Output& pOutput,
+ const llvm::MCSectionData& pSectionData,
+ MemoryRegion& pRegion) const;
+
+private:
+ // getSectEntrySize - compute ElfXX_Shdr::sh_entsize
+ uint64_t getELF32SectEntrySize(const LDSection& pSection) const;
+
+ // getSectEntrySize - compute ElfXX_Shdr::sh_entsize
+ uint64_t getELF64SectEntrySize(const LDSection& pSection) const;
+
+ // getSectEntrySize - compute ElfXX_Shdr::sh_link
+ uint64_t getSectLink(const LDSection& pSection, const Output& pOutput) const;
+
+ // getSectEntrySize - compute ElfXX_Shdr::sh_info
+ uint64_t getSectInfo(const LDSection& pSection, const Output& pOutput) const;
+
+ uint64_t getELF32LastStartOffset(const Output& pOutput) const;
+
+ uint64_t getELF64LastStartOffset(const Output& pOutput) const;
+
+protected:
+ GNULDBackend& f_Backend;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/GNUArchiveReader.h b/include/mcld/LD/GNUArchiveReader.h
new file mode 100644
index 0000000..57aee10
--- /dev/null
+++ b/include/mcld/LD/GNUArchiveReader.h
@@ -0,0 +1,86 @@
+//===- GNUArchiveReader.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_GNU_ARCHIVE_READER_H
+#define MCLD_GNU_ARCHIVE_READER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/LD/ArchiveReader.h"
+#include "mcld/Support/Path.h"
+#include <llvm/ADT/OwningPtr.h>
+
+#include <vector>
+#include <string>
+
+namespace llvm
+{
+class MemoryBuffer;
+
+}
+
+namespace mcld
+{
+class MCLDInfo;
+class Input;
+class InputTree;
+
+/** \class GNUArchiveReader
+ * \brief GNUArchiveReader reads GNU archive files.
+ */
+class GNUArchiveReader : public ArchiveReader
+{
+private:
+ struct ArchiveMemberHeader;
+ struct SymbolTableEntry;
+
+public:
+ explicit GNUArchiveReader(MCLDInfo &pLDInfo, LDReader::Endian endian)
+ : m_pLDInfo(pLDInfo),
+ m_endian(endian)
+ { }
+
+ ~GNUArchiveReader()
+ { }
+
+ /// Read an archive and extract each member in.
+ /// Construct the coresponding Input for each member.
+ InputTree *readArchive(Input &input);
+
+ bool isMyFormat(Input &input) const;
+
+ LDReader::Endian endian(Input& pFile) const;
+
+private:
+ /// set up the archive, including
+ /// first, read symbol table
+ /// second, read extended file name which is used in thin archive
+ InputTree *setupNewArchive(Input &pInput, size_t off);
+
+ /// parse the archive header, and return the member size
+ size_t parseMemberHeader(llvm::OwningPtr<llvm::MemoryBuffer> &mapFile,
+ off_t off,
+ std::string *p_Name,
+ off_t *nestedOff,
+ std::string &p_ExtendedName);
+
+ void readSymbolTable(llvm::OwningPtr<llvm::MemoryBuffer> &mapFile,
+ std::vector<SymbolTableEntry> &pSymbolTable,
+ off_t start,
+ size_t size);
+
+private:
+ MCLDInfo &m_pLDInfo;
+ LDReader::Endian m_endian;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/Group.h b/include/mcld/LD/Group.h
new file mode 100644
index 0000000..31c4a68
--- /dev/null
+++ b/include/mcld/LD/Group.h
@@ -0,0 +1,28 @@
+//===- Group.h ------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LD_GROUP_H
+#define LD_GROUP_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+/** \class Group
+ * \brief Group records the grouping of all regions
+ */
+class Group
+{
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/InputSymbolTable.h b/include/mcld/LD/InputSymbolTable.h
new file mode 100644
index 0000000..c5e3864
--- /dev/null
+++ b/include/mcld/LD/InputSymbolTable.h
@@ -0,0 +1,46 @@
+//===- InputSymbolTable.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef INPUTSYMBOLTABLE_H
+#define INPUTSYMBOLTABLE_H
+#include <llvm/ADT/StringRef.h>
+#include "mcld/LD/SymbolTableIF.h"
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+class LDSymbol;
+
+/** \class InputSymbolTable
+ * \brief Input symbol table, for MCLDInput.
+ *
+ * \see
+ */
+class InputSymbolTable : public SymbolTableIF
+{
+ /* draft. */
+ friend class SymbolTableFactory;
+private:
+ InputSymbolTable(StrSymPool &pStrSymPool,
+ size_t pNumOfSymbols,
+ StringTable &pEntireStringTable,
+ StringTable &pDynamicStringTable);
+private:
+ virtual void doInsertSymbol(LDSymbol *);
+ virtual void doMerge(const SymbolTableIF &);
+public:
+ virtual ~InputSymbolTable();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/LDContext.h b/include/mcld/LD/LDContext.h
new file mode 100644
index 0000000..878ba8d
--- /dev/null
+++ b/include/mcld/LD/LDContext.h
@@ -0,0 +1,105 @@
+//===- LDContext.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LDCONTEXT_H
+#define MCLD_LDCONTEXT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <vector>
+#include <mcld/LD/LDFileFormat.h>
+#include <llvm/Support/DataTypes.h>
+#include <string>
+#include <cassert>
+
+namespace llvm {
+class StringRef;
+}
+
+namespace mcld
+{
+
+class LDSymbol;
+class LDSection;
+
+/** \class LDContext
+ * \brief LDContext stores the data which a object file should has
+ */
+class LDContext
+{
+public:
+ typedef std::vector<LDSection*> SectionTable;
+ typedef SectionTable::iterator sect_iterator;
+ typedef SectionTable::const_iterator const_sect_iterator;
+
+ typedef std::vector<LDSymbol*> SymbolTable;
+ typedef SymbolTable::iterator sym_iterator;
+ typedef SymbolTable::const_iterator const_sym_iterator;
+
+public:
+ LDContext();
+
+ ~LDContext();
+
+ // ----- sections ----- //
+ SectionTable& getSectionTable()
+ { return m_SectionTable; }
+
+ const SectionTable& getSectionTable() const
+ { return m_SectionTable; }
+
+ sect_iterator sectBegin()
+ { return m_SectionTable.begin(); }
+
+ sect_iterator sectEnd()
+ { return m_SectionTable.end(); }
+
+ const_sect_iterator sectBegin() const
+ { return m_SectionTable.begin(); }
+
+ const_sect_iterator sectEnd() const
+ { return m_SectionTable.end(); }
+
+ LDSection* getSection(unsigned int pIdx);
+
+ const LDSection* getSection(unsigned int pIdx) const;
+
+ LDSection* getSection(const std::string& pName);
+
+ const LDSection* getSection(const std::string& pName) const;
+
+ size_t getSectionIdx(const std::string& pName) const;
+
+ size_t numOfSections() const
+ { return m_SectionTable.size(); }
+
+ // ----- symbols ----- //
+ LDSymbol* getSymbol(unsigned int pIdx);
+
+ const LDSymbol* getSymbol(unsigned int pIdx) const;
+
+ LDSymbol* getSymbol(const llvm::StringRef& pName);
+
+ const LDSymbol* getSymbol(const llvm::StringRef& pName) const;
+
+ void addSymbol(LDSymbol* pSym)
+ { m_SymTab.push_back(pSym); }
+
+private:
+ SectionTable m_SectionTable;
+ SymbolTable m_SymTab;
+
+ // FIXME : maintain a map<section name, section index>
+};
+
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/LDFileFormat.h b/include/mcld/LD/LDFileFormat.h
new file mode 100644
index 0000000..df80f67
--- /dev/null
+++ b/include/mcld/LD/LDFileFormat.h
@@ -0,0 +1,113 @@
+//===- LDFileFormat.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LDFILE_FORMAT_H
+#define MCLD_LDFILE_FORMAT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <cstdio>
+#include <cassert>
+
+namespace mcld
+{
+
+class MCLinker;
+class LDSection;
+
+/** \class LDFileFormat
+ * \brief LDFileFormat describes the common file formats.
+ */
+class LDFileFormat
+{
+public:
+ enum Kind {
+ Null,
+ Regular,
+ BSS,
+ NamePool,
+ Relocation,
+ Debug,
+ Target,
+ Exception,
+ Version,
+ Note,
+ MetaData,
+ Group,
+ };
+
+protected:
+ LDFileFormat();
+
+public:
+ virtual ~LDFileFormat();
+
+ /// initStdSections - initialize all standard sections.
+ void initStdSections(MCLinker& pLinker);
+
+ /// initObjectFormat - different format, such as ELF and MachO, should
+ /// implement this
+ virtual void initObjectFormat(MCLinker& pLinker) = 0;
+
+ /// initObjectType - different types, such as shared object, executable
+ /// files, should implement this
+ virtual void initObjectType(MCLinker& pLinker) = 0;
+
+ // ----- access functions ----- //
+ LDSection& getText() {
+ assert(NULL != f_pTextSection);
+ return *f_pTextSection;
+ }
+
+ const LDSection& getText() const {
+ assert(NULL != f_pTextSection);
+ return *f_pTextSection;
+ }
+
+ LDSection& getData() {
+ assert(NULL != f_pDataSection);
+ return *f_pDataSection;
+ }
+
+ const LDSection& getData() const {
+ assert(NULL != f_pDataSection);
+ return *f_pDataSection;
+ }
+
+ LDSection& getBSS() {
+ assert(NULL != f_pBSSSection);
+ return *f_pBSSSection;
+ }
+
+ const LDSection& getBSS() const {
+ assert(NULL != f_pBSSSection);
+ return *f_pBSSSection;
+ }
+
+ LDSection& getReadOnly() {
+ assert(NULL != f_pReadOnlySection);
+ return *f_pReadOnlySection;
+ }
+
+ const LDSection& getReadOnly() const {
+ assert(NULL != f_pReadOnlySection);
+ return *f_pReadOnlySection;
+ }
+protected:
+ // variable name : ELF MachO
+ LDSection* f_pTextSection; // .text __text
+ LDSection* f_pDataSection; // .data __data
+ LDSection* f_pBSSSection; // .bss __bss
+ LDSection* f_pReadOnlySection; // .rodata __const
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/LDReader.h b/include/mcld/LD/LDReader.h
new file mode 100644
index 0000000..4fde9f0
--- /dev/null
+++ b/include/mcld/LD/LDReader.h
@@ -0,0 +1,47 @@
+//===- LDReader.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_READER_INTERFACE_H
+#define MCLD_READER_INTERFACE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/DataTypes.h>
+
+namespace mcld
+{
+
+class Input;
+
+/** \class LDReader
+ * \brief LDReader provides the basic interfaces for all readers. It also
+ * provides basic functions to read data stream.
+ */
+class LDReader
+{
+public:
+ enum Endian {
+ LittleEndian,
+ BigEndian
+ };
+
+protected:
+ LDReader() { }
+
+public:
+ virtual ~LDReader() { }
+
+ virtual bool isMyFormat(Input& pInput) const = 0;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/LDSection.h b/include/mcld/LD/LDSection.h
new file mode 100644
index 0000000..4c793de
--- /dev/null
+++ b/include/mcld/LD/LDSection.h
@@ -0,0 +1,205 @@
+//===- LDSection.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_LD_LDSECTION_H
+#define MCLD_LD_LDSECTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/MC/MCSection.h>
+#include <llvm/MC/MCAssembler.h>
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/DataTypes.h>
+#include <mcld/LD/LDFileFormat.h>
+#include <string>
+
+namespace llvm {
+
+class MCAsmInfo;
+class raw_ostream;
+
+} // namespace of llvm
+
+namespace mcld {
+/** \class LDSection
+ * \brief LDSection represents a section header entry. It is a unified
+ * abstraction for various file formats.
+ *
+ * LDSection contains both the format-dependent data and LLVM specific data.
+ *
+ */
+class LDSection : public llvm::MCSection
+{
+public:
+ LDSection(const std::string& pName,
+ LDFileFormat::Kind pKind,
+ uint32_t pType,
+ uint32_t pFlag,
+ uint64_t pSize = 0,
+ uint64_t pOffset = 0,
+ uint64_t pAddr = 0);
+
+ /// name - the name of this section.
+ const std::string& name() const
+ { return m_Name; }
+
+ /// kind - the kind of this section, such as Text, BSS, GOT, and so on.
+ /// from LDFileFormat::Kind
+ LDFileFormat::Kind kind() const
+ { return m_Kind; }
+
+ /// type - The categorizes the section's contents and semantics. It's
+ /// different from llvm::SectionKind. Type is format-dependent, but
+ /// llvm::SectionKind is format independent and is used for bit-code.
+ /// In ELF, it is sh_type
+ /// In MachO, it's type field of struct section::flags
+ uint32_t type() const
+ { return m_Type; }
+
+ /// flag - An integer describes miscellaneous attributes.
+ /// In ELF, it is sh_flags.
+ /// In MachO, it's attribute field of struct section::flags
+ uint32_t flag() const
+ { return m_Flag; }
+
+ /// size - An integer specifying the size in bytes of the virtual memory
+ /// occupied by this section.
+ /// In ELF, if the type() is SHT_NOBITS, this function return zero.
+ /// Before layouting, output's LDSection::size() should return zero.
+ uint64_t size() const
+ { return m_Size; }
+
+ /// offset - An integer specifying the offset of this section in the file.
+ /// Before layouting, output's LDSection::offset() should return zero.
+ uint64_t offset() const
+ { return m_Offset; }
+
+ /// addr - An integer specifying the virtual address of this section in the
+ /// virtual image.
+ /// Before layouting, output's LDSection::offset() should return zero.
+ /// ELF uses sh_addralign to set alignment constraints. In LLVM, alignment
+ /// constraint is set in MCSectionData::setAlignment. addr() contains the
+ /// original ELF::sh_addr. Modulo sh_addr by sh_addralign is not necessary.
+ /// MachO uses the same scenario.
+ ///
+ /// Because addr() in output is changing during linking, MCLinker does not
+ /// store the address of the output here. The address is in Layout
+ uint64_t addr() const
+ { return m_Addr; }
+
+ /// align - An integer specifying the align of this section in the file.
+ /// Before layouting, output's LDSection::align() should return zero.
+ uint32_t align() const
+ { return m_Align; }
+
+ size_t index() const
+ { return m_Index; }
+
+ /// getLink - return the Link. When a section A needs the other section B
+ /// during linking or loading, we say B is A's Link section.
+ /// In ELF, InfoLink section control the ElfNN_Shdr::sh_link and sh_info.
+ ///
+ /// @return if the section needs no other sections, return NULL
+ LDSection* getLink()
+ { return m_pLink; }
+
+ const LDSection* getLink() const
+ { return m_pLink; }
+
+ size_t getInfo() const
+ { return m_Info; }
+
+ void setKind(LDFileFormat::Kind pKind)
+ { m_Kind = pKind; }
+
+ void setSize(uint64_t size)
+ { m_Size = size; }
+
+ void setOffset(uint64_t Offset)
+ { m_Offset = Offset; }
+
+ void setAddr(uint64_t addr)
+ { m_Addr = addr; }
+
+ void setAlign(uint32_t align)
+ { m_Align = align; }
+
+ void setFlag(uint32_t flag)
+ { m_Flag = flag; }
+
+ void setType(uint32_t type)
+ { m_Type = type; }
+
+ static bool classof(const MCSection *S)
+ { return S->getVariant() == SV_LDContext; }
+
+ static bool classof(const LDSection *)
+ { return true; }
+
+ // ----- methods for adapt to llvm::MCSection ----- //
+ void PrintSwitchToSection(const llvm::MCAsmInfo &MAI,
+ llvm::raw_ostream &OS) const
+ { }
+
+ bool UseCodeAlign() const
+ { return true; }
+
+ bool isVirtualSection() const
+ { return false; }
+
+ llvm::MCSectionData* getSectionData()
+ { return m_pSectionData; }
+
+ const llvm::MCSectionData* getSectionData() const
+ { return m_pSectionData; }
+
+ void setSectionData(llvm::MCSectionData* pSD)
+ { m_pSectionData = pSD; }
+
+ bool hasSectionData() const
+ { return (NULL != m_pSectionData); }
+
+ /// setLink - set the sections should link with.
+ /// if pLink is NULL, no Link section is set.
+ void setLink(LDSection* pLink)
+ { m_pLink = pLink; }
+
+ void setInfo(size_t pInfo)
+ { m_Info = pInfo; }
+
+ void setIndex(size_t pIndex)
+ { m_Index = pIndex; }
+
+private:
+ std::string m_Name;
+ LDFileFormat::Kind m_Kind;
+ uint32_t m_Type;
+ uint32_t m_Flag;
+
+ uint64_t m_Size;
+ uint64_t m_Offset;
+ uint64_t m_Addr;
+ uint32_t m_Align;
+
+ size_t m_Info;
+ LDSection* m_pLink;
+
+ // pointer to MCSectionData.
+ llvm::MCSectionData* m_pSectionData;
+
+ // the index of the file
+ size_t m_Index;
+
+}; // end of LDSection
+
+} // end namespace mcld
+
+#endif
+
diff --git a/include/mcld/LD/LDSectionFactory.h b/include/mcld/LD/LDSectionFactory.h
new file mode 100644
index 0000000..49b11c7
--- /dev/null
+++ b/include/mcld/LD/LDSectionFactory.h
@@ -0,0 +1,58 @@
+//===- LDSectionFactory.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LDSECTION_FACTORY_H
+#define MCLD_LDSECTION_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Support/GCFactory.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/LDFileFormat.h>
+#include <string>
+
+namespace mcld
+{
+
+/** \class LDSectionFactory
+ * \brief provide the interface to create and delete section data for output
+ */
+class LDSectionFactory : public GCFactory<LDSection, 0>
+{
+public:
+ /// LDSectionFactory - the factory of LDSection
+ /// pNum is the average number of the LDSections in the system.
+ LDSectionFactory(size_t pNum);
+ ~LDSectionFactory();
+
+ /// produce - produce an empty section information.
+ /// This function will create an empty MCSectionData and its LDSection.
+ /// @param pName - The name of the section.
+ /// @param pKind - The kind of the section. Used to create default section map
+ /// @param pType - sh_type in ELF.
+ /// @param pFlag - is the same as sh_flags.
+ LDSection* produce(const std::string& pName,
+ LDFileFormat::Kind pKind,
+ uint32_t pType,
+ uint32_t pFlag);
+
+ /// destroy - destruct the LDSection.
+ /// @oaram - the reference of the pointer to the destructed LDSection.
+ /// after the destruction, the pointer is set to zero.
+ void destroy(LDSection*& pSD);
+
+ /// find - find the LDSection* in factory from the given section name.
+ /// return NULL if not found.
+ /// @param pName - the name of section
+ LDSection* find(const std::string& pName);
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/LDSymbol.h b/include/mcld/LD/LDSymbol.h
new file mode 100644
index 0000000..45c0b75
--- /dev/null
+++ b/include/mcld/LD/LDSymbol.h
@@ -0,0 +1,128 @@
+//===- LDSymbol.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LD_SYMBOL_H
+#define MCLD_LD_SYMBOL_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/LD/ResolveInfo.h"
+#include "mcld/MC/MCFragmentRef.h"
+#include <llvm/MC/MCAssembler.h>
+#include <assert.h>
+
+namespace mcld
+{
+
+/** \class LDSymbol
+ * \brief LDSymbol provides a consistent abstraction for different formats
+ * in different targets.
+ */
+class LDSymbol
+{
+public:
+ // FIXME: use SizeTrait<32> or SizeTrait<64> instead of big type
+ typedef ResolveInfo::SizeType SizeType;
+ typedef uint64_t ValueType;
+ typedef MCFragmentRef::Offset Offset;
+
+public:
+ LDSymbol();
+ LDSymbol(const LDSymbol& pCopy);
+ LDSymbol& operator=(const LDSymbol& pCopy);
+ ~LDSymbol();
+
+ // ----- observers ----- //
+ const char* name() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->name();
+ }
+
+ unsigned int nameSize() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->nameSize();
+ }
+
+ llvm::StringRef str() const {
+ assert(NULL != m_pResolveInfo);
+ return llvm::StringRef(m_pResolveInfo->name(), m_pResolveInfo->nameSize());
+ }
+
+ bool isDyn() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->isDyn();
+ }
+
+ unsigned int type() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->type();
+ }
+ unsigned int desc() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->desc();
+ }
+ unsigned int binding() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->binding();
+ }
+
+ uint8_t other() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->other();
+ }
+
+ uint8_t visibility() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->other();
+ }
+
+ ValueType value() const
+ { return m_Value; }
+
+ const MCFragmentRef* fragRef() const
+ { return m_pFragRef; }
+
+ SizeType size() const
+ { return m_pResolveInfo->size(); }
+
+ ResolveInfo* resolveInfo()
+ { return m_pResolveInfo; }
+
+ const ResolveInfo* resolveInfo() const
+ { return m_pResolveInfo; }
+
+ bool hasFragRef() const
+ { return (NULL != m_pFragRef); }
+
+ // ----- modifiers ----- //
+ void setSize(SizeType pSize) {
+ assert(NULL != m_pResolveInfo);
+ m_pResolveInfo->setSize(pSize);
+ }
+
+ void setValue(ValueType pValue)
+ { m_Value = pValue; }
+
+ void setFragmentRef(MCFragmentRef* pFragmentRef);
+
+ void setResolveInfo(const ResolveInfo& pInfo);
+
+private:
+ // ----- Symbol's fields ----- //
+ ResolveInfo* m_pResolveInfo;
+ MCFragmentRef* m_pFragRef;
+ ValueType m_Value;
+
+};
+
+} // namespace mcld
+
+#endif
+
diff --git a/include/mcld/LD/LDWriter.h b/include/mcld/LD/LDWriter.h
new file mode 100644
index 0000000..78c2871
--- /dev/null
+++ b/include/mcld/LD/LDWriter.h
@@ -0,0 +1,41 @@
+//===- LDWriter.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// LDWriter provides an interface used by MCLinker,
+// which writes the result of linking into a .so file or a executable.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_WRITER_INTERFACE_H
+#define MCLD_WRITER_INTERFACE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Target/TargetLDBackend.h>
+
+namespace mcld
+{
+
+/** \class LDWriter
+ * \brief LDWriter provides the basic interfaces for all writers.
+ * (ObjectWriter, DynObjWriter, and EXEObjWriter)
+ */
+class LDWriter
+{
+protected:
+ LDWriter() { }
+
+public:
+ virtual ~LDWriter() { }
+
+};
+
+} //end namespace
+
+#endif
+
diff --git a/include/mcld/LD/Layout.h b/include/mcld/LD/Layout.h
new file mode 100644
index 0000000..28f2d83
--- /dev/null
+++ b/include/mcld/LD/Layout.h
@@ -0,0 +1,270 @@
+//===- Layout.h -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LAYOUT_H
+#define MCLD_LAYOUT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/ilist.h>
+#include <llvm/ADT/ilist_node.h>
+#include <llvm/ADT/DenseMap.h>
+#include <llvm/MC/MCAssembler.h>
+#include <mcld/MC/MCFragmentRef.h>
+#include <mcld/Support/GCFactory.h>
+#include <mcld/LD/LDSection.h>
+#include <map>
+
+namespace mcld
+{
+class MCLinker;
+class Output;
+class TargetLDBackend;
+
+/** \class Layout
+ * \brief Layout maintains the mapping between sections and fragments.
+ *
+ * MCLinker is a fragment-based linker. But readers and target backends
+ * still need section information. Layout is used to maintain the mapping
+ * between sections and fragments. Layout helps readers and target backends
+ * get the input or output section information from a fragment.
+ */
+class Layout
+{
+public:
+ typedef std::vector<LDSection*> SectionOrder;
+ typedef SectionOrder::iterator sect_iterator;
+ typedef SectionOrder::const_iterator const_sect_iterator;
+
+public:
+ /// constructor
+ Layout();
+
+ /// destructor
+ ~Layout();
+
+ /// getInputLDSection - give a MCFragment, return the corresponding input
+ /// LDSection*
+ ///
+ /// @return return NULL if the fragment is not found in input
+ LDSection* getInputLDSection(const llvm::MCFragment& pFrag);
+
+ /// getInputLDSection - give a MCFragment, return the corresponding input
+ /// LDSection*
+ ///
+ /// @return return NULL if the fragment is not found in input
+ const LDSection* getInputLDSection(const llvm::MCFragment& pFrag) const;
+
+ /// getFragmentRef - give a LDSection in input file and an offset, return
+ /// the fragment reference.
+ ///
+ /// @param pInputSection - the given input section
+ /// @param pOffset - the offset, cannot be larger than this input section.
+ /// @return if found, return the fragment. Otherwise, return NULL.
+ MCFragmentRef*
+ getFragmentRef(const LDSection& pInputSection, uint64_t pOffset);
+
+ /// getFragmentRef - give a fragment and a big offset, return the fragment
+ /// reference in the section data.
+ ///
+ /// @param pFrag - the given fragment
+ /// @param pBigOffset - the offset, can be larger than the fragment, but can
+ /// not larger than this input section.
+ /// @return if found, return the fragment. Otherwise, return NULL.
+ MCFragmentRef*
+ getFragmentRef(const llvm::MCFragment& pFrag, uint64_t pBigOffset);
+
+ /// getOutputOffset - Get the offset of the given fragment inside the
+ /// the output's MCSectionData.
+ uint64_t getOutputOffset(const llvm::MCFragment& pFrag);
+
+ /// getOutputOffset - Get the offset of the given fragment inside the
+ /// the output's MCSectionData.
+ uint64_t getOutputOffset(const llvm::MCFragment& pFrag) const;
+
+ /// getOutputOffset - Get the offset of the given fragment inside
+ /// the output's MCSectionData.
+ ///
+ /// @return return -1 if the fragment is not found in output's MCSectionData.
+
+ uint64_t getOutputOffset(const MCFragmentRef& pFragRef);
+ /// getOutputOffset - Get the offset of the given fragment inside
+ /// the output's MCSectionData.
+ ///
+ /// @return return -1 if the fragment is not found in output's MCSectionData.
+ uint64_t getOutputOffset(const MCFragmentRef& pFragRef) const;
+
+ /// getOutputLDSection - give a MCFragment, return the corresponding output
+ /// LDSection*
+ ///
+ /// @return return NULL if the fragment is not found in the output
+ LDSection* getOutputLDSection(const llvm::MCFragment& pFrag);
+
+ /// getOutputLDSection - give a MCFragment, return the corresponding output
+ /// LDSection*
+ ///
+ /// @return return NULL if the fragment is not found in the output
+ const LDSection* getOutputLDSection(const llvm::MCFragment& pFrag) const;
+
+ // ----- modifiers ----- //
+ bool layout(Output& pOutput, const TargetLDBackend& pBackend);
+
+ /// addInputRange
+ void addInputRange(const llvm::MCSectionData& pSD,
+ const LDSection& pInputHdr);
+
+ /// appendFragment - append the given MCFragment to the given MCSectionData,
+ /// and insert a MCAlignFragment to preserve the required align constraint if
+ /// needed
+ /// @return return the inserted size, i.e., the size of pFrag and alignment
+ /// size if any
+ uint64_t appendFragment(llvm::MCFragment& pFrag,
+ llvm::MCSectionData& pSD,
+ uint32_t pAlignConstraint = 1);
+private:
+ /** \class Range
+ * \brief Range is a <input's LDSection, previous rear fragment> pair
+ */
+ struct Range : public llvm::ilist_node<Range>
+ {
+ public:
+ Range();
+ Range(const LDSection& pHeader);
+ ~Range();
+
+ public:
+ LDSection* header;
+ llvm::MCFragment* prevRear;
+ };
+
+ typedef llvm::iplist<Range> RangeList;
+
+ typedef std::map<const llvm::MCSectionData*, RangeList*> SDRangeMap;
+
+ typedef GCFactory<MCFragmentRef, 0> FragRefFactory;
+
+private:
+ inline bool isFirstRange(const Range& pRange) const
+ { return (NULL == pRange.prevRear); }
+
+ inline bool isLastRange(const Range& pRange) const
+ { return (NULL == pRange.getNextNode()); }
+
+ inline bool isEmptyRange(const Range& pRange) const
+ {
+ if (isFirstRange(pRange)) {
+ if (!pRange.header->hasSectionData() ||
+ pRange.header->getSectionData()->getFragmentList().empty())
+ return true;
+ else
+ return false;
+ }
+ return (NULL == pRange.prevRear->getNextNode());
+ }
+
+ // get the front fragment in the range.
+ inline llvm::MCFragment* getFront(Range& pRange) const
+ {
+ if (!pRange.header->hasSectionData())
+ return NULL;
+ if (pRange.header->getSectionData()->getFragmentList().empty())
+ return NULL;
+
+ if (isFirstRange(pRange))
+ return &pRange.header->getSectionData()->getFragmentList().front();
+
+ if (isEmptyRange(pRange))
+ return NULL;
+
+ return pRange.prevRear->getNextNode();
+ }
+
+ inline const llvm::MCFragment* getFront(const Range& pRange) const
+ {
+ if (!pRange.header->hasSectionData())
+ return NULL;
+ if (pRange.header->getSectionData()->getFragmentList().empty())
+ return NULL;
+
+ if (isFirstRange(pRange))
+ return &pRange.header->getSectionData()->getFragmentList().front();
+
+ if (isEmptyRange(pRange))
+ return NULL;
+
+ return pRange.prevRear->getNextNode();
+ }
+
+ // get the rear fragment in the range.
+ inline llvm::MCFragment* getRear(Range& pRange) const
+ {
+ if (!pRange.header->hasSectionData())
+ return NULL;
+ if (pRange.header->getSectionData()->getFragmentList().empty())
+ return NULL;
+
+ if (isLastRange(pRange)) {
+ if (isEmptyRange(pRange))
+ return NULL;
+ return &pRange.header->getSectionData()->getFragmentList().back();
+ }
+ return pRange.getNextNode()->prevRear;
+ }
+
+ inline const llvm::MCFragment* getRear(const Range& pRange) const
+ {
+ if (!pRange.header->hasSectionData())
+ return NULL;
+ if (pRange.header->getSectionData()->getFragmentList().empty())
+ return NULL;
+
+ if (isLastRange(pRange)) {
+ if (isEmptyRange(pRange))
+ return NULL;
+ return &pRange.header->getSectionData()->getFragmentList().back();
+ }
+ return pRange.getNextNode()->prevRear;
+ }
+
+ MCFragmentRef* getFragmentRef(Range &pRange, uint64_t pOffset);
+
+ MCFragmentRef* getFragmentRef(llvm::MCFragment& pFront,
+ llvm::MCFragment& pRear,
+ uint64_t pOffset);
+
+ bool hasLayoutOrder(const llvm::MCFragment& pFragment) const
+ { return (pFragment.getLayoutOrder() != ~(0U)); }
+
+ bool hasLayoutOffset(const llvm::MCFragment& pFragment) const
+ { return (pFragment.Offset != ~UINT64_C(0)); }
+
+ bool isValidOffset(const llvm::MCFragment& pFrag, uint64_t pTargetOffset) const;
+
+ void setFragmentLayoutOrder(llvm::MCFragment* pFragment);
+
+ void setFragmentLayoutOffset(llvm::MCFragment* pFragment);
+
+ /// sortSectionOrder - perform sorting on m_SectionOrder to get final layout
+ /// ordering
+ void sortSectionOrder(const Output& pOutput,
+ const TargetLDBackend& pBackend);
+
+private:
+ /// a vector to describe the order of sections
+ SectionOrder m_SectionOrder;
+
+ /// the map from MCSectionData* to its own RangeList.
+ SDRangeMap m_SDRangeMap;
+
+ FragRefFactory m_FragRefFactory;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ObjectReader.h b/include/mcld/LD/ObjectReader.h
new file mode 100644
index 0000000..9dbe9ac
--- /dev/null
+++ b/include/mcld/LD/ObjectReader.h
@@ -0,0 +1,69 @@
+//===- ObjectReader.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_OBJECT_READER_H
+#define MCLD_OBJECT_READER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/LD/LDReader.h"
+#include <llvm/Support/system_error.h>
+#include <mcld/ADT/HashTable.h>
+#include <mcld/ADT/StringHash.h>
+#include <mcld/LD/ResolveInfo.h>
+#include <mcld/LD/ResolveInfoFactory.h>
+
+namespace mcld
+{
+
+class Input;
+
+/** \class ObjectReader
+ * \brief ObjectReader provides an common interface for different object
+ * formats.
+ */
+class ObjectReader : public LDReader
+{
+protected:
+ typedef HashTable<ResolveInfo,
+ StringHash<ELF>,
+ ResolveInfoFactory> GroupSignatureMap;
+
+protected:
+ ObjectReader()
+ { }
+
+public:
+ virtual ~ObjectReader() { }
+
+ virtual bool readObject(Input& pFile) = 0;
+
+ virtual bool readSymbols(Input& pFile) = 0;
+
+ virtual bool readSections(Input& pFile) = 0;
+
+ /// readRelocations - read relocation sections
+ ///
+ /// This function should be called after symbol resolution.
+ virtual bool readRelocations(Input& pFile) = 0;
+
+ GroupSignatureMap& signatures()
+ { return f_GroupSignatureMap; }
+
+ const GroupSignatureMap& signatures() const
+ { return f_GroupSignatureMap; }
+
+protected:
+ GroupSignatureMap f_GroupSignatureMap;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ObjectWriter.h b/include/mcld/LD/ObjectWriter.h
new file mode 100644
index 0000000..0c48723
--- /dev/null
+++ b/include/mcld/LD/ObjectWriter.h
@@ -0,0 +1,39 @@
+//===- ObjectWriter.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_OBJECT_WRITER_INTERFACE_H
+#define MCLD_OBJECT_WRITER_INTERFACE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/Support/system_error.h>
+
+namespace mcld
+{
+
+class Output;
+class GNULDBackend;
+
+/** \class ObjectWriter
+ * \brief ObjectWriter provides a common interface for object file writers.
+ */
+class ObjectWriter
+{
+protected:
+ ObjectWriter(GNULDBackend& pBackend);
+
+public:
+ virtual ~ObjectWriter();
+
+ virtual llvm::error_code writeObject(Output& pOutput) = 0;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/OutputSymbolTable.h b/include/mcld/LD/OutputSymbolTable.h
new file mode 100644
index 0000000..fdcf0bc
--- /dev/null
+++ b/include/mcld/LD/OutputSymbolTable.h
@@ -0,0 +1,44 @@
+//===- OutputSymbolTable.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef OUTPUTSYMBOLTABLE_H
+#define OUTPUTSYMBOLTABLE_H
+#include <llvm/ADT/StringRef.h>
+#include "mcld/LD/SymbolTableIF.h"
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+class LDSymbol;
+
+/** \class OutputSymbolTable
+ * \brief Output symbol table, for MCLDOutput.
+ *
+ * \see
+ */
+class OutputSymbolTable : public SymbolTableIF
+{
+ /* draft. */
+ friend class SymbolTableFactory;
+private:
+ OutputSymbolTable(StrSymPool &pStrSymPool,
+ size_t pNumOfSymbols,
+ StringTable &pEntireStringTable,
+ StringTable &pDynamicStringTable);
+private:
+ virtual void doInsertSymbol(LDSymbol *);
+ virtual void doMerge(const SymbolTableIF &);
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/Relocation.h b/include/mcld/LD/Relocation.h
new file mode 100644
index 0000000..09ff6e4
--- /dev/null
+++ b/include/mcld/LD/Relocation.h
@@ -0,0 +1,115 @@
+//===- Relocation.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LD_RELOCATION_H
+#define LD_RELOCATION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/ilist_node.h>
+#include <llvm/Support/DataTypes.h>
+#include <mcld/MC/MCFragmentRef.h>
+#include <mcld/LD/ResolveInfo.h>
+#include <mcld/LD/LDSymbol.h>
+
+
+namespace mcld
+{
+class Layout;
+class RelocationFactory;
+class MCLDInfo;
+
+class Relocation : public llvm::MCFragment
+{
+friend class RelocationFactory;
+
+public:
+ typedef uint64_t Address; // FIXME: use SizeTrait<T>::Address instead
+ typedef uint64_t DWord; // FIXME: use SizeTrait<T>::Word instead
+ typedef uint8_t Type;
+
+private:
+ Relocation(Type pType,
+ MCFragmentRef* pTargetRef,
+ Address pAddend,
+ DWord pTargetData);
+
+public:
+ ~Relocation();
+
+ /// type - relocation type
+ Type type() const
+ { return m_Type; }
+
+ /// symValue - S value - the symbol address
+ Address symValue() const;
+
+ /// addend - A value
+ Address addend() const
+ { return m_Addend; }
+
+ /// place - P value - address of the place being relocated
+ Address place(const Layout& pLayout) const;
+
+ /// symbol info - binding, type
+ const ResolveInfo* symInfo() const
+ { return m_pSymInfo; }
+
+ /// symbol info - binding, type
+ ResolveInfo* symInfo()
+ { return m_pSymInfo; }
+
+ /// target - the target data to relocate
+ DWord& target();
+
+ /// target - the target data to relocate
+ const DWord& target() const;
+
+ /// targetRef - the reference of the target data
+ MCFragmentRef& targetRef()
+ { return m_TargetAddress; }
+
+ /// targetRef - the reference of the target data
+ const MCFragmentRef& targetRef() const
+ { return m_TargetAddress; }
+
+ void apply(RelocationFactory& pRelocFactory, const MCLDInfo& pLDInfo);
+
+ /// ----- modifiers ----- ///
+ void setType(Type pType);
+
+ void setAddend(Address pAddend);
+
+ void setSymInfo(ResolveInfo* pSym);
+
+ // Relocation is a kind of MCFragment with type of FT_Reloc
+ static bool classof(const MCFragment *F)
+ { return F->getKind() == MCFragment::FT_Reloc;}
+ static bool classof(const Relocation *) { return true; }
+
+private:
+ /// m_Type - the type of the relocation entries
+ Type m_Type;
+
+ /// m_TargetData - target data of the place being relocated
+ DWord m_TargetData;
+
+ /// m_pSymInfo - resolved symbol info of relocation target symbol
+ ResolveInfo* m_pSymInfo;
+
+ /// m_TargetAddress - MCFragmentRef of the place being relocated
+ MCFragmentRef m_TargetAddress;
+
+ /// m_Addend - the addend
+ Address m_Addend;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/RelocationFactory.h b/include/mcld/LD/RelocationFactory.h
new file mode 100644
index 0000000..eed3eae
--- /dev/null
+++ b/include/mcld/LD/RelocationFactory.h
@@ -0,0 +1,81 @@
+//===- Relocation.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LD_RELOCATION_FACTORY_H
+#define LD_RELOCATION_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Support/GCFactory.h>
+#include <mcld/LD/Relocation.h>
+
+namespace mcld
+{
+
+class LDSymbol;
+class ResolveInfo;
+class MCFragmentRef;
+class Layout;
+class GOT;
+class TargetLDBackend;
+class MCLDInfo;
+
+/** \class RelocationFactory
+ * \brief RelocationFactory provides the interface for generating target
+ * relocation
+ *
+ */
+class RelocationFactory : public GCFactory<Relocation, 0>
+{
+public:
+ typedef Relocation::Type Type;
+ typedef Relocation::Address Address;
+ typedef Relocation::DWord DWord;
+
+public:
+ explicit RelocationFactory(size_t pNum);
+
+ virtual ~RelocationFactory();
+
+ /// apply - general apply function
+ virtual void applyRelocation(Relocation& pRelocation,
+ const MCLDInfo& pLDInfo) = 0;
+
+ // ----- production ----- //
+ /// produce - produce a relocation entry
+ /// @param pType - the type of the relocation entry
+ /// @param pFragRef - the place to apply the relocation
+ /// @param pAddend - the addend of the relocation entry
+ Relocation* produce(Type pType,
+ MCFragmentRef& pFragRef,
+ Address pAddend = 0);
+
+ /// produceEmptyEntry - produce an empty relocation which
+ /// occupied memory space but all contents set to zero.
+ Relocation* produceEmptyEntry();
+
+ void destroy(Relocation* pRelocation);
+
+ void setLayout(const Layout& pLayout);
+
+ // ------ observers -----//
+ const Layout& getLayout() const;
+
+ virtual TargetLDBackend& getTarget() = 0;
+
+ virtual const TargetLDBackend& getTarget() const = 0;
+
+private:
+ const Layout* m_pLayout;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ResolveInfo.h b/include/mcld/LD/ResolveInfo.h
new file mode 100644
index 0000000..f48f1c2
--- /dev/null
+++ b/include/mcld/LD/ResolveInfo.h
@@ -0,0 +1,279 @@
+//===- ResolveInfo.h ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_RESOLVE_INFO_H
+#define MCLD_RESOLVE_INFO_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/DataTypes.h>
+#include <llvm/ADT/StringRef.h>
+
+namespace mcld
+{
+
+class LDSymbol;
+
+/** \class ResolveInfo
+ * \brief ResolveInfo records the information about how to resolve a symbol.
+ *
+ * A symbol must have some `attributes':
+ * - Desc - Defined, Reference, Common or Indirect
+ * - Binding - Global, Local, Weak
+ * - IsDyn - appear in dynamic objects or regular objects
+ * - Type - what the symbol points to
+ * - Size - the size of the symbol point to
+ * - Value - the pointer to another LDSymbol
+ * In order to save the memory and speed up the performance, MCLinker uses
+ * a bit field to store all attributes.
+ *
+ * The maximum string length is (2^16 - 1)
+ */
+class ResolveInfo
+{
+friend class ResolveInfoFactory;
+friend class MCLinker;
+public:
+ typedef uint64_t SizeType;
+
+ /** \enum Type
+ * \brief What the symbol stand for
+ *
+ * It is like ELF32_ST_TYPE
+ * MachO does not need this, and can not jump between Thumb and ARM code.
+ */
+ enum Type {
+ NoType = 0,
+ Object = 1,
+ Function = 2,
+ Section = 3,
+ File = 4,
+ CommonBlock = 5,
+ ThreadLocal = 6,
+ LoProc = 13,
+ HiProc = 15
+ };
+
+ /** \enum Desc
+ * \brief Description of the symbols.
+ *
+ * Follow the naming in MachO. Like MachO nlist::n_desc
+ * In ELF, is a part of st_shndx
+ */
+ enum Desc {
+ Undefined = 0,
+ Define = 1,
+ Common = 2,
+ Indirect = 3,
+ NoneDesc
+ };
+
+ enum Binding {
+ Global = 0,
+ Weak = 1,
+ Local = 2,
+ Absolute = 3,
+ NoneBinding
+ };
+
+ enum Visibility {
+ Default = 0,
+ Internal = 1,
+ Hidden = 2,
+ Protected = 3
+ };
+
+ // ----- For HashTable ----- //
+ typedef llvm::StringRef key_type;
+
+public:
+ // ----- modifiers ----- //
+ /// setRegular - set the source of the file is a regular object
+ void setRegular();
+
+ /// setDynamic - set the source of the file is a dynamic object
+ void setDynamic();
+
+ /// setSource - set the source of the file
+ /// @param pIsDyn is the source from a dynamic object?
+ void setSource(bool pIsDyn);
+
+ void setType(uint32_t pType);
+
+ void setDesc(uint32_t pDesc);
+
+ void setBinding(uint32_t pBinding);
+
+ void setOther(uint32_t pOther);
+
+ void setVisibility(Visibility pVisibility);
+
+ void setIsSymbol(bool pIsSymbol);
+
+ void setReserved(uint32_t pReserved);
+
+ void setSize(SizeType pSize)
+ { m_Size = pSize; }
+
+ void override(const ResolveInfo& pForm);
+
+ void overrideAttributes(const ResolveInfo& pFrom);
+
+ void overrideVisibility(const ResolveInfo& pFrom);
+
+ void setSymPtr(const LDSymbol* pSymPtr)
+ { m_Ptr.sym_ptr = const_cast<LDSymbol*>(pSymPtr); }
+
+ void setLink(const ResolveInfo* pTarget) {
+ m_Ptr.info_ptr = const_cast<ResolveInfo*>(pTarget);
+ m_BitField |= indirect_flag;
+ }
+
+
+ // ----- observers ----- //
+ bool isSymbol() const;
+
+ bool isString() const;
+
+ bool isGlobal() const;
+
+ bool isWeak() const;
+
+ bool isLocal() const;
+
+ bool isAbsolute() const;
+
+ bool isDefine() const;
+
+ bool isUndef() const;
+
+ bool isDyn() const;
+
+ bool isCommon() const;
+
+ bool isIndirect() const;
+
+ uint32_t type() const;
+
+ uint32_t desc() const;
+
+ uint32_t binding() const;
+
+ uint32_t reserved() const;
+
+ uint8_t other() const
+ { return (uint8_t)visibility(); }
+
+ Visibility visibility() const;
+
+ LDSymbol* outSymbol()
+ { return m_Ptr.sym_ptr; }
+
+ const LDSymbol* outSymbol() const
+ { return m_Ptr.sym_ptr; }
+
+ ResolveInfo* link()
+ { return m_Ptr.info_ptr; }
+
+ const ResolveInfo* link() const
+ { return m_Ptr.info_ptr; }
+
+ SizeType size() const
+ { return m_Size; }
+
+ const char* name() const
+ { return m_Name; }
+
+ unsigned int nameSize() const
+ { return (m_BitField >> NAME_LENGTH_OFFSET); }
+
+ uint32_t info() const
+ { return (m_BitField & INFO_MASK); }
+
+ uint32_t bitfield() const
+ { return m_BitField; }
+
+ // ----- For HashTable ----- //
+ bool compare(const key_type& pKey);
+
+private:
+ static const uint32_t GLOBAL_OFFSET = 0;
+ static const uint32_t GLOBAL_MASK = 1;
+
+ static const uint32_t DYN_OFFSET = 1;
+ static const uint32_t DYN_MASK = 1 << DYN_OFFSET;
+
+ static const uint32_t DESC_OFFSET = 2;
+ static const uint32_t DESC_MASK = 0x3 << DESC_OFFSET;
+
+ static const uint32_t LOCAL_OFFSET = 4;
+ static const uint32_t LOCAL_MASK = 1 << LOCAL_OFFSET;
+
+ static const uint32_t BINDING_MASK = GLOBAL_MASK | LOCAL_MASK;
+
+ static const uint32_t VISIBILITY_OFFSET = 5;
+ static const uint32_t VISIBILITY_MASK = 0x3 << VISIBILITY_OFFSET;
+
+ static const uint32_t TYPE_OFFSET = 7;
+ static const uint32_t TYPE_MASK = 0xF << TYPE_OFFSET;
+
+ static const uint32_t SYMBOL_OFFSET = 11;
+ static const uint32_t SYMBOL_MASK = 1 << SYMBOL_OFFSET;
+
+ static const uint32_t RESERVED_OFFSET = 12;
+ static const uint32_t RESERVED_MASK = 0xF << RESERVED_OFFSET;
+ static const uint32_t NAME_LENGTH_OFFSET = 16;
+ static const uint32_t INFO_MASK = 0xF;
+ static const uint32_t RESOLVE_MASK = 0xFFFF;
+
+ union SymOrInfo {
+ LDSymbol* sym_ptr;
+ ResolveInfo* info_ptr;
+ };
+
+public:
+ static const uint32_t global_flag = 0 << GLOBAL_OFFSET;
+ static const uint32_t weak_flag = 1 << GLOBAL_OFFSET;
+ static const uint32_t regular_flag = 0 << DYN_OFFSET;
+ static const uint32_t dynamic_flag = 1 << DYN_OFFSET;
+ static const uint32_t undefine_flag = 0 << DESC_OFFSET;
+ static const uint32_t define_flag = 1 << DESC_OFFSET;
+ static const uint32_t common_flag = 2 << DESC_OFFSET;
+ static const uint32_t indirect_flag = 3 << DESC_OFFSET;
+ static const uint32_t local_flag = 1 << LOCAL_OFFSET;
+ static const uint32_t absolute_flag = BINDING_MASK;
+ static const uint32_t object_flag = Object << TYPE_OFFSET;
+ static const uint32_t function_flag = Function << TYPE_OFFSET;
+ static const uint32_t section_flag = Section << TYPE_OFFSET;
+ static const uint32_t file_flag = File << TYPE_OFFSET;
+ static const uint32_t string_flag = 0 << SYMBOL_OFFSET;
+ static const uint32_t symbol_flag = 1 << SYMBOL_OFFSET;
+
+private:
+ ResolveInfo();
+ ResolveInfo(const ResolveInfo& pCopy);
+ ResolveInfo& operator=(const ResolveInfo& pCopy);
+ ~ResolveInfo();
+
+private:
+ SizeType m_Size;
+ SymOrInfo m_Ptr;
+
+ /** m_BitField
+ * 31 ... 16 15 12 11 10..7 6 .. 5 4 3 2 1 0
+ * |length of m_Name|reserved|Symbol|Type |ELF visibility|Local|Com|Def|Dyn|Weak|
+ */
+ uint32_t m_BitField;
+ char m_Name[0];
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ResolveInfoFactory.h b/include/mcld/LD/ResolveInfoFactory.h
new file mode 100644
index 0000000..fcadf48
--- /dev/null
+++ b/include/mcld/LD/ResolveInfoFactory.h
@@ -0,0 +1,37 @@
+//===- ResolveInfoFactory.h -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_RESOLVE_INFO_FACTORY_H
+#define MCLD_RESOLVE_INFO_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/LD/ResolveInfo.h"
+
+namespace mcld
+{
+
+/** \class ResolveInfoFactory
+ * \brief ResolveInfoFactory creates ResolveInfos.
+ */
+class ResolveInfoFactory
+{
+public:
+ typedef ResolveInfo entry_type;
+ typedef ResolveInfo::key_type key_type;
+
+public:
+ entry_type* produce(const key_type& pKey);
+ void destroy(entry_type* pEntry);
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/Resolver.h b/include/mcld/LD/Resolver.h
new file mode 100644
index 0000000..98dfe2c
--- /dev/null
+++ b/include/mcld/LD/Resolver.h
@@ -0,0 +1,100 @@
+//===- Resolver.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SYMBOL_RESOLVER_H
+#define MCLD_SYMBOL_RESOLVER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <string>
+#include <utility>
+
+namespace mcld
+{
+
+class ResolveInfo;
+class StrSymPool;
+
+/** \class Resolver
+ * \brief Resolver binds a symbol reference from one file to a symbol
+ * definition of another file.
+ *
+ * Resolver seals up the algorithm of symbol resolution. The resolution of
+ * two symbols depends on their type, binding and whether it is belonging to
+ * a shared object.
+ */
+class Resolver
+{
+public:
+ enum Action {
+ Success,
+ Warning,
+ Abort,
+ LastAction
+ };
+
+ /** \class Resolver::Result
+ * \brief the result of symbol resolution
+ * - info, the pointer to overrided info
+ * - existent, if true, the info is existent
+ * - overriden, if true, the info is being overriden.
+ */
+ struct Result {
+ ResolveInfo* info;
+ bool existent;
+ bool overriden;
+ };
+
+public:
+ Resolver();
+
+ Resolver(const Resolver& pCopy);
+
+ virtual ~Resolver();
+
+ /// shouldOverride - Can resolver override the symbol pOld by the symbol pNew?
+ /// @return the action should be taken.
+ /// @param pOld the symbol which may be overridden.
+ /// @param pNew the symbol which is used to replace pOld
+ virtual unsigned int resolve(ResolveInfo & __restrict__ pOld,
+ const ResolveInfo & __restrict__ pNew,
+ bool &pOverride) = 0;
+
+ /// resolveAgain - Can override by derived classes.
+ /// @return the pointer to resolved ResolveInfo
+ /// @return is the symbol existent?
+ virtual void resolveAgain(StrSymPool& pStrSymPool,
+ unsigned int pAction,
+ ResolveInfo& __restrict__ pOld,
+ const ResolveInfo& __restrict__ pNew,
+ Result& pResult) {
+ pResult.info = NULL;
+ pResult.existent = false;
+ pResult.overriden = false;
+ }
+
+ const std::string& mesg() const
+ { return m_Mesg; }
+
+ void clearMesg();
+
+ Resolver* clone() const {
+ return doClone();
+ }
+
+protected:
+ std::string m_Mesg;
+
+private:
+ virtual Resolver* doClone() const = 0;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/SectionMap.h b/include/mcld/LD/SectionMap.h
new file mode 100644
index 0000000..424d785
--- /dev/null
+++ b/include/mcld/LD/SectionMap.h
@@ -0,0 +1,105 @@
+//===- SectionMap.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SECTION_MAP_H
+#define MCLD_SECTION_MAP_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/DataTypes.h>
+#include <vector>
+#include <string>
+
+namespace mcld
+{
+
+/** \class SectionMap
+ * \brief descirbe the mappings of input section's name (or prefix) to
+ * its associated output section's name and offset
+ */
+class SectionMap
+{
+public:
+ // a mapping in SectionMap is the triple of
+ // {input substr, output section's name, output section's offset}
+ struct Mapping {
+ std::string inputSubStr;
+ std::string outputStr;
+ uint64_t offset;
+ };
+
+ typedef std::vector<struct Mapping> SectionMappingTy;
+
+ typedef SectionMappingTy::iterator iterator;
+ typedef SectionMappingTy::const_iterator const_iterator;
+
+public:
+ SectionMap();
+ ~SectionMap();
+
+ // get the possible output section name based on the mapping table
+ // return NULL if not found
+ const std::string& getOutputSectName(const std::string& pInput);
+
+ // add a mapping from input substr to output name and offset.
+ bool push_back(const std::string& pInput,
+ const std::string& pOutput,
+ const uint64_t pOffset = 0);
+
+ // find - return the iterator to the mapping
+ iterator find(const std::string& pInput);
+
+ // at - return the pointer to the mapping
+ Mapping* at(const std::string& pInput);
+
+ // ----- observers ----- //
+ bool empty() const
+ { return m_SectMap.empty(); }
+
+ size_t size() const
+ { return m_SectMap.size(); }
+
+ size_t capacity () const
+ { return m_SectMap.capacity(); }
+
+ // ----- iterators ----- //
+ iterator begin()
+ { return m_SectMap.begin(); }
+
+ iterator end()
+ { return m_SectMap.end(); }
+
+ const_iterator begin() const
+ { return m_SectMap.begin(); }
+
+ const_iterator end() const
+ { return m_SectMap.end(); }
+
+ // initStdSectionMap - add common mappings of ELF and other formats
+ // to SectionMap
+ bool initStdSectionMap();
+
+private:
+ struct SectionNameMapping {
+ const char* from;
+ const char* to;
+ };
+
+ // used to store common mappings of ELF and other formants
+ static const SectionNameMapping m_StdSectionMap[];
+
+ static const int m_StdSectionMapSize;
+
+ SectionMappingTy m_SectMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/SectionMerger.h b/include/mcld/LD/SectionMerger.h
new file mode 100644
index 0000000..40f1453
--- /dev/null
+++ b/include/mcld/LD/SectionMerger.h
@@ -0,0 +1,98 @@
+//===- SectionMerger.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SECTION_MERGER_H
+#define MCLD_SECTION_MERGER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <vector>
+#include <string>
+#include <llvm/MC/MCAssembler.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/LD/SectionMap.h>
+
+namespace mcld
+{
+class MCLinker;
+
+/** \class SectionMerger
+ * \brief maintain the mappings of substr of input section name to associated
+ * output section (data)
+ */
+class SectionMerger
+{
+public:
+ struct Mapping {
+ std::string inputSubStr;
+ LDSection* outputSection;
+ };
+ typedef std::vector<Mapping> LDSectionMapTy;
+
+ typedef LDSectionMapTy::iterator iterator;
+ typedef LDSectionMapTy::const_iterator const_iterator;
+
+public:
+ SectionMerger(SectionMap& pSectionMap, LDContext& pContext);
+ ~SectionMerger();
+
+ /// getOutputSectHdr - return a associated output section header
+ LDSection* getOutputSectHdr(const std::string& pName);
+
+ /// getOutputSectData - return a associated output section data
+ llvm::MCSectionData* getOutputSectData(const std::string& pName);
+
+ /// addMapping - add a mapping as creating one new output LDSection
+ /// @param pName - a input section name
+ /// @param pSection - the output LDSection*
+ bool addMapping(const std::string& pName, LDSection* pSection);
+
+ // ----- observers ----- //
+ bool empty() const
+ { return m_LDSectionMap.empty(); }
+
+ size_t size() const
+ { return m_LDSectionMap.size(); }
+
+ size_t capacity () const
+ { return m_LDSectionMap.capacity(); }
+
+ // ----- iterators ----- //
+ iterator find(const std::string& pName);
+
+ iterator begin()
+ { return m_LDSectionMap.begin(); }
+
+ iterator end()
+ { return m_LDSectionMap.end(); }
+
+ const_iterator begin() const
+ { return m_LDSectionMap.begin(); }
+
+ const_iterator end() const
+ { return m_LDSectionMap.end(); }
+
+private:
+ /// initOutputSectMap - initialize the map from input substr to associated
+ /// output LDSection*
+ void initOutputSectMap();
+
+private:
+ SectionMap& m_SectionNameMap;
+
+ LDContext& m_Output;
+
+ LDSectionMapTy m_LDSectionMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/StaticResolver.h b/include/mcld/LD/StaticResolver.h
new file mode 100644
index 0000000..5bf5c5d
--- /dev/null
+++ b/include/mcld/LD/StaticResolver.h
@@ -0,0 +1,145 @@
+//===- StaticResolver.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_STATIC_SYMBOL_RESOLVER_H
+#define MCLD_STATIC_SYMBOL_RESOLVER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <string>
+#include <mcld/LD/Resolver.h>
+#include <mcld/LD/ResolveInfo.h>
+
+namespace mcld
+{
+
+class StrSymPool;
+
+/** \class StaticResolver
+ */
+class StaticResolver : public Resolver
+{
+public:
+ /** \enum LinkAction
+ * LinkAction follows BFD:linker.c (binary file descriptor).
+ * List all actions to take in the state table
+ */
+ enum LinkAction
+ {
+ FAIL, /* abort. */
+ NOACT, /* no action. */
+ UND, /* override by symbol undefined symbol. */
+ WEAK, /* override by symbol weak undefined. */
+ DEF, /* override by symbol defined. */
+ DEFW, /* override by symbol weak defined. */
+ DEFD, /* override by symbol dynamic defined. */
+ DEFWD, /* override by symbol dynamic weak defined. */
+ MDEFD, /* mark symbol dynamic defined. */
+ MDEFWD, /* mark symbol dynamic weak defined. */
+ DUND, /* override dynamic defined symbol by undefined one. */
+ DUNDW, /* oevrride dynamic defined symbol by weak undefined one. */
+ COM, /* override by symbol common. */
+ CREF, /* Possibly warn about common reference to defined symbol. */
+ CDEF, /* redefine existing common symbol. */
+ BIG, /* override by symbol common using largest size. */
+ MBIG, /* mark common symbol by larger size. */
+ IND, /* override by indirect symbol. */
+ CIND, /* mark indirect symbol from existing common symbol. */
+ MDEF, /* multiple definition error. */
+ MIND, /* multiple indirect symbols. */
+ REFC /* Mark indirect symbol referenced and then CYCLE. */
+ };
+
+private:
+ // These are the values generated by the bit codes.
+ /** Encoding:
+ * D -> define
+ * U -> undefine
+ * d -> dynamic
+ * w -> weak
+ * C -> common
+ * I -> indirect
+ */
+ enum
+ {
+ U = ResolveInfo::global_flag | ResolveInfo::regular_flag | ResolveInfo::undefine_flag,
+ w_U = ResolveInfo::weak_flag | ResolveInfo::regular_flag | ResolveInfo::undefine_flag,
+ d_U = ResolveInfo::global_flag | ResolveInfo::dynamic_flag | ResolveInfo::undefine_flag,
+ wd_U = ResolveInfo::weak_flag | ResolveInfo::dynamic_flag | ResolveInfo::undefine_flag,
+ D = ResolveInfo::global_flag | ResolveInfo::regular_flag | ResolveInfo::define_flag,
+ w_D = ResolveInfo::weak_flag | ResolveInfo::regular_flag | ResolveInfo::define_flag,
+ d_D = ResolveInfo::global_flag | ResolveInfo::dynamic_flag | ResolveInfo::define_flag,
+ wd_D = ResolveInfo::weak_flag | ResolveInfo::dynamic_flag | ResolveInfo::define_flag,
+ C = ResolveInfo::global_flag | ResolveInfo::regular_flag | ResolveInfo::common_flag,
+ w_C = ResolveInfo::weak_flag | ResolveInfo::regular_flag | ResolveInfo::common_flag,
+ d_C = ResolveInfo::global_flag | ResolveInfo::dynamic_flag | ResolveInfo::common_flag,
+ wd_C = ResolveInfo::weak_flag | ResolveInfo::dynamic_flag | ResolveInfo::common_flag,
+ I = ResolveInfo::global_flag | ResolveInfo::regular_flag | ResolveInfo::indirect_flag,
+ w_I = ResolveInfo::weak_flag | ResolveInfo::regular_flag | ResolveInfo::indirect_flag,
+ d_I = ResolveInfo::global_flag | ResolveInfo::dynamic_flag | ResolveInfo::indirect_flag,
+ wd_I = ResolveInfo::weak_flag | ResolveInfo::dynamic_flag | ResolveInfo::indirect_flag
+ };
+
+ enum ORDINATE
+ {
+ U_ORD,
+ w_U_ORD,
+ d_U_ORD,
+ wd_U_ORD,
+ D_ORD,
+ w_D_ORD,
+ d_D_ORD,
+ wd_D_ORD,
+ C_ORD,
+ w_C_ORD,
+ Cs_ORD,
+ Is_ORD,
+ LAST_ORD
+ };
+
+public:
+ StaticResolver();
+
+ StaticResolver(const StaticResolver& pCopy);
+
+ virtual ~StaticResolver();
+
+ /// shouldOverride - Can resolver override the symbol pOld by the symbol pNew?
+ /// @return the action should be taken.
+ /// @param pOld the symbol which may be overridden.
+ /// @param pNew the symbol which is used to replace pOld
+ virtual unsigned int resolve(ResolveInfo & __restrict__ pOld,
+ const ResolveInfo & __restrict__ pNew,
+ bool &pOverride);
+
+ StaticResolver* doClone() const {
+ return new StaticResolver(*this);
+ }
+
+private:
+ inline unsigned int getOrdinate(const ResolveInfo& pInfo) const {
+ if (pInfo.isAbsolute() && pInfo.isDyn())
+ return d_D_ORD;
+ if (pInfo.isAbsolute())
+ return D_ORD;
+ if (pInfo.isCommon() && pInfo.isDyn())
+ return Cs_ORD;
+ if (pInfo.isCommon() && pInfo.isDefine())
+ return C_ORD;
+ if (pInfo.isCommon() && pInfo.isWeak())
+ return w_C_ORD;
+ if (pInfo.isIndirect())
+ return Is_ORD;
+ return pInfo.info();
+ }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/StrSymPool.h b/include/mcld/LD/StrSymPool.h
new file mode 100644
index 0000000..da5ed1f
--- /dev/null
+++ b/include/mcld/LD/StrSymPool.h
@@ -0,0 +1,111 @@
+//===- StrSymPool.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_STRING_SYMBOL_POOL_H
+#define MCLD_STRING_SYMBOL_POOL_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/ADT/StringRef.h>
+#include <mcld/ADT/HashTable.h>
+#include <mcld/ADT/StringHash.h>
+#include <mcld/ADT/Uncopyable.h>
+#include <mcld/LD/ResolveInfo.h>
+#include <mcld/LD/Resolver.h>
+#include <mcld/LD/ResolveInfoFactory.h>
+#include <utility>
+
+namespace llvm
+{
+ class MCSectionData;
+}
+
+namespace mcld
+{
+
+class Resolver;
+class StringTable;
+class SymbolTableIF;
+
+/** \class StrSymPool
+ * \brief Store symbol and search symbol by name. Can help symbol resolution.
+ *
+ * - MCLinker is responsed for creating StrSymPool.
+ */
+class StrSymPool : private Uncopyable
+{
+public:
+ typedef HashTable<ResolveInfo, StringHash<ELF>, ResolveInfoFactory> Table;
+ typedef size_t size_type;
+
+public:
+ StrSymPool(const Resolver& pResolver, size_type pSize = 3);
+ ~StrSymPool();
+
+ // ----- modifiers ----- //
+ /// createSymbol - create a symbol but do not insert into the pool.
+ ResolveInfo* createSymbol(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ ResolveInfo::Visibility pVisibility = ResolveInfo::Default);
+
+ /// insertSymbol - insert a symbol and resolve the symbol immediately
+ /// @param pOldInfo - if pOldInfo is not NULL, the old ResolveInfo being
+ /// overriden is kept in pOldInfo.
+ /// @param pResult the result of symbol resultion.
+ /// @note pResult.override is true if the output LDSymbol also need to be
+ /// overriden
+ void insertSymbol(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ ResolveInfo::Visibility pVisibility,
+ ResolveInfo* pOldInfo,
+ Resolver::Result& pResult);
+
+ /// findSymbol - find the resolved output LDSymbol
+ LDSymbol* findSymbol(const llvm::StringRef& pName);
+ const LDSymbol* findSymbol(const llvm::StringRef& pName) const;
+
+ /// findInfo - find the resolved ResolveInfo
+ ResolveInfo* findInfo(const llvm::StringRef& pName);
+ const ResolveInfo* findInfo(const llvm::StringRef& pName) const;
+
+ /// insertString - insert a string
+ /// if the string has existed, modify pString to the existing string
+ /// @return the StringRef points to the hash table
+ llvm::StringRef insertString(const llvm::StringRef& pString);
+
+ // ----- observers ----- //
+ size_type size() const
+ { return m_Table.numOfEntries(); }
+
+ bool empty() const
+ { return m_Table.empty(); }
+
+ // ----- capacity ----- //
+ void reserve(size_type pN);
+
+ size_type capacity() const;
+
+private:
+ Resolver* m_pResolver;
+ Table m_Table;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/StringUnorderedMap.h b/include/mcld/LD/StringUnorderedMap.h
new file mode 100644
index 0000000..05788aa
--- /dev/null
+++ b/include/mcld/LD/StringUnorderedMap.h
@@ -0,0 +1,225 @@
+//===- StringUnorderedMap.h -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SEARCH_TABLE_H
+#define MCLD_SEARCH_TABLE_H
+#include <vector>
+// For std::allocate.
+#include <memory>
+// For uint32_t.
+#include <stdint.h>
+#include <cassert>
+// For memset.
+#include <cstring>
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+/* FIXME: Move StringUnorderedMap under ADT. */
+
+namespace mcld
+{
+
+struct StringUnorderedMapDefaultHash
+{
+ size_t operator()(const char *pStr) {
+ size_t hashVal = 31;
+ while (*pStr)
+ hashVal = hashVal * 131 + (*pStr++);
+ return hashVal;
+ }
+};
+
+template<typename ValueType,
+ typename KeyType>
+struct StringUnorderedMapEntryInit
+{
+ template <typename InitType>
+ void operator()(KeyType &pKey, ValueType &pValue,
+ const KeyType &pStr, InitType pInitVal) {
+ ::new ((void*)&pKey) KeyStorageType(pStr);
+ ::new ((void*)&pValue) ValueType(pInitVal);
+ }
+};
+
+uint32_t findNextPrime(uint32_t x);
+
+/** \class StringUnorderedMap
+ * \brief The most simple hash of linked list version.
+ *
+ * \see
+ */
+template<typename KeyType,
+ typename ValueType,
+ typename KeyCompareFunctor,
+ typename HashFunction = StringUnorderedMapDefaultHash,
+ typename Allocator = std::allocator<std::pair<KeyType, ValueType> > >
+class StringUnorderedMap
+{
+public:
+ explicit StringUnorderedMap(size_t pCapacity = 17)
+ : m_Impl(pCapacity)
+ {}
+
+ ~StringUnorderedMap();
+
+ void reserve(size_t pCapacity);
+
+ ValueType &getOrCreate(const KeyType &pStr, const ValueType &pInitVal);
+
+ ValueType &getOrCreate(const KeyType &pStr);
+
+ bool empty()
+ { return m_Size == 0; }
+
+ size_t capacity() const
+ { return m_Capacity; }
+
+ void clear();
+
+private:
+ struct HashEntry {
+ size_t hashVal;
+ std::pair<KeyType, ValueType>
+ HashEntry *next;
+ };
+ typedef Allocator::template rebind<HashEntry>::other HashEntryAllocator;
+ void rehash(size_t pCapacity);
+
+private:
+ size_t m_Capacity;
+ size_t m_Size;
+ // array of pointers to hash entries
+ HashEntry **m_HashTable;
+ HashEntryAllocator m_HashEntryAllocator;
+};
+
+
+// =================================implementation============================
+// StringUnorderedMap::StringUnorderedMapImpl
+template<typename ValueType,
+ typename KeyStorageType,
+ typename HashFunction,
+ typename Allocator>
+StringUnorderedMap<ValueType, KeyStorageType, HashFunction, Allocator>::
+StringUnorderedMapImpl::StringUnorderedMapImpl(size_t pCapacity)
+ : m_Capacity(0), m_Size(0), m_HashTable(0)
+{
+ this->reserve(pCapacity);
+}
+
+template<typename ValueType,
+ typename KeyStorageType,
+ typename HashFunction,
+ typename Allocator>
+void
+StringUnorderedMap<ValueType, KeyStorageType, HashFunction, Allocator>::
+StringUnorderedMapImpl::reserve(size_t pCapacity)
+{
+ if (pCapacity < this->m_Capacity)
+ return;
+ size_t nextSize = findNextPrime(static_cast<uint32_t>(pCapacity));
+ // FIXME: Error handling.
+ assert(nextSize > this->m_Capacity && "findNextPrime error.");
+ if (this->m_Capacity != nextSize)
+ this->rehash(nextSize);
+}
+
+template<typename ValueType,
+ typename KeyStorageType,
+ typename HashFunction,
+ typename Allocator>
+void
+StringUnorderedMap<ValueType, KeyStorageType, HashFunction, Allocator>::
+StringUnorderedMapImpl::rehash(size_t pCapacity)
+{
+ HashEntry **tmpTable = new HashEntry*[pCapacity];
+ std::memset(tmpTable, 0, pCapacity * sizeof(HashEntry*));
+ if (this->m_HashTable) {
+ for (size_t i = 0; i < this->m_Capacity; ++i)
+ for (HashEntry *j = this->m_HashTable[i]; j != 0; ) {
+ HashEntry *nextJ = j->next;
+ j->next = tmpTable[j->hashVal % pCapacity];
+ tmpTable[j->hashVal % pCapacity] = j;
+ j = nextJ;
+ }
+ delete[] m_HashTable;
+ }
+ this->m_Capacity = pCapacity;
+ this->m_HashTable = tmpTable;
+}
+
+template<typename ValueType,
+ typename KeyStorageType,
+ typename HashFunction,
+ typename Allocator>
+template<typename InitType>
+ValueType &
+StringUnorderedMap<ValueType, KeyStorageType, HashFunction, Allocator>::
+StringUnorderedMapImpl::getOrCreate(const KeyType &pStr, ValueType &pInitVal)
+{
+ HashFunction hash;
+ size_t hashVal = hash(pStr);
+ HashEntry *&head = this->m_HashTable[hashVal % this->m_Capacity];
+
+ HashEntry *ans = 0;
+ for(HashEntry *ptr = head; ptr != 0; ptr = ptr->next)
+ if(hashVal == ptr->hashVal && pStr.equals(ptr->str)) {
+ ans = ptr;
+ break;
+ }
+ if (ans == 0) {
+ ans = this->allocate(1);
+ ans->hashVal = hashVal;
+ StringUnorderedMapEntryInit<ValueType, KeyStorageType> init;
+ init(ans->str, ans->value, pStr, pInitVal);
+ ans->next = head;
+ head = ans;
+ ++m_Size;
+ if(this->m_Size * 4LL >= this->m_Capacity * 3LL) // load factor = 0.75
+ this->reserve(this->m_Capacity+1);
+ }
+
+ return ans->value;
+}
+
+template<typename ValueType,
+ typename KeyStorageType,
+ typename HashFunction,
+ typename Allocator>
+void
+StringUnorderedMap<ValueType, KeyStorageType, HashFunction, Allocator>::
+StringUnorderedMapImpl::clear()
+{
+ if (this->m_HashTable) {
+ for (size_t i = 0; i < this->m_Capacity; ++i)
+ for (HashEntry *j = this->m_HashTable[i]; j != 0; ) {
+ HashEntry *nextJ = j->next;
+ this->destroy(j);
+ this->deallocate(j, 1);
+ j = nextJ;
+ }
+ delete[] m_HashTable;
+ }
+}
+
+
+template<typename ValueType,
+ typename KeyStorageType,
+ typename HashFunction,
+ typename Allocator>
+StringUnorderedMap<ValueType, KeyStorageType, HashFunction, Allocator>::
+StringUnorderedMapImpl::~StringUnorderedMapImpl()
+{
+ this->clear();
+}
+
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/SymbolTableFactory.h b/include/mcld/LD/SymbolTableFactory.h
new file mode 100644
index 0000000..cc02241
--- /dev/null
+++ b/include/mcld/LD/SymbolTableFactory.h
@@ -0,0 +1,73 @@
+//===- SymbolTableFactory.h -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SYMBOL_TABLE_FACTORY_H
+#define MCLD_SYMBOL_TABLE_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/LD/InputSymbolTable.h"
+#include "mcld/LD/OutputSymbolTable.h"
+
+namespace mcld
+{
+
+class StringTable;
+class StrSymPool;
+
+/** \class SymbolTableFactory
+ * \brief SymbolTableFactory manages SymbolTableIFs.
+ *
+ * SymbolTableFactory is responsed for construction and destruction of
+ * SymbolTableIF. Since different MCLDFiles have different type of
+ * SymbolTableIF, SymbolTableFactory separates the construction of
+ * SymbolTableIF into createInputTable() and createOutputTable().
+ *
+ * @see SymbolTableIF InputSymbolTable OutputSymbolTable
+ */
+class SymbolTableFactory
+{
+public:
+ /// SymbolTableFactory - constructor
+ // @param pNumOfSymbolTables is the most appropriate number of created
+ // symbol tables.
+ // @param pStorage the real storage of created symbols
+ explicit SymbolTableFactory(size_t pNumOfSymbolTables,
+ StrSymPool& pStrSymPool);
+ /// ~SymbolTableFactory - destructor
+ // destructor destroys all created symbol tables.
+ ~SymbolTableFactory();
+
+ /// createInputTable - create a symbol table for an input file
+ // @param pEntireStringTable the string table of created Symbols.
+ // @param pDynamicStringTable the string table of created Dynamic Symbols.
+ // @param pReserve Created symbol table must reserve pReserve number of
+ // storages of symbol for creating symbols.
+ SymbolTableIF *createInputTable(StringTable &pEntireStringTable,
+ StringTable &pDynamicStringTable,
+ size_t pReserve=256);
+
+ /// createOutputTable - create a symbol table for an output file
+ // @param pEntireStringTable the string table of created Symbols.
+ // @param pDynamicStringTable the string table of created Dynamic Symbols.
+ // @param pReserve Created symbol table must reserve pReserve number of
+ // storages of symbol for creating symbols.
+ SymbolTableIF *createOutputTable(StringTable &pEntireStringTable,
+ StringTable &pDynamicStringTable,
+ size_t pReserve=256);
+private:
+ StrSymPool &m_StrSymPool;
+ GCFactory<InputSymbolTable, 0> m_InputFactory;
+ GCFactory<OutputSymbolTable, 0> m_OutputFactory;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/AttributeFactory.h b/include/mcld/MC/AttributeFactory.h
new file mode 100644
index 0000000..eb4368b
--- /dev/null
+++ b/include/mcld/MC/AttributeFactory.h
@@ -0,0 +1,99 @@
+//===- AttributeFactory.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ATTRIBUTE_FACTORY_H
+#define MCLD_ATTRIBUTE_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/MC/MCLDAttribute.h"
+
+namespace mcld
+{
+
+/** \class AttributeFactory
+ * \brief AttributeFactory contructs the AttributeProxys.
+ *
+ * Since the number of AttributeProxys is usually small, sequential search
+ * on a small vector is enough.
+ */
+class AttributeFactory : private Uncopyable
+{
+private:
+ typedef std::vector<Attribute*> AttrSet;
+
+public:
+ typedef AttrSet::iterator iterator;
+ typedef AttrSet::const_iterator const_iterator;
+
+public:
+ AttributeFactory();
+ explicit AttributeFactory(size_t pNum);
+ ~AttributeFactory();
+
+ // reserve - reserve the memory space for attributes
+ // @param pNum the number of reserved attributes
+ void reserve(size_t pNum);
+
+ // predefined - return the predefined attribute
+ Attribute& predefined();
+ const Attribute& predefined() const;
+
+ // constraint - return the constraint of attributes
+ AttrConstraint& constraint()
+ { return m_Constraint; }
+
+ const AttrConstraint& constraint() const
+ { return m_Constraint; }
+
+ // produce - produce a attribute, but do not record it yet.
+ // the produced attribute is identical to the pre-defined attribute.
+ AttributeProxy* produce();
+
+ // last - the last touched attribute.
+ AttributeProxy& last();
+ const AttributeProxy& last() const;
+
+ // exists- return the recorded attribute whose content is identical to the
+ // input attribute.
+ Attribute *exists(const Attribute& pAttr) const;
+
+ // record - record the attribute no mater if it has been recorded.
+ void record(Attribute& pAttr);
+
+ // ----- observers ----- //
+ size_t size() const
+ { return m_AttrSet.size(); }
+
+ bool empty() const
+ { return m_AttrSet.empty(); }
+
+ // ----- iterators ----- //
+ iterator begin()
+ { return m_AttrSet.begin(); }
+
+ iterator end()
+ { return m_AttrSet.end(); }
+
+ const_iterator begin() const
+ { return m_AttrSet.begin(); }
+
+ const_iterator end() const
+ { return m_AttrSet.end(); }
+
+private:
+ AttrSet m_AttrSet;
+ AttrConstraint m_Constraint;
+ AttributeProxy *m_pLast;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/ContextFactory.h b/include/mcld/MC/ContextFactory.h
new file mode 100644
index 0000000..1ae0d45
--- /dev/null
+++ b/include/mcld/MC/ContextFactory.h
@@ -0,0 +1,47 @@
+//===- ContextFactory.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_CONTEXT_FACTORY_H
+#define MCLD_CONTEXT_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/LDContext.h>
+#include <mcld/Support/UniqueGCFactory.h>
+#include <mcld/Support/Path.h>
+
+namespace mcld
+{
+/** \class ContextFactory
+ * \brief ContextFactory avoids the duplicated LDContext of the same file.
+ *
+ * MCLinker is designed for efficient memory usage. Because user can give
+ * MCLinker the same input file many times on the command line, MCLinker must
+ * avoid opening identical file twice.
+ *
+ * ContextFactory is the guard to prevent redundant opening. MCLinker does not
+ * create LDContext directly. Instead, it creates LDContext by ContextFactory.
+ * ContextFactory returns the identical reference of LDContext if it's openend.
+ *
+ * @see LDContext
+ * @see UniqueGCFactoryBase
+ */
+class ContextFactory : public UniqueGCFactoryBase<sys::fs::Path, LDContext, 0>
+{
+public:
+ explicit ContextFactory(size_t pNum);
+ ~ContextFactory();
+
+ LDContext* produce(const sys::fs::Path& pPath);
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/InputFactory.h b/include/mcld/MC/InputFactory.h
new file mode 100644
index 0000000..5dc99c4
--- /dev/null
+++ b/include/mcld/MC/InputFactory.h
@@ -0,0 +1,56 @@
+//===- InputFactory.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_INPUT_FACTORY_H
+#define MCLD_INPUT_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/Support/GCFactory.h"
+#include "mcld/MC/MCLDInput.h"
+
+namespace mcld
+{
+
+class AttributeFactory;
+
+/** \class InputFactory
+ * \brief InputFactory controls the production and destruction of
+ * MCLDInput.
+ *
+ * All MCLDFiles created by MCLDFileFactory are guaranteed to be destructed
+ * while MCLDFileFactory is destructed.
+ *
+ * FIXME: the number of the Inputs should be passed in by Target or any
+ * target specific class.
+ *
+ * \see llvm::sys::Path
+ */
+class InputFactory : public GCFactory<Input,0>
+{
+public:
+ typedef GCFactory<Input, 0> Alloc;
+
+public:
+ InputFactory(size_t pNum, AttributeFactory& pAttrFactory);
+ ~InputFactory();
+
+ // ----- production ----- //
+ Input* produce(llvm::StringRef pName,
+ const sys::fs::Path& pPath,
+ unsigned int pType = Input::Unknown,
+ off_t pFileOffset = 0);
+
+private:
+ AttributeFactory &m_AttrFactory;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCBitcodeInterceptor.h b/include/mcld/MC/MCBitcodeInterceptor.h
new file mode 100644
index 0000000..182b157
--- /dev/null
+++ b/include/mcld/MC/MCBitcodeInterceptor.h
@@ -0,0 +1,75 @@
+//===- MCBitcodeInterceptor.h ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_BITCODE_INTERCEPTOR_H
+#define MCLD_BITCODE_INTERCEPTOR_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/MC/MCObjectWriter.h>
+
+
+namespace llvm
+{
+ class MCStreamer;
+ class MCObjectStreamer;
+ class MCAsmLayout;
+ class MCAssembler;
+ class MCFixup;
+ class MCFragment;
+ class MCSymbol;
+ class MCSymbolData;
+ class MCSymbolRefExpr;
+ class MCValue;
+ class raw_ostream;
+} // namespace of llvm
+
+namespace mcld
+{
+
+class MCLDInfo;
+class TargetLDBackend;
+
+/** \class MCBitcodeInterceptor
+ * \brief MCBitcodeInterceptor converts bitcode into LDContext
+ *
+ * @see LDContext
+ * @see MCObjectWriter
+ */
+class MCBitcodeInterceptor : public llvm::MCObjectWriter
+{
+public:
+ MCBitcodeInterceptor(llvm::MCObjectStreamer&, TargetLDBackend&, MCLDInfo&);
+ ~MCBitcodeInterceptor();
+
+ void ExecutePostLayoutBinding(llvm::MCAssembler &Asm,
+ const llvm::MCAsmLayout &Layout);
+
+ /// RecordRelocation - record relocations
+ // make a LDRelocation and recordds in the LDContext.
+ void RecordRelocation(const llvm::MCAssembler &Asm,
+ const llvm::MCAsmLayout &Layout,
+ const llvm::MCFragment *Fragment,
+ const llvm::MCFixup &Fixup,
+ llvm::MCValue Target,
+ uint64_t &FixedValue);
+
+ /// WriteObject - not really write out a object. Instead, load data to
+ /// LDContext
+ void WriteObject(llvm::MCAssembler &Asm, const llvm::MCAsmLayout &Layout);
+
+private:
+ TargetLDBackend& m_Backend;
+ MCLDInfo& m_LDInfo;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCDataFragment.h b/include/mcld/MC/MCDataFragment.h
new file mode 100644
index 0000000..330c9be
--- /dev/null
+++ b/include/mcld/MC/MCDataFragment.h
@@ -0,0 +1,85 @@
+//===- MCDataFragment.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCDATAFRAGMENT_H
+#define MCDATAFRAGMENT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/MC/MCAssembler.h>
+#include <llvm/MC/MCInst.h>
+#include <llvm/ADT/SmallString.h>
+#include "mcld/LD/Relocation.h"
+
+namespace mcld
+{
+
+/** \class MCDataFragment
+ * \brief MCDataFragment for mcld
+ *
+ * \see
+ * \author Diana Chen <[email protected]>
+ */
+class MCDataFragment : public llvm::MCFragment
+{
+public:
+ typedef std::vector<Relocation*> RelocationsType;
+private:
+
+ /// m_pFragment - llvm MCDataFragment for this MCDataFragment
+ llvm::MCDataFragment* m_pFragment;
+
+ /// m_Relocation - The list of relocations in this fragment
+ RelocationsType m_Relocations;
+
+public:
+ typedef RelocationsType::const_iterator const_relocation_iterator;
+ typedef RelocationsType::iterator relocation_iterator;
+
+public:
+ MCDataFragment(llvm::MCDataFragment& pFragment)
+ : m_pFragment(&pFragment) {
+ setParent( pFragment.getParent() );
+ setAtom( pFragment.getAtom() );
+ setLayoutOrder( pFragment.getLayoutOrder());
+ }
+ ~MCDataFragment(){}
+
+ // ------ observers ------//
+ llvm::SmallString<32> &getContents() { return m_pFragment->getContents(); }
+ const llvm::SmallString<32> &getContents() const { return m_pFragment->getContents(); }
+
+ // relocation access
+ void addRelocation(Relocation &pReloc){ m_Relocations.push_back(&pReloc); }
+
+ RelocationsType &getRelocations() { return m_Relocations; }
+ const RelocationsType &getRelcoations() const { return m_Relocations; }
+
+ relocation_iterator relocation_begin() { return m_Relocations.begin(); }
+ const_relocation_iterator relocation_begin() const { return m_Relocations.begin(); }
+
+ relocation_iterator relocation_end() {return m_Relocations.end();}
+ const_relocation_iterator relocation_end() const {return m_Relocations.end();}
+
+ size_t relocations_size() const { return m_Relocations.size(); }
+
+ // fragment identification
+ static bool classof(const MCFragment *pF) {
+ return pF->getKind() == llvm::MCFragment::FT_Data;
+ }
+ static bool classof(const MCDataFragment *) { return true; }
+
+ // overwrite parent method
+ FragmentType getKind() const { return m_pFragment->getKind(); }
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCFragmentRef.h b/include/mcld/MC/MCFragmentRef.h
new file mode 100644
index 0000000..b7d94cd
--- /dev/null
+++ b/include/mcld/MC/MCFragmentRef.h
@@ -0,0 +1,85 @@
+//===- MCFragmentRef.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MCFRAGMENT_REFERENCE_H
+#define MCLD_MCFRAGMENT_REFERENCE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/MC/MCAssembler.h>
+#include <mcld/ADT/SizeTraits.h>
+#include <mcld/ADT/TypeTraits.h>
+
+namespace mcld
+{
+
+class Layout;
+
+/// compunteFragmentSize - compute the specific MCFragment size
+uint64_t computeFragmentSize(const Layout& pLayout,
+ const llvm::MCFragment& pFrag);
+
+/** \class MCFragmentRef
+ * \brief MCFragmentRef is a reference of a MCFragment's contetnt.
+ *
+ */
+class MCFragmentRef
+{
+public:
+ typedef uint64_t Offset; // FIXME: use SizeTraits<T>::Offset
+ typedef NonConstTraits<unsigned char>::pointer Address;
+ typedef ConstTraits<unsigned char>::pointer ConstAddress;
+
+public:
+ MCFragmentRef();
+ MCFragmentRef(llvm::MCFragment& pFrag, Offset pOffset = 0);
+ ~MCFragmentRef();
+
+ // ----- modifiers ----- //
+ MCFragmentRef& assign(const MCFragmentRef& pCopy);
+
+ MCFragmentRef& assign(llvm::MCFragment& pFrag, Offset pOffset = 0);
+
+ /// memcpy - copy memory
+ /// copy memory from the fragment to the pDesc.
+ /// @pDest - the destination address
+ /// @pNBytes - copies pNBytes from the fragment[offset()+pOffset]
+ /// @pOffset - additional offset.
+ /// the start address offset from fragment[offset()]
+ void memcpy(void* pDest, size_t pNBytes, Offset pOffset = 0) const;
+
+ // ----- observers ----- //
+ llvm::MCFragment* frag()
+ { return m_pFragment; }
+
+ const llvm::MCFragment* frag() const
+ { return m_pFragment; }
+
+ Offset offset() const
+ { return m_Offset; }
+
+ // ----- dereference ----- //
+ Address deref();
+
+ ConstAddress deref() const;
+
+ Address operator*()
+ { return deref(); }
+
+ ConstAddress operator*() const
+ { return deref(); }
+
+private:
+ llvm::MCFragment* m_pFragment;
+ Offset m_Offset;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCInstFragment.h b/include/mcld/MC/MCInstFragment.h
new file mode 100644
index 0000000..8625c42
--- /dev/null
+++ b/include/mcld/MC/MCInstFragment.h
@@ -0,0 +1,95 @@
+//===- MCInstFragment.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCINSTFRAGMENT_H
+#define MCINSTFRAGMENT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/MC/MCAssembler.h>
+#include <llvm/MC/MCInst.h>
+#include <llvm/ADT/SmallString.h>
+#include <llvm/ADT/ilist.h>
+#include "mcld/LD/Relocation.h"
+
+
+namespace mcld
+{
+
+/** \class MCInstFragment
+ * \brief MCInstFragment for mcld
+ *
+ * \see
+ * \author Diana Chen <[email protected]>
+ */
+class MCInstFragment : public llvm::MCFragment
+{
+public:
+ typedef std::vector<Relocation*> RelocationsType;
+private:
+
+ /// m_pFragment - llvm MCInstFragment for this MCInstFragment
+ llvm::MCInstFragment* m_pFragment;
+
+ /// m_Relocation - The list of relocations in this fragment
+ RelocationsType m_Relocations;
+
+public:
+ typedef RelocationsType::const_iterator const_relocation_iterator;
+ typedef RelocationsType::iterator relocation_iterator;
+
+public:
+ MCInstFragment( llvm::MCInstFragment& pFragment )
+ : m_pFragment(&pFragment){
+ setParent( pFragment.getParent() );
+ setAtom( pFragment.getAtom() );
+ setLayoutOrder( pFragment.getLayoutOrder());
+ }
+ ~MCInstFragment(){}
+
+ // ------ observers ------//
+ llvm::SmallVectorImpl<char> &getCode() { return m_pFragment->getCode(); }
+ const llvm::SmallVectorImpl<char> &getCode() const { return m_pFragment->getCode(); }
+
+ unsigned getInstSize() const { return m_pFragment->getCode().size(); }
+
+ llvm::MCInst &getInst() { return m_pFragment->getInst(); }
+ const llvm::MCInst &getInst() const { return m_pFragment->getInst(); }
+
+ // ----- modifiers ------//
+ void setInst(llvm::MCInst pValue) { m_pFragment->setInst(pValue); }
+
+ // relocation access
+ void addRelocation(Relocation &pReloc){ m_Relocations.push_back(&pReloc); }
+
+ RelocationsType &getRelocations() { return m_Relocations; }
+ const RelocationsType &getRelcoations() const { return m_Relocations; }
+
+ relocation_iterator relocation_begin() { return m_Relocations.begin(); }
+ const_relocation_iterator relocation_begin() const { return m_Relocations.begin(); }
+
+ relocation_iterator relocation_end() {return m_Relocations.end();}
+ const_relocation_iterator relocation_end() const {return m_Relocations.end();}
+
+ size_t relocations_size() const { return m_Relocations.size(); }
+
+ // fragment identification
+ static bool classof(const MCFragment *pF) {
+ return pF->getKind() == llvm::MCFragment::FT_Inst;
+ }
+ static bool classof(const MCInstFragment *) { return true; }
+
+ // overwrite parent method
+ FragmentType getKind() const { return m_pFragment->getKind(); }
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLDAttribute.h b/include/mcld/MC/MCLDAttribute.h
new file mode 100644
index 0000000..829cf61
--- /dev/null
+++ b/include/mcld/MC/MCLDAttribute.h
@@ -0,0 +1,247 @@
+//===- MCLDAttribute.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ATTRIBUTE_H
+#define MCLD_ATTRIBUTE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <vector>
+#include <string>
+
+namespace mcld
+{
+class AttributeFactory;
+
+/** \class AttributeBase
+ * \brief AttributeBase provides the real storage for attributes of options.
+ *
+ * Attributes are options affecting the link editing of input files.
+ * Some options affects the input files mentioned on the command line after
+ * them. For example, --whole-archive option affects archives mentioned on
+ * the command line after the --whole-archve option. We call such options
+ * "attributes of input files"
+ *
+ * AttributeBase is the storage for attributes of input files. Each input
+ * file (@see mcld::Input in MCLinker) has a pointer of an attribute. Since
+ * most attributes of input files are identical, our design lets input files
+ * which have identical attributes share common attribute. AttributeBase is
+ * the shared storage for attribute.
+ */
+class AttributeBase
+{
+public:
+ AttributeBase()
+ : m_WholeArchive(false),
+ m_AsNeeded(false),
+ m_AddNeeded(true),
+ m_Static(false)
+ { }
+
+ AttributeBase(const AttributeBase& pBase)
+ : m_WholeArchive(pBase.m_WholeArchive),
+ m_AsNeeded(pBase.m_AsNeeded),
+ m_AddNeeded(pBase.m_AddNeeded),
+ m_Static(pBase.m_Static)
+ { }
+
+ virtual ~AttributeBase()
+ { }
+
+ // ----- observers ----- //
+ // represent GNU ld --whole-archive/--no-whole-archive options
+ bool isWholeArchive() const
+ { return m_WholeArchive; }
+
+ // represent GNU ld --as-needed/--no-as-needed options
+ bool isAsNeeded() const
+ { return m_AsNeeded; }
+
+ // represent GNU ld --add-needed/--no-add-needed options
+ bool isAddNeeded() const
+ { return m_AddNeeded; }
+
+ // represent GNU ld -static option
+ bool isStatic() const
+ { return m_Static; }
+
+ // represent GNU ld -call_shared option
+ bool isDynamic() const
+ { return !m_Static; }
+public:
+ bool m_WholeArchive : 1;
+ bool m_AsNeeded : 1;
+ bool m_AddNeeded : 1;
+ bool m_Static : 1;
+};
+
+/** \class Attribute
+ * \brief The base class of attributes. Providing the raw operations of an
+ * attributes
+ *
+ * For conventience and producing less bugs, we move the stoarges of attributes
+ * onto AttributeBase, and modifiers remains with the class Attribute.
+ */
+class Attribute : public AttributeBase
+{
+public:
+ // ----- modifiers ----- //
+ void setWholeArchive()
+ { m_WholeArchive = true; }
+
+ void unsetWholeArchive()
+ { m_WholeArchive = false; }
+
+ void setAsNeeded()
+ { m_AsNeeded = true; }
+
+ void unsetAsNeeded()
+ { m_AsNeeded = false; }
+
+ void setAddNeeded()
+ { m_AddNeeded = true; }
+
+ void unsetAddNeeded()
+ { m_AddNeeded = false; }
+
+ void setStatic()
+ { m_Static = true; }
+
+ void setDynamic()
+ { m_Static = false; }
+};
+
+/** \class AttrConstraint
+ * \brief AttrConstarint is the constraint of a system.
+ *
+ * Some systems can not enable certain attributes of a input file.
+ * For example, systems which have no shared libraries can not enable
+ * --call_shared options. We call the ability of enabling attributes
+ * as the constraint of attributes of a system.
+ *
+ * Systems enable attributes at the target implementation of SectLinker.
+ *
+ * @see SectLinker
+ */
+class AttrConstraint : public AttributeBase
+{
+public:
+ void enableWholeArchive()
+ { m_WholeArchive = true; }
+
+ void disableWholeArchive()
+ { m_WholeArchive = false; }
+
+ void enableAsNeeded()
+ { m_AsNeeded = true; }
+
+ void disableAsNeeded()
+ { m_AsNeeded = false; }
+
+ void enableAddNeeded()
+ { m_AddNeeded = true; }
+
+ void disableAddNeeded()
+ { m_AddNeeded = false; }
+
+ void setSharedSystem()
+ { m_Static = false; }
+
+ void setStaticSystem()
+ { m_Static = true; }
+
+ bool isSharedSystem() const
+ { return !m_Static; }
+
+ bool isStaticSystem() const
+ { return m_Static; }
+
+ bool isLegal(const Attribute& pAttr, std::string& pErrMesg) const;
+};
+
+/** \class AttributeProxy
+ * \brief AttributeProxys is the illusion of private attribute of each
+ * input file.
+ *
+ * We designers want to hide the details of sharing common attributes
+ * between input files. We want input files under the illusion that they
+ * have their own private attributes to simplify the linking algorithms.
+ *
+ * AttributeProxy hides the reality of sharing. An input file can change
+ * its attribute without explicit searching of existing attributes
+ * as it has a private ownership of the attribute. AttributeProxy does
+ * the searching in the AttributeFactory and changes the pointer of
+ * the attribute of the input file. If the searching fails, AttributeProxy
+ * requests a new attribute from the AttributeFactory.
+ */
+class AttributeProxy
+{
+private:
+ friend class AttributeFactory;
+
+ explicit AttributeProxy(AttributeFactory& pParent, Attribute& pBase);
+ ~AttributeProxy();
+
+public:
+ // ----- observers ----- //
+ bool isWholeArchive() const;
+
+ bool isAsNeeded() const;
+
+ bool isAddNeeded() const;
+
+ bool isStatic() const;
+
+ bool isDynamic() const;
+
+ Attribute* attr()
+ { return m_pBase; }
+
+ const Attribute* attr() const
+ { return m_pBase; }
+
+ // ----- modifiers ----- //
+ void setWholeArchive();
+ void unsetWholeArchive();
+ void setAsNeeded();
+ void unsetAsNeeded();
+ void setAddNeeded();
+ void unsetAddNeeded();
+ void setStatic();
+ void setDynamic();
+
+private:
+ AttributeProxy* clone() const;
+
+ void change(Attribute* pBase)
+ { m_pBase = pBase; }
+
+private:
+ AttributeFactory &m_AttrPool;
+ Attribute *m_pBase;
+};
+
+
+// ----- comparisons ----- //
+inline bool operator== (const Attribute& pLHS, const Attribute& pRHS)
+{
+ return ((pLHS.isWholeArchive() == pRHS.isWholeArchive()) &&
+ (pLHS.isAsNeeded() == pRHS.isAsNeeded()) &&
+ (pLHS.isAddNeeded() == pRHS.isAddNeeded()) &&
+ (pLHS.isStatic() == pRHS.isStatic()));
+}
+
+inline bool operator!= (const Attribute& pLHS, const Attribute& pRHS)
+{
+ return !(pLHS == pRHS);
+}
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLDDirectory.h b/include/mcld/MC/MCLDDirectory.h
new file mode 100644
index 0000000..988f9d3
--- /dev/null
+++ b/include/mcld/MC/MCLDDirectory.h
@@ -0,0 +1,53 @@
+//===- MCLDDirectory.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MCLDDIRECTORY_H
+#define MCLD_MCLDDIRECTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/Support/Directory.h"
+#include "mcld/Support/FileSystem.h"
+#include <llvm/ADT/StringRef.h>
+#include <string>
+
+namespace mcld
+{
+
+/** \class MCLDDirectory
+ * \brief MCLDDirectory is an directory entry for library search.
+ *
+ */
+class MCLDDirectory : public sys::fs::Directory
+{
+public:
+ MCLDDirectory();
+ MCLDDirectory(const char* pName);
+ MCLDDirectory(const std::string& pName);
+ MCLDDirectory(llvm::StringRef pName);
+ virtual ~MCLDDirectory();
+
+public:
+ MCLDDirectory &assign(llvm::StringRef pName);
+ bool isInSysroot() const;
+
+ /// setSysroot - if MCLDDirectory is in sysroot, modify the path.
+ void setSysroot(const sys::fs::Path& pPath);
+
+ const std::string& name() const
+ { return m_Name; }
+
+private:
+ std::string m_Name;
+ bool m_bInSysroot;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLDDriver.h b/include/mcld/MC/MCLDDriver.h
new file mode 100644
index 0000000..b4a7288
--- /dev/null
+++ b/include/mcld/MC/MCLDDriver.h
@@ -0,0 +1,117 @@
+//===- MCLDDriver.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// MCLDDriver plays the same role as GNU collect2 to prepare all implicit
+// parameters for MCLinker.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_LDDRIVER_H
+#define MCLD_LDDRIVER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/SectionMap.h>
+namespace mcld
+{
+
+class MCLinker;
+class MCLDInfo;
+class TargetLDBackend;
+
+//===----------------------------------------------------------------------===//
+/// MCLDDriver - MCLDDriver prepares parameters for MCLinker.
+///
+class MCLDDriver
+{
+public:
+ MCLDDriver(MCLDInfo& pLDInfo, TargetLDBackend& pLDBackend);
+ ~MCLDDriver();
+
+ /// normalize - normalize the input files
+ void normalize();
+
+ /// linkable - check the linkability of current MCLDInfo
+ /// Check list:
+ /// - check the Attributes are not violate the constaint
+ /// - check every Input has a correct Attribute
+ bool linkable() const;
+
+ /// initMCLinker - initialize MCLinker
+ /// Connect all components in MCLinker
+ bool initMCLinker();
+
+ /// readSections - read all input section headers
+ bool readSections();
+
+ /// mergeSections - put allinput sections into output sections
+ bool mergeSections();
+
+ /// readSymbolTables - read symbol tables from the input files.
+ /// for each input file, loads its symbol table from file.
+ bool readSymbolTables();
+
+ /// mergeSymbolTables - merge the symbol tables of input files into the
+ /// output's symbol table.
+ bool mergeSymbolTables();
+
+ /// addStandardSymbols - shared object and executable files need some
+ /// standard symbols
+ /// @return if there are some input symbols with the same name to the
+ /// standard symbols, return false
+ bool addStandardSymbols();
+
+ /// addTargetSymbols - some targets, such as MIPS and ARM, need some
+ /// target-dependent symbols
+ /// @return if there are some input symbols with the same name to the
+ /// target symbols, return false
+ bool addTargetSymbols();
+
+ /// readRelocations - read all relocation entries
+ bool readRelocations();
+
+ /// prelayout - help backend to do some modification before layout
+ bool prelayout();
+
+ /// layout - linearly layout all output sections and reserve some space
+ /// for GOT/PLT
+ /// Because we do not support instruction relaxing in this early version,
+ /// if there is a branch can not jump to its target, we return false
+ /// directly
+ bool layout();
+
+ /// postlayout - help backend to do some modification after layout
+ bool postlayout();
+
+ /// relocate - applying relocation entries and create relocation
+ /// section in the output files
+ /// Create relocation section, asking TargetLDBackend to
+ /// read the relocation information into RelocationEntry
+ /// and push_back into the relocation section
+ bool relocate();
+
+ /// finalizeSymbolValue - finalize the symbol value
+ bool finalizeSymbolValue();
+
+ /// emitOutput - emit the output file.
+ bool emitOutput();
+
+ /// postProcessing - do modificatiion after all processes
+ bool postProcessing();
+
+private:
+ MCLDInfo& m_LDInfo;
+ TargetLDBackend &m_LDBackend;
+ MCLinker* m_pLinker;
+ SectionMap m_SectionMap;
+};
+
+} // end namespace mcld
+#endif
diff --git a/include/mcld/MC/MCLDFile.h b/include/mcld/MC/MCLDFile.h
new file mode 100644
index 0000000..30cac7e
--- /dev/null
+++ b/include/mcld/MC/MCLDFile.h
@@ -0,0 +1,173 @@
+//===- MCLDFile.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// MCLDFile represents a file, the content of the file is stored in LDContext.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_LDFILE_H
+#define MCLD_LDFILE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/LD/LDContext.h"
+#include "mcld/Support/Path.h"
+#include "mcld/Support/FileSystem.h"
+#include "mcld/Support/GCFactory.h"
+#include "mcld/Support/MemoryArea.h"
+#include <llvm/ADT/StringRef.h>
+#include <string>
+#include <sys/stat.h>
+
+
+namespace mcld
+{
+class MemoryArea;
+
+/** \class MCLDFile
+ * \brief MCLDFile represents the file being linked or produced.
+ *
+ * MCLDFile is the storage of name, path and type
+ * A MCLDFile just refers to LDContext, not owns it.
+ *
+ * @see mcld::sys::fs::Path LDContext
+ */
+class MCLDFile : private Uncopyable
+{
+public:
+ enum Type {
+ Unknown,
+ Object,
+ Exec,
+ DynObj,
+ CoreFile,
+ Script,
+ Archive
+ };
+
+public:
+ MCLDFile();
+ MCLDFile(llvm::StringRef pName);
+ MCLDFile(llvm::StringRef pName,
+ const sys::fs::Path& pPath,
+ unsigned int pType = Unknown);
+
+ virtual ~MCLDFile();
+
+ // ----- modifiers ----- //
+ void setType(unsigned int pType)
+ { m_Type = pType; }
+
+ void setContext(LDContext* pContext)
+ { m_pContext = pContext; }
+
+ void setPath(const sys::fs::Path& pPath)
+ { m_Path = pPath; }
+
+ void setMemArea(MemoryArea* pMemArea)
+ {
+ m_pMemArea = pMemArea;
+ }
+
+ /// setSOName - set the name of the shared object.
+ /// In ELF, this will be written in DT_SONAME
+ void setSOName(const std::string& pName);
+
+ // ----- observers ----- //
+ unsigned int type() const
+ { return m_Type; }
+
+ const std::string& name() const
+ { return m_Name; }
+
+ const sys::fs::Path& path() const
+ { return m_Path; }
+
+ bool hasContext() const
+ { return (0 != m_pContext); }
+
+ LDContext* context()
+ { return m_pContext; }
+
+ const LDContext* context() const
+ { return m_pContext; }
+
+ bool hasMemArea() const
+ { return (0 != m_pMemArea); }
+
+ MemoryArea* memArea()
+ { return m_pMemArea; }
+
+ const MemoryArea* memArea() const
+ { return m_pMemArea; }
+
+protected:
+ unsigned int m_Type;
+ LDContext *m_pContext;
+ sys::fs::Path m_Path;
+ std::string m_Name;
+ MemoryArea* m_pMemArea;
+};
+
+/** \class MCLDFileFactory
+ * \brief MCLDFileFactory controls the production and destruction of
+ * MCLDFiles.
+ *
+ * All MCLDFiles created by MCLDFileFactory are guaranteed to be destructed
+ * while MCLDFileFactory is destructed.
+ *
+ * MCLDFileFactory also provides the MCLCContextFactory to MCLDFile.
+ * MCLDFile is responsed for the life of LDContext, therefore, the best
+ * idea is let MCLDFile control the life of LDContext. Since SectLinker
+ * has the need to count the number of LDContext, we give a central factory
+ * for LDContext.
+ *
+ * \see llvm::sys::Path
+ */
+template<size_t NUM>
+class MCLDFileFactory : public GCFactory<MCLDFile, NUM>
+{
+public:
+ typedef GCFactory<MCLDFile, NUM> Alloc;
+
+public:
+ // ----- production ----- //
+ MCLDFile* produce(llvm::StringRef pName,
+ const sys::fs::Path& pPath,
+ unsigned int pType = MCLDFile::Unknown);
+
+ MCLDFile* produce();
+};
+
+} // namespace of mcld
+
+//===----------------------------------------------------------------------===//
+// MCLDFileFactory
+template<size_t NUM>
+mcld::MCLDFile* mcld::MCLDFileFactory<NUM>::produce(llvm::StringRef pName,
+ const mcld::sys::fs::Path& pPath,
+ unsigned int pType)
+{
+ mcld::MCLDFile* result = Alloc::allocate();
+ new (result) mcld::MCLDFile(pName, pPath, pType);
+ return result;
+}
+
+template<size_t NUM>
+mcld::MCLDFile* mcld::MCLDFileFactory<NUM>::produce()
+{
+ mcld::MCLDFile* result = Alloc::allocate();
+ new (result) mcld::MCLDFile();
+ return result;
+}
+
+#endif
+
diff --git a/include/mcld/MC/MCLDInfo.h b/include/mcld/MC/MCLDInfo.h
new file mode 100644
index 0000000..15e70ff
--- /dev/null
+++ b/include/mcld/MC/MCLDInfo.h
@@ -0,0 +1,138 @@
+//===- MCLDInfo.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LDINFO_H
+#define MCLD_LDINFO_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/ADT/Triple.h>
+
+#include <mcld/Support/FileSystem.h>
+#include <mcld/Support/MemoryAreaFactory.h>
+#include <mcld/MC/MCLDOutput.h>
+#include <mcld/MC/MCLDOptions.h>
+#include <mcld/MC/MCLDInputTree.h>
+#include <mcld/MC/AttributeFactory.h>
+#include <mcld/MC/ContextFactory.h>
+#include <mcld/LD/StrSymPool.h>
+
+#include <string>
+#include <cassert>
+
+namespace mcld
+{
+
+/** \class MCLDInfo
+ * \brief MCLDInfo is composed of argumments of MCLinker.
+ * options() - the general options.
+ * inputs() - the tree of inputs
+ * bitcode() - the bitcode being linked
+ * output() - the output file
+ * inputFactory() - the list of all inputs
+ * attrFactory() - the list of all attributes
+ * contextFactory() - the list of all contexts.
+ * memAreaFactory() - the list of all MemoryAreas.
+ */
+class MCLDInfo
+{
+public:
+ explicit MCLDInfo(const std::string &pTripleString,
+ size_t pAttrNum,
+ size_t InputSize);
+
+ virtual ~MCLDInfo();
+
+ GeneralOptions& options()
+ { return m_Options; }
+
+ const GeneralOptions& options() const
+ { return m_Options; }
+
+ void setBitcode(const Input& pInput);
+ Input& bitcode();
+ const Input& bitcode() const;
+
+ Output& output()
+ { return *m_pOutput; }
+
+ const Output& output() const
+ { return *m_pOutput; }
+
+ InputTree& inputs()
+ { return *m_pInputTree; }
+
+ const InputTree& inputs() const
+ { return *m_pInputTree; }
+
+ InputFactory& inputFactory()
+ { return *m_pInputFactory; }
+
+ const InputFactory& inputFactory() const
+ { return *m_pInputFactory; }
+
+ AttributeFactory& attrFactory()
+ { return *m_pAttrFactory; }
+
+
+ const AttributeFactory& attrFactory() const
+ { return *m_pAttrFactory; }
+
+ ContextFactory& contextFactory()
+ { return *m_pCntxtFactory; }
+
+ const ContextFactory& contextFactory() const
+ { return *m_pCntxtFactory; }
+
+ MemoryAreaFactory& memAreaFactory()
+ { return *m_pMemAreaFactory; }
+
+ const MemoryAreaFactory& memAreaFactory() const
+ { return *m_pMemAreaFactory; }
+
+ const llvm::Triple& triple() const
+ { return m_Triple; }
+
+ static const char* version();
+
+ void setNamePool(StrSymPool& pPool)
+ { m_pStrSymPool = &pPool; }
+
+ StrSymPool& getStrSymPool() {
+ assert(NULL != m_pStrSymPool);
+ return *m_pStrSymPool;
+ }
+
+ const StrSymPool& getStrSymPool() const {
+ assert(NULL != m_pStrSymPool);
+ return *m_pStrSymPool;
+ }
+
+private:
+ // ----- General Options ----- //
+ GeneralOptions m_Options;
+ InputTree *m_pInputTree;
+ Input* m_pBitcode;
+ Output* m_pOutput;
+ llvm::Triple m_Triple;
+
+ // ----- factories ----- //
+ InputFactory *m_pInputFactory;
+ AttributeFactory *m_pAttrFactory;
+ ContextFactory *m_pCntxtFactory;
+ MemoryAreaFactory *m_pMemAreaFactory;
+
+ // ----- string and symbols ----- //
+ StrSymPool* m_pStrSymPool;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLDInput.h b/include/mcld/MC/MCLDInput.h
new file mode 100644
index 0000000..097b8f6
--- /dev/null
+++ b/include/mcld/MC/MCLDInput.h
@@ -0,0 +1,86 @@
+//===- MCLDInput.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Input class inherits MCLDFile, which is used to represent a input file
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_INPUT_H
+#define MCLD_INPUT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/MC/MCLDFile.h"
+
+namespace mcld
+{
+
+class AttributeProxy;
+class Attribute;
+class InputFactory;
+
+/** \class Input
+ * \brief Input provides the information of a input file.
+ *
+ * @see MCLDFile
+ */
+class Input : public MCLDFile
+{
+friend class InputFactory;
+public:
+ enum Type {
+ Unknown = MCLDFile::Unknown,
+ Object = MCLDFile::Object,
+ DynObj = MCLDFile::DynObj,
+ Archive = MCLDFile::Archive,
+ Script = MCLDFile::Script
+ };
+
+private:
+ explicit Input(llvm::StringRef pName,
+ const AttributeProxy& pAttr);
+
+ Input(llvm::StringRef pName,
+ const sys::fs::Path& pPath,
+ const AttributeProxy& pAttr,
+ unsigned int pType = Unknown,
+ off_t pFileOffset = 0);
+
+public:
+ ~Input();
+
+ bool isRecognized() const
+ { return (m_Type != Unknown); }
+
+ const Attribute* attribute() const
+ { return m_pAttr; }
+
+ bool isNeeded() const
+ { return m_bNeeded; }
+
+ void setNeeded()
+ { m_bNeeded = true; }
+
+ off_t fileOffset() const
+ { return m_fileOffset; }
+
+ void setFileOffset(off_t pFileOffset)
+ { m_fileOffset = pFileOffset; }
+
+private:
+ Attribute *m_pAttr;
+ bool m_bNeeded;
+ off_t m_fileOffset;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLDInputTree.h b/include/mcld/MC/MCLDInputTree.h
new file mode 100644
index 0000000..7d8050c
--- /dev/null
+++ b/include/mcld/MC/MCLDInputTree.h
@@ -0,0 +1,237 @@
+//===- MCLDInputTree.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_INPUT_TREE_H
+#define MCLD_INPUT_TREE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/BinTree.h"
+#include "mcld/ADT/TypeTraits.h"
+#include "mcld/MC/MCLDInput.h"
+#include "mcld/MC/InputFactory.h"
+#include "mcld/Support/FileSystem.h"
+
+#include <string>
+
+
+namespace mcld
+{
+
+/** \class template<typename Traits, typename Iterator> PolicyIterator<mcld::Input>
+ * \brief PolicyIterator<mcld::Input> is a partially specific PolicyIterator
+ */
+template<typename Traits, typename IteratorType>
+class PolicyIterator<mcld::Input, Traits, IteratorType> : public PolicyIteratorBase<Input, Traits, IteratorType>
+{
+public:
+ typedef PolicyIterator<Input, Traits, IteratorType> Self;
+ typedef PolicyIteratorBase<Input, Traits, IteratorType> Base;
+ typedef PolicyIterator<Input, typename Traits::nonconst_traits, IteratorType> iterator;
+ typedef PolicyIterator<Input, typename Traits::const_traits, IteratorType> const_iterator;
+
+public:
+ PolicyIterator()
+ : Base() {}
+
+ PolicyIterator(const iterator &X)
+ : Base(X.m_pNode) {}
+
+ explicit PolicyIterator(NodeBase* X)
+ : Base(X) {}
+
+ virtual ~PolicyIterator() {}
+
+ bool isGroup() const
+ { return !Base::hasData(); }
+
+ Self& operator++() {
+ IteratorType::advance();
+ if (isGroup())
+ IteratorType::advance();
+ return *this;
+ }
+
+ Self operator++(int) {
+ Self tmp(*this);
+ IteratorType::advance();
+ if (isGroup())
+ IteratorType::advance();
+ return tmp;
+ }
+};
+
+/** \class InputTree
+ * \brief InputTree is the input tree to contains all inputs from the
+ * command line.
+ *
+ * InputTree, of course, is uncopyable.
+ *
+ * @see Input
+ */
+class InputTree : public BinaryTree<Input>
+{
+private:
+ typedef BinaryTree<Input> BinTreeTy;
+
+public:
+ enum Direction {
+ Inclusive = TreeIteratorBase::Leftward,
+ Positional = TreeIteratorBase::Rightward
+ };
+
+ typedef BinaryTree<Input>::iterator iterator;
+ typedef BinaryTree<Input>::const_iterator const_iterator;
+
+public:
+ struct Connector {
+ virtual ~Connector() {}
+ virtual void connect(iterator& pFrom, const const_iterator& pTo) const = 0;
+ virtual void move(iterator& pNode) const = 0;
+ };
+
+ struct Succeeder : public Connector {
+ virtual void connect(iterator& pFrom, const const_iterator& pTo) const {
+ proxy::hook<Positional>(pFrom.m_pNode, pTo.m_pNode);
+ }
+
+ virtual void move(iterator& pNode) const {
+ pNode.move<Positional>();
+ }
+ };
+
+ struct Includer : public Connector {
+ virtual void connect(iterator& pFrom, const const_iterator& pTo) const {
+ proxy::hook<Inclusive>(pFrom.m_pNode, pTo.m_pNode);
+ }
+
+ virtual void move(iterator& pNode) const {
+ pNode.move<Inclusive>();
+ }
+ };
+
+public:
+ static Succeeder Afterward;
+ static Includer Downward;
+
+public:
+
+ using BinTreeTy::merge;
+
+ InputTree(InputFactory& pInputFactory);
+ ~InputTree();
+
+ // ----- modify ----- //
+ /// insert - create a leaf node and merge it in the tree.
+ // This version of join determines the direction at run time.
+ // @param position the parent node
+ // @param value the value being pushed.
+ // @param pConnector the direction of the connecting edge of the parent node.
+ template<size_t DIRECT>
+ InputTree& insert(iterator pPosition,
+ const std::string& pNamespec,
+ const sys::fs::Path& pPath,
+ unsigned int pType = Input::Unknown);
+
+ template<size_t DIRECT>
+ InputTree& enterGroup(iterator pPosition);
+
+ template<size_t DIRECT>
+ InputTree& insert(iterator pPosition,
+ const Input& pInput);
+
+ InputTree& merge(iterator pPosition,
+ const Connector& pConnector,
+ InputTree& pTree);
+
+ InputTree& insert(iterator pPosition,
+ const Connector& pConnector,
+ const std::string& pNamespec,
+ const sys::fs::Path& pPath,
+ unsigned int pType = Input::Unknown);
+
+ InputTree& insert(iterator pPosition,
+ const Connector& pConnector,
+ const Input& pInput);
+
+ InputTree& enterGroup(iterator pPosition,
+ const Connector& pConnector);
+
+ // ----- observers ----- //
+ unsigned int numOfInputs() const
+ { return m_FileFactory.size(); }
+
+ bool hasInput() const
+ { return !m_FileFactory.empty(); }
+
+private:
+ InputFactory& m_FileFactory;
+
+};
+
+bool isGroup(const InputTree::iterator& pos);
+bool isGroup(const InputTree::const_iterator& pos);
+bool isGroup(const InputTree::dfs_iterator& pos);
+bool isGroup(const InputTree::const_dfs_iterator& pos);
+bool isGroup(const InputTree::bfs_iterator& pos);
+bool isGroup(const InputTree::const_bfs_iterator& pos);
+
+} // namespace of mcld
+
+//===----------------------------------------------------------------------===//
+// template member functions
+template<size_t DIRECT>
+mcld::InputTree&
+mcld::InputTree::insert(mcld::InputTree::iterator pPosition,
+ const std::string& pNamespec,
+ const mcld::sys::fs::Path& pPath,
+ unsigned int pType)
+{
+ BinTreeTy::node_type* node = createNode();
+ node->data = m_FileFactory.produce(pNamespec, pPath, pType);
+ if (pPosition.isRoot())
+ proxy::hook<TreeIteratorBase::Leftward>(pPosition.m_pNode,
+ const_cast<const node_type*>(node));
+ else
+ proxy::hook<DIRECT>(pPosition.m_pNode,
+ const_cast<const node_type*>(node));
+ return *this;
+}
+
+template<size_t DIRECT>
+mcld::InputTree&
+mcld::InputTree::enterGroup(mcld::InputTree::iterator pPosition)
+{
+ BinTreeTy::node_type* node = createNode();
+ if (pPosition.isRoot())
+ proxy::hook<TreeIteratorBase::Leftward>(pPosition.m_pNode,
+ const_cast<const node_type*>(node));
+ else
+ proxy::hook<DIRECT>(pPosition.m_pNode,
+ const_cast<const node_type*>(node));
+ return *this;
+}
+
+template<size_t DIRECT>
+mcld::InputTree& mcld::InputTree::insert(mcld::InputTree::iterator pPosition,
+ const mcld::Input& pInput)
+{
+ BinTreeTy::node_type* node = createNode();
+ node->data = const_cast<mcld::Input*>(&pInput);
+ if (pPosition.isRoot())
+ proxy::hook<TreeIteratorBase::Leftward>(pPosition.m_pNode,
+ const_cast<const node_type*>(node));
+ else
+ proxy::hook<DIRECT>(pPosition.m_pNode,
+ const_cast<const node_type*>(node));
+ return *this;
+}
+
+#endif
+
diff --git a/include/mcld/MC/MCLDOptions.h b/include/mcld/MC/MCLDOptions.h
new file mode 100644
index 0000000..06097aa
--- /dev/null
+++ b/include/mcld/MC/MCLDOptions.h
@@ -0,0 +1,98 @@
+//===- MCLDOptions.h ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_OPTIONS_H
+#define MCLD_OPTIONS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/Support/RealPath.h"
+#include "mcld/MC/SearchDirs.h"
+#include "mcld/Support/FileSystem.h"
+
+namespace mcld
+{
+class Input;
+
+/** \class ScriptOptions
+ *
+ */
+class ScriptOption
+{
+};
+
+/** \class GeneralOptions
+ * \brief GeneralOptions collects the options that not be one of the
+ * - input files
+ * - attribute of input files
+ * - script options
+ */
+class GeneralOptions
+{
+public:
+ /// default link script
+ bool hasDefaultLDScript() const;
+ const char* defaultLDScript() const;
+ void setDefaultLDScript(const std::string& pFilename);
+
+ /// sysroot
+ const sys::fs::Path& sysroot() const
+ { return m_Sysroot; }
+
+ void setSysroot(const sys::fs::Path &pPath);
+
+ /// search directory
+ SearchDirs& directories()
+ { return m_SearchDirs; }
+
+ const SearchDirs& directories() const
+ { return m_SearchDirs; }
+
+ /// trace
+ void setTrace(bool pEnableTrace = true)
+ { m_bTrace = pEnableTrace; }
+
+ bool trace() const
+ { return m_bTrace; }
+
+ void setVerbose(bool pVerbose = true)
+ { m_bVerbose = pVerbose; }
+
+ bool verbose() const
+ { return m_bVerbose; }
+
+ void setBsymbolic(bool pBsymbolic = false)
+ { m_Bsymbolic = pBsymbolic; }
+
+ bool Bsymbolic() const
+ { return m_Bsymbolic; }
+
+ bool hasEntry() const
+ { return !m_Entry.empty(); }
+
+ void setEntry(const std::string& pEntry)
+ { m_Entry = pEntry; }
+
+ const std::string& entry() const
+ { return m_Entry; }
+
+private:
+ Input* m_pDefaultBitcode;
+ std::string m_DefaultLDScript;
+ sys::fs::RealPath m_Sysroot;
+ SearchDirs m_SearchDirs;
+ bool m_bTrace;
+ bool m_bVerbose;
+ bool m_Bsymbolic;
+ std::string m_Entry;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLDOutput.h b/include/mcld/MC/MCLDOutput.h
new file mode 100644
index 0000000..14768ce
--- /dev/null
+++ b/include/mcld/MC/MCLDOutput.h
@@ -0,0 +1,52 @@
+//===- MCLDOutput.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Output class inherits MCLDFile, which is used to represent a output file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_OUTPUT_H
+#define MCLD_OUTPUT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/MC/MCLDFile.h>
+#include <mcld/Support/RealPath.h>
+#include <string>
+
+namespace mcld
+{
+
+/** \class MCLDOutput
+ * \brief MCLDOutput provides the information about the output.
+ *
+ * @see MCLDFile
+ */
+class Output : public MCLDFile
+{
+public:
+ enum Type {
+ Object = MCLDFile::Object,
+ DynObj = MCLDFile::DynObj,
+ Exec = MCLDFile::Exec
+ };
+
+public:
+ Output();
+ explicit Output(const sys::fs::Path& pRealPath,
+ Type pType);
+
+ ~Output();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLinker.h b/include/mcld/MC/MCLinker.h
new file mode 100644
index 0000000..8de7148
--- /dev/null
+++ b/include/mcld/MC/MCLinker.h
@@ -0,0 +1,279 @@
+//===- MCLinker.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a number of APIs used by SectLinker.
+// These APIs do the things which a linker should do.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MCLINKER_H
+#define MCLD_MCLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/ADT/ilist.h>
+#include <llvm/MC/MCAssembler.h>
+#include <mcld/LD/StrSymPool.h>
+#include <mcld/LD/StaticResolver.h>
+#include <mcld/LD/LDSectionFactory.h>
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/LD/Relocation.h>
+#include <mcld/LD/SectionMerger.h>
+#include <mcld/LD/Layout.h>
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/SymbolCategory.h>
+#include <mcld/Support/GCFactory.h>
+#include <mcld/Support/GCFactoryListTraits.h>
+#include <set>
+#include <string>
+
+namespace mcld {
+
+class TargetLDBackend;
+class MCLDInfo;
+class LDSection;
+class LDSectionFactory;
+class SectionMap;
+class Output;
+
+/** \class MCLinker
+ * \brief MCLinker provides a pass to link object files.
+ */
+class MCLinker
+{
+public:
+ enum DefinePolicy
+ {
+ Force,
+ AsRefered
+ };
+
+ enum ResolvePolicy
+ {
+ Unresolve,
+ Resolve
+ };
+
+public:
+ MCLinker(TargetLDBackend& pBackend,
+ MCLDInfo& pLDInfo,
+ LDContext& pContext,
+ SectionMap& pSectionMap,
+ const Resolver& pResolver = StaticResolver());
+ ~MCLinker();
+
+ // ----- about symbols ----- //
+ /// addDynSymbol - add a symbol and resolve it immediately
+ template<Input::Type FROM>
+ LDSymbol* addSymbol(const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility = ResolveInfo::Default);
+
+ /// defineSymbol - add a symbol
+ /// defineSymbol define a output symbol
+ ///
+ /// @tparam POLICY idicate how to define the symbol.
+ /// - Force
+ /// - Define the symbol forcefully. If the symbol has existed, override
+ /// it. Otherwise, define it.
+ /// - AsRefered
+ /// - If the symbol has existed, override it. Otherwise, return NULL
+ /// immediately.
+ ///
+ /// @tparam RESOLVE indicate whether to resolve the symbol or not.
+ /// - Unresolve
+ /// - Do not resolve the symbol, and override the symbol immediately.
+ /// - Resolve
+ /// - Resolve the defined symbol.
+ ///
+ /// @return If the output symbol has existed, return it. Otherwise, create
+ /// a new symbol and return the new one.
+ template<DefinePolicy POLICY, ResolvePolicy RESOLVE>
+ LDSymbol* defineSymbol(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility = ResolveInfo::Default);
+
+ /// mergeSymbolTable - merge the symbol table and resolve symbols.
+ /// Since in current design, MCLinker resolves symbols when reading symbol
+ /// tables, this function do nothing.
+ bool mergeSymbolTable(Input& pInput)
+ { return true; }
+
+ bool finalizeSymbols();
+
+ // ----- sections ----- //
+ /// getSectionMap - getSectionMap to change the behavior of SectionMerger
+ /// SectionMap& getSectionMap()
+ /// { return m_SectionMap; }
+
+ /// createSectHdr - for reader and standard/target format to create a section
+ /// header. This function will create a new LDSection and return it. If the
+ /// output has no related LDSection, this function will also create one and
+ /// push into the output.
+ LDSection& createSectHdr(const std::string& pName,
+ LDFileFormat::Kind pKind,
+ uint32_t pType,
+ uint32_t pFlag);
+
+ /// getOrCreateOutputSectHdr - for reader and standard/target format to get
+ /// or create the output's section header
+ LDSection& getOrCreateOutputSectHdr(const std::string& pName,
+ LDFileFormat::Kind pKind,
+ uint32_t pType,
+ uint32_t pFlag,
+ uint32_t pAlign = 0x0);
+
+ /// getOrCreateSectData - for reader to map and perform section merging immediately
+ llvm::MCSectionData& getOrCreateSectData(LDSection& pSection);
+
+ // ----- relocations ----- //
+ /// addRelocation - add a relocation entry in MCLinker (only for object file)
+ /// @param pType - the type of the relocation
+ /// @param pResolveInfo - the symbol should be the symbol in the input file. MCLinker
+ /// computes the real applied address by the output symbol.
+ /// @param pFragmentRef - the fragment reference of the applied address.
+ /// @param pAddend - the addend value for applying relocation
+ Relocation* addRelocation(Relocation::Type pType,
+ const LDSymbol& pSym,
+ ResolveInfo& pResolveInfo,
+ MCFragmentRef& pFragmentRef,
+ Relocation::Address pAddend = 0);
+
+ /// applyRelocations - apply all relocation enties.
+ bool applyRelocations();
+
+ /// syncRelocationResult - After applying relocation, write back relocation target
+ /// data to output file.
+ void syncRelocationResult();
+
+ // ----- layout ----- //
+ Layout& getLayout()
+ { return m_Layout; }
+
+ const Layout& getLayout() const
+ { return m_Layout; }
+
+ bool layout();
+
+ // ----- output symbols ----- //
+ SymbolCategory& getOutputSymbols()
+ { return m_OutputSymbols; }
+
+ const SymbolCategory& getOutputSymbols() const
+ { return m_OutputSymbols; }
+
+ // ----- capacity ----- //
+ MCLDInfo& getLDInfo()
+ { return m_Info; }
+
+ const MCLDInfo& getLDInfo() const
+ { return m_Info; }
+
+private:
+ LDSymbol* defineSymbolForcefully(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+
+ LDSymbol* defineAndResolveSymbolForcefully(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+
+ LDSymbol* defineSymbolAsRefered(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+
+ LDSymbol* defineAndResolveSymbolAsRefered(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+
+ bool shouldForceLocal(const ResolveInfo& pInfo) const;
+
+ LDSymbol* addSymbolFromDynObj(const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+
+ LDSymbol* addSymbolFromObject(const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+private:
+ typedef GCFactory<LDSymbol, 0> LDSymbolFactory;
+ typedef GCFactory<llvm::MCSectionData, 0> LDSectionDataFactory;
+ typedef llvm::iplist<llvm::MCFragment,
+ GCFactoryListTraits<llvm::MCFragment> > RelocationListType;
+ typedef std::set<LDSymbol*> ForceLocalSymbolTable;
+ typedef std::vector<LDSymbol*> OutputSymbolTable;
+
+private:
+ TargetLDBackend& m_Backend;
+ MCLDInfo& m_Info;
+ LDContext& m_Output;
+ SectionMap& m_SectionMap;
+ LDSymbolFactory m_LDSymbolFactory;
+ LDSectionFactory m_LDSectHdrFactory;
+ LDSectionDataFactory m_LDSectDataFactory;
+ SectionMerger m_SectionMerger;
+ StrSymPool m_StrSymPool;
+ Layout m_Layout;
+ RelocationListType m_RelocationList;
+ SymbolCategory m_OutputSymbols;
+
+};
+
+#include "MCLinker.tcc"
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLinker.tcc b/include/mcld/MC/MCLinker.tcc
new file mode 100644
index 0000000..19a83ec
--- /dev/null
+++ b/include/mcld/MC/MCLinker.tcc
@@ -0,0 +1,105 @@
+//===- MCLinker.tcc -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+/// addSymbol - add a symbol and resolve it immediately
+template<Input::Type FROM>
+LDSymbol* MCLinker::addSymbol(const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility)
+{
+ // These if/else should be optimized by compiler.
+ // This function is defined for clarity.
+ if (FROM == Input::DynObj)
+ return addSymbolFromDynObj(pName,
+ pType,
+ pDesc,
+ pBinding,
+ pSize,
+ pValue,
+ pFragmentRef,
+ pVisibility);
+
+ if (FROM == Input::Object)
+ return addSymbolFromObject(pName,
+ pType,
+ pDesc,
+ pBinding,
+ pSize,
+ pValue,
+ pFragmentRef,
+ pVisibility);
+
+ llvm::report_fatal_error("add a symbol from unknown file type.\n");
+ return NULL;
+}
+
+// defineSymbol - define a new symbol
+template<MCLinker::DefinePolicy POLICY, MCLinker::ResolvePolicy RESOLVE>
+LDSymbol* MCLinker::defineSymbol(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility)
+{
+ // These if/return should be optimized by compiler.
+ // This function is defined for clarity.
+ if (MCLinker::Force == POLICY && MCLinker::Unresolve == RESOLVE)
+ return defineSymbolForcefully(pName,
+ pIsDyn,
+ pType,
+ pDesc,
+ pBinding,
+ pSize,
+ pValue,
+ pFragmentRef,
+ pVisibility);
+
+ if (MCLinker::AsRefered == POLICY && MCLinker::Unresolve == RESOLVE)
+ return defineSymbolAsRefered(pName,
+ pIsDyn,
+ pType,
+ pDesc,
+ pBinding,
+ pSize,
+ pValue,
+ pFragmentRef,
+ pVisibility);
+
+ if (MCLinker::Force == POLICY && MCLinker::Resolve == RESOLVE)
+ return defineAndResolveSymbolForcefully(pName,
+ pIsDyn,
+ pType,
+ pDesc,
+ pBinding,
+ pSize,
+ pValue,
+ pFragmentRef,
+ pVisibility);
+
+ if (MCLinker::AsRefered == POLICY && MCLinker::Resolve == RESOLVE)
+ return defineAndResolveSymbolAsRefered(pName,
+ pIsDyn,
+ pType,
+ pDesc,
+ pBinding,
+ pSize,
+ pValue,
+ pFragmentRef,
+ pVisibility);
+}
+
diff --git a/include/mcld/MC/MCRegionFragment.h b/include/mcld/MC/MCRegionFragment.h
new file mode 100644
index 0000000..7dd088b
--- /dev/null
+++ b/include/mcld/MC/MCRegionFragment.h
@@ -0,0 +1,53 @@
+//===- MCRegionFragment.h - MCFragment containing MemoryRegion ------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_REGION_FRAGMENT_H
+#define MCLD_REGION_FRAGMENT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Support/MemoryRegion.h>
+#include <llvm/MC/MCAssembler.h>
+
+namespace mcld
+{
+
+/** \class MCRegionFragment
+ * \brief MCRegionFragment is a kind of MCFragment containing
+ * mcld::MemoryRegion
+ */
+class MCRegionFragment : public llvm::MCFragment
+{
+public:
+ MCRegionFragment(MemoryRegion& pRegion, llvm::MCSectionData* pSD = 0);
+ ~MCRegionFragment();
+
+ MemoryRegion& getRegion()
+ { return m_Region; }
+
+ const MemoryRegion& getRegion() const
+ { return m_Region; }
+
+ static bool classof(const MCFragment *F)
+ { return F->getKind() == llvm::MCFragment::FT_Region; }
+
+ static bool classof(const MCRegionFragment *)
+ { return true; }
+
+private:
+ MemoryRegion& m_Region;
+ llvm::MCSectionData* m_pSectionData;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCTargetFragment.h b/include/mcld/MC/MCTargetFragment.h
new file mode 100644
index 0000000..4050708
--- /dev/null
+++ b/include/mcld/MC/MCTargetFragment.h
@@ -0,0 +1,48 @@
+//===- MCTargetFragment.h - MCFragment containing MemoryRegion ------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_TARGET_FRAGMENT_H
+#define MCLD_TARGET_FRAGMENT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/MC/MCAssembler.h>
+
+namespace mcld
+{
+
+/** \class MCTargetFragment
+ * \brief MCTargetFragment is a kind of MCFragment inherited by
+ * target-depedent MCFragment.
+ */
+class MCTargetFragment : public llvm::MCFragment
+{
+protected:
+ MCTargetFragment(llvm::MCFragment::FragmentType pKind,
+ llvm::MCSectionData* pSD = 0) :
+ llvm::MCFragment(pKind, pSD) {}
+
+public:
+ virtual ~MCTargetFragment() {}
+
+ virtual size_t getSize() const = 0;
+
+public:
+ static bool classof(const MCFragment *F)
+ { return F->getKind() == llvm::MCFragment::FT_Target; }
+
+ static bool classof(const MCTargetFragment *)
+ { return true; }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/SearchDirs.h b/include/mcld/MC/SearchDirs.h
new file mode 100644
index 0000000..1a22cf4
--- /dev/null
+++ b/include/mcld/MC/SearchDirs.h
@@ -0,0 +1,76 @@
+//===- SearchDirs.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SEARCHDIRS_H
+#define SEARCHDIRS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/StringRef.h>
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/MC/MCLDInput.h"
+
+namespace mcld
+{
+
+class MCLDFile;
+class MCLDDirectory;
+
+namespace sys {
+namespace fs {
+class Path;
+} // namespace of fs
+} // namespace of sys
+
+/** \class SearchDirs
+ * \brief SearchDirs contains the list of paths that MCLinker will search for
+ * archive libraries and control scripts.
+ *
+ * SearchDirs is customized for linking. It handles -L on the command line
+ * and SEARCH_DIR macro in the link script.
+ *
+ * @see MCLDDirectory.
+ */
+class SearchDirs : private Uncopyable
+{
+public:
+ typedef std::vector<MCLDDirectory*> DirList;
+ typedef DirList::iterator iterator;
+ typedef DirList::const_iterator const_iterator;
+
+public:
+ SearchDirs();
+ ~SearchDirs();
+
+ /// find - give a namespec, return a real path of the shared object.
+ sys::fs::Path* find(const std::string& pNamespec, mcld::Input::Type pType);
+
+ // ----- iterators ----- //
+ iterator begin()
+ { return m_DirList.begin(); }
+
+ iterator end()
+ { return m_DirList.end(); }
+
+ const_iterator begin() const
+ { return m_DirList.begin(); }
+
+ const_iterator end() const
+ { return m_DirList.end(); }
+
+ // ----- modifiers ----- //
+ void add(const MCLDDirectory& pDirectory);
+
+private:
+ DirList m_DirList;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/SymbolCategory.h b/include/mcld/MC/SymbolCategory.h
new file mode 100644
index 0000000..9432c2a
--- /dev/null
+++ b/include/mcld/MC/SymbolCategory.h
@@ -0,0 +1,158 @@
+//===- SymbolCategory.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SYMBOL_CATEGORY_H
+#define MCLD_SYMBOL_CATEGORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/ADT/TypeTraits.h>
+#include <vector>
+
+namespace mcld
+{
+
+class LDSymbol;
+class ResolveInfo;
+/** \class SymbolCategory
+ * \brief SymbolCategory groups output LDSymbol into different categories.
+ */
+class SymbolCategory
+{
+private:
+ typedef std::vector<LDSymbol*> OutputSymbols;
+
+public:
+ typedef OutputSymbols::iterator iterator;
+ typedef OutputSymbols::const_iterator const_iterator;
+
+public:
+ SymbolCategory();
+
+ ~SymbolCategory();
+
+ // ----- modifiers ----- //
+ SymbolCategory& add(LDSymbol& pSymbol);
+
+ SymbolCategory& forceLocal(LDSymbol& pSymbol);
+
+ SymbolCategory& arrange(LDSymbol& pSymbol, const ResolveInfo& pSourceInfo);
+
+ SymbolCategory& changeCommonsToGlobal();
+
+ // ----- access ----- //
+ LDSymbol& at(size_t pPosition)
+ { return *m_OutputSymbols.at(pPosition); }
+
+ const LDSymbol& at(size_t pPosition) const
+ { return *m_OutputSymbols.at(pPosition); }
+
+ LDSymbol& operator[](size_t pPosition)
+ { return *m_OutputSymbols[pPosition]; }
+
+ const LDSymbol& operator[](size_t pPosition) const
+ { return *m_OutputSymbols[pPosition]; }
+
+ // ----- observers ----- //
+ size_t numOfSymbols() const;
+
+ size_t numOfLocals() const;
+
+ size_t numOfCommons() const;
+
+ size_t numOfRegulars() const;
+
+ bool empty() const;
+
+ bool emptyLocals() const;
+
+ bool emptyCommons() const;
+
+ bool emptyRegulars() const;
+
+ // ----- iterators ----- //
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ iterator localBegin();
+ iterator localEnd();
+ const_iterator localBegin() const;
+ const_iterator localEnd() const;
+
+ iterator commonBegin();
+ iterator commonEnd();
+ const_iterator commonBegin() const;
+ const_iterator commonEnd() const;
+
+ iterator regularBegin();
+ iterator regularEnd();
+ const_iterator regularBegin() const;
+ const_iterator regularEnd() const;
+
+private:
+ class Category
+ {
+ public:
+ enum Type {
+ File,
+ Local,
+ Common,
+ Weak,
+ Global
+ };
+
+ public:
+ Type type;
+
+ size_t begin;
+ size_t end;
+
+ Category* prev;
+ Category* next;
+
+ public:
+ Category(Type pType)
+ : type(pType),
+ begin(0),
+ end(0),
+ prev(NULL),
+ next(NULL) {
+ }
+
+ size_t size() const
+ { return (end - begin); }
+
+ bool empty() const
+ { return (begin == end); }
+
+ bool isFirst() const
+ { return (NULL == prev); }
+
+ bool isLast() const
+ { return (NULL == next); }
+
+ static Type categorize(const ResolveInfo& pInfo);
+
+ };
+
+private:
+ OutputSymbols m_OutputSymbols;
+
+ Category* m_pFile;
+ Category* m_pLocal;
+ Category* m_pCommon;
+ Category* m_pWeak;
+ Category* m_pGlobal;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/Allocators.h b/include/mcld/Support/Allocators.h
new file mode 100644
index 0000000..962c900
--- /dev/null
+++ b/include/mcld/Support/Allocators.h
@@ -0,0 +1,439 @@
+//===- Allocators.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ALLOCATORS_H
+#define LLVM_ALLOCATORS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/ADT/TypeTraits.h"
+#include "mcld/LD/LDContext.h"
+#include <cstdlib>
+
+namespace mcld
+{
+
+/** \class Chunk
+ * \brief Chunk is the basic unit of the storage of the LinearAllocator
+ *
+ * @see LinearAllocator
+ */
+template<typename DataType, size_t ChunkSize>
+struct Chunk
+{
+public:
+ typedef DataType value_type;
+public:
+ Chunk()
+ : next(0), bound(0)
+ { }
+
+ static size_t size() { return ChunkSize; }
+
+public:
+ Chunk* next;
+ size_t bound;
+ DataType data[ChunkSize];
+};
+
+template<typename DataType>
+struct Chunk<DataType, 0>
+{
+public:
+ typedef DataType value_type;
+
+public:
+ Chunk()
+ : next(0), bound(0) {
+ if (0 != m_Size)
+ data = (DataType*)malloc(sizeof(DataType)*m_Size);
+ else
+ data = 0;
+ }
+
+ ~Chunk() {
+ if (data)
+ free(data);
+ }
+
+ static size_t size() { return m_Size; }
+ static void setSize(size_t pSize) { m_Size = pSize; }
+
+public:
+ Chunk* next;
+ size_t bound;
+ DataType *data;
+ static size_t m_Size;
+};
+
+template<typename DataType>
+size_t Chunk<DataType, 0>::m_Size = 0;
+
+template<typename ChunkType>
+class LinearAllocatorBase : private Uncopyable
+{
+public:
+ typedef ChunkType chunk_type;
+ typedef typename ChunkType::value_type value_type;
+ typedef typename ChunkType::value_type* pointer;
+ typedef typename ChunkType::value_type& reference;
+ typedef const typename ChunkType::value_type* const_pointer;
+ typedef const typename ChunkType::value_type& const_reference;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef unsigned char byte_type;
+
+protected:
+ LinearAllocatorBase()
+ : m_pRoot(0),
+ m_pCurrent(0),
+ m_AllocatedNum(0) {
+ }
+
+ // LinearAllocatorBase does NOT mean to destroy the allocated memory.
+ // If you want a memory allocator to release memory at destruction, please
+ // use GCFactory series.
+ virtual ~LinearAllocatorBase()
+ { }
+
+public:
+ pointer address(reference X) const
+ { return &X; }
+
+ const_pointer address(const_reference X) const
+ { return &X; }
+
+ /// standard construct - constructing an object on the location pointed by
+ // pPtr, and using its copy constructor to initialized its value to pValue.
+ //
+ // @param pPtr the address where the object to be constructed
+ // @param pValue the value to be constructed
+ void construct(pointer pPtr, const_reference pValue)
+ { new (pPtr) value_type(pValue); }
+
+ /// default construct - constructing an object on the location pointed by
+ // pPtr, and using its default constructor to initialized its value to
+ // pValue.
+ //
+ // @param pPtr the address where the object to be constructed
+ void construct(pointer pPtr)
+ { new (pPtr) value_type(); }
+
+ /// standard destroy - destroy data on arbitrary address
+ // @para pPtr the address where the data to be destruected.
+ void destroy(pointer pPtr)
+ { pPtr->~value_type(); }
+
+ /// allocate - allocate N data in order.
+ // - Disallow to allocate a chunk whose size is bigger than a chunk.
+ //
+ // @param N the number of allocated data.
+ // @return the start address of the allocated memory
+ pointer allocate(size_type N) {
+ if (0 == N || N > chunk_type::size())
+ return 0;
+
+ if (empty())
+ initialize();
+
+ size_type rest_num_elem = chunk_type::size() - m_pCurrent->bound;
+ pointer result = 0;
+ if (N > rest_num_elem)
+ createChunk();
+ result = const_cast<pointer>(&(m_pCurrent->data[m_pCurrent->bound]));
+ m_pCurrent->bound += N;
+ return result;
+ }
+
+ /// allocate - clone function of allocating one datum.
+ pointer allocate() {
+ if (empty())
+ initialize();
+
+ pointer result = 0;
+ if (chunk_type::size() == m_pCurrent->bound)
+ createChunk();
+ result = const_cast<pointer>(&(m_pCurrent->data[m_pCurrent->bound]));
+ ++m_pCurrent->bound;
+ return result;
+ }
+
+ /// deallocate - deallocate N data from the pPtr
+ // - if we can simply release some memory, then do it. Otherwise, do
+ // nothing.
+ void deallocate(pointer &pPtr, size_type N) {
+ if (0 == N ||
+ N > chunk_type::size() ||
+ 0 == m_pCurrent->bound ||
+ N >= m_pCurrent->bound)
+ return;
+ if (!isAvailable(pPtr))
+ return;
+ m_pCurrent->bound -= N;
+ pPtr = 0;
+ }
+
+ /// deallocate - clone function of deallocating one datum
+ void deallocate(pointer &pPtr) {
+ if (0 == m_pCurrent->bound)
+ return;
+ if (!isAvailable(pPtr))
+ return;
+ m_pCurrent->bound -= 1;
+ pPtr = 0;
+ }
+
+ /// isIn - whether the pPtr is in the current chunk?
+ bool isIn(pointer pPtr) const {
+ if (pPtr >= &(m_pCurrent->data[0]) &&
+ pPtr <= &(m_pCurrent->data[chunk_type::size()-1]))
+ return true;
+ return false;
+ }
+
+ /// isIn - whether the pPtr is allocated, and can be constructed.
+ bool isAvailable(pointer pPtr) const {
+ if (pPtr >= &(m_pCurrent->data[m_pCurrent->bound]) &&
+ pPtr <= &(m_pCurrent->data[chunk_type::size()-1]))
+ return true;
+ return false;
+ }
+
+ void reset() {
+ m_pRoot = 0;
+ m_pCurrent = 0;
+ m_AllocatedNum = 0;
+ }
+
+ /// clear - clear all chunks
+ void clear() {
+ chunk_type *cur = m_pRoot, *prev;
+ while (0 != cur) {
+ unsigned int idx=0;
+ prev = cur;
+ cur = cur->next;
+ while (idx != prev->bound) {
+ destroy(&prev->data[idx]);
+ ++idx;
+ }
+ delete prev;
+ }
+ reset();
+ }
+
+ // ----- observers ----- //
+ bool empty() const {
+ return (0 == m_pRoot);
+ }
+
+ size_type max_size() const
+ { return m_AllocatedNum; }
+
+protected:
+ inline void initialize() {
+ m_pRoot = new chunk_type();
+ m_pCurrent = m_pRoot;
+ m_AllocatedNum += chunk_type::size();
+ }
+
+ inline chunk_type *createChunk() {
+ chunk_type *result = new chunk_type();
+ m_pCurrent->next = result;
+ m_pCurrent = result;
+ m_AllocatedNum += chunk_type::size();
+ return result;
+ }
+
+protected:
+ chunk_type *m_pRoot;
+ chunk_type *m_pCurrent;
+ size_type m_AllocatedNum;
+};
+
+/** \class LinearAllocator
+ * \brief LinearAllocator is another bump pointer allocator which should be
+ * limited in use of two-phase memory allocation.
+ *
+ * Two-phase memory allocation clear separates the use of memory into 'claim'
+ * and 'release' phases. There are no interleaving allocation and
+ * deallocation. Interleaving 'allocate' and 'deallocate' increases the size
+ * of allocated memory, and causes bad locality.
+ *
+ * The underlying concept of LinearAllocator is a memory pool. LinearAllocator
+ * is a simple implementation of boost::pool's ordered_malloc() and
+ * ordered_free().
+ *
+ * template argument DataType is the DataType to be allocated
+ * template argument ChunkSize is the number of bytes of a chunk
+ */
+template<typename DataType, size_t ChunkSize>
+class LinearAllocator : public LinearAllocatorBase<Chunk<DataType, ChunkSize> >
+{
+public:
+ template<typename NewDataType>
+ struct rebind {
+ typedef LinearAllocator<NewDataType, ChunkSize> other;
+ };
+
+public:
+ LinearAllocator()
+ : LinearAllocatorBase<Chunk<DataType, ChunkSize> >() {
+ }
+
+ virtual ~LinearAllocator()
+ { }
+};
+
+template<typename DataType>
+class LinearAllocator<DataType, 0> : public LinearAllocatorBase<Chunk<DataType, 0> >
+{
+public:
+ template<typename NewDataType>
+ struct rebind {
+ typedef LinearAllocator<NewDataType, 0> other;
+ };
+
+public:
+ explicit LinearAllocator(size_t pNum)
+ : LinearAllocatorBase<Chunk<DataType, 0> >() {
+ Chunk<DataType, 0>::setSize(pNum);
+ }
+
+ virtual ~LinearAllocator()
+ { }
+};
+
+template<typename DataType>
+class MallocAllocator
+{
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef DataType* pointer;
+ typedef const DataType* const_pointer;
+ typedef DataType& reference;
+ typedef const DataType& const_reference;
+ typedef DataType value_type;
+
+ template<typename OtherDataType>
+ struct rebind
+ {
+ typedef MallocAllocator<OtherDataType> other;
+ };
+
+public:
+ MallocAllocator() throw()
+ { }
+
+ MallocAllocator(const MallocAllocator&) throw()
+ { }
+
+ ~MallocAllocator() throw()
+ { }
+
+ pointer address(reference X) const
+ { return &X; }
+
+ const_pointer address(const_reference X) const
+ { return &X; }
+
+ pointer allocate(size_type pNumOfElements, const void* = 0)
+ {
+ return static_cast<DataType*>(
+ std::malloc(pNumOfElements*sizeof(DataType)));
+ }
+
+ void deallocate(pointer pObject, size_type)
+ { std::free(static_cast<void*>(pObject)); }
+
+ size_type max_size() const throw()
+ { return size_t(-1) / sizeof(DataType); }
+
+ void construct(pointer pObject, const DataType& pValue)
+ { ::new((void *)pObject) value_type(pValue); }
+
+ void destroy(pointer pObject)
+ { pObject->~DataType(); }
+
+};
+
+template<>
+class MallocAllocator<void>
+{
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef void* pointer;
+ typedef const void* const_pointer;
+ typedef void* reference;
+ typedef const void* const_reference;
+ typedef void* value_type;
+
+ template<typename OtherDataType>
+ struct rebind
+ {
+ typedef MallocAllocator<OtherDataType> other;
+ };
+
+public:
+ MallocAllocator() throw()
+ { }
+
+ MallocAllocator(const MallocAllocator&) throw()
+ { }
+
+ ~MallocAllocator() throw()
+ { }
+
+ size_type max_size() const throw()
+ { return size_t(-1) / sizeof(void*); }
+
+ pointer address(reference X) const
+ { return X; }
+
+ const_pointer address(const_reference X) const
+ { return X; }
+
+ template<typename DataType>
+ DataType* allocate(size_type pNumOfElements, const void* = 0) {
+ return static_cast<DataType*>(
+ std::malloc(pNumOfElements*sizeof(DataType)));
+ }
+
+ pointer allocate(size_type pNumOfElements, const void* = 0) {
+ return std::malloc(pNumOfElements);
+ }
+
+ template<typename DataType>
+ void deallocate(DataType* pObject, size_type)
+ { std::free(static_cast<void*>(pObject)); }
+
+ void deallocate(pointer pObject, size_type)
+ { std::free(pObject); }
+
+ template<typename DataType>
+ void construct(DataType* pObject, const DataType& pValue)
+ { /* do nothing */ }
+
+ void construct(pointer pObject, const_reference pValue)
+ { /* do nothing */ }
+
+ template<typename DataType>
+ void destroy(DataType* pObject)
+ { /* do nothing */ }
+
+ void destroy(pointer pObject)
+ { /* do nothing */ }
+};
+
+} // namespace mcld
+
+#endif
+
diff --git a/include/mcld/Support/CommandLine.h b/include/mcld/Support/CommandLine.h
new file mode 100644
index 0000000..e52c4a3
--- /dev/null
+++ b/include/mcld/Support/CommandLine.h
@@ -0,0 +1,63 @@
+//===- CommandLine.h ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_COMMANDLINE_H
+#define MCLD_COMMANDLINE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/CommandLine.h>
+#include "mcld/Support/FileSystem.h"
+#include "mcld/MC/MCLDDirectory.h"
+
+//--------------------------------------------------
+// parser<mcld::sys::fs::Path>
+//
+namespace llvm {
+namespace cl {
+
+template<>
+class parser<mcld::sys::fs::Path> : public basic_parser<mcld::sys::fs::Path>
+{
+public:
+ bool parse(Option &O,
+ StringRef ArgName,
+ StringRef Arg,
+ mcld::sys::fs::Path &Val);
+
+ virtual const char *getValueName() const { return "path"; }
+ void printOptionDiff(const Option &O,
+ const mcld::sys::fs::Path &V,
+ OptVal Default,
+ size_t GlobalWidth) const;
+ virtual void anchor();
+};
+
+//--------------------------------------------------
+// parser<mcld::MCLDDirectory>
+//
+template<>
+class parser<mcld::MCLDDirectory> : public llvm::cl::basic_parser<mcld::MCLDDirectory>
+{
+public:
+ bool parse(Option &O, StringRef ArgName, StringRef Arg, mcld::MCLDDirectory &Val);
+
+ virtual const char *getValueName() const { return "directory"; }
+ void printOptionDiff(const Option &O,
+ const mcld::MCLDDirectory &V,
+ OptVal Default,
+ size_t GlobalWidth) const;
+ virtual void anchor();
+};
+
+} // namespace of cl
+} // namespace of llvm
+
+#endif
+
diff --git a/include/mcld/Support/DerivedPositionDependentOptions.h b/include/mcld/Support/DerivedPositionDependentOptions.h
new file mode 100644
index 0000000..2254a5f
--- /dev/null
+++ b/include/mcld/Support/DerivedPositionDependentOptions.h
@@ -0,0 +1,137 @@
+//===- DerivedPositionDependentOptions.h ----------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_DERIVEDPOSITIONDEPENDENTOPTIONS_H
+#define MCLD_DERIVEDPOSITIONDEPENDENTOPTIONS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <string>
+
+#include "mcld/Support/RealPath.h"
+#include "mcld/Support/PositionDependentOption.h"
+
+namespace mcld
+{
+
+ /** \class DerivedPositionDependentOptions
+ * \brief This file contains the declarations of classes derived from PositionDependentOption.
+ */
+
+ class FileOption : public PositionDependentOption {
+ private:
+ sys::fs::RealPath m_Path;
+
+ protected:
+ FileOption(unsigned pPosition, Type pType, const sys::fs::Path &pPath)
+ : PositionDependentOption(pPosition, pType)
+ { m_Path.assign(pPath); }
+
+ public:
+ inline const sys::fs::Path *path() const { return &m_Path; }
+ };
+
+ class NamespecOption : public PositionDependentOption {
+ private:
+ std::string m_pNamespec;
+
+ public:
+ NamespecOption(unsigned pPosition, const std::string &pNamespec)
+ : PositionDependentOption(pPosition, PositionDependentOption::NAMESPEC),
+ m_pNamespec(pNamespec) { }
+
+ inline const std::string &namespec() const { return m_pNamespec; }
+ };
+
+ class BitcodeOption : public FileOption {
+ public:
+ BitcodeOption(unsigned pPosition, const sys::fs::Path &pPath)
+ : FileOption(pPosition, PositionDependentOption::BITCODE, pPath) { }
+ };
+
+ class StartGroupOption : public PositionDependentOption {
+ public:
+ StartGroupOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::START_GROUP) { }
+ };
+
+ class EndGroupOption : public PositionDependentOption {
+ public:
+ EndGroupOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::END_GROUP) { }
+ };
+
+ class InputFileOption : public FileOption {
+ public:
+ InputFileOption(unsigned pPosition, const sys::fs::Path &pPath)
+ : FileOption(pPosition, PositionDependentOption::INPUT_FILE, pPath) { }
+ };
+
+ class WholeArchiveOption : public PositionDependentOption {
+ public:
+ WholeArchiveOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::WHOLE_ARCHIVE) { }
+ };
+
+ class NoWholeArchiveOption : public PositionDependentOption {
+ public:
+ NoWholeArchiveOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::NO_WHOLE_ARCHIVE) { }
+ };
+
+ class AsNeededOption : public PositionDependentOption {
+ public:
+ AsNeededOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::AS_NEEDED) { }
+ };
+
+ class NoAsNeededOption : public PositionDependentOption {
+ public:
+ NoAsNeededOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::NO_AS_NEEDED) { }
+ };
+
+ class AddNeededOption : public PositionDependentOption {
+ public:
+ AddNeededOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::ADD_NEEDED) { }
+ };
+
+ class NoAddNeededOption : public PositionDependentOption {
+ public:
+ NoAddNeededOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::NO_ADD_NEEDED) { }
+ };
+
+ class BDynamicOption : public PositionDependentOption {
+ public:
+ BDynamicOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::BDYNAMIC) { }
+ };
+
+ class BStaticOption : public PositionDependentOption {
+ public:
+ BStaticOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::BSTATIC) { }
+ };
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/Directory.h b/include/mcld/Support/Directory.h
new file mode 100644
index 0000000..8383e9e
--- /dev/null
+++ b/include/mcld/Support/Directory.h
@@ -0,0 +1,153 @@
+//===- Directory.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_DIRECTORY_H
+#define MCLD_DIRECTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/TypeTraits.h"
+#include "mcld/Support/FileSystem.h"
+#include "mcld/Support/Path.h"
+#include "mcld/Support/PathCache.h"
+#include <llvm/Support/Allocator.h>
+
+
+namespace mcld {
+namespace sys {
+namespace fs {
+
+class DirIterator;
+
+/** \class Directory
+ * \brief A Directory object stores a Path object, a FileStatus object for
+ * non-symbolic link status, and a FileStatus object for symbolic link
+ * status. The FileStatus objects act as value caches.
+ */
+class Directory
+{
+friend mcld::sys::fs::PathCache::entry_type* detail::bring_one_into_cache(DirIterator& pIter);
+friend void detail::open_dir(Directory& pDir);
+friend void detail::close_dir(Directory& pDir);
+private:
+ friend class DirIterator;
+
+public:
+ typedef DirIterator iterator;
+
+public:
+ /// default constructor
+ Directory();
+
+ /// constructor - a directory whose path is pPath
+ explicit Directory(const Path& pPath,
+ FileStatus st = FileStatus(),
+ FileStatus symlink_st = FileStatus());
+
+ /// copy constructor
+ /// when a copying construction happens, the cache is not copied.
+ Directory(const Directory& pCopy);
+
+ /// assignment
+ /// When an assignment occurs, the cache is clear.
+ Directory& operator=(const Directory& pCopy);
+
+ /// destructor, inheritable.
+ virtual ~Directory();
+
+ /// Since we have default construtor, we must provide assign.
+ void assign(const Path& pPath,
+ FileStatus st = FileStatus(),
+ FileStatus symlink_st = FileStatus());
+
+ /// clear - clear the cache and close the directory handler
+ void clear();
+
+ bool isGood() const;
+
+ /// path - the path of the directory
+ const Path& path() const
+ { return m_Path; }
+
+ FileStatus status() const;
+ FileStatus symlinkStatus() const;
+
+ // ----- iterators ----- //
+ // While the iterators move, the direcotry is modified.
+ // Thus, we only provide non-constant iterator.
+ iterator begin();
+ iterator end();
+
+protected:
+ mcld::sys::fs::Path m_Path;
+ mutable FileStatus m_FileStatus;
+ mutable FileStatus m_SymLinkStatus;
+ intptr_t m_Handler;
+ // the cache of directory
+ mcld::sys::fs::PathCache m_Cache;
+ bool m_CacheFull;
+};
+
+/** \class DirIterator
+ * \brief A DirIterator object can traverse all entries in a Directory
+ *
+ * DirIterator will open the directory and add entry into Directory::m_Cache
+ * DirIterator() is the end of a directory.
+ * If the end of the directory elements is reached, the iterator becomes
+ * equal to the end iterator value - DirIterator().
+ *
+ * @see Directory
+ */
+class DirIterator
+{
+friend mcld::sys::fs::PathCache::entry_type* detail::bring_one_into_cache(DirIterator& pIter);
+friend class Directory;
+public:
+ typedef mcld::sys::fs::PathCache DirCache;
+
+public:
+ typedef Directory value_type;
+ typedef ConstTraits<Directory> const_traits;
+ typedef NonConstTraits<Directory> non_const_traits;
+ typedef std::input_iterator_tag iterator_category;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+private:
+ explicit DirIterator(Directory* pParent,
+ const DirCache::iterator& pIter);
+
+public:
+ // Since StringMapIterator has no default constructor, we also have none.
+ DirIterator(const DirIterator &X);
+ ~DirIterator();
+ DirIterator& operator=(const DirIterator& pCopy);
+
+ DirIterator& operator++();
+ DirIterator operator++(int);
+
+ Path* generic_path();
+
+ Path* path();
+ const Path* path() const;
+
+ bool operator==(const DirIterator& y) const;
+ bool operator!=(const DirIterator& y) const;
+
+private:
+ Directory* m_pParent; // get handler
+ DirCache::iterator m_Iter; // for full situation
+ DirCache::entry_type* m_pEntry;
+};
+
+} // namespace of fs
+} // namespace of sys
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Support/FileSystem.h b/include/mcld/Support/FileSystem.h
new file mode 100644
index 0000000..28dc563
--- /dev/null
+++ b/include/mcld/Support/FileSystem.h
@@ -0,0 +1,119 @@
+//===- FileSystem.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file declares the mcld::sys::fs:: namespace. It follows TR2/boost
+// filesystem (v3), but modified to remove exception handling and the
+// path class.
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_FILE_SYSTEM_H
+#define MCLD_FILE_SYSTEM_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/Support/PathCache.h"
+#include <string>
+#include <iosfwd>
+#include <locale>
+
+namespace mcld {
+namespace sys {
+namespace fs {
+
+enum FileType
+{
+ StatusError,
+ StatusUnknown = StatusError,
+ FileNotFound,
+ RegularFile,
+ DirectoryFile,
+ SymlinkFile,
+ BlockFile,
+ CharacterFile,
+ FifoFile,
+ SocketFile,
+ ReparseFile,
+ TypeUnknown,
+ StatusKnown,
+ IsSymLink
+};
+
+/** \class FileStatus
+ * \brief FileStatus
+ */
+class FileStatus
+{
+public:
+ FileStatus()
+ : m_Value(StatusError) {}
+
+ explicit FileStatus(FileType v)
+ : m_Value(v) {}
+
+ void setType(FileType v) { m_Value = v; }
+ FileType type() const { return m_Value; }
+
+private:
+ FileType m_Value;
+};
+
+inline bool operator==(const FileStatus& rhs, const FileStatus& lhs) {
+ return rhs.type() == lhs.type();
+}
+
+inline bool operator!=(const FileStatus& rhs, const FileStatus& lhs ) {
+ return !(rhs == lhs);
+}
+
+class Path;
+class DirIterator;
+class Directory;
+
+bool exists(const Path &pPath);
+bool is_directory(const Path &pPath);
+
+inline static bool exists(FileStatus f) {
+ return (f.type() != StatusError)&&(f.type() != FileNotFound);
+}
+
+inline static bool is_directory(FileStatus f) {
+ return f.type() == mcld::sys::fs::DirectoryFile;
+}
+
+namespace detail
+{
+
+typedef unsigned char* Address;
+typedef off_t Offset;
+extern std::string static_library_extension;
+extern std::string shared_library_extension;
+extern std::string executable_extension;
+extern std::string relocatable_extension;
+extern std::string assembly_extension;
+extern std::string bitcode_extension;
+
+size_t canonicalize(std::string& pPathName);
+bool not_found_error(int perrno);
+void status(const Path& p, FileStatus& pFileStatus);
+void symlink_status(const Path& p, FileStatus& pFileStatus);
+mcld::sys::fs::PathCache::entry_type* bring_one_into_cache(DirIterator& pIter);
+void open_dir(Directory& pDir);
+void close_dir(Directory& pDir);
+void get_pwd(std::string& pPWD);
+size_t pread(int pFD, Address pBuf, size_t pCount, off_t pOffset);
+size_t pwrite(int pFD, const Address pBuf, size_t pCount, off_t pOffset);
+char *strerror(int pErrnum);
+
+} // namespace of detail
+} // namespace of fs
+} // namespace of sys
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/GCFactory.h b/include/mcld/Support/GCFactory.h
new file mode 100644
index 0000000..103188e
--- /dev/null
+++ b/include/mcld/Support/GCFactory.h
@@ -0,0 +1,230 @@
+//===- GCFactory.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_GC_FACTORY_H
+#define MCLD_GC_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/ADT/TypeTraits.h"
+#include "mcld/Support/Allocators.h"
+
+#include <assert.h>
+#include <iterator>
+
+namespace mcld
+{
+
+/** \class DataIteratorBase
+ * \brief DataIteratorBase provides the basic functions of DataIterator
+ * @see DataIterator
+ */
+template<typename ChunkType>
+struct DataIteratorBase
+{
+public:
+ ChunkType* m_pChunk;
+ unsigned int m_Pos;
+
+public:
+ DataIteratorBase(ChunkType* X, unsigned int pPos)
+ : m_pChunk(X), m_Pos(pPos)
+ { }
+
+ inline void advance() {
+ ++m_Pos;
+ if ((m_Pos == m_pChunk->bound) && (0 == m_pChunk->next))
+ return;
+ if (m_Pos == m_pChunk->bound) {
+ m_pChunk = m_pChunk->next;
+ m_Pos = 0;
+ }
+ }
+
+ bool operator==(const DataIteratorBase& y) const
+ { return ((this->m_pChunk == y.m_pChunk) && (this->m_Pos == y.m_Pos)); }
+
+ bool operator!=(const DataIteratorBase& y) const
+ { return ((this->m_pChunk != y.m_pChunk) || (this->m_Pos != y.m_Pos)); }
+};
+
+/** \class DataIterator
+ * \brief DataIterator provides STL compatible iterator for allocators
+ */
+template<typename ChunkType, class Traits>
+class DataIterator : public DataIteratorBase<ChunkType>
+{
+public:
+ typedef typename ChunkType::value_type value_type;
+ typedef Traits traits;
+ typedef typename traits::pointer pointer;
+ typedef typename traits::reference reference;
+ typedef DataIterator<ChunkType, Traits> Self;
+ typedef DataIteratorBase<ChunkType> Base;
+
+ typedef typename traits::nonconst_traits nonconst_traits;
+ typedef DataIterator<ChunkType, nonconst_traits> iterator;
+ typedef typename traits::const_traits const_traits;
+ typedef DataIterator<ChunkType, const_traits> const_iterator;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+public:
+ DataIterator()
+ : Base(0, 0)
+ { }
+
+ DataIterator(ChunkType* pChunk, unsigned int pPos)
+ : Base(pChunk, pPos)
+ { }
+
+ DataIterator(const DataIterator& pCopy)
+ : Base(pCopy.m_pChunk, pCopy.m_Pos)
+ { }
+
+ ~DataIterator()
+ { }
+
+ // ----- operators ----- //
+ reference operator*() {
+ if (0 == this->m_pChunk)
+ assert(0 && "data iterator goes to a invalid position");
+ return this->m_pChunk->data[Base::m_Pos];
+ }
+
+ Self& operator++() {
+ this->Base::advance();
+ return *this;
+ }
+
+ Self operator++(int) {
+ Self tmp = *this;
+ this->Base::advance();
+ return tmp;
+ }
+};
+
+template<typename Alloc>
+class GCFactoryBase : public Alloc
+{
+public:
+ typedef DataIterator<typename Alloc::chunk_type,
+ NonConstTraits<
+ typename Alloc::value_type> > iterator;
+ typedef DataIterator<typename Alloc::chunk_type,
+ ConstTraits<
+ typename Alloc::value_type> > const_iterator;
+
+ typedef typename Alloc::value_type value_type;
+ typedef typename Alloc::pointer pointer;
+ typedef typename Alloc::reference reference;
+ typedef typename Alloc::size_type size_type;
+
+protected:
+ GCFactoryBase()
+ : Alloc(), m_NumAllocData(0)
+ { }
+
+ GCFactoryBase(size_t pNum)
+ : Alloc(pNum), m_NumAllocData(0)
+ { }
+
+public:
+ virtual ~GCFactoryBase()
+ { Alloc::clear(); }
+
+ // ----- modifiers ----- //
+ value_type* allocate(size_t N) {
+ value_type* result = Alloc::allocate(N);
+ if (0 != result)
+ m_NumAllocData += N;
+ return result;
+ }
+
+ value_type* allocate() {
+ ++m_NumAllocData;
+ return Alloc::allocate();
+ }
+
+ void deallocate(pointer &pPtr, size_type N) {
+ Alloc::deallocate(pPtr, N);
+ if (0 == pPtr)
+ m_NumAllocData -= N;
+ }
+
+ void deallocate(pointer &pPtr) {
+ Alloc::deallocate(pPtr);
+ if (0 == pPtr)
+ --m_NumAllocData;
+ }
+
+ void reset() {
+ Alloc::reset();
+ m_NumAllocData = 0;
+ }
+
+ // ----- iterators ----- //
+ iterator begin()
+ { return iterator(Alloc::m_pRoot, 0); }
+
+ const_iterator begin() const
+ { return const_iterator(Alloc::m_pRoot, 0); }
+
+ iterator end() {
+ return (0 == Alloc::m_pCurrent)?
+ begin():
+ iterator(Alloc::m_pCurrent, Alloc::m_pCurrent->bound);
+ }
+
+ const_iterator end() const {
+ return (0 == Alloc::m_pCurrent)?
+ begin():
+ const_iterator(Alloc::m_pCurrent, Alloc::m_pCurrent->bound);
+ }
+
+ // ----- observers ----- //
+ bool empty() const
+ { return Alloc::empty(); }
+
+ unsigned int capacity() const
+ { return Alloc::max_size(); }
+
+ unsigned int size() const
+ { return m_NumAllocData; }
+
+protected:
+ unsigned int m_NumAllocData;
+};
+
+/** \class GCFactory
+ * \brief GCFactory provides a factory that guaratees to remove all allocated
+ * data.
+ */
+template<typename DataType, size_t ChunkSize>
+class GCFactory : public GCFactoryBase<LinearAllocator<DataType, ChunkSize> >
+{
+public:
+ GCFactory()
+ : GCFactoryBase<LinearAllocator<DataType, ChunkSize> >()
+ { }
+};
+
+template<typename DataType>
+class GCFactory<DataType, 0> : public GCFactoryBase<LinearAllocator<DataType, 0> >
+{
+public:
+ GCFactory(size_t pNum)
+ : GCFactoryBase<LinearAllocator<DataType, 0> >(pNum)
+ { }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/GCFactoryListTraits.h b/include/mcld/Support/GCFactoryListTraits.h
new file mode 100644
index 0000000..418ec57
--- /dev/null
+++ b/include/mcld/Support/GCFactoryListTraits.h
@@ -0,0 +1,65 @@
+//===- GCFactoryListTraits.h ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_GC_FACTORY_LIST_TRAITS_H
+#define MCLD_GC_FACTORY_LIST_TRAITS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/ADT/ilist_node.h>
+#include <llvm/ADT/ilist.h>
+
+#include <assert.h>
+
+namespace mcld
+{
+
+/** \class GCFactoryListTraits
+ * \brief GCFactoryListTraits provides trait class for llvm::iplist when
+ * the nodes in the list is produced by GCFactory.
+ */
+template<typename DataType>
+class GCFactoryListTraits : public llvm::ilist_default_traits<DataType> {
+private:
+ class SentinelNode : public llvm::ilist_node<DataType> {
+ public:
+ SentinelNode() : llvm::ilist_node<DataType>() { }
+ };
+
+public:
+ // override the traits provided in llvm::ilist_sentinel_traits since we've
+ // defined our own sentinel.
+ DataType *createSentinel() const
+ { return reinterpret_cast<DataType*>(&mSentinel); }
+
+ static void destroySentinel(DataType*) { }
+
+ DataType *provideInitialHead() const
+ { return createSentinel(); }
+
+ DataType *ensureHead(DataType*) const
+ { return createSentinel(); }
+
+ static void noteHead(DataType*, DataType*) { }
+
+ // override the traits provided in llvm::ilist_node_traits since
+ static DataType *createNode(const DataType &V) {
+ assert(false && "Only GCFactory knows how to create a node.");
+ }
+ static void deleteNode(DataType *V) {
+ // No action. GCFactory will handle it by itself.
+ }
+
+private:
+ mutable SentinelNode mSentinel;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Support/LEB128.h b/include/mcld/Support/LEB128.h
new file mode 100644
index 0000000..816ed72
--- /dev/null
+++ b/include/mcld/Support/LEB128.h
@@ -0,0 +1,117 @@
+//===- LEB128.h -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_LEB128_H
+#define MCLD_LEB128_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace mcld {
+
+namespace leb128 {
+
+typedef unsigned char ByteType;
+
+/* Forward declarations */
+template<typename IntType>
+size_t encode(ByteType *&pBuf, IntType pValue);
+
+template<typename IntType>
+IntType decode(const ByteType *pBuf, size_t &pSize);
+
+template<typename IntType>
+IntType decode(const ByteType *&pBuf);
+
+/*
+ * Given an integer, this function returns the number of bytes required to
+ * encode it in ULEB128 format.
+ */
+template<typename IntType>
+size_t size(IntType pValue) {
+ size_t size = 1;
+ while (pValue > 0x80) {
+ pValue >>= 7;
+ ++size;
+ }
+ return size;
+}
+
+/*
+ * Write an unsigned integer in ULEB128 to the given buffer. The client should
+ * ensure there's enough space in the buffer to hold the result. Update the
+ * given buffer pointer to the point just past the end of the write value and
+ * return the number of bytes being written.
+ */
+template<>
+size_t encode<uint64_t>(ByteType *&pBuf, uint64_t pValue);
+
+template<>
+size_t encode<uint32_t>(ByteType *&pBuf, uint32_t pValue);
+
+/*
+ * Encoding functions for signed LEB128.
+ */
+template<>
+size_t encode<int64_t>(ByteType *&pBuf, int64_t pValue);
+
+template<>
+size_t encode<int32_t>(ByteType *&pBuf, int32_t pValue);
+
+/*
+ * Read an integer encoded in ULEB128 format from the given buffer. pSize will
+ * contain the number of bytes used in the buffer to encode the returned
+ * integer.
+ */
+template<>
+uint64_t decode<uint64_t>(const ByteType *pBuf, size_t &pSize);
+
+/*
+ * Read an integer encoded in ULEB128 format from the given buffer. Update the
+ * given buffer pointer to the point just past the end of the read value.
+ */
+template<>
+uint64_t decode<uint64_t>(const ByteType *&pBuf);
+
+/*
+ * Decoding functions for signed LEB128.
+ */
+template<>
+int64_t decode<int64_t>(const ByteType *pBuf, size_t &pSize);
+
+template<>
+int64_t decode<int64_t>(const ByteType *&pBuf);
+
+/*
+ * The functions below handle the signed byte stream. This helps the user to get
+ * rid of annoying type conversions when using the LEB128 encoding/decoding APIs
+ * defined above.
+ */
+template<typename IntType>
+size_t encode(char *&pBuf, IntType pValue) {
+ return encode<IntType>(reinterpret_cast<ByteType*&>(pBuf), pValue);
+}
+
+template<typename IntType>
+IntType decode(const char *pBuf, size_t &pSize) {
+ return decode<IntType>(reinterpret_cast<const ByteType*>(pBuf), pSize);
+}
+
+template<typename IntType>
+IntType decode(const char *&pBuf) {
+ return decode<IntType>(reinterpret_cast<const ByteType*&>(pBuf));
+}
+
+} // namespace of leb128
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Support/MemoryArea.h b/include/mcld/Support/MemoryArea.h
new file mode 100644
index 0000000..2c04aff
--- /dev/null
+++ b/include/mcld/Support/MemoryArea.h
@@ -0,0 +1,260 @@
+//===- MemoryArea.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MEMORY_AREA_H
+#define MCLD_MEMORY_AREA_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/Support/FileSystem.h"
+#include "mcld/Support/Path.h"
+#include <llvm/ADT/ilist.h>
+#include <llvm/ADT/ilist_node.h>
+#include <fcntl.h>
+#include <string>
+#include <list>
+
+#if defined(ENABLE_UNITTEST)
+namespace mcldtest
+{
+ class MemoryAreaTest;
+} // namespace of mcldtest
+
+#endif
+namespace mcld
+{
+
+class MemoryRegion;
+class RegionFactory;
+
+/** \class MemoryArea
+ * \brief MemoryArea is used to manage distinct MemoryRegions of address space.
+ *
+ * Good linkers must well manipulate memory mapped I/O and dynamic memory.
+ * In MCLinker, MemoryArea is the decision-maker to use memory mapped I/O or
+ * dynamic memory. When a client requests MemoryArea for a piece of memory
+ * to hold a part of a file, MemoryArea is going to see whether the requested
+ * part of the file is already in any existing memory which is requested
+ * before. If it is, MemoryArea creates a new MemoryRegion within the memory
+ * requested before. Otherwise, MemoryArea uses memory mapped I/O or dynamic
+ * memory to load the file.
+ *
+ * If the part a file being loaded is larger than 3/4 pages, MemoryArea uses
+ * memory mapped I/O to load the file. Otherwise, MemoryArea uses dynamic
+ * memory to read the content of file into the memory space.
+ */
+class MemoryArea : private Uncopyable
+{
+#if defined(ENABLE_UNITTEST)
+friend class mcldtest::MemoryAreaTest;
+#endif
+public:
+ enum IOState
+ {
+ GoodBit = 0,
+ BadBit = 1L << 0,
+ EOFBit = 1L << 1,
+ FailBit = 1L << 2,
+ IOStateEnd = 1L << 16
+ };
+
+ enum AccessMode
+ {
+ ReadOnly = O_RDONLY,
+ WriteOnly = O_WRONLY,
+ ReadWrite = O_RDWR,
+ AccessMask = O_ACCMODE
+ };
+
+private:
+ typedef sys::fs::detail::Address Address;
+
+ friend class MemoryRegion;
+ friend class RegionFactory;
+ struct Space : public llvm::ilist_node<Space>
+ {
+ public:
+ enum Type
+ {
+ ALLOCATED_ARRAY,
+ MMAPED,
+ UNALLOCATED
+ };
+
+ public:
+ Space()
+ : m_pParent(NULL),
+ type(UNALLOCATED),
+ file_offset(0),
+ size(0),
+ data(0),
+ region_num(0)
+ { }
+
+ Space(MemoryArea* pParent, size_t pOffset, size_t pLength)
+ : m_pParent(pParent),
+ type(UNALLOCATED),
+ file_offset(pOffset),
+ size(pLength),
+ data(0),
+ region_num(0)
+ { }
+
+ ~Space()
+ { }
+
+ void sync()
+ { m_pParent->write(*this); }
+
+ private:
+ MemoryArea* m_pParent;
+
+ public:
+ Type type;
+ size_t file_offset;
+ size_t size;
+ sys::fs::detail::Address data;
+ size_t region_num;
+ };
+
+ friend class Space;
+ typedef llvm::iplist<Space> SpaceList;
+
+public:
+ // constructor
+ // @param pRegionFactory the factory to manage MemoryRegions
+ MemoryArea(RegionFactory& pRegionFactory);
+
+ // destructor
+ ~MemoryArea();
+
+ // request - create a MemoryRegion within a sufficient space
+ // find an existing space to hold the MemoryRegion.
+ // if MemoryArea does not find such space, then it creates a new space and
+ // assign a MemoryRegion into the space.
+ MemoryRegion* request(size_t pOffset, size_t pLength);
+
+ // release - release a MemoryRegion.
+ // release a MemoryRegion does not cause
+ void release(MemoryRegion* pRegion);
+
+ // clean - release all MemoryRegion and unmap all spaces.
+ void clean();
+
+ // sync - sync all MemoryRegion
+ void sync();
+
+ // map - open the file pPath and mapped it onto MemoryArea
+ // @param flags see man 2 open
+ void map(const sys::fs::Path& pPath, int flags);
+
+ // map - open the file pPath and mapped it onto MemoryArea
+ // @param flags see man 2 open
+ // @param mode see man 2 open
+ void map(const sys::fs::Path& pPath, int flags, int mode);
+
+ // unmap - close the opened file and unmap the MemoryArea
+ void unmap();
+
+ // path - the path of the mapped file.
+ const sys::fs::Path& path() const
+ { return m_FilePath; }
+
+ // size - the real size of the mapped file.
+ size_t size() const
+ { return m_FileSize; }
+
+ // isMapped - check if MemoryArea is mapped to a file
+ bool isMapped() const;
+
+ // isGood - check if the state of the opened area is good for read/write
+ // operations
+ bool isGood() const;
+
+ // isBad - check if an error causes the loss of integrity of the memory space
+ bool isBad() const;
+
+ // isFailed - check if an error related to the internal logic of the operation
+ // itself occurs
+ bool isFailed() const;
+
+ // isEOF - check if we reach the end of the file
+ bool isEOF() const;
+
+ // isReadable - check if the memory area is readable
+ bool isReadable() const;
+
+ // isWriteable - check if the memory area is writable
+ bool isWritable() const;
+
+ // rdstate - get error state flags
+ // Returns the current internal error state flags of the stream
+ int rdstate() const;
+
+ // setState - set error state flag
+ void setState(IOState pState);
+
+ // clear - set error state flag
+ void clear(IOState pState = GoodBit);
+
+private:
+ // readToBuffer - read data from the file behind this MemorySpace and store
+ // those bytes in pBuf. Return the number of byte read or -1 on error.
+ ssize_t readToBuffer(sys::fs::detail::Address pBuf,
+ size_t pSize, size_t pOffset);
+
+private:
+ // find - first fit search
+ Space* find(size_t pOffset, size_t pLength);
+
+ // release a Space, but does not remove it from space list
+ void release(Space* pSpace);
+
+ // read - read data from mapped file into virtual memroy of pSpace. Return
+ // false on error.
+ bool read(Space& pSpace);
+
+ // write - write back the virtual memory of pSpace into mapped file.
+ void write(const Space& pSpace);
+
+ // truncate - truncate the file size to length.
+ void truncate(size_t pLength);
+
+ // policy - decide whehter to use dynamic memory or memory mapped I/O
+ Space::Type policy(off_t pOffset, size_t pLength);
+
+ // the size of one page
+ static const off_t PageSize = 4096;
+
+ // page_boundary - Given a file size, return the size to read integral pages.
+ // return the first page boundary after pFileOffset
+ static off_t page_boundary(off_t pFileOffset)
+ { return (pFileOffset + (PageSize - 1)) & ~ (PageSize - 1); }
+
+ // Given a file offset, return the page offset.
+ // return the first page boundary before pFileOffset
+ static off_t page_offset(off_t pFileOffset)
+ { return pFileOffset & ~ (PageSize - 1); }
+
+private:
+ RegionFactory& m_RegionFactory;
+ sys::fs::Path m_FilePath;
+ int m_FileDescriptor;
+ size_t m_FileSize;
+ int m_AccessFlags;
+ int m_State;
+
+ SpaceList m_SpaceList;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/MemoryAreaFactory.h b/include/mcld/Support/MemoryAreaFactory.h
new file mode 100644
index 0000000..f9ffa6e
--- /dev/null
+++ b/include/mcld/Support/MemoryAreaFactory.h
@@ -0,0 +1,64 @@
+//===- MemoryAreaFactory.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MEMORY_AREA_FACTORY_H
+#define MCLD_MEMORY_AREA_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/Support/UniqueGCFactory.h"
+#include "mcld/Support/MemoryArea.h"
+#include "mcld/Support/Path.h"
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+namespace mcld
+{
+
+class RegionFactory;
+/** \class MemoryAreaFactory
+ * \brief MemoryAreaFactory avoids creating duplicated MemoryAreas of the
+ * same file.
+ *
+ * Users can give duplicated input files on the command line. In order to
+ * prevent opening the same file twice, and create redundant MemoryRegions,
+ * mcld::Input should not create MemoryArea directly. Instead, it should ask
+ * MemoryAreaFactory and get the unique MemoryArea.
+ *
+ * The timing of opening and closing files is not strictly bound to the
+ * constructor and destructor of MCLDFile. For mcld::Output, MCLinker
+ * opens the file rather after assigning offset to sections. On the other
+ * aside, mcld::Input opens the file at constructor. In order to hide the
+ * file operations, MemoryAreaFactory actually open the file untill the first
+ * MemoryRegion is requested.
+ *
+ * @see MemoryRegion
+ * @see UniqueGCFactoryBase
+ */
+class MemoryAreaFactory : public UniqueGCFactoryBase<sys::fs::Path, MemoryArea, 0>
+{
+public:
+ explicit MemoryAreaFactory(size_t pNum);
+ ~MemoryAreaFactory();
+
+ // produce - create a MemoryArea and open its file
+ // If the file fails to be opened, the returned MemoryArea::isMapped()
+ // should be false
+ MemoryArea* produce(const sys::fs::Path& pPath, int pFlags);
+ MemoryArea* produce(const sys::fs::Path& pPath, int pFlags, mode_t pMode);
+
+private:
+ RegionFactory* m_pRegionFactory;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/MemoryRegion.h b/include/mcld/Support/MemoryRegion.h
new file mode 100644
index 0000000..49f5fda
--- /dev/null
+++ b/include/mcld/Support/MemoryRegion.h
@@ -0,0 +1,97 @@
+//===- MemoryRegion.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LD_MEMORY_REGION_H
+#define LD_MEMORY_REGION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/ADT/Uncopyable.h>
+#include <mcld/ADT/SizeTraits.h>
+#include <mcld/ADT/TypeTraits.h>
+#include <mcld/Support/FileSystem.h>
+#include <mcld/Support/MemoryArea.h>
+#include <llvm/ADT/ilist.h>
+#include <llvm/ADT/StringRef.h>
+
+namespace mcld
+{
+
+/** \class MemoryRegion
+ * \brief MemoryRegion is a range of virtual memory which is mapped onto a
+ * range of files which is opened by MemoryArea.
+ *
+ * MemoryArea maps a file onto virtual memory. Clients can get a range of
+ * mapped memory space by requesting a MemoryRegion from MemoryArea, and
+ * read/write the mapped file through the MemoryRegion.
+ *
+ * When two different MemoryRegion may overlap memory space, race condition
+ * may occurs. Clients must call MemoryRegion::sync() explicit to tell the
+ * MemoryArea when to synchronize the virtual memory space with the mapped
+ * file.
+ */
+class MemoryRegion : private Uncopyable
+{
+friend class RegionFactory;
+friend class MemoryArea;
+
+public:
+typedef NonConstTraits<mcld::sys::fs::detail::Address>::value_type Address;
+typedef ConstTraits<mcld::sys::fs::detail::Address>::value_type ConstAddress;
+typedef NonConstTraits<mcld::sys::fs::detail::Offset>::value_type Offset;
+typedef ConstTraits<mcld::sys::fs::detail::Offset>::value_type ConstOffset;
+
+private:
+ MemoryRegion(MemoryArea::Space* pParentSpace,
+ const Address pVMAStart,
+ size_t pSize);
+
+ // drift - leave parent space
+ void drift();
+
+ MemoryArea::Space* parent()
+ { return m_pParentSpace; }
+
+ const MemoryArea::Space* parent() const
+ { return m_pParentSpace; }
+
+public:
+ ~MemoryRegion();
+
+ Address start()
+ { return m_VMAStart; }
+
+ ConstAddress start() const
+ { return m_VMAStart; }
+
+ Address end()
+ { return m_VMAStart+m_Length; }
+
+ ConstAddress end() const
+ { return m_VMAStart+m_Length; }
+
+ size_t size() const
+ { return m_Length; }
+
+ Address getBuffer(Offset pOffset = 0)
+ { return m_VMAStart+pOffset; }
+
+ ConstAddress getBuffer(Offset pOffset = 0) const
+ { return m_VMAStart+pOffset; }
+
+private:
+ MemoryArea::Space* m_pParentSpace;
+ Address m_VMAStart;
+ size_t m_Length;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/Path.h b/include/mcld/Support/Path.h
new file mode 100644
index 0000000..f5ee56c
--- /dev/null
+++ b/include/mcld/Support/Path.h
@@ -0,0 +1,179 @@
+//===- Path.h -------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file declares the mcld::sys::fs:: namespace. It follows TR2/boost
+// filesystem (v3), but modified to remove exception handling and the
+// path class.
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_PATH_H
+#define MCLD_PATH_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/raw_ostream.h>
+#include <functional>
+#include <string>
+
+//#include "mcld/Support/Directory.h"
+namespace mcld {
+namespace sys {
+namespace fs {
+
+#ifdef LLVM_ON_WIN32
+const wchar_t separator = L'\\';
+const wchar_t preferred_separator = L'\\';
+#else
+const char separator = '/';
+const char preferred_separator = '/';
+#endif
+
+/** \class Path
+ * \brief Path provides an abstraction for the path to a file or directory in
+ * the operating system's filesystem.
+ *
+ * FIXME: current Path library only support UTF-8 chararcter set.
+ *
+ */
+class Path
+{
+public:
+#ifdef LLVM_ON_WIN32
+ typedef wchar_t ValueType;
+#else
+ typedef char ValueType;
+#endif
+ typedef std::basic_string<ValueType> StringType;
+
+public:
+ Path();
+ Path(const ValueType* s);
+ Path(const StringType &s);
+ Path(const Path& pCopy);
+ virtual ~Path();
+
+ // ----- assignments ----- //
+ template <class InputIterator>
+ Path& assign(InputIterator begin, InputIterator end);
+ Path& assign(const StringType &s);
+ Path& assign(const ValueType* s, unsigned int length);
+
+ // ----- appends ----- //
+ template <class InputIterator>
+ Path& append(InputIterator begin, InputIterator end);
+ Path& append(const Path& pPath);
+
+ // ----- observers ----- //
+ bool empty() const;
+
+ bool isFromRoot() const;
+ bool isFromPWD() const;
+
+ const StringType &native() const
+ { return m_PathName; }
+
+ StringType &native()
+ { return m_PathName; }
+
+ const ValueType* c_str() const
+ { return m_PathName.c_str(); }
+
+ std::string string() const;
+
+ // ----- decomposition ----- //
+ Path stem() const;
+ Path extension() const;
+
+ // ----- generic form observers ----- //
+ StringType generic_string() const;
+ bool canonicalize();
+
+public:
+ StringType::size_type m_append_separator_if_needed();
+ void m_erase_redundant_separator(StringType::size_type sep_pos);
+
+protected:
+ StringType m_PathName;
+};
+
+bool operator==(const Path& pLHS,const Path& pRHS);
+bool operator!=(const Path& pLHS,const Path& pRHS);
+
+//--------------------------------------------------------------------------//
+// non-member functions //
+//--------------------------------------------------------------------------//
+
+/// is_separator - is the given character a separator of a path.
+// @param value a character
+// @result true if \a value is a path separator character on the host OS
+//bool status_known(FileStatus f) { return f.type() != StatusError; }
+
+bool is_separator(char value);
+
+bool exists(const Path &pPath);
+
+bool is_directory(const Path &pPath);
+
+
+std::ostream &operator<<(std::ostream& pOS, const Path& pPath);
+
+std::istream &operator>>(std::istream& pOS, Path& pPath);
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Path &pPath);
+
+
+//--------------------------------------------------------------------------------------//
+// class path member template implementation //
+//--------------------------------------------------------------------------------------//
+template <class InputIterator>
+Path& Path::assign(InputIterator begin, InputIterator end)
+{
+ m_PathName.clear();
+ if (begin != end)
+ m_PathName.append<InputIterator>(begin, end);
+ return *this;
+}
+
+template <class InputIterator>
+Path& Path::append(InputIterator begin, InputIterator end)
+{
+ if (begin == end)
+ return *this;
+ StringType::size_type sep_pos(m_append_separator_if_needed());
+ m_PathName.append<InputIterator>(begin, end);
+ if (sep_pos)
+ m_erase_redundant_separator(sep_pos);
+ return *this;
+}
+
+} // namespace of fs
+} // namespace of sys
+} // namespace of mcld
+
+//-------------------------------------------------------------------------//
+// STL compatible functions //
+//-------------------------------------------------------------------------//
+namespace std {
+
+template<>
+struct less<mcld::sys::fs::Path> : public binary_function<mcld::sys::fs::Path,
+ mcld::sys::fs::Path,
+ bool>
+{
+ bool operator() (const mcld::sys::fs::Path& pX,const mcld::sys::fs::Path& pY) const {
+ if (pX.generic_string().size() < pY.generic_string().size())
+ return true;
+ return (pX.generic_string() < pY.generic_string());
+ }
+};
+
+} // namespace of std
+
+#endif
+
diff --git a/include/mcld/Support/PathCache.h b/include/mcld/Support/PathCache.h
new file mode 100644
index 0000000..89ec513
--- /dev/null
+++ b/include/mcld/Support/PathCache.h
@@ -0,0 +1,38 @@
+//===- PathCache.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_PATHCACHE_H
+#define MCLD_PATHCACHE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/HashEntry.h"
+#include "mcld/ADT/HashTable.h"
+#include "mcld/ADT/StringHash.h"
+#include "mcld/Support/Path.h"
+
+namespace mcld {
+namespace sys {
+namespace fs {
+
+namespace {
+ typedef HashEntry<llvm::StringRef,
+ mcld::sys::fs::Path*,
+ StringCompare<llvm::StringRef> > HashEntryType;
+} // anonymous namespace
+
+typedef HashTable<HashEntryType, StringHash<BKDR>, EntryFactory<HashEntryType> > PathCache;
+
+} // namespace of fs
+} // namespace of sys
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/PositionDependentOption.h b/include/mcld/Support/PositionDependentOption.h
new file mode 100644
index 0000000..b5d60e8
--- /dev/null
+++ b/include/mcld/Support/PositionDependentOption.h
@@ -0,0 +1,63 @@
+//===- PositionDependentOption.h ------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_POSITIONDEPENDENTOPTION_H
+#define MCLD_POSITIONDEPENDENTOPTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <vector>
+
+namespace mcld
+{
+
+ /** \class PositionDependentOption
+ * \brief PositionDependentOptions converts LLVM options into MCLDInfo
+ */
+ class PositionDependentOption
+ {
+ public:
+ enum Type {
+ BITCODE,
+ NAMESPEC,
+ INPUT_FILE,
+ START_GROUP,
+ END_GROUP,
+ WHOLE_ARCHIVE,
+ NO_WHOLE_ARCHIVE,
+ AS_NEEDED,
+ NO_AS_NEEDED,
+ ADD_NEEDED,
+ NO_ADD_NEEDED,
+ BDYNAMIC,
+ BSTATIC
+ };
+
+ protected:
+ PositionDependentOption(unsigned pPosition, Type pType)
+ : m_Type(pType),
+ m_Position(pPosition) {}
+
+ public:
+ inline const Type& type() const
+ { return m_Type; }
+
+ inline unsigned position() const
+ { return m_Position; }
+
+ private:
+ Type m_Type;
+ unsigned m_Position;
+ };
+
+ typedef std::vector<PositionDependentOption*> PositionDependentOptions;
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/RealPath.h b/include/mcld/Support/RealPath.h
new file mode 100644
index 0000000..6c0cd40
--- /dev/null
+++ b/include/mcld/Support/RealPath.h
@@ -0,0 +1,72 @@
+//===- RealPath.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_REAL_PATH_H
+#define MCLD_REAL_PATH_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/Support/Path.h"
+#include <string>
+
+namespace mcld {
+namespace sys {
+namespace fs {
+
+/** \class RealPath
+ * \brief The canonicalized absolute pathname.
+ *
+ */
+class RealPath : public Path
+{
+public:
+ typedef Path::ValueType ValueType;
+ typedef Path::StringType StringType;
+
+public:
+ RealPath();
+ explicit RealPath(const ValueType* s );
+ explicit RealPath(const StringType &s );
+ explicit RealPath(const Path& pPath);
+
+ ~RealPath();
+
+ RealPath& assign(const Path& pPath);
+
+protected:
+ void initialize();
+};
+
+} // namespace of fs
+} // namespace of sys
+} // namespace of mcld
+
+//-------------------------------------------------------------------------//
+// STL compatible functions //
+//-------------------------------------------------------------------------//
+namespace std {
+
+template<>
+struct less<mcld::sys::fs::RealPath> : public binary_function<
+ mcld::sys::fs::RealPath,
+ mcld::sys::fs::RealPath,
+ bool>
+{
+ bool operator() (const mcld::sys::fs::RealPath& pX,
+ const mcld::sys::fs::RealPath& pY) const {
+ if (pX.native().size() < pY.native().size())
+ return true;
+ return (pX.native() < pY.native());
+ }
+};
+
+} // namespace of std
+
+
+#endif
+
diff --git a/include/mcld/Support/RegionFactory.h b/include/mcld/Support/RegionFactory.h
new file mode 100644
index 0000000..ba9a88d
--- /dev/null
+++ b/include/mcld/Support/RegionFactory.h
@@ -0,0 +1,48 @@
+//===- RegionFactory.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_REGION_FACTORY_H
+#define MCLD_REGION_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/Support/GCFactory.h"
+#include "mcld/Support/MemoryRegion.h"
+#include "mcld/Support/MemoryArea.h"
+#include "mcld/Support/FileSystem.h"
+
+namespace mcld
+{
+
+class MemoryArea;
+
+/** \class RegionFactory
+ * \brief RegionFactory produces and destroys MemoryRegions
+ *
+ */
+class RegionFactory : public GCFactory<MemoryRegion, 0>
+{
+public:
+ typedef GCFactory<MemoryRegion, 0> Alloc;
+
+public:
+ RegionFactory(size_t pNum);
+ ~RegionFactory();
+
+ // ----- production ----- //
+ MemoryRegion* produce(MemoryArea::Space* pSpace,
+ const sys::fs::detail::Address pVMAStart,
+ size_t pSize);
+
+ void destruct(MemoryRegion* pRegion);
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/TargetRegistry.h b/include/mcld/Support/TargetRegistry.h
new file mode 100644
index 0000000..a9ad875
--- /dev/null
+++ b/include/mcld/Support/TargetRegistry.h
@@ -0,0 +1,230 @@
+//===- TargetRegistry.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TARGET_REGISTRY_H
+#define TARGET_REGISTRY_H
+#include <llvm/Support/TargetRegistry.h>
+#include <string>
+#include <list>
+
+namespace llvm {
+class TargetMachine;
+class MCCodeEmitter;
+class MCContext;
+class AsmPrinter;
+} // namespace of llvm
+
+namespace mcld {
+class LLVMTargetMachine;
+class TargetRegistry;
+class SectLinker;
+class SectLinkerOption;
+class TargetLDBackend;
+class AttributeFactory;
+class InputFactory;
+class ContextFactory;
+
+//===----------------------------------------------------------------------===//
+/// Target - mcld::Target is an object adapter of llvm::Target
+///
+class Target
+{
+ friend class mcld::LLVMTargetMachine;
+ friend class mcld::TargetRegistry;
+public:
+ typedef mcld::LLVMTargetMachine *(*TargetMachineCtorTy)(const mcld::Target &,
+ llvm::TargetMachine &,
+ const std::string&);
+
+ typedef SectLinker *(*SectLinkerCtorTy)(const std::string& pTriple,
+ SectLinkerOption &,
+ TargetLDBackend&);
+
+ typedef TargetLDBackend *(*TargetLDBackendCtorTy)(const llvm::Target&,
+ const std::string&);
+
+private:
+ TargetMachineCtorTy TargetMachineCtorFn;
+ SectLinkerCtorTy SectLinkerCtorFn;
+ TargetLDBackendCtorTy TargetLDBackendCtorFn;
+
+public:
+ Target();
+
+ void setTarget(const llvm::Target& pTarget) {
+ m_pT = &pTarget;
+ }
+
+ mcld::LLVMTargetMachine *createTargetMachine(const std::string &pTriple,
+ const std::string &pCPU, const std::string &pFeatures,
+ const llvm::TargetOptions &Options,
+ llvm::Reloc::Model RM = llvm::Reloc::Default,
+ llvm::CodeModel::Model CM = llvm::CodeModel::Default,
+ llvm::CodeGenOpt::Level OL = llvm::CodeGenOpt::Default) const {
+ if (TargetMachineCtorFn && m_pT) {
+ llvm::TargetMachine *tm = m_pT->createTargetMachine(pTriple, pCPU, pFeatures, Options, RM, CM, OL);
+ if (tm)
+ return TargetMachineCtorFn(*this, *tm, pTriple);
+ }
+ return 0;
+ }
+
+ /// createSectLinker - create target-specific SectLinker
+ ///
+ /// @return created SectLinker
+ SectLinker *createSectLinker(const std::string &pTriple,
+ SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend) const {
+ if (!SectLinkerCtorFn)
+ return 0;
+ return SectLinkerCtorFn(pTriple,
+ pOption,
+ pLDBackend);
+ }
+
+ /// createLDBackend - create target-specific LDBackend
+ ///
+ /// @return created TargetLDBackend
+ TargetLDBackend *createLDBackend(const llvm::Target& T, const std::string& Triple) const {
+ if (!TargetLDBackendCtorFn)
+ return 0;
+ return TargetLDBackendCtorFn(T, Triple);
+ }
+
+ const llvm::Target* get() const {
+ return m_pT;
+ }
+
+private:
+ const llvm::Target* m_pT;
+};
+
+//===----------------------------------------------------------------------===//
+/// TargetRegistry - mcld::TargetRegistry is an object adapter of
+/// llvm::TargetRegistry
+///
+class TargetRegistry
+{
+public:
+ typedef std::list<mcld::Target*> TargetListTy;
+ typedef TargetListTy::iterator iterator;
+
+private:
+ static TargetListTy s_TargetList;
+
+public:
+ static iterator begin() { return s_TargetList.begin(); }
+ static iterator end() { return s_TargetList.end(); }
+
+ static size_t size() { return s_TargetList.size(); }
+ static bool empty() { return s_TargetList.empty(); }
+
+ /// RegisterTarget - Register the given target. Attempts to register a
+ /// target which has already been registered will be ignored.
+ ///
+ /// Clients are responsible for ensuring that registration doesn't occur
+ /// while another thread is attempting to access the registry. Typically
+ /// this is done by initializing all targets at program startup.
+ ///
+ /// @param T - The target being registered.
+ static void RegisterTarget(mcld::Target &T);
+
+ /// RegisterTargetMachine - Register a TargetMachine implementation for the
+ /// given target.
+ ///
+ /// @param T - The target being registered.
+ /// @param Fn - A function to construct a TargetMachine for the target.
+ static void RegisterTargetMachine(mcld::Target &T, mcld::Target::TargetMachineCtorTy Fn) {
+ // Ignore duplicate registration.
+ if (!T.TargetMachineCtorFn)
+ T.TargetMachineCtorFn = Fn;
+ }
+
+ /// RegisterSectLinker - Register a SectLinker implementation for the given
+ /// target.
+ ///
+ /// @param T - the target being registered
+ /// @param Fn - A function to create SectLinker for the target
+ static void RegisterSectLinker(mcld::Target &T, mcld::Target::SectLinkerCtorTy Fn) {
+ if (!T.SectLinkerCtorFn)
+ T.SectLinkerCtorFn = Fn;
+ }
+
+ /// RegisterTargetLDBackend - Register a TargetLDBackend implementation for
+ /// the given target.
+ ///
+ /// @param T - The target being registered
+ /// @param Fn - A function to create TargetLDBackend for the target
+ static void RegisterTargetLDBackend(mcld::Target &T, mcld::Target::TargetLDBackendCtorTy Fn) {
+ if (!T.TargetLDBackendCtorFn)
+ T.TargetLDBackendCtorFn = Fn;
+ }
+
+ /// lookupTarget - Lookup a target based on a llvm::Target.
+ ///
+ /// @param T - The llvm::Target to find
+ static const mcld::Target *lookupTarget(const llvm::Target& T);
+
+ /// lookupTarget - function wrapper of llvm::TargetRegistry::lookupTarget
+ ///
+ /// @param Triple - The Triple string
+ /// @param Error - The returned error message
+ static const mcld::Target *lookupTarget(const std::string &Triple,
+ std::string &Error);
+};
+
+/// RegisterTarget - Helper function for registering a target, for use in the
+/// target's initialization function. Usage:
+///
+/// Target TheFooTarget; // The global target instance.
+///
+/// extern "C" void LLVMInitializeFooTargetInfo() {
+/// RegisterTarget X(TheFooTarget, "foo", "Foo description");
+/// }
+struct RegisterTarget
+{
+ RegisterTarget(mcld::Target &T, const char *Name) {
+ llvm::TargetRegistry::iterator TIter, TEnd = llvm::TargetRegistry::end();
+ // lookup llvm::Target
+ for( TIter=llvm::TargetRegistry::begin(); TIter!=TEnd; ++TIter ) {
+ if( 0==strcmp(TIter->getName(), Name) )
+ break;
+ }
+ T.setTarget(*TIter);
+
+ TargetRegistry::RegisterTarget(T);
+ }
+};
+
+/// RegisterTargetMachine - Helper template for registering a target machine
+/// implementation, for use in the target machine initialization
+/// function. Usage:
+///
+/// extern "C" void LLVMInitializeFooTarget() {
+/// extern mcld::Target TheFooTarget;
+/// RegisterTargetMachine<mcld::FooTargetMachine> X(TheFooTarget);
+/// }
+template<class TargetMachineImpl>
+struct RegisterTargetMachine
+{
+ RegisterTargetMachine(mcld::Target &T) {
+ TargetRegistry::RegisterTargetMachine(T, &Allocator);
+ }
+
+private:
+ static mcld::LLVMTargetMachine *Allocator(const mcld::Target &T,
+ llvm::TargetMachine& TM,
+ const std::string &Triple) {
+ return new TargetMachineImpl(TM, T, Triple);
+ }
+};
+
+} //end namespace mcld
+
+#endif
+
diff --git a/include/mcld/Support/TargetSelect.h b/include/mcld/Support/TargetSelect.h
new file mode 100644
index 0000000..e040ae2
--- /dev/null
+++ b/include/mcld/Support/TargetSelect.h
@@ -0,0 +1,77 @@
+//===- TargetSelect.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TARGETSELECT_H
+#define TARGETSELECT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+extern "C" {
+ // Declare all of the target-initialization functions that are available.
+#define LLVM_TARGET(TargetName) void LLVMInitialize##TargetName##LDTargetInfo();
+#include "mcld/Config/Targets.def"
+
+ // Declare all of the target-dependent functions that are available.
+#define LLVM_TARGET(TargetName) void LLVMInitialize##TargetName##LDTarget();
+#include "mcld/Config/Targets.def"
+
+ // Declare all of the target-depedent linker information
+#define LLVM_LINKER(TargetName) void LLVMInitialize##TargetName##LDInfo();
+#include "mcld/Config/Linkers.def"
+
+ // Declare all of the available linker environment.
+#define LLVM_LINKER(TargetName) void LLVMInitialize##TargetName##SectLinker();
+#include "mcld/Config/Linkers.def"
+
+ // Declare all of the available target-specific linker
+#define LLVM_LINKER(TargetName) void LLVMInitialize##TargetName##LDBackend();
+#include "mcld/Config/Linkers.def"
+} // extern "C"
+
+namespace mcld
+{
+ /// InitializeAllTargetInfos - The main program should call this function if
+ /// it wants access to all available targets that LLVM is configured to
+ /// support, to make them available via the TargetRegistry.
+ ///
+ /// It is legal for a client to make multiple calls to this function.
+ inline void InitializeAllTargetInfos() {
+#define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##LDTargetInfo();
+#include "mcld/Config/Targets.def"
+ }
+
+ /// InitializeAllTargets - The main program should call this function if it
+ /// wants access to all available target machines that LLVM is configured to
+ /// support, to make them available via the TargetRegistry.
+ ///
+ /// It is legal for a client to make multiple calls to this function.
+ inline void InitializeAllTargets() {
+ mcld::InitializeAllTargetInfos();
+
+#define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##LDTarget();
+#include "mcld/Config/Targets.def"
+ }
+
+ /// InitializeAllLinkers - The main program should call this function if it
+ /// wants all linkers that LLVM is configured to support, to make them
+ /// available via the TargetRegistry.
+ ///
+ /// It is legal for a client to make multiple calls to this function.
+ inline void InitializeAllLinkers() {
+#define LLVM_LINKER(TargetName) LLVMInitialize##TargetName##SectLinker();
+#include "mcld/Config/Linkers.def"
+
+#define LLVM_LINKER(TargetName) LLVMInitialize##TargetName##LDBackend();
+#include "mcld/Config/Linkers.def"
+ }
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/UniqueGCFactory.h b/include/mcld/Support/UniqueGCFactory.h
new file mode 100644
index 0000000..3147bab
--- /dev/null
+++ b/include/mcld/Support/UniqueGCFactory.h
@@ -0,0 +1,94 @@
+//===- UniqueGCFactory.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_UNIQUE_GCFACTORY_H
+#define MCLD_UNIQUE_GCFACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/Support/GCFactory.h"
+#include <map>
+#include <utility>
+
+namespace mcld
+{
+
+/** \class UniqueGCFactoryBase
+ * \brief UniqueGCFactories are unique associative factories, meaning that
+ * no two elements have the same key.
+ */
+template<typename KeyType, typename DataType, size_t ChunkSize>
+class UniqueGCFactoryBase : public GCFactoryBase<LinearAllocator<DataType, ChunkSize> >
+{
+protected:
+ typedef GCFactoryBase<LinearAllocator<DataType, ChunkSize> > Alloc;
+ typedef std::map<KeyType, DataType*> KeyMap;
+
+protected:
+ UniqueGCFactoryBase()
+ : GCFactoryBase<LinearAllocator<DataType, ChunkSize> >()
+ { }
+
+ UniqueGCFactoryBase(size_t pNum)
+ : GCFactoryBase<LinearAllocator<DataType, ChunkSize> >(pNum)
+ { }
+
+public:
+ virtual ~UniqueGCFactoryBase()
+ { f_KeyMap.clear(); }
+
+ DataType* find(const KeyType& pKey) {
+ typename KeyMap::iterator dataIter = f_KeyMap.find(pKey);
+ if (dataIter != f_KeyMap.end())
+ return dataIter->second;
+ return 0;
+ }
+
+ const DataType* find(const KeyType& pKey) const {
+ typename KeyMap::const_iterator dataIter = f_KeyMap.find(pKey);
+ if (dataIter != f_KeyMap.end())
+ return dataIter->second;
+ return 0;
+ }
+
+ DataType* produce(const KeyType& pKey, bool& pExist) {
+ typename KeyMap::iterator dataIter = f_KeyMap.find(pKey);
+ if (dataIter != f_KeyMap.end()) {
+ pExist = true;
+ return dataIter->second;
+ }
+ DataType* data = Alloc::allocate();
+ construct(data);
+ f_KeyMap.insert(std::make_pair(pKey, data));
+ pExist = false;
+ return data;
+ }
+
+ DataType* produce(const KeyType& pKey, const DataType& pValue, bool& pExist) {
+ typename KeyMap::iterator dataIter = f_KeyMap.find(pKey);
+ if (dataIter != f_KeyMap.end()) {
+ pExist = true;
+ return dataIter->second;
+ }
+ DataType* data = Alloc::allocate();
+ construct(data, pValue);
+ f_KeyMap.insert(std::make_pair(pKey, data));
+ pExist = false;
+ return data;
+ }
+
+protected:
+ KeyMap f_KeyMap;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/AndroidSectLinker.h b/include/mcld/Target/AndroidSectLinker.h
new file mode 100644
index 0000000..dd68ff2
--- /dev/null
+++ b/include/mcld/Target/AndroidSectLinker.h
@@ -0,0 +1,42 @@
+//===- AndroidSectLinker.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// AndroidSectLinker is a customized linker pass for Android platform.
+// This pass set up default parameters for Android.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ANDROID_SECTLINKER_H
+#define ANDROID_SECTLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/CodeGen/SectLinker.h>
+
+namespace mcld
+{
+
+class AndroidSectLinker : public SectLinker
+{
+public:
+ AndroidSectLinker(SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend);
+
+ virtual ~AndroidSectLinker();
+
+ // addTargetInputs - add Android-specific linker options
+ virtual void addTargetOptions(llvm::Module &pM,
+ SectLinkerOption &pOption);
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/DarwinLDBackend.h b/include/mcld/Target/DarwinLDBackend.h
new file mode 100644
index 0000000..d55055a
--- /dev/null
+++ b/include/mcld/Target/DarwinLDBackend.h
@@ -0,0 +1,31 @@
+//===- DarwinLDBackend.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef DARWINLDBACKEND_H
+#define DARWINLDBACKEND_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+/** \class DarwinLDBackend
+ * \brief DarwinLDBackend provides a common interface for all Darwin OS LDBackend.
+ *
+ * \see
+ */
+class DarwinLDBackend
+{
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/ELFDynamic.h b/include/mcld/Target/ELFDynamic.h
new file mode 100644
index 0000000..ed18dc0
--- /dev/null
+++ b/include/mcld/Target/ELFDynamic.h
@@ -0,0 +1,174 @@
+//===- ELFDynamic.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_DYNAMIC_SECTION_H
+#define MCLD_ELF_DYNAMIC_SECTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/ELF.h>
+#include <mcld/LD/LDSection.h>
+#include <vector>
+#include <cstring>
+
+namespace mcld
+{
+
+class GNULDBackend;
+class ELFFileFormat;
+class MCLDInfo;
+class MemoryRegion;
+
+namespace elf_dynamic {
+
+/** \class EntryIF
+* \brief EntryIF provides a common interface for one entry in the dynamic
+* section
+*/
+class EntryIF
+{
+protected:
+ EntryIF();
+
+public:
+ virtual ~EntryIF();
+
+ virtual EntryIF* clone() const = 0;
+ virtual size_t size() const = 0;
+ virtual size_t symbolSize() const = 0;
+ virtual size_t relSize() const = 0;
+ virtual size_t relaSize() const = 0;
+ virtual size_t emit(uint8_t* pAddress) const = 0;
+ virtual void setValue(uint64_t pTag, uint64_t pValue) = 0;
+};
+
+template<size_t BITNUMBER, bool LITTLEENDIAN>
+class Entry
+{ };
+
+template<>
+class Entry<32, true> : public EntryIF
+{
+public:
+ typedef llvm::ELF::Elf32_Dyn Pair;
+ typedef llvm::ELF::Elf32_Sym Symbol;
+ typedef llvm::ELF::Elf32_Rel Rel;
+ typedef llvm::ELF::Elf32_Rela Rela;
+
+public:
+ inline Entry();
+
+ inline ~Entry();
+
+ Entry* clone() const
+ { return new Entry(); }
+
+ size_t size() const
+ { return sizeof(Pair); }
+
+ size_t symbolSize() const
+ { return sizeof(Symbol); }
+
+ size_t relSize() const
+ { return sizeof(Rel); }
+
+ size_t relaSize() const
+ { return sizeof(Rela); }
+
+ inline void setValue(uint64_t pTag, uint64_t pValue);
+
+ inline size_t emit(uint8_t* pAddress) const;
+
+private:
+ Pair m_Pair;
+};
+
+#include "ELFDynamic.tcc"
+
+} // namespace of elf_dynamic
+
+/** \class ELFDynamic
+ * \brief ELFDynamic is the .dynamic section in ELF shared and executable
+ * files.
+ */
+class ELFDynamic
+{
+public:
+ typedef std::vector<elf_dynamic::EntryIF*> EntryListType;
+ typedef EntryListType::iterator iterator;
+ typedef EntryListType::const_iterator const_iterator;
+
+public:
+ ELFDynamic(const GNULDBackend& pParent);
+
+ virtual ~ELFDynamic();
+
+ size_t size() const;
+
+ size_t entrySize() const;
+
+ size_t numOfBytes() const;
+
+ /// reserveEntries - reserve entries
+ void reserveEntries(const MCLDInfo& pInfo,
+ const ELFFileFormat& pFormat);
+
+ /// reserveNeedEntry - reserve on DT_NEED entry.
+ void reserveNeedEntry();
+
+ /// applyEntries - apply entries
+ void applyEntries(const MCLDInfo& pInfo,
+ const ELFFileFormat& pFormat);
+
+ void applySoname(uint64_t pStrTabIdx);
+
+ iterator needBegin()
+ { return m_NeedList.begin(); }
+
+ iterator needEnd()
+ { return m_NeedList.end(); }
+
+ const_iterator needBegin() const
+ { return m_NeedList.begin(); }
+
+ const_iterator needEnd() const
+ { return m_NeedList.end(); }
+
+ /// emit
+ void emit(const LDSection& pSection, MemoryRegion& pRegion) const;
+
+protected:
+ /// reserveTargetEntries - reserve target dependent entries
+ virtual void reserveTargetEntries(const ELFFileFormat& pFormat) = 0;
+
+ /// applyTargetEntries - apply target-dependant
+ virtual void applyTargetEntries(const ELFFileFormat& pFormat) = 0;
+
+protected:
+ void reserveOne(uint64_t pTag);
+
+ void applyOne(uint64_t pTag, uint64_t pValue);
+
+ size_t symbolSize() const;
+
+private:
+ EntryListType m_EntryList;
+ EntryListType m_NeedList;
+ elf_dynamic::EntryIF* m_pEntryFactory;
+
+ // The entry reserved and the entry being applied are not must matched.
+ // For better performance, we use a simple counter and apply entry one-by-one
+ // by the counter. m_Idx is the counter indicating to the entry being applied.
+ size_t m_Idx;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/ELFDynamic.tcc b/include/mcld/Target/ELFDynamic.tcc
new file mode 100644
index 0000000..8b04651
--- /dev/null
+++ b/include/mcld/Target/ELFDynamic.tcc
@@ -0,0 +1,33 @@
+//===- ELFDynamic.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+Entry<32, true>::Entry()
+{
+ m_Pair.d_tag = 0;
+ m_Pair.d_un.d_val = 0;
+}
+
+Entry<32, true>::~Entry()
+{
+}
+
+void Entry<32, true>::setValue(uint64_t pTag, uint64_t pValue)
+{
+ m_Pair.d_tag = pTag;
+ m_Pair.d_un.d_val = pValue;
+}
+
+size_t Entry<32, true>::emit(uint8_t* pAddress) const
+{
+ memcpy(reinterpret_cast<void*>(pAddress),
+ reinterpret_cast<const void*>(&m_Pair),
+ sizeof(Pair));
+ return sizeof(Pair);
+}
+
diff --git a/include/mcld/Target/GNULDBackend.h b/include/mcld/Target/GNULDBackend.h
new file mode 100644
index 0000000..7f51448
--- /dev/null
+++ b/include/mcld/Target/GNULDBackend.h
@@ -0,0 +1,322 @@
+//===- GNULDBackend.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TARGET_GNU_LDBACKEND_H
+#define MCLD_TARGET_GNU_LDBACKEND_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/ELF.h>
+#include <mcld/ADT/HashTable.h>
+#include <mcld/ADT/HashEntry.h>
+#include <mcld/LD/ELFDynObjReader.h>
+#include <mcld/LD/ELFDynObjWriter.h>
+#include <mcld/LD/ELFObjectReader.h>
+#include <mcld/LD/ELFObjectWriter.h>
+#include <mcld/LD/ELFDynObjFileFormat.h>
+#include <mcld/LD/ELFExecFileFormat.h>
+#include <mcld/LD/ELFSegment.h>
+#include <mcld/LD/GNUArchiveReader.h>
+#include <mcld/Support/GCFactory.h>
+#include <mcld/Target/ELFDynamic.h>
+#include <mcld/Target/TargetLDBackend.h>
+#include <mcld/LD/ELFSegmentFactory.h>
+
+namespace mcld
+{
+
+struct SymCompare
+{
+ bool operator()(const LDSymbol* X, const LDSymbol* Y) const
+ { return (X==Y); }
+};
+
+struct PtrHash
+{
+ size_t operator()(const LDSymbol* pKey) const
+ {
+ return (unsigned((uintptr_t)pKey) >> 4) ^
+ (unsigned((uintptr_t)pKey) >> 9);
+ }
+};
+
+class MCLDInfo;
+class Layout;
+class SymbolCategory;
+
+/** \class GNULDBackend
+ * \brief GNULDBackend provides a common interface for all GNU Unix-OS
+ * LDBackend.
+ */
+class GNULDBackend : public TargetLDBackend
+{
+ // These dynamic section tags are GNU extension.
+ enum {
+ DT_RELACOUNT = 0x6ffffff9,
+ DT_RELCOUNT = 0x6ffffffa,
+ DT_FLAGS_1 = 0x6ffffffb,
+ DT_VERDEF = 0x6ffffffc,
+ DT_VERDEFNUM = 0x6ffffffd,
+ DT_VERNEED = 0x6ffffffe,
+ DT_VERNEEDNUM = 0x6fffffff
+ };
+
+protected:
+ // Based on Kind in LDFileFormat to define basic section orders for ELF, and
+ // refer gold linker to add more enumerations to handle Regular and BSS kind
+ enum SectionOrder {
+ SHO_INTERP = 1, // .interp
+ SHO_RO_NOTE, // .note.ABI-tag, .note.gnu.build-id
+ SHO_NAMEPOOL, // *.hash, .dynsym, .dynstr
+ SHO_RELOCATION, // .rel.*, .rela.*
+ SHO_REL_PLT, // .rel.plt should come after other .rel.*
+ SHO_INIT, // .init
+ SHO_PLT, // .plt
+ SHO_TEXT, // .text
+ SHO_FINI, // .fini
+ SHO_RO, // .rodata
+ SHO_EHFRAME, // .eh_frame_hdr, .eh_frame
+ SHO_TLS_DATA, // .tdata
+ SHO_TLS_BSS, // .tbss
+ SHO_RELRO_LOCAL, // .data.rel.ro.local
+ SHO_RELRO, // .data.rel.ro,
+ SHO_RELRO_LAST, // for x86 to adjust .got if needed
+ SHO_NON_RELRO_FIRST, // for x86 to adjust .got.plt if needed
+ SHO_DATA, // .data
+ SHO_LARGE_DATA, // .ldata
+ SHO_RW_NOTE, //
+ SHO_SMALL_DATA, // .sdata
+ SHO_SMALL_BSS, // .sbss
+ SHO_BSS, // .bss
+ SHO_LARGE_BSS, // .lbss
+ SHO_UNDEFINED = ~(0U) // default order
+ };
+
+protected:
+ GNULDBackend();
+
+public:
+ virtual ~GNULDBackend();
+
+ bool initArchiveReader(MCLinker& pLinker, MCLDInfo& pInfo);
+ bool initObjectReader(MCLinker& pLinker);
+ bool initDynObjReader(MCLinker& pLinker);
+ bool initObjectWriter(MCLinker& pLinker);
+ bool initDynObjWriter(MCLinker& pLinker);
+
+ bool initExecSections(MCLinker& pMCLinker);
+ bool initDynObjSections(MCLinker& pMCLinker);
+
+ bool initStandardSymbols(MCLinker& pLinker);
+
+ GNUArchiveReader *getArchiveReader();
+ GNUArchiveReader *getArchiveReader() const;
+
+ ELFObjectReader *getObjectReader();
+ ELFObjectReader *getObjectReader() const;
+
+ ELFDynObjReader *getDynObjReader();
+ ELFDynObjReader *getDynObjReader() const;
+
+ ELFObjectWriter *getObjectWriter();
+ ELFObjectWriter *getObjectWriter() const;
+
+ ELFDynObjWriter *getDynObjWriter();
+ ELFDynObjWriter *getDynObjWriter() const;
+
+ ELFDynObjFileFormat* getDynObjFileFormat();
+ ELFDynObjFileFormat* getDynObjFileFormat() const;
+
+ ELFExecFileFormat* getExecFileFormat();
+ ELFExecFileFormat* getExecFileFormat() const;
+
+ size_t sectionStartOffset() const;
+
+ /// The return value of machine() it the same as e_machine in the ELF header*/
+ virtual uint32_t machine() const = 0;
+
+ /// ELFVersion - the value of e_ident[EI_VERSION]
+ virtual uint8_t ELFVersion() const
+ { return llvm::ELF::EV_CURRENT; }
+
+ /// OSABI - the value of e_ident[EI_OSABI]
+ virtual uint8_t OSABI() const = 0;
+
+ /// ABIVersion - the value of e_ident[EI_ABIVRESION]
+ virtual uint8_t ABIVersion() const = 0;
+
+ /// flags - the value of ElfXX_Ehdr::e_flags
+ virtual uint64_t flags() const = 0;
+
+ /// entry - the symbol name of the entry point
+ virtual const char* entry() const
+ { return "_start"; }
+
+ /// sizeNamePools - compute the size of regular name pools
+ /// In ELF executable files, regular name pools are .symtab, .strtab.,
+ /// .dynsym, .dynstr, and .hash
+ virtual void sizeNamePools(const Output& pOutput,
+ const SymbolCategory& pSymbols,
+ const MCLDInfo& pLDInfo);
+
+ /// emitSectionData - emit target-dependent section data
+ virtual uint64_t emitSectionData(const Output& pOutput,
+ const LDSection& pSection,
+ const MCLDInfo& pInfo,
+ MemoryRegion& pRegion) const = 0;
+
+ /// emitRegNamePools - emit regular name pools - .symtab, .strtab
+ virtual void emitRegNamePools(Output& pOutput,
+ SymbolCategory& pSymbols,
+ const Layout& pLayout,
+ const MCLDInfo& pLDInfo);
+
+ /// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash
+ virtual void emitDynNamePools(Output& pOutput,
+ SymbolCategory& pSymbols,
+ const Layout& pLayout,
+ const MCLDInfo& pLDInfo);
+
+ /// getSectionOrder - compute the layout order of the section
+ /// Layout calls this function to get the default order of the pSectHdr.
+ /// If the pSectHdr.type() is LDFileFormat::Target, then getSectionOrder()
+ /// will call getTargetSectionOrder().
+ ///
+ /// If targets favors certain order for general sections, please override
+ /// this function.
+ ///
+ /// @see getTargetSectionOrder
+ virtual unsigned int getSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const;
+
+ /// getTargetSectionOrder - compute the layout order of target section
+ /// If the target favors certain order for the given gSectHdr, please
+ /// override this function.
+ ///
+ /// By default, this function returns the maximun order, and pSectHdr
+ /// will be the last section to be laid out.
+ virtual unsigned int
+ getTargetSectionOrder(const Output& pOutput, const LDSection& pSectHdr) const
+ { return (unsigned int)-1; }
+
+ /// emitProgramHdrs - emit ELF program headers
+ /// if the target favors other ways to emit program header, please override
+ /// this function
+ virtual void emitProgramHdrs(Output& pOutput);
+
+ /// numOfSegments - return the number of segments
+ /// if the target favors other ways to emit program header, please override
+ /// this function
+ virtual unsigned int numOfSegments() const
+ { return m_ELFSegmentTable.size(); }
+
+ /// pagesize - the page size of the target machine, we set it to 4K here.
+ /// If target favors tht different size of page, please override this function
+ virtual unsigned int pagesize() const
+ { return 0x1000; }
+
+ /// getSymbolIdx - get the symbol index of ouput symbol table
+ size_t getSymbolIdx(LDSymbol* pSymbol) const;
+
+private:
+ /// createProgramHdrs - base on output sections to create the program headers
+ void createProgramHdrs(LDContext& pContext);
+
+ /// writeELF32ProgramHdrs - write out the ELF32 program headers
+ void writeELF32ProgramHdrs(Output& pOutput);
+
+ /// writeELF64ProgramHdrs - write out the ELF64 program headers
+ void writeELF64ProgramHdrs(Output& pOutput);
+
+ /// getSegmentFlag - give a section flag and return the corresponding segment
+ /// flag
+ inline uint32_t getSegmentFlag(const uint32_t pSectionFlag)
+ {
+ uint32_t flag = llvm::ELF::PF_R;
+ if (0 != (pSectionFlag & llvm::ELF::SHF_WRITE))
+ flag |= llvm::ELF::PF_W;
+ if (0 != (pSectionFlag & llvm::ELF::SHF_EXECINSTR))
+ flag |= llvm::ELF::PF_X;
+ return flag;
+ }
+
+ /// preLayout - Backend can do any needed modification before layout
+ void preLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+ /// postLayout -Backend can do any needed modification after layout
+ void postLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+protected:
+ uint64_t getSymbolSize(const LDSymbol& pSymbol) const;
+
+ uint64_t getSymbolInfo(const LDSymbol& pSymbol) const;
+
+ uint64_t getSymbolValue(const LDSymbol& pSymbol) const;
+
+ uint64_t getSymbolShndx(const LDSymbol& pSymbol, const Layout& pLayout) const;
+
+private:
+ /// preLayout - Backend can do any needed modification before layout
+ virtual void doPreLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker) = 0;
+
+ /// postLayout -Backend can do any needed modification after layout
+ virtual void doPostLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker) = 0;
+
+ /// dynamic - the dynamic section of the target machine.
+ virtual ELFDynamic& dynamic() = 0;
+
+ /// dynamic - the dynamic section of the target machine.
+ virtual const ELFDynamic& dynamic() const = 0;
+
+protected:
+ // ----- readers and writers ----- //
+ GNUArchiveReader* m_pArchiveReader;
+ ELFObjectReader* m_pObjectReader;
+ ELFDynObjReader* m_pDynObjReader;
+ ELFObjectWriter* m_pObjectWriter;
+ ELFDynObjWriter* m_pDynObjWriter;
+
+ // ----- file formats ----- //
+ ELFDynObjFileFormat* m_pDynObjFileFormat;
+ ELFExecFileFormat* m_pExecFileFormat;
+
+ // ----- ELF segment factory ----- //
+ ELFSegmentFactory m_ELFSegmentTable;
+
+ // ----- ELF special sections ----- //
+
+protected:
+ /// getHashBucketCount - calculate hash bucket count.
+ /// @ref Google gold linker, dynobj.cc:791
+ static unsigned getHashBucketCount(unsigned pNumOfSymbols, bool pIsGNUStyle);
+
+ /// isDynamicSymbol
+ /// @ref Google gold linker: symtab.cc:311
+ static bool isDynamicSymbol(const LDSymbol& pSymbol, const Output& pOutput);
+
+protected:
+ typedef HashEntry<LDSymbol*, size_t, SymCompare> HashEntryType;
+ typedef HashTable<HashEntryType, PtrHash, EntryFactory<HashEntryType> > HashTableType;
+
+ /// m_pSymIndexMap - Map the LDSymbol to its index in the output symbol table
+ HashTableType* m_pSymIndexMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/GOT.h b/include/mcld/Target/GOT.h
new file mode 100644
index 0000000..eb0873a
--- /dev/null
+++ b/include/mcld/Target/GOT.h
@@ -0,0 +1,106 @@
+//===- GOT.h --------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_GOT_H
+#define MCLD_GOT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/LDSection.h>
+#include <mcld/MC/MCTargetFragment.h>
+
+namespace mcld
+{
+
+class GOT;
+class ResolveInfo;
+
+/** \class GOTEntry
+ * \brief The entry of Global Offset Table
+ */
+class GOTEntry : public MCTargetFragment
+{
+public:
+ explicit GOTEntry(uint64_t pContent, size_t pEntrySize,
+ llvm::MCSectionData* pParent);
+
+ virtual ~GOTEntry();
+
+ uint64_t& getContent()
+ { return f_Content; }
+
+ uint64_t getContent() const
+ { return f_Content; }
+
+ void setContent(uint64_t pValue)
+ { f_Content = pValue; }
+
+ static bool classof(const MCFragment *pFrag)
+ { return pFrag->getKind() == llvm::MCFragment::FT_Target; }
+
+ static bool classof(const GOTEntry* pFrag)
+ { return true; }
+
+ // Override pure virtual function
+ size_t getSize() const
+ { return m_EntrySize; }
+
+protected:
+ uint64_t f_Content;
+ size_t m_EntrySize;
+};
+
+/** \class GOT
+ * \brief The Global Offset Table
+ */
+class GOT
+{
+protected:
+ GOT(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ size_t pEntrySize);
+
+public:
+ virtual ~GOT();
+
+ /// entrySize - the number of bytes per entry
+ size_t getEntrySize() const;
+
+ const LDSection& getSection() const
+ { return m_Section; }
+
+ llvm::MCSectionData& getSectionData()
+ { return m_SectionData; }
+
+ const llvm::MCSectionData& getSectionData() const
+ { return m_SectionData; }
+
+public:
+ /// reserveEntry - reseve number of pNum of empty entries
+ /// Before layout, we scan all relocations to determine if GOT entries are
+ /// needed. If an entry is needed, the empty entry is reserved for layout
+ /// to adjust the fragment offset. After that, we fill up the entries when
+ /// applying relocations.
+ virtual void reserveEntry(size_t pNum = 1) = 0;
+
+ /// getEntry - get an empty entry or an exitsted filled entry with pSymbol.
+ /// @param pSymbol - the target symbol
+ /// @param pExist - ture if a filled entry with pSymbol existed, otherwise false.
+ virtual GOTEntry* getEntry(const ResolveInfo& pSymbol, bool& pExist) = 0;
+
+protected:
+ LDSection& m_Section;
+ llvm::MCSectionData& m_SectionData;
+ size_t f_EntrySize;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/OutputRelocSection.h b/include/mcld/Target/OutputRelocSection.h
new file mode 100644
index 0000000..c0cb5ca
--- /dev/null
+++ b/include/mcld/Target/OutputRelocSection.h
@@ -0,0 +1,71 @@
+//===- OutputRelocSection.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef OUTPUTRELOCSECTION_H
+#define OUTPUTRELOCSECTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/MC/MCAssembler.h>
+#include <llvm/ADT/DenseMap.h>
+#include <mcld/LD/RelocationFactory.h>
+
+namespace mcld
+{
+
+class ResolveInfo;
+class Relocation;
+
+/** \class OutputRelocSection
+ * \brief Dynamic relocation section for ARM .rel.dyn and .rel.plt
+ */
+class OutputRelocSection
+{
+public:
+ typedef llvm::DenseMap<const ResolveInfo*, Relocation*> SymRelMapType;
+ typedef SymRelMapType::iterator SymRelMapIterator;
+
+ typedef llvm::MCSectionData::iterator MCFragmentIterator;
+
+public:
+ OutputRelocSection(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ unsigned int pEntrySize);
+ ~OutputRelocSection();
+
+ void reserveEntry(RelocationFactory& pRelFactory, size_t pNum=1);
+
+ Relocation* getEntry(const ResolveInfo& pSymbol,
+ bool isForGOT,
+ bool& pExist);
+
+private:
+ /// m_pSection - LDSection of this Section
+ LDSection* m_pSection;
+
+ /// m_SectionData - MCSectionData which contains the dynamic relocations
+ llvm::MCSectionData* m_pSectionData;
+
+ /// m_EntryBytes - size of a relocation entry
+ unsigned int m_EntryBytes;
+
+ /// m_isVisit - First time visit the function getEntry() or not
+ bool m_isVisit ;
+
+ /// m_ValidEntryIterator - point to the first valid entry
+ MCFragmentIterator m_ValidEntryIterator;
+
+ /// m_SymRelMap - map the resolved symbol to the Relocation entry
+ SymRelMapType m_SymRelMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/PLT.h b/include/mcld/Target/PLT.h
new file mode 100644
index 0000000..6a7522a
--- /dev/null
+++ b/include/mcld/Target/PLT.h
@@ -0,0 +1,86 @@
+//===- PLT.h --------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef PROCEDURE_LINKAGE_TABLE_H
+#define PROCEDURE_LINKAGE_TABLE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/LDSection.h>
+#include <mcld/MC/MCTargetFragment.h>
+#include <llvm/ADT/ilist.h>
+
+namespace mcld
+{
+
+class ResolveInfo;
+
+/** \class PLTEntry
+ */
+class PLTEntry : public MCTargetFragment
+{
+public:
+ PLTEntry(size_t pSize, llvm::MCSectionData* pParent);
+ virtual ~PLTEntry();
+
+ size_t getEntrySize() const
+ { return m_EntrySize; }
+
+ void setContent(unsigned char* pContent)
+ { m_pContent = pContent; }
+
+ const unsigned char* getContent() const
+ { return m_pContent; }
+
+ //Used by llvm::cast<>.
+ static bool classof(const MCFragment *O)
+ { return true; }
+
+ size_t getSize() const
+ { return m_EntrySize; }
+
+protected:
+ size_t m_EntrySize;
+ unsigned char* m_pContent;
+};
+
+/** \class PLT
+ * \brief Procedure linkage table
+ */
+class PLT
+{
+public:
+ PLT(LDSection& pSection, llvm::MCSectionData& pSectionData);
+ virtual ~PLT();
+
+ const LDSection& getSection() const
+ { return m_Section; }
+
+ const llvm::MCSectionData& getSectionData() const
+ { return m_SectionData; }
+
+public:
+ /// reserveEntry - reseve the number of pNum of empty entries
+ /// The empty entris are reserved for layout to adjust the fragment offset.
+ virtual void reserveEntry(size_t pNum = 1) = 0;
+
+ /// getPLTEntry - get an empty entry or an exitsted filled entry with pSymbol.
+ /// @param pSymbol - the target symbol
+ /// @param pExist - ture if the a filled entry with pSymbol existed, otherwise false.
+ virtual PLTEntry* getPLTEntry(const ResolveInfo& pSymbol, bool& pExist) = 0;
+
+protected:
+ LDSection& m_Section;
+ llvm::MCSectionData& m_SectionData;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/Stub.h b/include/mcld/Target/Stub.h
new file mode 100644
index 0000000..3bc778f
--- /dev/null
+++ b/include/mcld/Target/Stub.h
@@ -0,0 +1,30 @@
+//===- Stub.h -------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LD_STUB_H
+#define LD_STUB_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/LD/Relocation.h"
+
+namespace mcld
+{
+
+/** \class Stub
+ * \brief Stub is a piece of jumpping code.
+ */
+class Stub
+{
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/TargetLDBackend.h b/include/mcld/Target/TargetLDBackend.h
new file mode 100644
index 0000000..781b86f
--- /dev/null
+++ b/include/mcld/Target/TargetLDBackend.h
@@ -0,0 +1,146 @@
+//===-- llvm/Target/TargetLDBackend.h - Target LD Backend -----*- C++ -*-===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TARGET_TARGETLDBACKEND_H
+#define LLVM_TARGET_TARGETLDBACKEND_H
+
+#include <llvm/Support/DataTypes.h>
+#include <mcld/MC/MCLDOutput.h>
+
+namespace mcld {
+
+class MCLinker;
+class Relocation;
+class RelocationFactory;
+class Layout;
+class ArchiveReader;
+class ObjectReader;
+class DynObjReader;
+class ObjectWriter;
+class DynObjWriter;
+class LDContext;
+class SectionMap;
+class Output;
+class MCLDInfo;
+class SymbolCategory;
+class Input;
+class LDFileFormat;
+class GOT;
+
+//===----------------------------------------------------------------------===//
+/// TargetLDBackend - Generic interface to target specific assembler backends.
+///
+class TargetLDBackend
+{
+ TargetLDBackend(const TargetLDBackend &); // DO NOT IMPLEMENT
+ void operator=(const TargetLDBackend &); // DO NOT IMPLEMENT
+
+protected:
+ TargetLDBackend();
+
+public:
+ virtual ~TargetLDBackend();
+
+ // ----- target dependent ----- //
+ virtual bool initTargetSectionMap(SectionMap& pSectionMap) { return true;}
+ virtual void initTargetSegments(MCLinker& pLinker) { }
+ virtual void initTargetSections(MCLinker& pLinker) { }
+ virtual void initTargetSymbols(MCLinker& pLinker) { }
+ virtual void initTargetRelocation(MCLinker& pLinker) { }
+ virtual bool initStandardSymbols(MCLinker& pLinker) = 0;
+ virtual bool initRelocFactory(const MCLinker& pLinker) = 0;
+
+ virtual RelocationFactory* getRelocFactory() = 0;
+
+ /// scanRelocation - When read in relocations, backend can do any modification
+ /// to relocation and generate empty entries, such as GOT, dynamic relocation
+ /// entries and other target dependent entries. These entries are generated
+ /// for layout to adjust the ouput offset.
+ /// @param pReloc - a read in relocation entry
+ /// @param pInputSym - the input LDSymbol of relocation target symbol
+ /// @param pOutput - the ouput file
+ virtual void scanRelocation(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) = 0;
+
+ // ----- format dependent ----- //
+ virtual bool initArchiveReader(MCLinker&, MCLDInfo&) = 0;
+ virtual bool initObjectReader(MCLinker&) = 0;
+ virtual bool initDynObjReader(MCLinker&) = 0;
+ virtual bool initObjectWriter(MCLinker&) = 0;
+ virtual bool initDynObjWriter(MCLinker&) = 0;
+
+ virtual bool initExecSections(MCLinker&) = 0;
+ virtual bool initDynObjSections(MCLinker&) = 0;
+
+ virtual ArchiveReader *getArchiveReader() = 0;
+ virtual ObjectReader *getObjectReader() = 0;
+ virtual DynObjReader *getDynObjReader() = 0;
+ virtual ObjectWriter *getObjectWriter() = 0;
+ virtual DynObjWriter *getDynObjWriter() = 0;
+
+ virtual LDFileFormat* getDynObjFileFormat() = 0;
+ virtual LDFileFormat* getExecFileFormat() = 0;
+
+ /// preLayout - Backend can do any needed modification before layout
+ virtual void preLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker) = 0;
+
+ /// postLayout -Backend can do any needed modification after layout
+ virtual void postLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker) = 0;
+
+ /// Is the target machine little endian? **/
+ virtual bool isLittleEndian() const = 0;
+
+ /// bit class. the bit length of the target machine, 32 or 64 **/
+ virtual unsigned int bitclass() const = 0;
+
+ /// the page size of the target machine
+ virtual unsigned int pagesize() const = 0;
+
+ /// section start offset in the output file
+ virtual size_t sectionStartOffset() const = 0;
+
+ /// computeSectionOrder - compute the layout order of the given section
+ virtual unsigned int getSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const = 0;
+
+ /// sizeNamePools - compute the size of regular name pools
+ /// In ELF executable files, regular name pools are .symtab, .strtab.,
+ /// .dynsym, .dynstr, and .hash
+ virtual void
+ sizeNamePools(const Output& pOutput,
+ const SymbolCategory& pSymbols,
+ const MCLDInfo& pLDInfo) = 0;
+
+ /// finalizeSymbol - Linker checks pSymbol.reserved() if it's not zero,
+ /// then it will ask backend to finalize the symbol value.
+ /// @return ture - if backend set the symbol value sucessfully
+ /// @return false - if backend do not recognize the symbol
+ virtual bool finalizeSymbol(LDSymbol& pSymbol) const = 0;
+
+ /// allocateCommonSymbols - allocate common symbols in the corresponding
+ /// sections.
+ virtual bool allocateCommonSymbols(const MCLDInfo& pLDInfo, MCLinker& pLinker) const = 0;
+
+ /// readSection - read a target dependent section
+ virtual bool readSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr)
+ { return true; }
+
+};
+
+} // End mcld namespace
+
+#endif
diff --git a/include/mcld/Target/TargetMachine.h b/include/mcld/Target/TargetMachine.h
new file mode 100644
index 0000000..438edfd
--- /dev/null
+++ b/include/mcld/Target/TargetMachine.h
@@ -0,0 +1,127 @@
+//===- TargetMachine.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TARGET_MACHINE_H
+#define MCLD_TARGET_MACHINE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/Target/TargetMachine.h>
+#include <string>
+#include "mcld/MC/MCLDFile.h"
+
+namespace llvm
+{
+class Target;
+class TargetData;
+class TargetMachine;
+class PassManagerBase;
+class formatted_raw_ostream;
+
+} // namespace of llvm
+
+namespace mcld
+{
+
+class Target;
+class MCLDInfo;
+class SectLinkerOption;
+using namespace llvm;
+
+enum CodeGenFileType {
+ CGFT_ASMFile,
+ CGFT_OBJFile,
+ CGFT_ARCFile,
+ CGFT_DSOFile,
+ CGFT_EXEFile,
+ CGFT_NULLFile
+};
+
+
+/** \class mcld::LLVMTargetMachine
+ * \brief mcld::LLVMTargetMachine is a object adapter of
+ * llvm::LLVMTargetMachine.
+ *
+ * mcld::LLVMTargetMachine is also in charge of MCLDInfo.
+ *
+ * @see MCLDInfo
+ */
+class LLVMTargetMachine
+{
+public:
+ /// Adapter of llvm::TargetMachine
+ ///
+ LLVMTargetMachine(llvm::TargetMachine &pTM,
+ const mcld::Target &pTarget,
+ const std::string &pTriple);
+ virtual ~LLVMTargetMachine();
+
+ /// getTarget - adapt llvm::TargetMachine::getTarget
+ const mcld::Target& getTarget() const;
+
+ /// getTM - return adapted the llvm::TargetMachine.
+ const llvm::TargetMachine& getTM() const { return m_TM; }
+ llvm::TargetMachine& getTM() { return m_TM; }
+
+ /// getLDInfo - return the mcld::MCLDInfo
+ virtual mcld::MCLDInfo& getLDInfo() = 0;
+ virtual const mcld::MCLDInfo& getLDInfo() const = 0;
+
+ /// appPassesToEmitFile - The target function which we has to modify as
+ /// upstreaming.
+ bool addPassesToEmitFile(PassManagerBase &,
+ formatted_raw_ostream &Out,
+ const std::string &pOutputFilename,
+ mcld::CodeGenFileType,
+ CodeGenOpt::Level,
+ SectLinkerOption *pLinkerOpt = NULL,
+ bool DisableVerify = true);
+
+ /// getTargetData
+ const TargetData *getTargetData() const { return m_TM.getTargetData(); }
+
+ /// setAsmVerbosityDefault
+ static void setAsmVerbosityDefault(bool pAsmVerbose) {
+ llvm::TargetMachine::setAsmVerbosityDefault(pAsmVerbose);
+ }
+
+private:
+ /// addCommonCodeGenPasses - Add standard LLVM codegen passes used for
+ /// both emitting to assembly files or machine code output.
+ bool addCommonCodeGenPasses(PassManagerBase &,
+ mcld::CodeGenFileType,
+ CodeGenOpt::Level,
+ bool DisableVerify,
+ llvm::MCContext *&OutCtx);
+
+ bool addCompilerPasses(PassManagerBase &,
+ formatted_raw_ostream &Out,
+ const std::string& pOutputFilename,
+ llvm::MCContext *&OutCtx);
+
+ bool addAssemblerPasses(PassManagerBase &,
+ formatted_raw_ostream &Out,
+ const std::string& pOutputFilename,
+ llvm::MCContext *&OutCtx);
+
+ bool addLinkerPasses(PassManagerBase &,
+ SectLinkerOption *pLinkerOpt,
+ const std::string& pOutputFilename,
+ MCLDFile::Type pOutputLinkType,
+ llvm::MCContext *&OutCtx);
+
+private:
+ llvm::TargetMachine &m_TM;
+ const mcld::Target *m_pTarget;
+ const std::string& m_Triple;
+};
+
+} // namespace of mcld
+
+#endif
+