Merge "Update MCLinker to work with LLVM 3.4."
diff --git a/LICENSE.TXT b/LICENSE.TXT
index 8d5fff6..562a772 100644
--- a/LICENSE.TXT
+++ b/LICENSE.TXT
@@ -4,11 +4,13 @@
University of Illinois/NCSA
Open Source License
-Copyright (c) 2011-2011 MediaTek Inc.
+Copyright (c) 2011-2013 MediaTek Inc.
All rights reserved.
Developed by:
+ MCLinker Team.
+
MediaTek Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of
diff --git a/include/mcld/ADT/BinTree.h b/include/mcld/ADT/BinTree.h
index 76de607..4093b72 100644
--- a/include/mcld/ADT/BinTree.h
+++ b/include/mcld/ADT/BinTree.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_BINARY_TREE_H
-#define MCLD_BINARY_TREE_H
+#ifndef MCLD_ADT_BITREE_H
+#define MCLD_ADT_BITREE_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -438,16 +438,16 @@
// @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) {
+ template<size_t DIRECT>
+ BinaryTree& join(TreeIteratorBase& pPosition, const DataType& pValue) {
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));
+ node->data = const_cast<DataType*>(&pValue);
+
+ if (pPosition.isRoot())
+ pPosition.hook<TreeIteratorBase::Leftward>(node);
else
- proxy::hook<DIRECT>(position.m_pNode,
- const_cast<const node_type*>(node));
+ pPosition.hook<DIRECT>(node);
+
return *this;
}
@@ -456,14 +456,13 @@
// @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) {
+ template<size_t DIRECT>
+ BinaryTree& merge(TreeIteratorBase& pPosition, 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));
+ pPosition.hook<DIRECT>(pTree.m_Root.node.left);
BinaryTreeBase<DataType>::m_Root.summon(
pTree.BinaryTreeBase<DataType>::m_Root);
BinaryTreeBase<DataType>::m_Root.delegate(pTree.m_Root);
diff --git a/include/mcld/ADT/Flags.h b/include/mcld/ADT/Flags.h
index d38d941..c6a41e8 100644
--- a/include/mcld/ADT/Flags.h
+++ b/include/mcld/ADT/Flags.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_FLAGS_H
-#define MCLD_FLAGS_H
+#ifndef MCLD_ADT_FLAGS_H
+#define MCLD_ADT_FLAGS_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/ADT/GraphLite/Digraph.h b/include/mcld/ADT/GraphLite/Digraph.h
new file mode 100644
index 0000000..9e1b604
--- /dev/null
+++ b/include/mcld/ADT/GraphLite/Digraph.h
@@ -0,0 +1,85 @@
+//===- Digraph.h ----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ADT_GRAPHLITE_DIGRAPH_H
+#define MCLD_ADT_GRAPHLITE_DIGRAPH_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/ADT/Uncopyable.h>
+#include <mcld/ADT/GraphLite/GraphBasicTypes.h>
+#include <stdint.h>
+
+namespace mcld {
+namespace graph {
+
+/** \class Digraph
+ * \brief Digraph provides the common interface of all directed graphs.
+ */
+class Digraph : private Uncopyable
+{
+public:
+ typedef DirectedTag direction_tag;
+
+ class Node
+ {
+ friend class Digraph;
+ public:
+ Node() {}
+
+ bool operator==(const Node& pOther) const { return m_ID == pOther.m_ID; }
+ bool operator!=(const Node& pOther) const { return m_ID != pOther.m_ID; }
+
+ protected:
+ intptr_t m_ID;
+ };
+
+ class Arc
+ {
+ friend class Digraph;
+ public:
+ Arc();
+
+ bool operator==(const Node& pOther) const;
+ bool operator!=(const Node& pOther) const;
+
+ Node source() const;
+ Node target() const;
+
+ protected:
+ Arc(Digraph& pParent);
+
+ protected:
+ intptr_t m_ID;
+ Digraph* m_Parent;
+ };
+
+public:
+ Digraph();
+
+ Node addNode();
+
+ Arc addArc(const Node& pSource, const Node& pTarget);
+
+ void erase(const Node& pNode);
+
+ void erase(const Arc& pArc);
+
+ void clear();
+
+ unsigned int numOfNodes() const;
+
+ unsigned int numOfArcs() const;
+
+};
+
+} // namespace of graph
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/GraphLite/GraphBasicTypes.h b/include/mcld/ADT/GraphLite/GraphBasicTypes.h
new file mode 100644
index 0000000..5862bcb
--- /dev/null
+++ b/include/mcld/ADT/GraphLite/GraphBasicTypes.h
@@ -0,0 +1,29 @@
+//===- GraphBasicTypes.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ADT_GRAPHLITE_GRAPHBASICTYPES_H
+#define MCLD_ADT_GRAPHLITE_GRAPHBASICTYPES_H
+
+namespace mcld {
+namespace graph {
+
+/** \class UndirectedTag
+ * \brief Undirected graph category.
+ */
+struct UndirectedTag {};
+
+/** \class DirectedTag
+ * \brief Directed graph category.
+ */
+struct DirectedTag {};
+
+} // namespace of graph
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/GraphLite/ListDigraph.h b/include/mcld/ADT/GraphLite/ListDigraph.h
new file mode 100644
index 0000000..4ae2c50
--- /dev/null
+++ b/include/mcld/ADT/GraphLite/ListDigraph.h
@@ -0,0 +1,92 @@
+//===- ListDigraph.h ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ADT_GRAPHLITE_LISTDIGRAPH_H
+#define MCLD_ADT_GRAPHLITE_LISTDIGRAPH_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Support/GCFactory.h>
+
+namespace mcld {
+namespace graph {
+
+/** \class ListDigraph
+ * \brief ListDigraph provides an linked-list inplementation of a graph.
+ *
+ * ListDigraph is designed to get well performance for most algorithms of
+ * graph theory.
+ *
+ * Function | Complexity | Best Complexity
+ * ----------------|------------|--------------------------
+ * Storage | V + E |
+ * Add node | O(1) |
+ * Add arc | O(1) |
+ * Remove node | O(E) | O(#(fan-in) + #(fan-out))
+ * Remove edge | O(1) |
+ * Query adjacency | O(E) | O(#(fan-in) + #(fan-out))
+ *
+ */
+class ListDigraph
+{
+public:
+ struct Node;
+ struct Arc;
+
+ struct Node {
+ public:
+ Node();
+
+ public:
+ Node *prev, *next;
+ Arc *first_in, *first_out;
+ };
+
+ struct Arc {
+ public:
+ Arc();
+
+ public:
+ Node *target, *source;
+ Arc *prev_in, *next_in;
+ Arc *prev_out, *next_out;
+ };
+
+public:
+ ListDigraph();
+
+ Node* addNode();
+
+ Arc* addArc(Node& pU, Node& pV);
+
+ void erase(Node& pNode);
+
+ void erase(Arc& pArc);
+
+ void clear();
+
+ void getHead(Node*& pNode) const { pNode = m_pNodeHead; }
+
+private:
+ typedef GCFactory<Node, 0> NodeList;
+ typedef GCFactory<Arc, 0> ArcList;
+
+private:
+ Node* m_pNodeHead;
+ Node* m_pFreeNodeHead;
+ Arc* m_pFreeArcHead;
+
+ NodeList m_NodeList;
+ ArcList m_ArcList;
+};
+
+} // namespace of graph
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/HashBase.h b/include/mcld/ADT/HashBase.h
index 896f5b8..f3332a0 100644
--- a/include/mcld/ADT/HashBase.h
+++ b/include/mcld/ADT/HashBase.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_HASH_BASE_H
-#define MCLD_HASH_BASE_H
+#ifndef MCLD_ADT_HASHBASE_H
+#define MCLD_ADT_HASHBASE_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/ADT/HashBase.tcc b/include/mcld/ADT/HashBase.tcc
index 165f4ae..50f6ac4 100644
--- a/include/mcld/ADT/HashBase.tcc
+++ b/include/mcld/ADT/HashBase.tcc
@@ -7,8 +7,9 @@
//
//===----------------------------------------------------------------------===//
-//===--------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
// internal non-member functions
+//===----------------------------------------------------------------------===//
inline static unsigned int compute_bucket_count(unsigned int pNumOfBuckets)
{
static const unsigned int bucket_size[] =
@@ -30,8 +31,9 @@
return (pNumOfBuckets+131101); // rare case. increase constantly
}
-//===--------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
// template implementation of HashBucket
+//===----------------------------------------------------------------------===//
template<typename DataType>
typename HashBucket<DataType>::entry_type*
HashBucket<DataType>::getEmptyBucket()
@@ -48,8 +50,9 @@
return tombstone;
}
-//===--------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
// template implementation of HashTableImpl
+//===----------------------------------------------------------------------===//
template<typename HashEntryTy,
typename HashFunctionTy>
HashTableImpl<HashEntryTy, HashFunctionTy>::HashTableImpl()
diff --git a/include/mcld/ADT/HashEntry.h b/include/mcld/ADT/HashEntry.h
index c034783..5c3557f 100644
--- a/include/mcld/ADT/HashEntry.h
+++ b/include/mcld/ADT/HashEntry.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_HASH_ENTRY_H
-#define MCLD_HASH_ENTRY_H
+#ifndef MCLD_ADT_HASHENTRY_H
+#define MCLD_ADT_HASHENTRY_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/ADT/HashEntryFactory.h b/include/mcld/ADT/HashEntryFactory.h
index 42aa5e7..91deab4 100644
--- a/include/mcld/ADT/HashEntryFactory.h
+++ b/include/mcld/ADT/HashEntryFactory.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_HASH_ENTRY_FACTORY_H
-#define MCLD_HASH_ENTRY_FACTORY_H
+#ifndef MCLD_ADT_HASHENTRYFACTORY_H
+#define MCLD_ADT_HASHENTRYFACTORY_H
namespace mcld {
diff --git a/include/mcld/ADT/HashIterator.h b/include/mcld/ADT/HashIterator.h
index 078b20a..c25870f 100644
--- a/include/mcld/ADT/HashIterator.h
+++ b/include/mcld/ADT/HashIterator.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_HASH_ITERATOR_H
-#define MCLD_HASH_ITERATOR_H
+#ifndef MCLD_ADT_HASHITERATOR_H
+#define MCLD_ADT_HASHITERATOR_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/ADT/HashTable.h b/include/mcld/ADT/HashTable.h
index 0b6757e..522ab48 100644
--- a/include/mcld/ADT/HashTable.h
+++ b/include/mcld/ADT/HashTable.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_HASH_TABLE_H
-#define MCLD_HASH_TABLE_H
+#ifndef MCLD_ADT_HASHTABLE_H
+#define MCLD_ADT_HASHTABLE_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/ADT/SizeTraits.h b/include/mcld/ADT/SizeTraits.h
index dbd5d7b..3baf129 100644
--- a/include/mcld/ADT/SizeTraits.h
+++ b/include/mcld/ADT/SizeTraits.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_SIZE_TRAITS_H
-#define MCLD_SIZE_TRAITS_H
+#ifndef MCLD_ADT_SIZETRAITS_H
+#define MCLD_ADT_SIZETRAITS_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -153,6 +153,36 @@
((pData & 0x00000000000000FFULL) << 56));
}
+template<size_t SIZE>
+typename SizeTraits<SIZE>::Word bswap(typename SizeTraits<SIZE>::Word pData);
+
+template<>
+inline SizeTraits<32>::Word bswap<32>(SizeTraits<32>::Word pData)
+{
+ return bswap32(pData);
+}
+
+template<>
+inline SizeTraits<64>::Word bswap<64>(SizeTraits<64>::Word pData)
+{
+ return bswap64(pData);
+}
+
+template <size_t WIDTH>
+inline uint64_t signExtend(uint64_t pVal)
+{
+ uint64_t mask = (~((uint64_t)0)) >> (64 - WIDTH);
+ uint64_t sign_bit = 1 << (WIDTH - 1);
+
+ return ((pVal & mask) ^ sign_bit) - sign_bit;
+}
+
+template <>
+inline uint64_t signExtend<64>(uint64_t pVal)
+{
+ return pVal;
+}
+
template <size_t SizeOfStr, typename FieldType>
class StringSizerHelper
{
diff --git a/include/mcld/ADT/StringEntry.h b/include/mcld/ADT/StringEntry.h
index e6d1c20..3588c05 100644
--- a/include/mcld/ADT/StringEntry.h
+++ b/include/mcld/ADT/StringEntry.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_STRING_ENTRY_H
-#define MCLD_STRING_ENTRY_H
+#ifndef MCLD_ADT_STRINGENTRY_H
+#define MCLD_ADT_STRINGENTRY_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/ADT/StringHash.h b/include/mcld/ADT/StringHash.h
index a9c0025..048f35f 100644
--- a/include/mcld/ADT/StringHash.h
+++ b/include/mcld/ADT/StringHash.h
@@ -6,15 +6,15 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_STRING_HASH_FUNCTION_H
-#define MCLD_STRING_HASH_FUNCTION_H
+#ifndef MCLD_ADT_STRINGHASH_H
+#define MCLD_ADT_STRINGHASH_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <llvm/ADT/StringRef.h>
#include <llvm/Support/DataTypes.h>
-#include <llvm/Support/ErrorHandling.h>
#include <cctype>
+#include <cassert>
#include <functional>
namespace mcld {
@@ -43,7 +43,8 @@
{
uint32_t operator()(const llvm::StringRef& pKey) const
{
- llvm::report_fatal_error("Undefined StringHash function.\n");
+ assert(false && "Undefined StringHash function.\n");
+ return 0;
}
};
diff --git a/include/mcld/ADT/TreeAllocator.h b/include/mcld/ADT/TreeAllocator.h
index 10de761..b2bb39b 100644
--- a/include/mcld/ADT/TreeAllocator.h
+++ b/include/mcld/ADT/TreeAllocator.h
@@ -6,13 +6,13 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_TREE_ALLOCATOR_H
-#define MCLD_TREE_ALLOCATOR_H
+#ifndef MCLD_ADT_TREEALLOCATOR_H
+#define MCLD_ADT_TREEALLOCATOR_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <set>
-#include "mcld/Support/GCFactory.h"
+#include <mcld/Support/GCFactory.h>
namespace mcld {
diff --git a/include/mcld/ADT/TreeBase.h b/include/mcld/ADT/TreeBase.h
index 13eb474..bca375f 100644
--- a/include/mcld/ADT/TreeBase.h
+++ b/include/mcld/ADT/TreeBase.h
@@ -6,9 +6,9 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_TREE_BASE_H
-#define MCLD_TREE_BASE_H
-#include "mcld/ADT/TypeTraits.h"
+#ifndef MCLD_ADT_TREEBASE_H
+#define MCLD_ADT_TREEBASE_H
+#include <mcld/ADT/TypeTraits.h>
#include <cstddef>
#include <cassert>
@@ -28,18 +28,6 @@
{ }
};
-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
-
class TreeIteratorBase
{
public:
@@ -67,9 +55,10 @@
virtual ~TreeIteratorBase(){};
template<size_t DIRECT>
- inline void move() {
- proxy::move<DIRECT>(m_pNode);
- }
+ void move() { assert(0 && "not allowed"); }
+
+ template<size_t DIRECT>
+ void hook(NodeBase* pNode) { assert(0 && "not allowed"); }
bool isRoot() const
{ return (m_pNode->right == m_pNode); }
@@ -87,25 +76,29 @@
{ return this->m_pNode != y.m_pNode; }
};
-namespace proxy
+template<> inline
+void TreeIteratorBase::move<TreeIteratorBase::Leftward>()
{
- template<>
- inline void move<TreeIteratorBase::Leftward>(NodeBase *&X)
- { X = X->left; }
+ this->m_pNode = this->m_pNode->left;
+}
- template<>
- inline void move<TreeIteratorBase::Rightward>(NodeBase *&X)
- { X = X->right; }
+template<> inline
+void TreeIteratorBase::move<TreeIteratorBase::Rightward>()
+{
+ this->m_pNode = this->m_pNode->right;
+}
- template<>
- inline void hook<TreeIteratorBase::Leftward>(NodeBase *X, const NodeBase *Y)
- { X->left = const_cast<NodeBase*>(Y); }
+template<> inline
+void TreeIteratorBase::hook<TreeIteratorBase::Leftward>(NodeBase* pOther)
+{
+ this->m_pNode->left = pOther;
+}
- template<>
- inline void hook<TreeIteratorBase::Rightward>(NodeBase* X, const NodeBase* Y)
- { X->right = const_cast<NodeBase*>(Y); }
-
-} //namespace of template proxy
+template<> inline
+void TreeIteratorBase::hook<TreeIteratorBase::Rightward>(NodeBase* pOther)
+{
+ this->m_pNode->right = pOther;
+}
template<typename DataType>
class Node : public NodeBase
diff --git a/include/mcld/ADT/TypeTraits.h b/include/mcld/ADT/TypeTraits.h
index 90b2224..7f872da 100644
--- a/include/mcld/ADT/TypeTraits.h
+++ b/include/mcld/ADT/TypeTraits.h
@@ -6,16 +6,16 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_TYPE_TRAITS_H
-#define MCLD_TYPE_TRAITS_H
+#ifndef MCLD_ADT_TYPETRAITS_H
+#define MCLD_ADT_TYPETRAITS_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <cstdlib>
-namespace mcld
-{
+namespace mcld {
+
template<typename DataType>
struct NonConstTraits;
diff --git a/include/mcld/ADT/Uncopyable.h b/include/mcld/ADT/Uncopyable.h
index 7ddfbe3..d899a0a 100644
--- a/include/mcld/ADT/Uncopyable.h
+++ b/include/mcld/ADT/Uncopyable.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_UNCOPYABLE_H
-#define MCLD_UNCOPYABLE_H
+#ifndef MCLD_ADT_UNCOPYABLE_H
+#define MCLD_ADT_UNCOPYABLE_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/AttributeOption.h b/include/mcld/AttributeOption.h
index 18d7278..a0130d2 100644
--- a/include/mcld/AttributeOption.h
+++ b/include/mcld/AttributeOption.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ATTRIBUTE_OPTIONS_H
-#define MCLD_ATTRIBUTE_OPTIONS_H
+#ifndef MCLD_ATTRIBUTEOPTION_H
+#define MCLD_ATTRIBUTEOPTION_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/BitcodeOption.h b/include/mcld/BitcodeOption.h
index 4e9a5e1..6d2b9b7 100644
--- a/include/mcld/BitcodeOption.h
+++ b/include/mcld/BitcodeOption.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_BITCODE_OPTIONS_H
-#define MCLD_BITCODE_OPTIONS_H
+#ifndef MCLD_BITCODEOPTION_H
+#define MCLD_BITCODEOPTION_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/CodeGen/MCLinker.h b/include/mcld/CodeGen/MCLinker.h
index 34ddcb7..10423bb 100644
--- a/include/mcld/CodeGen/MCLinker.h
+++ b/include/mcld/CodeGen/MCLinker.h
@@ -28,10 +28,10 @@
namespace mcld {
class Module;
-class MemoryArea;
class IRBuilder;
class LinkerConfig;
class Linker;
+class FileHandle;
/** \class MCLinker
* \brief MCLinker provides a linking pass for standard compilation flow
@@ -54,7 +54,7 @@
// - the standard symbols
MCLinker(LinkerConfig& pConfig,
mcld::Module& pModule,
- MemoryArea& pOutput);
+ FileHandle& pFileHandle);
public:
virtual ~MCLinker();
@@ -71,7 +71,7 @@
protected:
LinkerConfig& m_Config;
mcld::Module& m_Module;
- MemoryArea& m_Output;
+ FileHandle& m_FileHandle;
IRBuilder* m_pBuilder;
Linker* m_pLinker;
diff --git a/include/mcld/Target/TargetMachine.h b/include/mcld/CodeGen/TargetMachine.h
similarity index 66%
rename from include/mcld/Target/TargetMachine.h
rename to include/mcld/CodeGen/TargetMachine.h
index 669e860..6454d87 100644
--- a/include/mcld/Target/TargetMachine.h
+++ b/include/mcld/CodeGen/TargetMachine.h
@@ -6,12 +6,9 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_TARGET_TARGET_MACHINE_H
-#define MCLD_TARGET_TARGET_MACHINE_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-#include <llvm/Target/TargetMachine.h>
+#ifndef MCLD_CODEGEN_TARGETMACHINE_H
+#define MCLD_CODEGEN_TARGETMACHINE_H
+#include <llvm/Support/CodeGen.h>
#include <string>
namespace llvm {
@@ -19,20 +16,22 @@
class Target;
class TargetData;
class TargetMachine;
+class MCContext;
+class raw_ostream;
+class formatted_raw_ostream;
+namespace legacy {
class PassManagerBase;
-
-} // namespace of llvm
+} // namepsace legacy
+} // namespace llvm
namespace mcld {
class Module;
class Target;
-class MemoryArea;
+class FileHandle;
class LinkerConfig;
class ToolOutputFile;
-using namespace llvm;
-
enum CodeGenFileType {
CGFT_ASMFile,
CGFT_OBJFile,
@@ -52,9 +51,10 @@
public:
/// Adapter of llvm::TargetMachine
///
- MCLDTargetMachine(llvm::TargetMachine &pTM,
- const mcld::Target &pTarget,
- const std::string &pTriple);
+ MCLDTargetMachine(llvm::TargetMachine& pTM,
+ const llvm::Target& pLLMVTarget,
+ const mcld::Target& pMCLDTarget,
+ const std::string& pTriple);
virtual ~MCLDTargetMachine();
@@ -67,48 +67,41 @@
/// appPassesToEmitFile - The target function which we has to modify as
/// upstreaming.
- bool addPassesToEmitFile(PassManagerBase &,
+ bool addPassesToEmitFile(llvm::legacy::PassManagerBase &,
mcld::ToolOutputFile& pOutput,
mcld::CodeGenFileType,
- CodeGenOpt::Level,
+ llvm::CodeGenOpt::Level,
mcld::Module& pModule,
mcld::LinkerConfig& pConfig,
bool DisableVerify = true);
- /// getDataLayout
- const DataLayout *getDataLayout() const { return m_TM.getDataLayout(); }
-
- /// 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 &,
+ bool addCommonCodeGenPasses(llvm::legacy::PassManagerBase &,
mcld::CodeGenFileType,
- CodeGenOpt::Level,
+ llvm::CodeGenOpt::Level,
bool DisableVerify,
llvm::MCContext *&OutCtx);
- bool addCompilerPasses(PassManagerBase &pPM,
+ bool addCompilerPasses(llvm::legacy::PassManagerBase &pPM,
llvm::formatted_raw_ostream &pOutput,
llvm::MCContext *&OutCtx);
- bool addAssemblerPasses(PassManagerBase &pPM,
+ bool addAssemblerPasses(llvm::legacy::PassManagerBase &pPM,
llvm::raw_ostream &pOutput,
llvm::MCContext *&OutCtx);
- bool addLinkerPasses(PassManagerBase &pPM,
- LinkerConfig& pConfig,
- Module& pModule,
- mcld::MemoryArea& pOutput,
+ bool addLinkerPasses(llvm::legacy::PassManagerBase &pPM,
+ mcld::LinkerConfig& pConfig,
+ mcld::Module& pModule,
+ mcld::FileHandle& pFileHandle,
llvm::MCContext *&OutCtx);
private:
llvm::TargetMachine &m_TM;
- const mcld::Target *m_pTarget;
+ const llvm::Target *m_pLLVMTarget;
+ const mcld::Target *m_pMCLDTarget;
const std::string& m_Triple;
};
diff --git a/include/mcld/Config/Config.h b/include/mcld/Config/Config.h
index 94946df..9e52d54 100644
--- a/include/mcld/Config/Config.h
+++ b/include/mcld/Config/Config.h
@@ -40,5 +40,7 @@
#define MCLD_SYMBOLS_PER_INPUT 128
#define MCLD_RELOCATIONS_PER_INPUT 1024
+#define MCLD_SEGMENTS_PER_OUTPUT 8
+
#endif
diff --git a/include/mcld/Fragment/AlignFragment.h b/include/mcld/Fragment/AlignFragment.h
index 14d0051..1175c07 100644
--- a/include/mcld/Fragment/AlignFragment.h
+++ b/include/mcld/Fragment/AlignFragment.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LD_ALIGNFRAGMENT_H
-#define MCLD_LD_ALIGNFRAGMENT_H
+#ifndef MCLD_FRAGMENT_ALIGNFRAGMENT_H
+#define MCLD_FRAGMENT_ALIGNFRAGMENT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Fragment/FGNode.h b/include/mcld/Fragment/FGNode.h
deleted file mode 100644
index 0afee0e..0000000
--- a/include/mcld/Fragment/FGNode.h
+++ /dev/null
@@ -1,91 +0,0 @@
-//===- FGNode.h -----------------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_FGNODE_H
-#define MCLD_FGNODE_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-
-#include <llvm/Support/DataTypes.h>
-
-#include <vector>
-
-namespace mcld
-{
-
-class Relocation;
-class ResolveInfo;
-class Fragment;
-
-/** \class FGNode
- * \brief FGNode is a node for FragmentGraph
- */
-class FGNode
-{
-public:
- typedef ResolveInfo* Slot;
- typedef Relocation* Signal;
-
- typedef std::vector<Fragment*> FragmentListType;
- typedef FragmentListType::iterator frag_iterator;
- typedef FragmentListType::const_iterator const_frag_iterator;
-
- typedef std::vector<Slot> SlotListType;
- typedef SlotListType::iterator slot_iterator;
- typedef SlotListType::const_iterator const_slot_iterator;
-
- typedef std::vector<Signal> SignalListType;
- typedef SignalListType::iterator signal_iterator;
- typedef SignalListType::const_iterator const_signal_iterator;
-
-public:
- FGNode();
- explicit FGNode(uint32_t pIndex);
-
- void addFragment(Fragment* pFrag);
- void addSignal(Signal pSignal);
- void addSlot(Slot pSlot);
-
- /// ----- observers ----- ///
- uint32_t getIndex() const
- { return m_Index; }
-
- slot_iterator slot_begin () { return m_Slots.begin(); }
- const_slot_iterator slot_begin () const { return m_Slots.begin(); }
- slot_iterator slot_end () { return m_Slots.end(); }
- const_slot_iterator slot_end () const { return m_Slots.end(); }
-
- signal_iterator signal_begin () { return m_Signals.begin(); }
- const_signal_iterator signal_begin () const { return m_Signals.begin(); }
- signal_iterator signal_end () { return m_Signals.end(); }
- const_signal_iterator signal_end () const { return m_Signals.end(); }
-
- frag_iterator frag_begin () { return m_Fragments.begin(); }
- const_frag_iterator frag_begin () const { return m_Fragments.begin(); }
- frag_iterator frag_end () { return m_Fragments.end(); }
- const_frag_iterator frag_end () const { return m_Fragments.end(); }
-
-private:
- FragmentListType m_Fragments;
-
- /// m_Signals - a list of relocations describes the possible fan-out of this
- /// node
- SignalListType m_Signals;
-
- /// m_Slots - a list of symbols describes the possible fan-in of this node
- SlotListType m_Slots;
-
- /// m_Index - the index in the reachability matrix
- uint32_t m_Index;
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/Fragment/FillFragment.h b/include/mcld/Fragment/FillFragment.h
index af78237..aa32ec8 100644
--- a/include/mcld/Fragment/FillFragment.h
+++ b/include/mcld/Fragment/FillFragment.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LD_FILLFRAGMENT_H
-#define MCLD_LD_FILLFRAGMENT_H
+#ifndef MCLD_FRAGMENT_FILLFRAGMENT_H
+#define MCLD_FRAGMENT_FILLFRAGMENT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Fragment/FragmentGraph.h b/include/mcld/Fragment/FragmentGraph.h
deleted file mode 100644
index 96d438f..0000000
--- a/include/mcld/Fragment/FragmentGraph.h
+++ /dev/null
@@ -1,177 +0,0 @@
-//===- FragmentGraph.h ----------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_FRAGMENTGRAPH_H
-#define MCLD_FRAGMENTGRAPH_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-
-#include <vector>
-
-#include <mcld/ADT/HashTable.h>
-#include <mcld/ADT/HashEntry.h>
-#include <mcld/Config/Config.h>
-#include <mcld/Fragment/FGNode.h>
-#include <mcld/Fragment/FGEdge.h>
-#include <mcld/Support/GCFactory.h>
-
-#include <llvm/Support/DataTypes.h>
-
-namespace mcld
-{
-class Module;
-class ResolveInfo;
-class Relocation;
-class LinkerConfig;
-
-/** \class FragmentGraph
- * \brief FragmentGraph describes the references between fragments.
- */
-class FragmentGraph
-{
-public:
- typedef FGNode::Slot Slot;
- typedef FGNode::Signal Signal;
-
- typedef GCFactory<FGNode, MCLD_SECTIONS_PER_INPUT> NodeFactoryType;
- typedef NodeFactoryType::iterator node_iterator;
- typedef NodeFactoryType::const_iterator const_node_iterator;
-
- typedef std::vector<FGEdge> EdgeListType;
- typedef EdgeListType::iterator edge_iterator;
- typedef EdgeListType::const_iterator const_edge_iterator;
-
-
-public:
- FragmentGraph();
- ~FragmentGraph();
-
- /// construct - construct the whole graph from input Fragments, relocations
- /// and symbols
- bool construct(const LinkerConfig& pConfig, Module& pModule);
-
- /// connect - connect two nodes
- bool connect(Signal pSignal, Slot pSlot);
- bool connect(FGNode& pFrom, Slot pSlot);
-
- /// getEdges - given a node, get the list of edges which are the fan-out of
- /// this node
- /// @param pEdges - the edge list which contains the found edges
- /// @return false - the given node
- bool getEdges(FGNode& pNode, EdgeListType& pEdges);
-
- /// ----- observers -----///
- /// getNode - given a fragment, finde the node which the fragment is belong to
- FGNode* getNode(const Fragment& pFrag);
- const FGNode* getNode(const Fragment& pFrag) const;
-
- FGNode* getNode(const ResolveInfo& pSym);
- const FGNode* getNode(const ResolveInfo& pSym) const;
-
-private:
- typedef std::vector<Relocation*> RelocationListType;
- typedef RelocationListType::iterator reloc_iterator;
- typedef RelocationListType::const_iterator const_reloc_iterator;
-
- struct PtrCompare
- {
- bool operator()(const void* X, const void* Y) const
- { return (X==Y); }
- };
-
- struct PtrHash
- {
- size_t operator()(const void* pKey) const
- {
- return (unsigned((uintptr_t)pKey) >> 4) ^
- (unsigned((uintptr_t)pKey) >> 9);
- }
- };
-
- /// HashTable for Fragment* to Node*
- typedef HashEntry<const Fragment*, FGNode*, PtrCompare> FragHashEntryType;
- typedef HashTable<FragHashEntryType,
- PtrHash,
- EntryFactory<FragHashEntryType> > FragHashTableType;
-
- /// HashTable for ResolveInfo* to Node*
- typedef HashEntry<const ResolveInfo*, FGNode*, PtrCompare> SymHashEntryType;
- typedef HashTable<SymHashEntryType,
- PtrHash,
- EntryFactory<SymHashEntryType> > SymHashTableType;
-
- /** \class ReachMatrix
- * \brief ReachMatrix is the reachability matrix which describes the relation
- * of Nodes in FragmentGraph
- */
- class ReachMatrix
- {
- public:
- typedef std::vector<uint32_t> MatrixDataType;
-
- public:
- ReachMatrix(size_t pSize);
- ~ReachMatrix();
- uint32_t& at(uint32_t pX, uint32_t pY);
- uint32_t at(uint32_t pX, uint32_t pY) const;
-
- uint32_t getN() const
- { return m_N; }
-
- void print();
-
- private:
- // m_Data - the contents of the matrix. Here we use a one dimensional array
- // to represent the two dimensional matrix
- MatrixDataType m_Data;
-
- // m_N - this is an m_N x m_N matrix
- size_t m_N;
- };
-
-private:
- FGNode* producePseudoNode();
- FGNode* produceRegularNode();
- void destroyPseudoNode();
- void destroyRegularNode();
-
- void initMatrix();
-
- bool createRegularNodes(Module& pModule);
- bool setNodeSlots(Module& pModule);
- bool createPseudoNodes(Module& pModule);
-
- bool createRegularEdges(Module& pModule);
- bool createPseudoEdges(Module& pModule);
-
-private:
- NodeFactoryType* m_pPseudoNodeFactory;
- NodeFactoryType* m_pRegularNodeFactory;
-
- /// m_pFragNodeMap - HashTable to map the fragment to the node it belongs to
- FragHashTableType* m_pFragNodeMap;
-
- /// m_pSymNodeMap - HashTable to map the ResolveInfo to the node. The node is
- /// the pseudo node which the contains it's fan-out is to the ResolveInfo
- SymHashTableType* m_pSymNodeMap;
-
- ReachMatrix* m_pMatrix;
-
- /// m_NumOfPNodes - number of pseudo nodes
- size_t m_NumOfPNodes;
- /// m_NumOfRNodes - number of regular nodes
- size_t m_NumOfRNodes;
- /// m_NumOfEdges - number of edges
- size_t m_NumOfEdges;
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/Fragment/FragmentLinker.h b/include/mcld/Fragment/FragmentLinker.h
deleted file mode 100644
index 45ef85d..0000000
--- a/include/mcld/Fragment/FragmentLinker.h
+++ /dev/null
@@ -1,78 +0,0 @@
-//===- FragmentLinker.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_FRAGMENT_FRAGMENT_LINKER_H
-#define MCLD_FRAGMENT_FRAGMENT_LINKER_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-
-#include <string>
-
-#include <mcld/LinkerConfig.h>
-#include <mcld/LD/LDFileFormat.h>
-#include <mcld/LD/LDSymbol.h>
-#include <mcld/Fragment/Relocation.h>
-#include <mcld/MC/MCLDInput.h>
-
-namespace mcld {
-
-class Module;
-class TargetLDBackend;
-class LinkerConfig;
-class MemoryArea;
-
-/** \class FragmentLinker
- * \brief FragmentLinker provides a pass to link object files.
- */
-class FragmentLinker
-{
-public:
- FragmentLinker(const LinkerConfig& pConfig,
- Module& pModule,
- TargetLDBackend& pBackend);
-
- ~FragmentLinker();
-
- bool finalizeSymbols();
-
- /// applyRelocations - apply all relocation enties.
- bool applyRelocations();
-
- /// syncRelocationResult - After applying relocation, write back relocation target
- /// data to output file.
- void syncRelocationResult(MemoryArea& pOutput);
-
-private:
- /// normalSyncRelocationResult - sync relocation result when producing shared
- /// objects or executables
- void normalSyncRelocationResult(MemoryArea& pOutput);
-
- /// partialSyncRelocationResult - sync relocation result when doing partial
- /// link
- void partialSyncRelocationResult(MemoryArea& pOutput);
-
- /// writeRelocationResult - helper function of syncRelocationResult, write
- /// relocation target data to output
- void writeRelocationResult(Relocation& pReloc, uint8_t* pOutput);
-
-private:
- const LinkerConfig& m_Config;
- Module& m_Module;
- TargetLDBackend& m_Backend;
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/Fragment/FragmentRef.h b/include/mcld/Fragment/FragmentRef.h
index 3fce7c9..3bfd804 100644
--- a/include/mcld/Fragment/FragmentRef.h
+++ b/include/mcld/Fragment/FragmentRef.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_FRAGMENT_FRAGMENT_REFERENCE_H
-#define MCLD_FRAGMENT_FRAGMENT_REFERENCE_H
+#ifndef MCLD_FRAGMENT_FRAGMENTREF_H
+#define MCLD_FRAGMENT_FRAGMENTREF_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -78,17 +78,6 @@
Offset getOutputOffset() const;
- // ----- dereference ----- //
- Address deref();
-
- ConstAddress deref() const;
-
- Address operator*()
- { return deref(); }
-
- ConstAddress operator*() const
- { return deref(); }
-
private:
friend FragmentRef& NullFragmentRef();
friend class Chunk<FragmentRef, MCLD_SECTIONS_PER_INPUT>;
diff --git a/include/mcld/Fragment/NullFragment.h b/include/mcld/Fragment/NullFragment.h
index 1c84fae..3440453 100644
--- a/include/mcld/Fragment/NullFragment.h
+++ b/include/mcld/Fragment/NullFragment.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LD_NULL_FRAGMENT_H
-#define MCLD_LD_NULL_FRAGMENT_H
+#ifndef MCLD_FRAGMENT_NULLFRAGMENT_H
+#define MCLD_FRAGMENT_NULLFRAGMENT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Fragment/RegionFragment.h b/include/mcld/Fragment/RegionFragment.h
index e077264..4f1908a 100644
--- a/include/mcld/Fragment/RegionFragment.h
+++ b/include/mcld/Fragment/RegionFragment.h
@@ -6,30 +6,29 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LD_REGION_FRAGMENT_H
-#define MCLD_LD_REGION_FRAGMENT_H
+#ifndef MCLD_FRAGMENT_REGIONFRAGMENT_H
+#define MCLD_FRAGMENT_REGIONFRAGMENT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <mcld/Fragment/Fragment.h>
+#include <llvm/ADT/StringRef.h>
namespace mcld {
-class MemoryRegion;
-
/** \class RegionFragment
- * \brief RegionFragment is a kind of Fragment containing mcld::MemoryRegion
+ * \brief RegionFragment is a kind of Fragment containing input memory region
*/
class RegionFragment : public Fragment
{
public:
- RegionFragment(MemoryRegion& pRegion, SectionData* pSD = NULL);
+ RegionFragment(llvm::StringRef pRegion, SectionData* pSD = NULL);
~RegionFragment();
- const MemoryRegion& getRegion() const { return m_Region; }
- MemoryRegion& getRegion() { return m_Region; }
+ const llvm::StringRef getRegion() const { return m_Region; }
+ llvm::StringRef getRegion() { return m_Region; }
static bool classof(const Fragment *F)
{ return F->getKind() == Fragment::Region; }
@@ -40,7 +39,7 @@
size_t size() const;
private:
- MemoryRegion& m_Region;
+ llvm::StringRef m_Region;
};
} // namespace of mcld
diff --git a/include/mcld/Fragment/Relocation.h b/include/mcld/Fragment/Relocation.h
index e8c57e4..3824dd5 100644
--- a/include/mcld/Fragment/Relocation.h
+++ b/include/mcld/Fragment/Relocation.h
@@ -34,7 +34,7 @@
typedef uint64_t Address; // FIXME: use SizeTrait<T>::Address instead
typedef uint64_t DWord; // FIXME: use SizeTrait<T>::Word instead
typedef int64_t SWord; // FIXME: use SizeTrait<T>::SWord instead
- typedef uint8_t Type;
+ typedef uint32_t Type;
typedef uint32_t Size;
private:
diff --git a/include/mcld/Fragment/TargetFragment.h b/include/mcld/Fragment/TargetFragment.h
index 665fcea..76148ea 100644
--- a/include/mcld/Fragment/TargetFragment.h
+++ b/include/mcld/Fragment/TargetFragment.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LD_TARGET_FRAGMENT_H
-#define MCLD_LD_TARGET_FRAGMENT_H
+#ifndef MCLD_FRAGMENT_TARGETFRAGMENT_H
+#define MCLD_FRAGMENT_TARGETFRAGMENT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/GeneralOptions.h b/include/mcld/GeneralOptions.h
index 77232ac..8348b6f 100644
--- a/include/mcld/GeneralOptions.h
+++ b/include/mcld/GeneralOptions.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_GENERAL_OPTIONS_H
-#define MCLD_GENERAL_OPTIONS_H
+#ifndef MCLD_GENERALOPTIONS_H
+#define MCLD_GENERALOPTIONS_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -15,11 +15,11 @@
#include <vector>
#include <mcld/Support/RealPath.h>
#include <mcld/Support/FileSystem.h>
-#include <mcld/MC/ZOption.h>
namespace mcld {
class Input;
+class ZOption;
/** \class GeneralOptions
* \brief GeneralOptions collects the options that not be one of the
@@ -46,6 +46,10 @@
typedef RpathList::iterator rpath_iterator;
typedef RpathList::const_iterator const_rpath_iterator;
+ typedef std::vector<std::string> ScriptList;
+ typedef ScriptList::iterator script_iterator;
+ typedef ScriptList::const_iterator const_script_iterator;
+
typedef std::vector<std::string> AuxiliaryList;
typedef AuxiliaryList::iterator aux_iterator;
typedef AuxiliaryList::const_iterator const_aux_iterator;
@@ -54,11 +58,6 @@
GeneralOptions();
~GeneralOptions();
- /// default link script
- bool hasDefaultLDScript() const;
- const char* defaultLDScript() const;
- void setDefaultLDScript(const std::string& pFilename);
-
/// trace
void setTrace(bool pEnableTrace = true)
{ m_bTrace = pEnableTrace; }
@@ -84,15 +83,6 @@
bool Bgroup() const
{ return m_Bgroup; }
- bool hasEntry() const
- { return !m_Entry.empty(); }
-
- void setEntry(const std::string& pEntry)
- { m_Entry = pEntry; }
-
- const std::string& entry() const
- { return m_Entry; }
-
void setDyld(const std::string& pDyld)
{ m_Dyld = pDyld; }
@@ -132,10 +122,10 @@
{ return m_bColor; }
void setNoUndefined(bool pEnable = true)
- { m_bNoUndefined = pEnable; }
+ { m_NoUndefined = (pEnable?YES:NO); }
void setMulDefs(bool pEnable = true)
- { m_bMulDefs = pEnable; }
+ { m_MulDefs = (pEnable?YES:NO); }
void setEhFrameHdr(bool pEnable = true)
{ m_bCreateEhFrameHdr = pEnable; }
@@ -146,8 +136,11 @@
bool hasCombReloc() const
{ return m_bCombReloc; }
+ bool hasNoUndefined() const
+ { return (Unknown != m_NoUndefined); }
+
bool isNoUndefined() const
- { return m_bNoUndefined; }
+ { return (YES == m_NoUndefined); }
bool hasStackSet() const
{ return (Unknown != m_ExecStack); }
@@ -165,7 +158,10 @@
{ return m_bLoadFltr; }
bool hasMulDefs() const
- { return m_bMulDefs; }
+ { return (Unknown != m_MulDefs); }
+
+ bool isMulDefs() const
+ { return (YES == m_MulDefs); }
bool hasNoCopyReloc() const
{ return m_bNoCopyReloc; }
@@ -278,6 +274,26 @@
bool printMap() const
{ return m_bPrintMap; }
+ void setWarnMismatch(bool pEnable = true)
+ { m_bWarnMismatch = pEnable; }
+
+ bool warnMismatch() const
+ { return m_bWarnMismatch; }
+
+ // --gc-sections
+ void setGCSections(bool pEnable = true)
+ { m_bGCSections = pEnable; }
+
+ bool GCSections() const
+ { return m_bGCSections; }
+
+ // --ld-generated-unwind-info
+ void setGenUnwindInfo(bool pEnable = true)
+ { m_bGenUnwindInfo = pEnable; }
+
+ bool genUnwindInfo() const
+ { return m_bGenUnwindInfo; }
+
// -G, max GP size option
void setGPSize(int gpsize)
{ m_GPSize = gpsize; }
@@ -299,6 +315,15 @@
const_rpath_iterator rpath_end () const { return m_RpathList.end(); }
rpath_iterator rpath_end () { return m_RpathList.end(); }
+ // ----- link-in script ----- //
+ const ScriptList& getScriptList() const { return m_ScriptList; }
+ ScriptList& getScriptList() { return m_ScriptList; }
+
+ const_script_iterator script_begin() const { return m_ScriptList.begin(); }
+ script_iterator script_begin() { return m_ScriptList.begin(); }
+ const_script_iterator script_end () const { return m_ScriptList.end(); }
+ script_iterator script_end () { return m_ScriptList.end(); }
+
// ----- filter and auxiliary filter ----- //
void setFilter(const std::string& pFilter)
{ m_Filter = pFilter; }
@@ -327,21 +352,20 @@
private:
Input* m_pDefaultBitcode;
std::string m_DefaultLDScript;
- std::string m_Entry;
std::string m_Dyld;
std::string m_SOName;
int8_t m_Verbose; // --verbose[=0,1,2]
uint16_t m_MaxErrorNum; // --error-limit=N
uint16_t m_MaxWarnNum; // --warning-limit=N
status m_ExecStack; // execstack, noexecstack
+ status m_NoUndefined; // defs, --no-undefined
+ status m_MulDefs; // muldefs, --allow-multiple-definition
uint64_t m_CommPageSize; // common-page-size=value
uint64_t m_MaxPageSize; // max-page-size=value
bool m_bCombReloc : 1; // combreloc, nocombreloc
- bool m_bNoUndefined : 1; // defs, --no-undefined
bool m_bInitFirst : 1; // initfirst
bool m_bInterPose : 1; // interpose
bool m_bLoadFltr : 1; // loadfltr
- bool m_bMulDefs : 1; // muldefs
bool m_bNoCopyReloc : 1; // nocopyreloc
bool m_bNoDefaultLib : 1; // nodefaultlib
bool m_bNoDelete : 1; // nodelete
@@ -367,9 +391,13 @@
bool m_bNewDTags: 1; // --enable-new-dtags
bool m_bNoStdlib: 1; // -nostdlib
bool m_bPrintMap: 1; // --print-map
+ bool m_bWarnMismatch: 1; // --no-warn-mismatch
+ bool m_bGCSections: 1; // --gc-sections
+ bool m_bGenUnwindInfo: 1; // --ld-generated-unwind-info
uint32_t m_GPSize; // -G, --gpsize
StripSymbolMode m_StripSymbols;
RpathList m_RpathList;
+ ScriptList m_ScriptList;
unsigned int m_HashStyle;
std::string m_Filter;
AuxiliaryList m_AuxiliaryList;
diff --git a/include/mcld/IRBuilder.h b/include/mcld/IRBuilder.h
index e9f1d13..7cacb36 100644
--- a/include/mcld/IRBuilder.h
+++ b/include/mcld/IRBuilder.h
@@ -14,7 +14,7 @@
#ifndef MCLD_IRBUILDER_H
#define MCLD_IRBUILDER_H
-#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/Input.h>
#include <mcld/MC/InputBuilder.h>
#include <mcld/LD/LDSection.h>
@@ -29,7 +29,6 @@
#include <mcld/Support/Path.h>
#include <mcld/Support/FileHandle.h>
-#include <mcld/Support/raw_mem_ostream.h>
namespace mcld {
@@ -129,19 +128,6 @@
Input* ReadInput(const std::string& pNameSpec);
/// ReadInput - To read an input file and append it to the input tree.
- ///
- /// This function is like to add an input in the command line.
- ///
- /// LLVM compiler usually emits outputs by llvm::raw_ostream.
- /// mcld::raw_mem_ostream inherits llvm::raw_ostream and is suitable to be
- /// the output of LLVM compier. Users can connect LLVM compiler and MCLinker
- /// by passing mcld::raw_mem_ostream from LLVM compiler to MCLinker.
- ///
- /// @param pMemOStream [in] The input raw_mem_stream
- /// @param the create mcld::Input.
- Input* ReadInput(raw_mem_ostream& pMemOStream);
-
- /// ReadInput - To read an input file and append it to the input tree.
/// Another way to open file manually. Use MCLinker's mcld::FileHandle.
Input* ReadInput(FileHandle& pFileHandle);
@@ -470,6 +456,10 @@
uint32_t pOffset,
Relocation::Address pAddend = 0);
+ /// shouldForceLocal - The helper function for AddSymbol to check if the
+ /// symbols should be force to local symbols
+ bool shouldForceLocal(const ResolveInfo& pInfo, const LinkerConfig& pConfig);
+
private:
LDSymbol* addSymbolFromObject(const std::string& pName,
ResolveInfo::Type pType,
diff --git a/include/mcld/InputTree.h b/include/mcld/InputTree.h
index 0c7e060..0213527 100644
--- a/include/mcld/InputTree.h
+++ b/include/mcld/InputTree.h
@@ -6,15 +6,15 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_MC_INPUT_TREE_H
-#define MCLD_MC_INPUT_TREE_H
+#ifndef MCLD_INPUTTREE_H
+#define MCLD_INPUTTREE_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/Input.h>
#include <mcld/Support/Path.h>
#include <string>
@@ -182,16 +182,16 @@
// @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 Input& value) {
+ template<size_t DIRECT>
+ BinaryTree& join(TreeIteratorBase& pPosition, const Input& value) {
node_type *node = BinaryTreeBase<Input>::createNode();
node->data = const_cast<Input*>(&value);
- if (position.isRoot())
- proxy::hook<TreeIteratorBase::Leftward>(position.m_pNode,
- const_cast<const node_type*>(node));
+
+ if (pPosition.isRoot())
+ pPosition.hook<TreeIteratorBase::Leftward>(node);
else
- proxy::hook<DIRECT>(position.m_pNode,
- const_cast<const node_type*>(node));
+ pPosition.hook<DIRECT>(node);
+
return *this;
}
@@ -200,14 +200,13 @@
// @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) {
+ template<size_t DIRECT>
+ BinaryTree& merge(TreeIteratorBase& pPosition, 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));
+ pPosition.hook<DIRECT>(pTree.m_Root.node.left);
BinaryTreeBase<Input>::m_Root.summon(
pTree.BinaryTreeBase<Input>::m_Root);
BinaryTreeBase<Input>::m_Root.delegate(pTree.m_Root);
@@ -248,20 +247,20 @@
* connects two nodes of the given iterators togather.
*/
struct Mover {
- virtual ~Mover() {}
- virtual void connect(TreeIteratorBase& pFrom, const TreeIteratorBase& pTo) const = 0;
+ virtual void connect(TreeIteratorBase& pFrom, NodeBase* pTo) const = 0;
virtual void move(TreeIteratorBase& pNode) const = 0;
+ virtual ~Mover() { }
};
/** \class Succeeder
* \brief class Succeeder moves the iterator afterward.
*/
struct Succeeder : public Mover {
- virtual void connect(TreeIteratorBase& pFrom, const TreeIteratorBase& pTo) const {
- proxy::hook<Positional>(pFrom.m_pNode, pTo.m_pNode);
+ void connect(TreeIteratorBase& pFrom, NodeBase* pTo) const {
+ pFrom.hook<Positional>(pTo);
}
- virtual void move(TreeIteratorBase& pNode) const {
+ void move(TreeIteratorBase& pNode) const {
pNode.move<Positional>();
}
};
@@ -270,11 +269,11 @@
* \brief class Includer moves the iterator downward.
*/
struct Includer : public Mover {
- virtual void connect(TreeIteratorBase& pFrom, const TreeIteratorBase& pTo) const {
- proxy::hook<Inclusive>(pFrom.m_pNode, pTo.m_pNode);
+ void connect(TreeIteratorBase& pFrom, NodeBase* pTo) const {
+ pFrom.hook<Inclusive>(pTo);
}
- virtual void move(TreeIteratorBase& pNode) const {
+ void move(TreeIteratorBase& pNode) const {
pNode.move<Inclusive>();
}
};
@@ -325,12 +324,12 @@
mcld::InputTree::enterGroup(mcld::TreeIteratorBase pRoot)
{
BinTreeTy::node_type* node = createNode();
+
if (pRoot.isRoot())
- proxy::hook<TreeIteratorBase::Leftward>(pRoot.m_pNode,
- const_cast<const node_type*>(node));
+ pRoot.hook<TreeIteratorBase::Leftward>(node);
else
- proxy::hook<DIRECT>(pRoot.m_pNode,
- const_cast<const node_type*>(node));
+ pRoot.hook<DIRECT>(node);
+
return *this;
}
@@ -340,12 +339,12 @@
{
BinTreeTy::node_type* node = createNode();
node->data = &pInput;
+
if (pRoot.isRoot())
- proxy::hook<TreeIteratorBase::Leftward>(pRoot.m_pNode,
- const_cast<const node_type*>(node));
+ pRoot.hook<TreeIteratorBase::Leftward>(node);
else
- proxy::hook<DIRECT>(pRoot.m_pNode,
- const_cast<const node_type*>(node));
+ pRoot.hook<DIRECT>(node);
+
return *this;
}
diff --git a/include/mcld/LD/Archive.h b/include/mcld/LD/Archive.h
index 7dc2205..26de7c3 100644
--- a/include/mcld/LD/Archive.h
+++ b/include/mcld/LD/Archive.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ARCHIVE_H
-#define MCLD_ARCHIVE_H
+#ifndef MCLD_LD_ARCHIVE_H
+#define MCLD_LD_ARCHIVE_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -26,9 +26,6 @@
class Input;
class InputFactory;
class InputBuilder;
-class AttributeFactory;
-class ContextFactory;
-class MemoryAreaFactory;
/** \class Archive
* \brief This class define the interfacee to Archive files
@@ -40,6 +37,7 @@
static const char THIN_MAGIC[]; ///< magic of thin archive
static const size_t MAGIC_LEN; ///< length of magic string
static const char SVR4_SYMTAB_NAME[]; ///< SVR4 symtab entry name
+ static const char IRIX6_SYMTAB_NAME[]; ///< Irix6 symtab entry name
static const char STRTAB_NAME[]; ///< Name of string table
static const char PAD[]; ///< inter-file align padding
static const char MEMBER_MAGIC[]; ///< fmag field magic #
@@ -98,7 +96,7 @@
public:
typedef HashTable<ArchiveMemberEntryType,
- hash::StringHash<hash::ELF>,
+ hash::StringHash<hash::DJB>,
EntryFactory<ArchiveMemberEntryType> > ArchiveMemberMapType;
struct Symbol
diff --git a/include/mcld/LD/ArchiveReader.h b/include/mcld/LD/ArchiveReader.h
index 5f24f49..eb6bec5 100644
--- a/include/mcld/LD/ArchiveReader.h
+++ b/include/mcld/LD/ArchiveReader.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ARCHIVE_READER_INTERFACE_H
-#define MCLD_ARCHIVE_READER_INTERFACE_H
+#ifndef MCLD_LD_ARCHIVEREADER_H
+#define MCLD_LD_ARCHIVEREADER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -16,6 +16,7 @@
namespace mcld
{
+class LinkerConfig;
class Archive;
/** \class ArchiveReader
@@ -34,7 +35,7 @@
ArchiveReader();
virtual ~ArchiveReader();
- virtual bool readArchive(Archive& pArchive) = 0;
+ virtual bool readArchive(const LinkerConfig& pConfig, Archive& pArchive) = 0;
};
} // namespace of mcld
diff --git a/include/mcld/LD/BSDArchiveReader.h b/include/mcld/LD/BSDArchiveReader.h
index 7abeecc..fd49966 100644
--- a/include/mcld/LD/BSDArchiveReader.h
+++ b/include/mcld/LD/BSDArchiveReader.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_BSD_ARCHIVE_READER_H
-#define MCLD_BSD_ARCHIVE_READER_H
+#ifndef MCLD_LD_BSDARCHIVEREADER_H
+#define MCLD_LD_BSDARCHIVEREADER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -18,6 +18,7 @@
class Input;
class Archive;
+class LinkerConfig;
/** \class BSDArchiveReader
* \brief BSDArchiveReader reads BSD-variant archive files.
@@ -29,8 +30,8 @@
BSDArchiveReader();
~BSDArchiveReader();
- bool readArchive(Archive& pArchive);
- bool isMyFormat(Input& pInput) const;
+ bool readArchive(const LinkerConfig& pConfig, Archive& pArchive);
+ bool isMyFormat(Input& pInput, bool &pContinue) const;
};
} // namespace of mcld
diff --git a/include/mcld/LD/BinaryReader.h b/include/mcld/LD/BinaryReader.h
index e9c47db..6b61dba 100644
--- a/include/mcld/LD/BinaryReader.h
+++ b/include/mcld/LD/BinaryReader.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_Binary_READER_H
-#define MCLD_Binary_READER_H
+#ifndef MCLD_LD_BINARYREADER_H
+#define MCLD_LD_BINARYREADER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -25,16 +25,11 @@
*/
class BinaryReader : public LDReader
{
-protected:
- BinaryReader()
- { }
-
public:
- virtual ~BinaryReader()
- { }
+ virtual ~BinaryReader() = 0;
- virtual bool isMyFormat(Input& pInput) const
- { return true; }
+ virtual bool isMyFormat(Input& pInput, bool &pContinue) const
+ { pContinue = true; return false; }
virtual bool readBinary(Input& pFile) = 0;
};
diff --git a/include/mcld/LD/BranchIsland.h b/include/mcld/LD/BranchIsland.h
index f340f0a..ca1543f 100644
--- a/include/mcld/LD/BranchIsland.h
+++ b/include/mcld/LD/BranchIsland.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LD_BRANCH_ISLAND_H
-#define MCLD_LD_BRANCH_ISLAND_H
+#ifndef MCLD_LD_BRANCHISLAND_H
+#define MCLD_LD_BRANCHISLAND_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -125,7 +125,7 @@
size_t operator() (const Key& KEY) const
{
llvm::StringRef sym_name(KEY.symbol()->name());
- hash::StringHash<hash::ELF> str_hasher;
+ hash::StringHash<hash::DJB> str_hasher;
return (size_t((uintptr_t)KEY.prototype())) ^
str_hasher(sym_name) ^
KEY.addend();
diff --git a/include/mcld/LD/BranchIslandFactory.h b/include/mcld/LD/BranchIslandFactory.h
index 755cc31..9431fb3 100644
--- a/include/mcld/LD/BranchIslandFactory.h
+++ b/include/mcld/LD/BranchIslandFactory.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LD_BRANCH_ISLAND_FACTORY_H
-#define MCLD_LD_BRANCH_ISLAND_FACTORY_H
+#ifndef MCLD_LD_BRANCHISLANDFACTORY_H
+#define MCLD_LD_BRANCHISLANDFACTORY_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -20,6 +20,7 @@
{
class Fragment;
+class Module;
/** \class BranchIslandFactory
* \brief
@@ -37,6 +38,10 @@
~BranchIslandFactory();
+ /// group - group fragments and create islands when needed
+ /// @param pSectionData - the SectionData holds fragments need to be grouped
+ void group(Module& pModule);
+
/// produce - produce a island for the given fragment
/// @param pFragment - the fragment needs a branch island
BranchIsland* produce(Fragment& pFragment);
diff --git a/include/mcld/LD/DWARFLineInfo.h b/include/mcld/LD/DWARFLineInfo.h
index 004d597..4f19312 100644
--- a/include/mcld/LD/DWARFLineInfo.h
+++ b/include/mcld/LD/DWARFLineInfo.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_DWARF_LINE_INFO_H
-#define MCLD_DWARF_LINE_INFO_H
+#ifndef MCLD_LD_DWARFLINEINFO_H
+#define MCLD_LD_DWARFLINEINFO_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/LD/DiagAttribute.inc b/include/mcld/LD/DiagAttribute.inc
new file mode 100644
index 0000000..453ae65
--- /dev/null
+++ b/include/mcld/LD/DiagAttribute.inc
@@ -0,0 +1,19 @@
+// General
+DIAG(warn_unsupported_attribute_section_format, DiagnosticEngine::Warning, "unsupported format of attribute section in input %0 (version=%1).", "unsupported format of attribute section in input %0 (version=%1).")
+DIAG(warn_unrecognized_vendor_subsection, DiagnosticEngine::Warning, "skip unrecognized private vendor subsection with name '%0' in %1.", "skip unrecognized private vendor subsection with name '%0' in %1.")
+
+// ARM attributes
+DIAG(error_unknown_cpu_arch, DiagnosticEngine::Error, "input %0 has unknown CPU architecture profile.", "input %0 has unknown CPU architecture profile.")
+DIAG(warn_mismatch_cpu_arch_profile, DiagnosticEngine::Warning, "conflicting architecture profiles %0 in %1.", "conflicting architecture profiles %0 in %1.")
+DIAG(error_mismatch_mpextension_use, DiagnosticEngine::Error, "conflicting values from Tag_MPextension_use and Tag_MPextension_use_legacy in %0", "conflicting values from Tag_MPextension_use and Tag_MPextension_use_legacy in %0")
+DIAG(warn_mismatch_enum_size, DiagnosticEngine::Warning, "the size of enumerated data item in input %0 (value=%1) is not compatible with the output (value=%2).", "the size of enumerated data item in input %0 (value=%1) is not compatible with the output (value=%2).")
+DIAG(warn_mismatch_fp16_format, DiagnosticEngine::Warning, "conflicting 16-bit FP number format in %0", "conflicting 16-bit FP number format in %0")
+DIAG(warn_unrecognized_virtualization_use, DiagnosticEngine::Warning, "value of Tag_Virtualization_use cannot be recognized in %0 (value=%1).", "value of Tag_Virtualization_use cannot be recognized in %0 (value=%1).")
+DIAG(warn_mismatch_abi_wmmx_args, DiagnosticEngine::Warning, "%0 uses different way to pass WMMX parameters and results.", "%0 uses different way to pass WMMX parameters and results.")
+DIAG(warn_mismatch_pcs_config, DiagnosticEngine::Warning, "conflicting procedure call standard config in input %0.", "conflicting procedure call standard config in input %0.")
+DIAG(warn_mismatch_r9_use, DiagnosticEngine::Warning, "conflicting way to use R9 in input %0.", "conflicting way to use R9 in input %0.")
+DIAG(warn_conflict_rw_data_and_r9, DiagnosticEngine::Warning, "RW static data addressing (SB-relative) conflicts the use of R9 (Tag_ABI_PCS_R9_use) in input %0.", "RW static data addressing (SB-relative) conflicts the use of R9 (Tag_ABI_PCS_R9_use) in input %0.")
+DIAG(warn_mismatch_wchar_size, DiagnosticEngine::Warning, "incompatible size of wchar_t in input %0 (value=%1) with the output (value=%2).", "incompatible size of wchar_t in input %0 (value=%1) with the output (value=%2).")
+DIAG(warn_unknown_mandatory_attribute, DiagnosticEngine::Warning, "unknown mandatory attribute with tag %0 was ignored in %1.", "unknown mandatory attribute with tag %0 was ignored in %1.")
+DIAG(warn_unknown_attribute, DiagnosticEngine::Warning, "unknown attribute with tag %0 was ignored in %1.", "unknown attribute with tag %0 was ignored in %1.")
+DIAG(warn_mismatch_vfp_args, DiagnosticEngine::Warning, "%0 uses different way to pass the floating point parameter and results.", "%0 uses different way to pass the floating point parameter and results.")
diff --git a/include/mcld/LD/DiagCommonKinds.inc b/include/mcld/LD/DiagCommonKinds.inc
index e7d6328..539eafb 100644
--- a/include/mcld/LD/DiagCommonKinds.inc
+++ b/include/mcld/LD/DiagCommonKinds.inc
@@ -3,7 +3,7 @@
DIAG(warn_cannot_open_search_dir, DiagnosticEngine::Warning, "can not open search directory `-L%0'", "can not open search directory `-L%0'")
DIAG(err_no_inputs, DiagnosticEngine::Error, "no inputs", "no inputs")
DIAG(err_empty_input, DiagnosticEngine::Error, "Empty input file `%0' : %1", "Empty input file `%0' : %1")
-DIAG(err_unrecognized_input_file, DiagnosticEngine::Fatal, "cannot recognize the format of file `%0'.\n object format or given target machine (%1) is wrong.","cannot recognize the format of file `%0'.\n object format or given target machine (%1) is wrong.")
+DIAG(warn_unrecognized_input_file, DiagnosticEngine::Warning, "cannot recognize the format of file `%0'.\n object format or given target machine (%1) is incompatible.","cannot recognize the format of file `%0'.\n object format or given target machine (%1) is incompatible.")
DIAG(err_cannot_find_namespec, DiagnosticEngine::Fatal, "cannot recognize namespec -l%0", "cannot recognize namespec -l%0")
DIAG(err_cannot_identify_option, DiagnosticEngine::Fatal, "unknown command line argument `%0' at %1", "unknown command line argument `%0' at %1")
DIAG(err_mixed_shared_static_objects, DiagnosticEngine::Error, "cannot link shared objects with -static option.\nShared object `%0': %1", "cannot link shared objects with -static option.\nShared object `%0': %1")
@@ -40,7 +40,7 @@
DIAG(fatal_cannot_init_target, DiagnosticEngine::Fatal, "Cannot initialize mcld::Target for given triple '%0'.\n(Detail: %1)", "Cannot initialize mcld::Target for given triple '%0'.\n(Detail: %1)")
DIAG(fatal_cannot_init_lineinfo, DiagnosticEngine::Fatal, "Cannot initialize mcld::DiagnosticLineInfo for given triple '%0'", "Cannot initialize mcld::DiagnosticLineInfo for given triple '%0'")
DIAG(fatal_cannot_init_backend, DiagnosticEngine::Fatal, "Cannot initialize mcld::TargetLDBackend for given triple '%0'.", "Cannot initialize mcld::TargetLDBackend for given triple '%0'.")
-DIAG(fatal_forbid_nest_group, DiagnosticEngine::Fatal, "May not nest groups", "May not nest groups")
+DIAG(fatal_forbid_nest_group, DiagnosticEngine::Fatal, "not matched --start-group and --end-group", "not matched --start-group and --end-group")
DIAG(fatal_unwritable_output, DiagnosticEngine::Fatal, "unable to write output file %0", "unable to write output file %0")
DIAG(warn_unsupported_option, DiagnosticEngine::Warning, "Option `%0' is not implemented yet!", "Option `%0' is not implemented yet!")
DIAG(warn_shared_textrel, DiagnosticEngine::Warning, "Add DT_TEXTREL in a shared object!", "Add DT_TEXTREL in a shared object.")
@@ -48,3 +48,6 @@
DIAG(err_nmagic_not_static, DiagnosticEngine::Error, "cannot mix -nmagic option with -shared", "cannot mix -nmagic option with -shared")
DIAG(err_omagic_not_static, DiagnosticEngine::Error, "cannot mix -omagic option with -shared", "cannot mix -omagic option with -shared")
DIAG(err_invalid_emulation, DiagnosticEngine::Error, "Invalid target emulation: `%0'.", "Invalid target emulation: `%0'.")
+DIAG(err_cannot_find_scriptfile, DiagnosticEngine::Fatal, "cannot open %0 file %1", "cannot open %0 file %1")
+DIAG(err_unsupported_archive, DiagnosticEngine::Error, "Unsupported archive type.", "Unsupported archive type.")
+DIAG(unexpected_frag_type, DiagnosticEngine::Unreachable, "Unexpected fragment type `%0' when constructing FG", "Unexpected fragment type `%0' when constructing FG")
diff --git a/include/mcld/LD/DiagLDScript.inc b/include/mcld/LD/DiagLDScript.inc
new file mode 100644
index 0000000..c752773
--- /dev/null
+++ b/include/mcld/LD/DiagLDScript.inc
@@ -0,0 +1,3 @@
+DIAG(err_unterminated_comment, DiagnosticEngine::Error, "%0:%1:%2: error: unterminated comment\n", "%0:%1:%2: error: unterminated comment\n")
+DIAG(err_syntax_error, DiagnosticEngine::Error, "%0:%1:%2: error: %3\n", "%0:%1:%2: error: %3\n")
+DIAG(err_assert_failed, DiagnosticEngine::Error,"Assertion failed: %0\n", "Assertion failed: %0\n")
diff --git a/include/mcld/LD/DiagRelocations.inc b/include/mcld/LD/DiagRelocations.inc
index 7ada05f..bacae6e 100644
--- a/include/mcld/LD/DiagRelocations.inc
+++ b/include/mcld/LD/DiagRelocations.inc
@@ -1,6 +1,7 @@
DIAG(reloc_factory_has_not_config, DiagnosticEngine::Fatal, "Please call mcld::Linker::config before creating relocations", "Please call mcld::Linker::config before creating relocations")
DIAG(unsupported_bitclass, DiagnosticEngine::Fatal, "Only supports 32 and 64 bits targets. (Target: %0, bitclass:%1)", "Only supports 32 and 64 bits targets. (Target: %0, bitclass:%1)")
-DIAG(undefined_reference, DiagnosticEngine::Fatal, "undefined reference to `%0'", "In %1:%2, variable %0 must be defined")
+DIAG(undefined_reference, DiagnosticEngine::Fatal, "%1(%2+%3): undefined reference to `%0'", "%1(%2+%3): undefined reference to `%0'")
+DIAG(undefined_reference_text, DiagnosticEngine::Fatal, "%1:%2:function %3: undefined reference to `%0'", "%1:%2: undefined reference to `%0'")
DIAG(non_pic_relocation, DiagnosticEngine::Error, "attempt to generate unsupported relocation type `%0' for symbol `%1', recompile with -fPIC", "attempt to generate unsupported relocation type `%0' for symbol `%1, recompile with -fPIC")
DIAG(base_relocation, DiagnosticEngine::Fatal, "relocation type `%0' is not supported for symbol `%1'\nPlease report to %2", "relocation type `%0' is not supported for symbol `%1'\nPlease report to %2")
DIAG(dynamic_relocation, DiagnosticEngine::Fatal, "unexpected relocation type `%0' in object file", "unexpected relocation type `%0' in object file")
@@ -11,3 +12,4 @@
DIAG(result_badreloc, DiagnosticEngine::Error, "applying relocation `%0' encounters unexpected opcode on symbol `%1'","applying relocation `%0' encounters unexpected opcode on symbol `%1'")
DIAG(invalid_tls, DiagnosticEngine::Error, "TLS relocation against invalid symbol `%0' in section `%1'", "TLS relocation against invalid symbol `%0' in section `%1'")
DIAG(unknown_reloc_section_type, DiagnosticEngine::Unreachable, "unknown relocation section type: `%0' in section `%1'", "unknown relocation section type: `%0' in section `%1'")
+DIAG(unsupport_cond_branch_reloc, DiagnosticEngine::Error, "applying relocation `%0', conditional branch to PLT in THUMB-2 not supported yet", "applying relocation `%0', conditional branch to PLT in THUMB-2 not supported yet")
diff --git a/include/mcld/LD/DiagSymbolResolutions.inc b/include/mcld/LD/DiagSymbolResolutions.inc
index 786eb4b..04113dc 100644
--- a/include/mcld/LD/DiagSymbolResolutions.inc
+++ b/include/mcld/LD/DiagSymbolResolutions.inc
@@ -8,3 +8,4 @@
DIAG(indirect_refer_to_inexist, DiagnosticEngine::Fatal, "indirect symbol %0 points to a undefined symbol", "variable %0 is undefined")
DIAG(multiple_definitions, DiagnosticEngine::Error, "multiple definition of symbol `%0'", "you define variable %0 twice")
DIAG(undefined_situation, DiagnosticEngine::Unreachable, "reach undefined situation, action: %0, old(%1) -> new(%2)", "reach undefined situation, action: %0, old(%1) -> new(%2)")
+DIAG(multiple_absolute_definitions, DiagnosticEngine::Error, "inconsistent definitions of absolute symbol `%0': old(%1) -> new(%2)", "you defined an absolute symbol with different values")
diff --git a/include/mcld/LD/Diagnostic.h b/include/mcld/LD/Diagnostic.h
index 2e4db11..1982ef0 100644
--- a/include/mcld/LD/Diagnostic.h
+++ b/include/mcld/LD/Diagnostic.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_DIAGNOSTIC_H
-#define MCLD_DIAGNOSTIC_H
+#ifndef MCLD_LD_DIAGNOSTIC_H
+#define MCLD_LD_DIAGNOSTIC_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/LD/DiagnosticEngine.h b/include/mcld/LD/DiagnosticEngine.h
index 1c825a2..b003955 100644
--- a/include/mcld/LD/DiagnosticEngine.h
+++ b/include/mcld/LD/DiagnosticEngine.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_DIAGNOSTIC_ENGINE_H
-#define MCLD_DIAGNOSTIC_ENGINE_H
+#ifndef MCLD_LD_DIAGNOSTICENGINE_H
+#define MCLD_LD_DIAGNOSTICENGINE_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/LD/DiagnosticInfos.h b/include/mcld/LD/DiagnosticInfos.h
index cb9bdbd..16ebbab 100644
--- a/include/mcld/LD/DiagnosticInfos.h
+++ b/include/mcld/LD/DiagnosticInfos.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_DIAGNOSTIC_INFORMATION_H
-#define MCLD_DIAGNOSTIC_INFORMATION_H
+#ifndef MCLD_LD_DIAGNOSTICINFORMATION_H
+#define MCLD_LD_DIAGNOSTICINFORMATION_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -18,12 +18,14 @@
namespace diag {
enum ID {
#define DIAG(ENUM, CLASS, ADDRMSG, LINEMSG) ENUM,
+#include "mcld/LD/DiagAttribute.inc"
#include "mcld/LD/DiagCommonKinds.inc"
#include "mcld/LD/DiagReaders.inc"
#include "mcld/LD/DiagSymbolResolutions.inc"
#include "mcld/LD/DiagRelocations.inc"
#include "mcld/LD/DiagLayouts.inc"
#include "mcld/LD/DiagGOTPLT.inc"
+#include "mcld/LD/DiagLDScript.inc"
#undef DIAG
NUM_OF_BUILDIN_DIAGNOSTIC_INFO
};
diff --git a/include/mcld/LD/DiagnosticLineInfo.h b/include/mcld/LD/DiagnosticLineInfo.h
index 30f0546..db35287 100644
--- a/include/mcld/LD/DiagnosticLineInfo.h
+++ b/include/mcld/LD/DiagnosticLineInfo.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_DIAGNOSTICLINEINFO_H
-#define MCLD_DIAGNOSTICLINEINFO_H
+#ifndef MCLD_LD_DIAGNOSTICLINEINFO_H
+#define MCLD_LD_DIAGNOSTICLINEINFO_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/LD/DiagnosticPrinter.h b/include/mcld/LD/DiagnosticPrinter.h
index b3617a7..7cf5c8e 100644
--- a/include/mcld/LD/DiagnosticPrinter.h
+++ b/include/mcld/LD/DiagnosticPrinter.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_DIAGNOSTIC_PRINTER_H
-#define MCLD_DIAGNOSTIC_PRINTER_H
+#ifndef MCLD_LD_DIAGNOSTICPRINTER_H
+#define MCLD_LD_DIAGNOSTICPRINTER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/LD/DynObjFileFormat.h b/include/mcld/LD/DynObjFileFormat.h
index 7b1626d..e0972c3 100644
--- a/include/mcld/LD/DynObjFileFormat.h
+++ b/include/mcld/LD/DynObjFileFormat.h
@@ -1,4 +1,4 @@
-//===- header.h -----------------------------------------------------------===//
+//===- DynObjFileFormat.h -------------------------------------------------===//
//
// The MCLinker Project
//
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef DYNOBJFORMAT_H
-#define DYNOBJFORMAT_H
+#ifndef MCLD_LD_DYNOBJFILEFORMAT_H
+#define MCLD_LD_DYNOBJFILEFORMAT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/LD/DynObjReader.h b/include/mcld/LD/DynObjReader.h
index ddc9500..8a7a6be 100644
--- a/include/mcld/LD/DynObjReader.h
+++ b/include/mcld/LD/DynObjReader.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_DYNAMIC_SHARED_OBJECT_READER_H
-#define MCLD_DYNAMIC_SHARED_OBJECT_READER_H
+#ifndef MCLD_LD_DYNOBJREADER_H
+#define MCLD_LD_DYNOBJREADER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/LD/ELFBinaryReader.h b/include/mcld/LD/ELFBinaryReader.h
index fc3a067..9da4535 100644
--- a/include/mcld/LD/ELFBinaryReader.h
+++ b/include/mcld/LD/ELFBinaryReader.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ELF_Binary_READER_H
-#define MCLD_ELF_Binary_READER_H
+#ifndef MCLD_LD_ELFBINARYREADER_H
+#define MCLD_LD_ELFBINARYREADER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -19,7 +19,6 @@
class Module;
class Input;
class IRBuilder;
-class GNULDBackend;
class LinkerConfig;
/** \lclass ELFBinaryReader
@@ -28,16 +27,15 @@
class ELFBinaryReader : public BinaryReader
{
public:
- ELFBinaryReader(GNULDBackend& pBackend,
- IRBuilder& pBuilder,
- const LinkerConfig& pConfig);
+ ELFBinaryReader(IRBuilder& pBuilder, const LinkerConfig& pConfig);
~ELFBinaryReader();
- virtual bool readBinary(Input& pInput);
+ bool isMyFormat(Input& pInput, bool &pContinue) const;
+
+ bool readBinary(Input& pInput);
private:
- GNULDBackend& m_Backend;
IRBuilder& m_Builder;
const LinkerConfig& m_Config;
};
diff --git a/include/mcld/LD/ELFDynObjFileFormat.h b/include/mcld/LD/ELFDynObjFileFormat.h
index 2ee97a6..dd9cbb9 100644
--- a/include/mcld/LD/ELFDynObjFileFormat.h
+++ b/include/mcld/LD/ELFDynObjFileFormat.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ELF_DYNAMIC_OBJECT_FILE_FROMAT_H
-#define MCLD_ELF_DYNAMIC_OBJECT_FILE_FROMAT_H
+#ifndef MCLD_LD_ELFDYNOBJFILEFROMAT_H
+#define MCLD_LD_ELFDYNOBJFILEFROMAT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/LD/ELFDynObjReader.h b/include/mcld/LD/ELFDynObjReader.h
index f6d2067..23b96ad 100644
--- a/include/mcld/LD/ELFDynObjReader.h
+++ b/include/mcld/LD/ELFDynObjReader.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ELF_DYNAMIC_SHARED_OBJECT_READER_H
-#define MCLD_ELF_DYNAMIC_SHARED_OBJECT_READER_H
+#ifndef MCLD_LD_ELFDYNOBJREADER_H
+#define MCLD_LD_ELFDYNOBJREADER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -35,7 +35,7 @@
~ELFDynObjReader();
// ----- observers ----- //
- bool isMyFormat(Input &pFile) const;
+ bool isMyFormat(Input &pFile, bool &pContinue) const;
// ----- readers ----- //
bool readHeader(Input& pFile);
diff --git a/include/mcld/LD/ELFObjectReader.h b/include/mcld/LD/ELFObjectReader.h
index 27e4489..a124676 100644
--- a/include/mcld/LD/ELFObjectReader.h
+++ b/include/mcld/LD/ELFObjectReader.h
@@ -46,7 +46,7 @@
~ELFObjectReader();
// ----- observers ----- //
- bool isMyFormat(Input &pFile) const;
+ bool isMyFormat(Input &pFile, bool &pContinue) const;
// ----- readers ----- //
bool readHeader(Input& pFile);
diff --git a/include/mcld/LD/ELFObjectWriter.h b/include/mcld/LD/ELFObjectWriter.h
index 12a5842..9caa76a 100644
--- a/include/mcld/LD/ELFObjectWriter.h
+++ b/include/mcld/LD/ELFObjectWriter.h
@@ -6,18 +6,20 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ELF_OBJECT_WRITER_H
-#define MCLD_ELF_OBJECT_WRITER_H
+#ifndef MCLD_LD_ELFOBJWRITER_H
+#define MCLD_LD_ELFOBJWRITER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <mcld/LD/ObjectWriter.h>
#include <cassert>
+#include <mcld/Support/FileOutputBuffer.h>
#include <llvm/Support/system_error.h>
namespace mcld {
+class EhFrame;
class Module;
class LinkerConfig;
class GNULDBackend;
@@ -27,8 +29,6 @@
class SectionData;
class RelocData;
class Output;
-class MemoryRegion;
-class MemoryArea;
/** \class ELFObjectWriter
* \brief ELFObjectWriter writes the target-independent parts of object files.
@@ -42,10 +42,13 @@
~ELFObjectWriter();
- llvm::error_code writeObject(Module& pModule, MemoryArea& pOutput);
+ llvm::error_code writeObject(Module& pModule, FileOutputBuffer& pOutput);
+
+ size_t getOutputSize(const Module& pModule) const;
private:
- void writeSection(MemoryArea& pOutput, LDSection *section);
+ void writeSection(Module& pModule,
+ FileOutputBuffer& pOutput, LDSection *section);
GNULDBackend& target() { return m_Backend; }
@@ -55,7 +58,7 @@
template<size_t SIZE>
void writeELFHeader(const LinkerConfig& pConfig,
const Module& pModule,
- MemoryArea& pOutput) const;
+ FileOutputBuffer& pOutput) const;
uint64_t getEntryPoint(const LinkerConfig& pConfig,
const Module& pModule) const;
@@ -64,19 +67,21 @@
template<size_t SIZE>
void emitSectionHeader(const Module& pModule,
const LinkerConfig& pConfig,
- MemoryArea& pOutput) const;
+ FileOutputBuffer& pOutput) const;
// emitProgramHeader - emit ElfXX_Phdr
template<size_t SIZE>
- void emitProgramHeader(MemoryArea& pOutput) const;
+ void emitProgramHeader(FileOutputBuffer& pOutput) const;
// emitShStrTab - emit .shstrtab
void emitShStrTab(const LDSection& pShStrTab,
const Module& pModule,
- MemoryArea& pOutput);
+ FileOutputBuffer& pOutput);
- void emitSectionData(const LDSection& pSection,
- MemoryRegion& pRegion) const;
+ void emitSectionData(const LDSection& pSection, MemoryRegion& pRegion) const;
+
+ void emitEhFrame(Module& pModule,
+ EhFrame& pFrame, MemoryRegion& pRegion) const;
void emitRelocation(const LinkerConfig& pConfig,
const LDSection& pSection,
diff --git a/include/mcld/LD/ELFReader.h b/include/mcld/LD/ELFReader.h
index 9df21d3..6750ebd 100644
--- a/include/mcld/LD/ELFReader.h
+++ b/include/mcld/LD/ELFReader.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ELF_READER_H
-#define MCLD_ELF_READER_H
+#ifndef MCLD_LD_ELFREADER_H
+#define MCLD_LD_ELFREADER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -20,8 +20,6 @@
#include <mcld/LD/ResolveInfo.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/Target/GNULDBackend.h>
-#include <mcld/Support/MemoryRegion.h>
-#include <mcld/Support/MemoryArea.h>
namespace mcld {
@@ -60,19 +58,19 @@
{ return sizeof(ELFHeader); }
/// isELF - is this a ELF file
- bool isELF(void* pELFHeader) const;
+ bool isELF(const void* pELFHeader) const;
/// isMyEndian - is this ELF file in the same endian to me?
- bool isMyEndian(void* pELFHeader) const;
+ bool isMyEndian(const void* pELFHeader) const;
/// isMyMachine - is this ELF file generated for the same machine.
- bool isMyMachine(void* pELFHeader) const;
+ bool isMyMachine(const void* pELFHeader) const;
/// fileType - the file type of this file
- Input::Type fileType(void* pELFHeader) const;
+ Input::Type fileType(const void* pELFHeader) const;
/// readSectionHeaders - read ELF section header table and create LDSections
- bool readSectionHeaders(Input& pInput, void* pELFHeader) const;
+ bool readSectionHeaders(Input& pInput, const void* pELFHeader) const;
/// readRegularSection - read a regular section and create fragments.
bool readRegularSection(Input& pInput, SectionData& pSD) const;
@@ -80,24 +78,24 @@
/// readSymbols - read ELF symbols and create LDSymbol
bool readSymbols(Input& pInput,
IRBuilder& pBuilder,
- const MemoryRegion& pRegion,
+ llvm::StringRef pRegion,
const char* StrTab) const;
/// readSignature - read a symbol from the given Input and index in symtab
/// This is used to get the signature of a group section.
ResolveInfo* readSignature(Input& pInput,
- LDSection& pSymTab,
- uint32_t pSymIdx) const;
+ LDSection& pSymTab,
+ uint32_t pSymIdx) const;
/// readRela - read ELF rela and create Relocation
bool readRela(Input& pInput,
LDSection& pSection,
- const MemoryRegion& pRegion) const;
+ llvm::StringRef pRegion) const;
/// readRel - read ELF rel and create Relocation
bool readRel(Input& pInput,
LDSection& pSection,
- const MemoryRegion& pRegion) const;
+ llvm::StringRef pRegion) const;
/// readDynamic - read ELF .dynamic in input dynobj
bool readDynamic(Input& pInput) const;
@@ -150,19 +148,19 @@
{ return sizeof(ELFHeader); }
/// isELF - is this a ELF file
- bool isELF(void* pELFHeader) const;
+ bool isELF(const void* pELFHeader) const;
/// isMyEndian - is this ELF file in the same endian to me?
- bool isMyEndian(void* pELFHeader) const;
+ bool isMyEndian(const void* pELFHeader) const;
/// isMyMachine - is this ELF file generated for the same machine.
- bool isMyMachine(void* pELFHeader) const;
+ bool isMyMachine(const void* pELFHeader) const;
/// fileType - the file type of this file
- Input::Type fileType(void* pELFHeader) const;
+ Input::Type fileType(const void* pELFHeader) const;
/// readSectionHeaders - read ELF section header table and create LDSections
- bool readSectionHeaders(Input& pInput, void* pELFHeader) const;
+ bool readSectionHeaders(Input& pInput, const void* pELFHeader) const;
/// readRegularSection - read a regular section and create fragments.
bool readRegularSection(Input& pInput, SectionData& pSD) const;
@@ -170,24 +168,24 @@
/// readSymbols - read ELF symbols and create LDSymbol
bool readSymbols(Input& pInput,
IRBuilder& pBuilder,
- const MemoryRegion& pRegion,
+ llvm::StringRef pRegion,
const char* StrTab) const;
/// readSignature - read a symbol from the given Input and index in symtab
/// This is used to get the signature of a group section.
ResolveInfo* readSignature(Input& pInput,
- LDSection& pSymTab,
- uint32_t pSymIdx) const;
+ LDSection& pSymTab,
+ uint32_t pSymIdx) const;
/// readRela - read ELF rela and create Relocation
bool readRela(Input& pInput,
LDSection& pSection,
- const MemoryRegion& pRegion) const;
+ llvm::StringRef pRegion) const;
/// readRel - read ELF rel and create Relocation
bool readRel(Input& pInput,
LDSection& pSection,
- const MemoryRegion& pRegion) const;
+ llvm::StringRef pRegion) const;
/// readDynamic - read ELF .dynamic in input dynobj
bool readDynamic(Input& pInput) const;
diff --git a/include/mcld/LD/ELFReaderIf.h b/include/mcld/LD/ELFReaderIf.h
index 245b542..0ce5992 100644
--- a/include/mcld/LD/ELFReaderIf.h
+++ b/include/mcld/LD/ELFReaderIf.h
@@ -1,4 +1,4 @@
-//===- ELFReader.h --------------------------------------------------------===//
+//===- ELFReaderIf.h ------------------------------------------------------===//
//
// The MCLinker Project
//
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ELF_READER_INTERFACE_H
-#define MCLD_ELF_READER_INTERFACE_H
+#ifndef MCLD_LD_ELFREADERIF_H
+#define MCLD_LD_ELFREADERIF_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -46,16 +46,16 @@
virtual size_t getELFHeaderSize() const = 0;
/// isELF - is this a ELF file
- virtual bool isELF(void* pELFHeader) const = 0;
+ virtual bool isELF(const void* pELFHeader) const = 0;
/// isMyEndian - is this ELF file in the same endian to me?
- virtual bool isMyEndian(void* pELFHeader) const = 0;
+ virtual bool isMyEndian(const void* pELFHeader) const = 0;
/// isMyMachine - is this ELF file generated for the same machine.
- virtual bool isMyMachine(void* pELFHeader) const = 0;
+ virtual bool isMyMachine(const void* pELFHeader) const = 0;
/// fileType - the file type of this file
- virtual Input::Type fileType(void* pELFHeader) const = 0;
+ virtual Input::Type fileType(const void* pELFHeader) const = 0;
/// target - the target backend
const GNULDBackend& target() const { return m_Backend; }
@@ -63,7 +63,8 @@
/// readSectionHeaders - read ELF section header table and create LDSections
- virtual bool readSectionHeaders(Input& pInput, void* pELFHeader) const = 0;
+ virtual bool readSectionHeaders(Input& pInput,
+ const void* pELFHeader) const = 0;
/// readRegularSection - read a regular section and create fragments.
virtual bool readRegularSection(Input& pInput, SectionData& pSD) const = 0;
@@ -71,7 +72,7 @@
/// readSymbols - read ELF symbols and create LDSymbol
virtual bool readSymbols(Input& pInput,
IRBuilder& pBuilder,
- const MemoryRegion& pRegion,
+ llvm::StringRef pRegion,
const char* StrTab) const = 0;
/// readSignature - read a symbol from the given Input and index in symtab
@@ -83,12 +84,12 @@
/// readRela - read ELF rela and create Relocation
virtual bool readRela(Input& pInput,
LDSection& pSection,
- const MemoryRegion& pRegion) const = 0;
+ llvm::StringRef pRegion) const = 0;
/// readRel - read ELF rel and create Relocation
virtual bool readRel(Input& pInput,
LDSection& pSection,
- const MemoryRegion& pRegion) const = 0;
+ llvm::StringRef pRegion) const = 0;
/// readDynamic - read ELF .dynamic in input dynobj
virtual bool readDynamic(Input& pInput) const = 0;
diff --git a/include/mcld/LD/ELFSegment.h b/include/mcld/LD/ELFSegment.h
index d7f769e..5079b54 100644
--- a/include/mcld/LD/ELFSegment.h
+++ b/include/mcld/LD/ELFSegment.h
@@ -6,45 +6,52 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ELF_SEGMENT_H
-#define MCLD_ELF_SEGMENT_H
+#ifndef MCLD_LD_ELFSEGMENT_H
+#define MCLD_LD_ELFSEGMENT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
+#include <mcld/Support/Allocators.h>
+#include <mcld/Config/Config.h>
#include <llvm/Support/ELF.h>
#include <llvm/Support/DataTypes.h>
-#include <mcld/LD/LDSection.h>
-#include <cassert>
#include <vector>
namespace mcld
{
+class LDSection;
+
/** \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;
+ typedef std::vector<LDSection*> SectionList;
+ typedef SectionList::iterator iterator;
+ typedef SectionList::const_iterator const_iterator;
+ typedef SectionList::reverse_iterator reverse_iterator;
+ typedef SectionList::const_reverse_iterator const_reverse_iterator;
+
+private:
+ friend class Chunk<ELFSegment, MCLD_SEGMENTS_PER_OUTPUT>;
+ ELFSegment();
+ ELFSegment(uint32_t pType, uint32_t pFlag = llvm::ELF::PF_R);
+
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,
- uint64_t pMaxSectAlign = 0);
~ELFSegment();
/// ----- iterators ----- ///
- sect_iterator begin() { return m_SectionList.begin(); }
- const_sect_iterator begin() const { return m_SectionList.begin(); }
- sect_iterator end() { return m_SectionList.end(); }
- const_sect_iterator end() const { return m_SectionList.end(); }
+ iterator begin() { return m_SectionList.begin(); }
+ const_iterator begin() const { return m_SectionList.begin(); }
+ iterator end() { return m_SectionList.end(); }
+ const_iterator end() const { return m_SectionList.end(); }
+
+ reverse_iterator rbegin() { return m_SectionList.rbegin(); }
+ const_reverse_iterator rbegin() const { return m_SectionList.rbegin(); }
+ reverse_iterator rend() { return m_SectionList.rend(); }
+ const_reverse_iterator rend() const { return m_SectionList.rend(); }
LDSection* front() { return m_SectionList.front(); }
const LDSection* front() const { return m_SectionList.front(); }
@@ -52,35 +59,20 @@
const LDSection* back() const { return m_SectionList.back(); }
/// ----- observers ----- ///
- uint32_t type() const
- { return m_Type; }
+ 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 std::max(m_Align, m_MaxSectionAlign); }
- uint64_t offset() const
- { return m_Offset; }
+ size_t size() const { return m_SectionList.size(); }
+ bool empty() const { return m_SectionList.empty(); }
- 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 std::max(m_Align, m_MaxSectionAlign); }
-
- size_t numOfSections() const
- { return m_SectionList.size(); }
-
+ bool isLoadSegment() const;
bool isDataSegment() const;
-
bool isBssSegment() const;
/// ----- modifiers ----- ///
@@ -112,13 +104,14 @@
void setAlign(uint64_t pAlign)
{ m_Align = pAlign; }
- void addSection(LDSection* pSection)
- {
- assert(NULL != pSection);
- if (pSection->align() > m_MaxSectionAlign)
- m_MaxSectionAlign = pSection->align();
- m_SectionList.push_back(pSection);
- }
+ iterator insert(iterator pPos, LDSection* pSection);
+
+ void append(LDSection* pSection);
+
+ /* factory methods */
+ static ELFSegment* Create(uint32_t pType, uint32_t pFlag = llvm::ELF::PF_R);
+ static void Destroy(ELFSegment*& pSegment);
+ static void Clear();
private:
uint32_t m_Type; // Type of segment
@@ -130,7 +123,7 @@
uint64_t m_Memsz; // # of bytes in mem image of segment (may be 0)
uint64_t m_Align; // alignment constraint
uint64_t m_MaxSectionAlign; // max alignment of the sections in this segment
- std::vector<LDSection*> m_SectionList;
+ SectionList m_SectionList;
};
} // namespace of mcld
diff --git a/include/mcld/LD/ELFSegmentFactory.h b/include/mcld/LD/ELFSegmentFactory.h
index 5085a18..6df0389 100644
--- a/include/mcld/LD/ELFSegmentFactory.h
+++ b/include/mcld/LD/ELFSegmentFactory.h
@@ -6,38 +6,64 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ELFSEGMENT_FACTORY_H
-#define MCLD_ELFSEGMENT_FACTORY_H
+#ifndef MCLD_LD_ELFSEGMENTFACTORY_H
+#define MCLD_LD_ELFSEGMENTFACTORY_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
-#include <mcld/Support/GCFactory.h>
-#include <mcld/LD/ELFSegment.h>
+
+#include <llvm/Support/DataTypes.h>
+#include <llvm/Support/ELF.h>
+#include <vector>
namespace mcld
{
+class ELFSegment;
+class LDSection;
+
/** \class ELFSegmentFactory
* \brief provide the interface to create and delete an ELFSegment
*/
-class ELFSegmentFactory : public GCFactory<ELFSegment, 0>
+class ELFSegmentFactory
{
public:
- /// ELFSegmentFactory - the factory of ELFSegment
- /// pNum is the magic number of the ELF segments in the output
- ELFSegmentFactory(size_t pNum);
- ~ELFSegmentFactory();
+ typedef std::vector<ELFSegment*> Segments;
+ typedef Segments::const_iterator const_iterator;
+ typedef Segments::iterator iterator;
+
+ const_iterator begin() const { return m_Segments.begin(); }
+ iterator begin() { return m_Segments.begin(); }
+ const_iterator end() const { return m_Segments.end(); }
+ iterator end() { return m_Segments.end(); }
+
+ const ELFSegment* front() const { return m_Segments.front(); }
+ ELFSegment* front() { return m_Segments.front(); }
+ const ELFSegment* back() const { return m_Segments.back(); }
+ ELFSegment* back() { return m_Segments.back(); }
+
+ size_t size() const { return m_Segments.size(); }
+
+ bool empty() const { return m_Segments.empty(); }
+
+ iterator find(uint32_t pType, uint32_t pFlagSet, uint32_t pFlagClear);
+
+ const_iterator
+ find(uint32_t pType, uint32_t pFlagSet, uint32_t pFlagClear) const;
+
+ iterator find(uint32_t pType, const LDSection* pSection);
+
+ const_iterator find(uint32_t pType, const LDSection* pSection) const;
/// 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, uint32_t pFlag = llvm::ELF::PF_R);
- ELFSegment*
- find(uint32_t pType, uint32_t pFlagSet, uint32_t pFlagClear);
+ void erase(iterator pSegment);
- const ELFSegment*
- find(uint32_t pType, uint32_t pFlagSet, uint32_t pFlagClear) const;
+private:
+ Segments m_Segments;
};
} // namespace of mcld
diff --git a/include/mcld/LD/EhFrame.h b/include/mcld/LD/EhFrame.h
index c067746..6663d0f 100644
--- a/include/mcld/LD/EhFrame.h
+++ b/include/mcld/LD/EhFrame.h
@@ -6,23 +6,30 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LD_EH_FRAME_H
-#define MCLD_LD_EH_FRAME_H
+#ifndef MCLD_LD_EHFRAME_H
+#define MCLD_LD_EHFRAME_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <mcld/Config/Config.h>
#include <mcld/Fragment/RegionFragment.h>
-#include <mcld/Fragment/NullFragment.h>
+#include <mcld/LD/SectionData.h>
#include <mcld/Support/Allocators.h>
+#include <llvm/ADT/StringRef.h>
+#include <list>
+#include <map>
+#include <set>
#include <vector>
namespace mcld {
+class Input;
+class Module;
class LDSection;
-class SectionData;
+class ObjectLinker;
+class Relocation;
/** \class EhFrame
* \brief EhFrame represents .eh_frame section
@@ -41,53 +48,128 @@
EhFrame& operator=(const EhFrame&); // DO NOT IMPLEMENT
public:
+ enum RecordType {
+ RECORD_UNKNOWN,
+ RECORD_INPUT,
+ RECORD_GENERATED
+ };
+
+ class CIE;
+ class FDE;
+
+ typedef std::vector<CIE*> CIEList;
+ typedef CIEList::iterator cie_iterator;
+ typedef CIEList::const_iterator const_cie_iterator;
+
+ typedef std::list<FDE*> FDEList;
+ typedef FDEList::iterator fde_iterator;
+ typedef FDEList::const_iterator const_fde_iterator;
+
+ typedef std::map</*offset*/size_t, CIE*> CIEMap;
+
+ // A super class of CIE and FDE, containing the same part
+ class Record : public RegionFragment
+ {
+ public:
+ Record(llvm::StringRef pRegion);
+ virtual ~Record();
+
+ const llvm::StringRef getRegion() const { return RegionFragment::getRegion(); }
+ llvm::StringRef getRegion() { return RegionFragment::getRegion(); }
+ virtual RecordType getRecordType() const { return RECORD_UNKNOWN; }
+
+ private:
+ Record(const Record&); // DO NOT IMPLEMENT
+ Record& operator=(const Record&); // DO NOT IMPLEMENT
+ };
+
/** \class CIE
* \brief Common Information Entry.
* The CIE structure refers to LSB Core Spec 4.1, chap.10.6. Exception Frames.
*/
- class CIE : public RegionFragment
+ class CIE : public Record
{
public:
- CIE(MemoryRegion& pRegion);
+ CIE(llvm::StringRef pRegion);
+ ~CIE();
+
+ virtual RecordType getRecordType() const { return RECORD_INPUT; }
void setFDEEncode(uint8_t pEncode) { m_FDEEncode = pEncode; }
uint8_t getFDEEncode() const { return m_FDEEncode; }
+ void setMergeable(bool pVal = true) { m_Mergeable = pVal; }
+ virtual bool getMergeable() const { return m_Mergeable; }
+
+ void setRelocation(const Relocation& pReloc) { m_pReloc = &pReloc; }
+ const Relocation* getRelocation() const { return m_pReloc; }
+
+ void setPersonalityOffset(uint64_t pOffset) { m_PersonalityOffset = pOffset; }
+ uint64_t getPersonalityOffset() const { return m_PersonalityOffset; }
+
+ void setPersonalityName(const std::string& pStr) { m_PersonalityName = pStr; }
+ const std::string& getPersonalityName() const { return m_PersonalityName; }
+
+ void setAugmentationData(const std::string& pStr) { m_AugmentationData = pStr; }
+ const std::string& getAugmentationData() const { return m_AugmentationData; }
+
+ void add(FDE& pFDE) { m_FDEs.push_back(&pFDE); }
+ void remove(FDE& pFDE) { m_FDEs.remove(&pFDE); }
+ void clearFDEs() { m_FDEs.clear(); }
+ size_t numOfFDEs() const { return m_FDEs.size(); }
+
+ const_fde_iterator begin() const { return m_FDEs.begin(); }
+ fde_iterator begin() { return m_FDEs.begin(); }
+ const_fde_iterator end() const { return m_FDEs.end(); }
+ fde_iterator end() { return m_FDEs.end(); }
+
private:
uint8_t m_FDEEncode;
+ bool m_Mergeable;
+ const Relocation* m_pReloc;
+ uint64_t m_PersonalityOffset;
+ std::string m_PersonalityName;
+ std::string m_AugmentationData;
+ FDEList m_FDEs;
};
/** \class FDE
* \brief Frame Description Entry
* The FDE structure refers to LSB Core Spec 4.1, chap.10.6. Exception Frames.
*/
- class FDE : public RegionFragment
+ class FDE : public Record
{
public:
- FDE(MemoryRegion& pRegion,
- const CIE& pCIE,
- uint32_t pDataStart);
+ FDE(llvm::StringRef pRegion, CIE& pCIE);
+ ~FDE();
- const CIE& getCIE() const { return m_CIE; }
-
- uint32_t getDataStart() const { return m_DataStart; }
+ void setCIE(CIE& pCIE);
+ const CIE& getCIE() const { return *m_pCIE; }
+ CIE& getCIE() { return *m_pCIE; }
private:
- const CIE& m_CIE;
- uint32_t m_DataStart;
+ CIE* m_pCIE; // Referenced CIE may change when merging.
};
- typedef std::vector<CIE*> CIEList;
+ // These are created for PLT
+ class GeneratedCIE : public CIE
+ {
+ public:
+ GeneratedCIE(llvm::StringRef pRegion);
+ ~GeneratedCIE();
- // cie_iterator and const_cie_iterator must be a kind of random access iterator
- typedef CIEList::iterator cie_iterator;
- typedef CIEList::const_iterator const_cie_iterator;
+ virtual RecordType getRecordType() const { return RECORD_GENERATED; }
+ virtual bool getMergeable() const { return true; }
+ };
- typedef std::vector<FDE*> FDEList;
+ class GeneratedFDE : public FDE
+ {
+ public:
+ GeneratedFDE(llvm::StringRef pRegion, CIE& pCIE);
+ ~GeneratedFDE();
- // fde_iterator and const_fde_iterator must be a kind of random access iterator
- typedef FDEList::iterator fde_iterator;
- typedef FDEList::const_iterator const_fde_iterator;
+ virtual RecordType getRecordType() const { return RECORD_GENERATED; }
+ };
public:
static EhFrame* Create(LDSection& pSection);
@@ -97,7 +179,7 @@
static void Clear();
/// merge - move all data from pOther to this object.
- EhFrame& merge(EhFrame& pOther);
+ EhFrame& merge(const Input& pInput, EhFrame& pInFrame);
const LDSection& getSection() const;
LDSection& getSection();
@@ -106,17 +188,13 @@
SectionData* getSectionData() { return m_pSectionData; }
// ----- fragment ----- //
- /// addFragment - when we start treating CIEs and FDEs as regular fragments,
- /// we call this function instead of addCIE() and addFDE().
- void addFragment(RegionFragment& pFrag);
-
- void addFragment(NullFragment& pFrag);
+ void addFragment(Fragment& pFrag);
/// addCIE - add a CIE entry in EhFrame
- void addCIE(CIE& pCIE);
+ void addCIE(CIE& pCIE, bool pAlsoAddFragment = true);
/// addFDE - add a FDE entry in EhFrame
- void addFDE(FDE& pFDE);
+ void addFDE(FDE& pFDE, bool pAlsoAddFragment = true);
// ----- CIE ----- //
const_cie_iterator cie_begin() const { return m_CIEs.begin(); }
@@ -129,29 +207,54 @@
const CIE& cie_back () const { return *m_CIEs.back(); }
CIE& cie_back () { return *m_CIEs.back(); }
+ bool emptyCIEs() const { return m_CIEs.empty(); }
size_t numOfCIEs() const { return m_CIEs.size(); }
+ size_t numOfFDEs() const;
- // ----- FDE ----- //
- const_fde_iterator fde_begin() const { return m_FDEs.begin(); }
- fde_iterator fde_begin() { return m_FDEs.begin(); }
- const_fde_iterator fde_end () const { return m_FDEs.end(); }
- fde_iterator fde_end () { return m_FDEs.end(); }
+ const CIEMap& getCIEMap() const { return m_FoundCIEs; }
+ CIEMap& getCIEMap() { return m_FoundCIEs; }
- const FDE& fde_front() const { return *m_FDEs.front(); }
- FDE& fde_front() { return *m_FDEs.front(); }
- const FDE& fde_back () const { return *m_FDEs.back(); }
- FDE& fde_back () { return *m_FDEs.back(); }
+public:
+ size_t computeOffsetSize();
- size_t numOfFDEs() const { return m_FDEs.size(); }
+ /// getDataStartOffset - Get the offset after length and ID field.
+ /// The offset is 8byte for 32b, and 16byte for 64b.
+ /// We can just use "BITCLASS/4" to represent offset.
+ template <size_t BITCLASS>
+ static size_t getDataStartOffset() { return BITCLASS / 4; }
+
+private:
+ // We needs to check if it is mergeable and check personality name
+ // before merging them. The important note is we must do this after
+ // ALL readSections done, that is the reason why we don't check this
+ // immediately when reading.
+ void setupAttributes(const LDSection* reloc_sect);
+ void removeDiscardedFDE(CIE& pCIE, const LDSection* pRelocEhFrameSect);
+
+private:
+ void removeAndUpdateCIEForFDE(EhFrame& pInFrame, CIE& pInCIE, CIE& pOutCIE,
+ const LDSection* reloc_sect);
+ void moveInputFragments(EhFrame& pInFrame);
+ void moveInputFragments(EhFrame& pInFrame, CIE& pInCIE, CIE* pOutCIE = 0);
private:
LDSection* m_pSection;
SectionData* m_pSectionData;
+ // Each eh_frame has a list of CIE, and each CIE has a list of FDE
+ // pointing to the CIE itself. This is used by management when we are
+ // processing eh_frame merge.
+ // However, don't forget we need to handle the Fragments inside SectionData
+ // correctly since they are truly used when output emission.
CIEList m_CIEs;
- FDEList m_FDEs;
+
+ // We need this map to find the corresponding CIE for FDE. Not all FDE point
+ // to the nearest CIE.
+ CIEMap m_FoundCIEs;
};
+bool operator==(const EhFrame::CIE&, const EhFrame::CIE&);
+
} // namespace of mcld
#endif
diff --git a/include/mcld/LD/EhFrameHdr.h b/include/mcld/LD/EhFrameHdr.h
index 3a5971d..2d7b0e9 100644
--- a/include/mcld/LD/EhFrameHdr.h
+++ b/include/mcld/LD/EhFrameHdr.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_EHFRAMEHDR_H
-#define MCLD_EHFRAMEHDR_H
+#ifndef MCLD_LD_EHFRAMEHDR_H
+#define MCLD_LD_EHFRAMEHDR_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -15,11 +15,11 @@
#include <cassert>
#include <mcld/LD/EhFrame.h>
+#include <mcld/Support/FileOutputBuffer.h>
namespace mcld {
class LDSection;
-class MemoryArea;
-class MemoryRegion;
+class FileOutputBuffer;
/** \class EhFrameHdr
* \brief EhFrameHdr represents .eh_frame_hdr section.
@@ -47,13 +47,14 @@
/// emitOutput - write out eh_frame_hdr
template<size_t size>
- void emitOutput(MemoryArea& pOutput)
+ void emitOutput(FileOutputBuffer& pOutput)
{ assert(false && "Call invalid EhFrameHdr::emitOutput"); }
private:
/// computePCBegin - return the address of FDE's pc
/// @ref binutils gold: ehframe.cc:222
- uint32_t computePCBegin(const EhFrame::FDE& pFDE, const MemoryRegion& pEhFrameRegion);
+ uint32_t computePCBegin(const EhFrame::FDE& pFDE,
+ const MemoryRegion& pEhFrameRegion);
private:
/// .eh_frame_hdr section
@@ -68,7 +69,7 @@
//===----------------------------------------------------------------------===//
/// emitOutput - write out eh_frame_hdr
template<>
-void EhFrameHdr::emitOutput<32>(MemoryArea& pOutput);
+void EhFrameHdr::emitOutput<32>(FileOutputBuffer& pOutput);
} // namespace of mcld
diff --git a/include/mcld/LD/EhFrameReader.h b/include/mcld/LD/EhFrameReader.h
index 1ac0351..509debf 100644
--- a/include/mcld/LD/EhFrameReader.h
+++ b/include/mcld/LD/EhFrameReader.h
@@ -6,17 +6,18 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_EH_FRAME_READER_H
-#define MCLD_EH_FRAME_READER_H
+#ifndef MCLD_LD_EHFRAMEREADER_H
+#define MCLD_LD_EHFRAMEREADER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
-#include <mcld/Support/MemoryRegion.h>
+#include <mcld/LD/EhFrame.h>
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/DataTypes.h>
namespace mcld {
class Input;
-class EhFrame;
class LDSection;
/** \class EhFrameReader
@@ -28,8 +29,8 @@
class EhFrameReader
{
public:
- typedef const uint8_t* ConstAddress;
- typedef uint8_t* Address;
+ typedef const char* ConstAddress;
+ typedef char* Address;
public:
/// read - read an .eh_frame section and create the corresponding
@@ -70,29 +71,29 @@
/// @param pSection - the input .eh_frame section
/// @param pRegion - the memory region that needs to handle with.
typedef bool (*Action)(EhFrame& pEhFrame,
- MemoryRegion& pRegion,
+ llvm::StringRef pRegion,
const Token& pToken);
private:
/// scan - scan pData from pHandler for a token.
- template<bool SAME_ENDIAN> Token
- scan(ConstAddress pHandler, uint64_t pOffset, const MemoryRegion& pData) const;
+ template<bool SAME_ENDIAN> Token scan(ConstAddress pHandler,
+ uint64_t pOffset,
+ llvm::StringRef pData) const;
static bool addCIE(EhFrame& pEhFrame,
- MemoryRegion& pRegion,
+ llvm::StringRef pRegion,
const Token& pToken);
static bool addFDE(EhFrame& pEhFrame,
- MemoryRegion& pRegion,
+ llvm::StringRef pRegion,
const Token& pToken);
static bool addTerm(EhFrame& pEhFrame,
- MemoryRegion& pRegion,
+ llvm::StringRef pRegion,
const Token& pToken);
static bool reject(EhFrame& pEhFrame,
- MemoryRegion& pRegion,
+ llvm::StringRef pRegion,
const Token& pToken);
-
};
template<> bool
@@ -101,7 +102,7 @@
template<> EhFrameReader::Token
EhFrameReader::scan<true>(ConstAddress pHandler,
uint64_t pOffset,
- const MemoryRegion& pData) const;
+ llvm::StringRef pData) const;
} // namespace of mcld
diff --git a/include/mcld/LD/GNUArchiveReader.h b/include/mcld/LD/GNUArchiveReader.h
index 7a33ff4..1c2e10a 100644
--- a/include/mcld/LD/GNUArchiveReader.h
+++ b/include/mcld/LD/GNUArchiveReader.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_GNU_ARCHIVE_READER_H
-#define MCLD_GNU_ARCHIVE_READER_H
+#ifndef MCLD_LD_GNUARCHIVEREADER_H
+#define MCLD_LD_GNUARCHIVEREADER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -20,8 +20,8 @@
class Module;
class Input;
class ELFObjectReader;
-class MemoryAreaFactory;
class Archive;
+class LinkerConfig;
/** \class GNUArchiveReader
* \brief GNUArchiveReader reads GNU archive files.
@@ -35,10 +35,10 @@
/// readArchive - read an archive, include the needed members, and build up
/// the subtree
- bool readArchive(Archive& pArchive);
+ bool readArchive(const LinkerConfig& pConfig, Archive& pArchive);
/// isMyFormat
- bool isMyFormat(Input& input) const;
+ bool isMyFormat(Input& input, bool &pContinue) const;
private:
/// isArchive
@@ -78,13 +78,16 @@
/// includeMember - include the object member in the given file offset, and
/// return the size of the object
+ /// @param pConfig - LinkerConfig
/// @param pArchiveRoot - the archive root
/// @param pFileOffset - file offset of the member header in the archive
- size_t includeMember(Archive& pArchiveRoot, uint32_t pFileOffset);
+ size_t includeMember(const LinkerConfig& pConfig,
+ Archive& pArchiveRoot,
+ uint32_t pFileOffset);
/// includeAllMembers - include all object members. This is called if
/// --whole-archive is the attribute for this archive file.
- bool includeAllMembers(Archive& pArchive);
+ bool includeAllMembers(const LinkerConfig& pConfig, Archive& pArchive);
private:
Module& m_Module;
diff --git a/include/mcld/LD/GarbageCollection.h b/include/mcld/LD/GarbageCollection.h
new file mode 100644
index 0000000..3476cd1
--- /dev/null
+++ b/include/mcld/LD/GarbageCollection.h
@@ -0,0 +1,94 @@
+//===- GarbageCollection.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LD_GARBAGECOLLECTION_H
+#define MCLD_LD_GARBAGECOLLECTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <map>
+#include <set>
+#include <vector>
+
+namespace mcld {
+
+class LDSection;
+class LinkerConfig;
+class Module;
+class TargetLDBackend;
+
+/** \class GarbageCollection
+ * \brief Implementation of garbage collection for --gc-section.
+ * @ref GNU gold, gc.
+ */
+class GarbageCollection
+{
+public:
+ typedef std::set<const LDSection*> SectionListTy;
+ typedef std::vector<const LDSection*> SectionVecTy;
+
+ /** \class SectionReachedListMap
+ * \brief Map the section to the list of sections which it can reach directly
+ */
+ class SectionReachedListMap
+ {
+ public:
+ SectionReachedListMap() {}
+
+ /// addReference - add a reference from pFrom to pTo
+ void addReference(const LDSection& pFrom, const LDSection& pTo);
+
+ /// getReachedList - get the list of sections which can be reached by
+ /// pSection, create one if the list has not existed
+ SectionListTy& getReachedList(const LDSection& pSection);
+
+ /// findReachedList - find the list of sections which can be reached by
+ /// pSection, return NULL if the list not exists
+ SectionListTy* findReachedList(const LDSection& pSection);
+
+ private:
+ typedef std::map<const LDSection*, SectionListTy> ReachedSectionsTy;
+
+ private:
+ /// m_ReachedSections - map a section to the reachable sections list
+ ReachedSectionsTy m_ReachedSections;
+ };
+
+public:
+ GarbageCollection(const LinkerConfig& pConfig,
+ const TargetLDBackend& pBackend,
+ Module& pModule);
+ ~GarbageCollection();
+
+ /// run - do garbage collection
+ bool run();
+
+private:
+ void setUpReachedSections();
+ void findReferencedSections(SectionVecTy& pEntry);
+ void getEntrySections(SectionVecTy& pEntry);
+ void stripSections();
+
+private:
+ /// m_SectionReachedListMap - map the section to the list of sections which it
+ /// can reach directly
+ SectionReachedListMap m_SectionReachedListMap;
+
+ /// m_ReferencedSections - a list of sections which can be reached from entry
+ SectionListTy m_ReferencedSections;
+
+ const LinkerConfig& m_Config;
+ const TargetLDBackend& m_Backend;
+ Module& m_Module;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/Group.h b/include/mcld/LD/Group.h
index 31c4a68..30e8f63 100644
--- a/include/mcld/LD/Group.h
+++ b/include/mcld/LD/Group.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef LD_GROUP_H
-#define LD_GROUP_H
+#ifndef MCLD_LD_GROUP_H
+#define MCLD_LD_GROUP_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/LD/GroupReader.h b/include/mcld/LD/GroupReader.h
index 01178a0..fa1e182 100644
--- a/include/mcld/LD/GroupReader.h
+++ b/include/mcld/LD/GroupReader.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_GROUPREADER_H
-#define MCLD_GROUPREADER_H
+#ifndef MCLD_LD_GROUPREADER_H
+#define MCLD_LD_GROUPREADER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -43,6 +43,7 @@
/// readGroup - handle the input sub-tree wich its root is pRoot
/// @param pRoot - the root Group node of the sub-tree
bool readGroup(Module::input_iterator pRoot,
+ Module::input_iterator pEnd,
InputBuilder& pBuilder,
const LinkerConfig& pConfig);
diff --git a/include/mcld/LD/LDContext.h b/include/mcld/LD/LDContext.h
index 3ab6ce1..c9f30ae 100644
--- a/include/mcld/LD/LDContext.h
+++ b/include/mcld/LD/LDContext.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LDCONTEXT_H
-#define MCLD_LDCONTEXT_H
+#ifndef MCLD_LD_LDCONTEXT_H
+#define MCLD_LD_LDCONTEXT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -72,6 +72,12 @@
void addSymbol(LDSymbol* pSym)
{ m_SymTab.push_back(pSym); }
+ const_sym_iterator symTabBegin() const { return m_SymTab.begin(); }
+ sym_iterator symTabBegin() { return m_SymTab.begin(); }
+
+ const_sym_iterator symTabEnd() const { return m_SymTab.end(); }
+ sym_iterator symTabEnd() { return m_SymTab.end(); }
+
// ----- relocations ----- //
const_sect_iterator relocSectBegin() const { return m_RelocSections.begin(); }
sect_iterator relocSectBegin() { return m_RelocSections.begin(); }
diff --git a/include/mcld/LD/LDFileFormat.h b/include/mcld/LD/LDFileFormat.h
index 4fa58ce..fb5ab63 100644
--- a/include/mcld/LD/LDFileFormat.h
+++ b/include/mcld/LD/LDFileFormat.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LDFILE_FORMAT_H
-#define MCLD_LDFILE_FORMAT_H
+#ifndef MCLD_LD_LDFILEFORMAT_H
+#define MCLD_LD_LDFILEFORMAT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/LD/LDReader.h b/include/mcld/LD/LDReader.h
index 4fde9f0..38bf24d 100644
--- a/include/mcld/LD/LDReader.h
+++ b/include/mcld/LD/LDReader.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_READER_INTERFACE_H
-#define MCLD_READER_INTERFACE_H
+#ifndef MCLD_LD_LDREADER_H
+#define MCLD_LD_LDREADER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -37,7 +37,7 @@
public:
virtual ~LDReader() { }
- virtual bool isMyFormat(Input& pInput) const = 0;
+ virtual bool isMyFormat(Input& pInput, bool &pContinue) const = 0;
};
diff --git a/include/mcld/LD/LDSymbol.h b/include/mcld/LD/LDSymbol.h
index b40213c..bebdd18 100644
--- a/include/mcld/LD/LDSymbol.h
+++ b/include/mcld/LD/LDSymbol.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LD_SYMBOL_H
-#define MCLD_LD_SYMBOL_H
+#ifndef MCLD_LD_LDSYMBOL_H
+#define MCLD_LD_LDSYMBOL_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -19,7 +19,12 @@
#include <mcld/LD/ResolveInfo.h>
#include <mcld/Support/Allocators.h>
-#include <llvm/Support/ManagedStatic.h>
+namespace llvm {
+
+// forware declaration
+template<class T> void* object_creator();
+
+} // namespace of llvm
namespace mcld {
diff --git a/include/mcld/LD/MsgHandler.h b/include/mcld/LD/MsgHandler.h
index 9b1ed80..62def8e 100644
--- a/include/mcld/LD/MsgHandler.h
+++ b/include/mcld/LD/MsgHandler.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_MESSAGE_HANDLER_H
-#define MCLD_MESSAGE_HANDLER_H
+#ifndef MCLD_LD_MSGHANDLER_H
+#define MCLD_LD_MSGHANDLER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/LD/NamePool.h b/include/mcld/LD/NamePool.h
index 32354ea..7a8f816 100644
--- a/include/mcld/LD/NamePool.h
+++ b/include/mcld/LD/NamePool.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_NAME_POOL_H
-#define MCLD_NAME_POOL_H
+#ifndef MCLD_LD_NAMEPOOL_H
+#define MCLD_LD_NAMEPOOL_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -38,7 +38,14 @@
class NamePool : private Uncopyable
{
public:
- typedef HashTable<ResolveInfo, hash::StringHash<hash::ELF> > Table;
+ typedef HashTable<ResolveInfo, hash::StringHash<hash::DJB> > Table;
+ typedef Table::iterator syminfo_iterator;
+ typedef Table::const_iterator const_syminfo_iterator;
+
+ typedef GCFactory<ResolveInfo*, 128> FreeInfoSet;
+ typedef FreeInfoSet::iterator freeinfo_iterator;
+ typedef FreeInfoSet::const_iterator const_freeinfo_iterator;
+
typedef size_t size_type;
public:
@@ -56,7 +63,7 @@
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.
@@ -69,6 +76,7 @@
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBinding,
ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
ResolveInfo::Visibility pVisibility,
ResolveInfo* pOldInfo,
Resolver::Result& pResult);
@@ -93,15 +101,39 @@
bool empty() const
{ return m_Table.empty(); }
+ // syminfo_iterator - traverse the ResolveInfo in the resolved HashTable
+ syminfo_iterator syminfo_begin()
+ { return m_Table.begin(); }
+
+ syminfo_iterator syminfo_end()
+ { return m_Table.end(); }
+
+ const_syminfo_iterator syminfo_begin() const
+ { return m_Table.begin(); }
+
+ const_syminfo_iterator syminfo_end() const
+ { return m_Table.end(); }
+
+ // freeinfo_iterator - traverse the ResolveInfo those do not need to be
+ // resolved, for example, local symbols
+ freeinfo_iterator freeinfo_begin()
+ { return m_FreeInfoSet.begin(); }
+
+ freeinfo_iterator freeinfo_end()
+ { return m_FreeInfoSet.end(); }
+
+ const_freeinfo_iterator freeinfo_begin() const
+ { return m_FreeInfoSet.begin(); }
+
+ const_freeinfo_iterator freeinfo_end() const
+ { return m_FreeInfoSet.end(); }
+
// ----- capacity ----- //
void reserve(size_type pN);
size_type capacity() const;
private:
- typedef GCFactory<ResolveInfo*, 128> FreeInfoSet;
-
-private:
Resolver* m_pResolver;
Table m_Table;
FreeInfoSet m_FreeInfoSet;
diff --git a/include/mcld/LD/ObjectReader.h b/include/mcld/LD/ObjectReader.h
index 2ca3173..34427f8 100644
--- a/include/mcld/LD/ObjectReader.h
+++ b/include/mcld/LD/ObjectReader.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_OBJECT_READER_H
-#define MCLD_OBJECT_READER_H
+#ifndef MCLD_LD_OBJECTREADER_H
+#define MCLD_LD_OBJECTREADER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -29,7 +29,7 @@
class ObjectReader : public LDReader
{
protected:
- typedef HashTable<ResolveInfo, hash::StringHash<hash::ELF> > GroupSignatureMap;
+ typedef HashTable<ResolveInfo, hash::StringHash<hash::DJB> > GroupSignatureMap;
protected:
ObjectReader()
diff --git a/include/mcld/LD/ObjectWriter.h b/include/mcld/LD/ObjectWriter.h
index c1dcac6..2a42aed 100644
--- a/include/mcld/LD/ObjectWriter.h
+++ b/include/mcld/LD/ObjectWriter.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_OBJECT_WRITER_INTERFACE_H
-#define MCLD_OBJECT_WRITER_INTERFACE_H
+#ifndef MCLD_LD_OBJECTWRITER_H
+#define MCLD_LD_OBJECTWRITER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -16,7 +16,7 @@
namespace mcld {
class Module;
-class MemoryArea;
+class FileOutputBuffer;
/** \class ObjectWriter
* \brief ObjectWriter provides a common interface for object file writers.
@@ -29,7 +29,10 @@
public:
virtual ~ObjectWriter();
- virtual llvm::error_code writeObject(Module& pModule, MemoryArea& pOutput) = 0;
+ virtual llvm::error_code writeObject(Module& pModule,
+ FileOutputBuffer& pOutput) = 0;
+
+ virtual size_t getOutputSize(const Module& pModule) const = 0;
};
} // namespace of mcld
diff --git a/include/mcld/LD/RelocData.h b/include/mcld/LD/RelocData.h
index b53151a..68bc7e1 100644
--- a/include/mcld/LD/RelocData.h
+++ b/include/mcld/LD/RelocData.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_RELOCATION_DATA_H
-#define MCLD_RELOCATION_DATA_H
+#ifndef MCLD_LD_RELOCDATA_H
+#define MCLD_LD_RELOCDATA_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -21,6 +21,8 @@
#include <llvm/ADT/ilist_node.h>
#include <llvm/Support/DataTypes.h>
+#include <list>
+
namespace mcld {
class LDSection;
@@ -73,6 +75,7 @@
bool empty() const { return m_Relocations.empty(); }
RelocData& append(Relocation& pRelocation);
+ Relocation& remove(Relocation& pRelocation);
reference front () { return m_Relocations.front(); }
const_reference front () const { return m_Relocations.front(); }
@@ -88,6 +91,18 @@
const_reverse_iterator rend () const { return m_Relocations.rend(); }
reverse_iterator rend () { return m_Relocations.rend(); }
+ template<class Comparator> void sort(Comparator pComparator) {
+ /* FIXME: use llvm::iplist::sort */
+ std::list<Relocation*> relocs;
+ for (iterator it = begin(), ie = end(); it != ie; ++it)
+ relocs.push_back(it);
+ relocs.sort(pComparator);
+ m_Relocations.clear();
+ for (std::list<Relocation*>::iterator it = relocs.begin(),
+ ie = relocs.end(); it != ie; ++it)
+ m_Relocations.push_back(*it);
+ }
+
private:
RelocationListType m_Relocations;
LDSection* m_pSection;
diff --git a/include/mcld/LD/Relocator.h b/include/mcld/LD/Relocator.h
index 54ea7e8..2828a5b 100644
--- a/include/mcld/LD/Relocator.h
+++ b/include/mcld/LD/Relocator.h
@@ -61,10 +61,21 @@
/// @param pReloc - a read in relocation entry
/// @param pInputSym - the input LDSymbol of relocation target symbol
/// @param pSection - the section of relocation applying target
+ /// @param pInput - the input file of relocation
virtual void scanRelocation(Relocation& pReloc,
IRBuilder& pBuilder,
Module& pModule,
- LDSection& pSection) = 0;
+ LDSection& pSection,
+ Input& pInput) = 0;
+
+ /// issueUndefRefError - Provides a basic version for undefined reference dump.
+ /// It will handle the filename and function name automatically.
+ /// @param pReloc - a read in relocation entry
+ /// @param pSection - the section of relocation applying target
+ /// @ param pInput - the input file of relocation
+ virtual void issueUndefRef(Relocation& pReloc,
+ LDSection& pSection,
+ Input& pInput);
/// initializeScan - do initialization before scan relocations in pInput
/// @return - return true for initialization success
diff --git a/include/mcld/LD/ResolveInfo.h b/include/mcld/LD/ResolveInfo.h
index 6f28169..9616719 100644
--- a/include/mcld/LD/ResolveInfo.h
+++ b/include/mcld/LD/ResolveInfo.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_RESOLVE_INFO_H
-#define MCLD_RESOLVE_INFO_H
+#ifndef MCLD_LD_RESOLVEINFO_H
+#define MCLD_LD_RESOLVEINFO_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -18,6 +18,7 @@
namespace mcld {
class LDSymbol;
+class LinkerConfig;
/** \class ResolveInfo
* \brief ResolveInfo records the information about how to resolve a symbol.
@@ -142,6 +143,10 @@
m_BitField |= indirect_flag;
}
+ /// setInDyn - set if the symbol has been seen in the dynamic objects. Once
+ /// InDyn set, then it won't be set back to false
+ void setInDyn();
+
// ----- observers ----- //
bool isNull() const;
@@ -167,6 +172,8 @@
bool isIndirect() const;
+ bool isInDyn() const;
+
uint32_t type() const;
uint32_t desc() const;
@@ -207,6 +214,9 @@
uint32_t bitfield() const
{ return m_BitField; }
+ // shouldForceLocal - check if this symbol should be forced to local
+ bool shouldForceLocal(const LinkerConfig& pConfig);
+
// ----- For HashTable ----- //
bool compare(const key_type& pKey);
@@ -236,7 +246,11 @@
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 IN_DYN_OFFSET = 16;
+ static const uint32_t IN_DYN_MASK = 1 << IN_DYN_OFFSET;
+
+ static const uint32_t NAME_LENGTH_OFFSET = 17;
static const uint32_t INFO_MASK = 0xF;
static const uint32_t RESOLVE_MASK = 0xFFFF;
@@ -262,6 +276,7 @@
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;
+ static const uint32_t indyn_flag = 1 << IN_DYN_OFFSET;
private:
ResolveInfo();
@@ -274,8 +289,8 @@
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|
+ * 31 ... 17 16 15 12 11 10..7 6 .. 5 4 3 2 1 0
+ * |length of m_Name|InDyn|reserved|Symbol|Type |ELF visibility|Local|Com|Def|Dyn|Weak|
*/
uint32_t m_BitField;
char m_Name[];
diff --git a/include/mcld/LD/Resolver.h b/include/mcld/LD/Resolver.h
index d506a2d..069a167 100644
--- a/include/mcld/LD/Resolver.h
+++ b/include/mcld/LD/Resolver.h
@@ -6,13 +6,14 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_SYMBOL_RESOLVER_H
-#define MCLD_SYMBOL_RESOLVER_H
+#ifndef MCLD_LD_RESOLVER_H
+#define MCLD_LD_RESOLVER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <string>
#include <utility>
+#include <mcld/LD/LDSymbol.h>
namespace mcld
{
@@ -59,7 +60,7 @@
/// @param pNew the symbol which is used to replace pOld
virtual bool resolve(ResolveInfo & __restrict__ pOld,
const ResolveInfo & __restrict__ pNew,
- bool &pOverride) const = 0;
+ bool &pOverride, LDSymbol::ValueType pValue) const = 0;
/// resolveAgain - Can override by derived classes.
/// @return the pointer to resolved ResolveInfo
diff --git a/include/mcld/LD/SectionData.h b/include/mcld/LD/SectionData.h
index 4f58afa..0a74961 100644
--- a/include/mcld/LD/SectionData.h
+++ b/include/mcld/LD/SectionData.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LD_SECTION_DATA_H
-#define MCLD_LD_SECTION_DATA_H
+#ifndef MCLD_LD_SECTIONDATA_H
+#define MCLD_LD_SECTIONDATA_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/LD/SectionSymbolSet.h b/include/mcld/LD/SectionSymbolSet.h
index 801fe37..fe814a7 100644
--- a/include/mcld/LD/SectionSymbolSet.h
+++ b/include/mcld/LD/SectionSymbolSet.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_SECTIONSYMBOLSET_H
-#define MCLD_SECTIONSYMBOLSET_H
+#ifndef MCLD_LD_SECTIONSYMBOLSET_H
+#define MCLD_LD_SECTIONSYMBOLSET_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/LD/StaticResolver.h b/include/mcld/LD/StaticResolver.h
index 9fc6104..586e44d 100644
--- a/include/mcld/LD/StaticResolver.h
+++ b/include/mcld/LD/StaticResolver.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_STATIC_SYMBOL_RESOLVER_H
-#define MCLD_STATIC_SYMBOL_RESOLVER_H
+#ifndef MCLD_LD_STATICRESOLVER_H
+#define MCLD_LD_STATICRESOLVER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -111,7 +111,7 @@
/// @param pNew the symbol which is used to replace pOld
virtual bool resolve(ResolveInfo & __restrict__ pOld,
const ResolveInfo & __restrict__ pNew,
- bool &pOverride) const;
+ bool &pOverride, LDSymbol::ValueType pValue) const;
private:
inline unsigned int getOrdinate(const ResolveInfo& pInfo) const {
diff --git a/include/mcld/LD/StubFactory.h b/include/mcld/LD/StubFactory.h
index 8548e5a..4298c16 100644
--- a/include/mcld/LD/StubFactory.h
+++ b/include/mcld/LD/StubFactory.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LD_STUB_FACTORY_H
-#define MCLD_LD_STUB_FACTORY_H
+#ifndef MCLD_LD_STUBFACTORY_H
+#define MCLD_LD_STUBFACTORY_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/LD/TextDiagnosticPrinter.h b/include/mcld/LD/TextDiagnosticPrinter.h
index 3e7d4c4..6400fa2 100644
--- a/include/mcld/LD/TextDiagnosticPrinter.h
+++ b/include/mcld/LD/TextDiagnosticPrinter.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_TEXT_DIAGNOSTIC_PRINTER_H
-#define MCLD_TEXT_DIAGNOSTIC_PRINTER_H
+#ifndef MCLD_LD_TEXTDIAGNOSTICPRINTER_H
+#define MCLD_LD_TEXTDIAGNOSTICPRINTER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Linker.h b/include/mcld/Linker.h
index 83eb295..80f6586 100644
--- a/include/mcld/Linker.h
+++ b/include/mcld/Linker.h
@@ -27,7 +27,7 @@
class ObjectLinker;
class FileHandle;
-class MemoryArea;
+class FileOutputBuffer;
/** \class Linker
* \brief Linker is a modular linker.
@@ -46,7 +46,7 @@
bool normalize(Module& pModule, IRBuilder& pBuilder);
/// resolve - To build up the topology of mcld::Module.
- bool resolve();
+ bool resolve(Module& pModule);
/// layout - To serialize the final result of the output mcld::Module.
bool layout();
@@ -54,15 +54,15 @@
/// link - A convenient way to resolve and to layout the output mcld::Module.
bool link(Module& pModule, IRBuilder& pBuilder);
- /// emit - To emit output mcld::Module to a output MemoryArea
- bool emit(MemoryArea& pOutput);
+ /// emit - To emit output mcld::Module to a FileOutputBuffer.
+ bool emit(FileOutputBuffer& pOutput);
/// emit - To open a file for output in pPath and to emit output mcld::Module
/// to the file.
- bool emit(const std::string& pPath);
+ bool emit(const Module& pModule, const std::string& pPath);
/// emit - To emit output mcld::Module in the pFileDescriptor.
- bool emit(int pFileDescriptor);
+ bool emit(const Module& pModule, int pFileDescriptor);
bool reset();
diff --git a/include/mcld/LinkerConfig.h b/include/mcld/LinkerConfig.h
index 96dd5dc..a41be39 100644
--- a/include/mcld/LinkerConfig.h
+++ b/include/mcld/LinkerConfig.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LINKER_CONFIG_H
-#define MCLD_LINKER_CONFIG_H
+#ifndef MCLD_LINKERCONFIG_H
+#define MCLD_LINKERCONFIG_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/LinkerScript.h b/include/mcld/LinkerScript.h
index 91e4bdb..bdd0917 100644
--- a/include/mcld/LinkerScript.h
+++ b/include/mcld/LinkerScript.h
@@ -6,21 +6,26 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LINKER_SCRIPT_H
-#define MCLD_LINKER_SCRIPT_H
+#ifndef MCLD_LINKERSCRIPT_H
+#define MCLD_LINKERSCRIPT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <string>
+#include <vector>
#include <llvm/ADT/StringRef.h>
#include <mcld/ADT/StringEntry.h>
#include <mcld/ADT/StringHash.h>
#include <mcld/ADT/HashTable.h>
#include <mcld/Object/SectionMap.h>
#include <mcld/MC/SearchDirs.h>
+#include <mcld/Script/Assignment.h>
+#include <mcld/Script/AssertCmd.h>
namespace mcld {
+class LDSymbol;
+
/** \class LinkerScript
*
*/
@@ -28,16 +33,16 @@
{
public:
typedef HashTable<StringEntry<llvm::StringRef>,
- hash::StringHash<hash::ELF>,
+ hash::StringHash<hash::DJB>,
StringEntryFactory<llvm::StringRef> > SymbolRenameMap;
typedef HashTable<StringEntry<uint64_t>,
- hash::StringHash<hash::ELF>,
+ hash::StringHash<hash::DJB>,
StringEntryFactory<uint64_t> > AddressMap;
- typedef HashTable<StringEntry<llvm::StringRef>,
- hash::StringHash<hash::ELF>,
- StringEntryFactory<llvm::StringRef> > DefSymMap;
+ typedef std::vector<std::pair<LDSymbol*, Assignment> > Assignments;
+
+ typedef std::vector<AssertCmd> Assertions;
public:
LinkerScript();
@@ -53,8 +58,11 @@
const SectionMap& sectionMap() const { return m_SectionMap; }
SectionMap& sectionMap() { return m_SectionMap; }
- const DefSymMap& defSymMap() const { return m_DefSymMap; }
- DefSymMap& defSymMap() { return m_DefSymMap; }
+ const Assignments& assignments() const { return m_Assignments; }
+ Assignments& assignments() { return m_Assignments; }
+
+ const Assertions& assertions() const { return m_Assertions; }
+ Assertions& assertions() { return m_Assertions; }
/// search directory
const SearchDirs& directories() const { return m_SearchDirs; }
@@ -67,12 +75,29 @@
bool hasSysroot() const;
+ /// entry point
+ const std::string& entry() const;
+
+ void setEntry(const std::string& pEntry);
+
+ bool hasEntry() const;
+
+ /// output filename
+ const std::string& outputFile() const;
+
+ void setOutputFile(const std::string& pOutputFile);
+
+ bool hasOutputFile() const;
+
private:
SymbolRenameMap m_SymbolRenames;
AddressMap m_AddressMap;
SectionMap m_SectionMap;
- DefSymMap m_DefSymMap;
+ Assignments m_Assignments;
+ Assertions m_Assertions;
SearchDirs m_SearchDirs;
+ std::string m_Entry;
+ std::string m_OutputFile;
};
} // namespace of mcld
diff --git a/include/mcld/MC/Attribute.h b/include/mcld/MC/Attribute.h
index 11f6d26..a7c7176 100644
--- a/include/mcld/MC/Attribute.h
+++ b/include/mcld/MC/Attribute.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ATTRIBUTE_H
-#define MCLD_ATTRIBUTE_H
+#ifndef MCLD_MC_ATTRIBUTE_H
+#define MCLD_MC_ATTRIBUTE_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/MC/AttributeSet.h b/include/mcld/MC/AttributeSet.h
index e50384d..97b20a9 100644
--- a/include/mcld/MC/AttributeSet.h
+++ b/include/mcld/MC/AttributeSet.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ATTRIBUTE_SET_H
-#define MCLD_ATTRIBUTE_SET_H
+#ifndef MCLD_MC_ATTRIBUTESET_H
+#define MCLD_MC_ATTRIBUTESET_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/MC/CommandAction.h b/include/mcld/MC/CommandAction.h
index a0ff909..19f74fd 100644
--- a/include/mcld/MC/CommandAction.h
+++ b/include/mcld/MC/CommandAction.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_MC_COMMAND_ACTION_H
-#define MCLD_MC_COMMAND_ACTION_H
+#ifndef MCLD_MC_COMMANDACTION_H
+#define MCLD_MC_COMMANDACTION_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -15,11 +15,13 @@
#include <string>
#include <mcld/Support/Path.h>
#include <mcld/MC/InputAction.h>
+#include <mcld/Script/ScriptFile.h>
namespace mcld {
class SearchDirs;
class InputBuilder;
+class LinkerConfig;
//===----------------------------------------------------------------------===//
// Derived InputAction
@@ -44,7 +46,7 @@
public:
NamespecAction(unsigned int pPosition,
const std::string &pNamespec,
- SearchDirs& pSearchDirs);
+ const SearchDirs& pSearchDirs);
const std::string &namespec() const { return m_Namespec; }
@@ -52,7 +54,7 @@
private:
std::string m_Namespec;
- SearchDirs& m_SearchDirs;
+ const SearchDirs& m_SearchDirs;
};
/// BitcodeAction
@@ -159,6 +161,41 @@
bool activate(InputBuilder&) const;
};
+/// DefSymAction
+class DefSymAction : public InputAction
+{
+public:
+ explicit DefSymAction(unsigned int pPosition, std::string& pAssignment);
+
+ bool activate(InputBuilder&) const;
+
+ const std::string& assignment() const { return m_Assignment; }
+
+private:
+ std::string& m_Assignment;
+};
+
+/// ScriptAction
+class ScriptAction : public InputAction
+{
+public:
+ ScriptAction(unsigned int pPosition,
+ const std::string& pFileName,
+ ScriptFile::Kind pKind,
+ const SearchDirs& pSearchDirs);
+
+ bool activate(InputBuilder&) const;
+
+ const std::string& filename() const { return m_FileName; }
+
+ ScriptFile::Kind kind() const { return m_Kind; }
+
+private:
+ std::string m_FileName;
+ ScriptFile::Kind m_Kind;
+ const SearchDirs& m_SearchDirs;
+};
+
} // end of namespace mcld
#endif
diff --git a/include/mcld/MC/ContextFactory.h b/include/mcld/MC/ContextFactory.h
index dde2627..169dbfa 100644
--- a/include/mcld/MC/ContextFactory.h
+++ b/include/mcld/MC/ContextFactory.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_CONTEXT_FACTORY_H
-#define MCLD_CONTEXT_FACTORY_H
+#ifndef MCLD_MC_CONTEXTFACTORY_H
+#define MCLD_MC_CONTEXTFACTORY_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/MC/FileAction.h b/include/mcld/MC/FileAction.h
index 4644405..269c700 100644
--- a/include/mcld/MC/FileAction.h
+++ b/include/mcld/MC/FileAction.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_MC_FILE_ACTION_H
-#define MCLD_MC_FILE_ACTION_H
+#ifndef MCLD_MC_FILEACTION_H
+#define MCLD_MC_FILEACTION_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -17,7 +17,6 @@
namespace mcld {
class ContextFactory;
-class MemoryAreaFactory;
/** \class ContextAction
* \brief ContextAction is a command object to create input's LDContext.
diff --git a/include/mcld/MC/MCLDInput.h b/include/mcld/MC/Input.h
similarity index 95%
rename from include/mcld/MC/MCLDInput.h
rename to include/mcld/MC/Input.h
index 94b9479..a8e9c35 100644
--- a/include/mcld/MC/MCLDInput.h
+++ b/include/mcld/MC/Input.h
@@ -1,4 +1,4 @@
-//===- MCLDInput.h --------------------------------------------------------===//
+//===- Input.h ------------------------------------------------------------===//
//
// The MCLinker Project
//
@@ -10,8 +10,8 @@
// Input class inherits MCLDFile, which is used to represent a input file
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_INPUT_H
-#define MCLD_INPUT_H
+#ifndef MCLD_MC_INPUT_H
+#define MCLD_MC_INPUT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -35,6 +35,7 @@
public:
enum Type {
Unknown,
+ Binary,
Object,
Exec,
DynObj,
diff --git a/include/mcld/MC/InputAction.h b/include/mcld/MC/InputAction.h
index fb7d660..4b94378 100644
--- a/include/mcld/MC/InputAction.h
+++ b/include/mcld/MC/InputAction.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_MC_INPUT_ACTION_H
-#define MCLD_MC_INPUT_ACTION_H
+#ifndef MCLD_MC_INPUTACTION_H
+#define MCLD_MC_INPUTACTION_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/MC/InputBuilder.h b/include/mcld/MC/InputBuilder.h
index 0301c15..1b2e8b9 100644
--- a/include/mcld/MC/InputBuilder.h
+++ b/include/mcld/MC/InputBuilder.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_MC_INPUT_BUILDER_H
-#define MCLD_MC_INPUT_BUILDER_H
+#ifndef MCLD_MC_INPUTBUILDER_H
+#define MCLD_MC_INPUTBUILDER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -16,7 +16,7 @@
#include <stack>
#include <mcld/InputTree.h>
-#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/Input.h>
#include <mcld/Support/FileHandle.h>
namespace mcld {
@@ -26,7 +26,6 @@
class ContextFactory;
class MemoryAreaFactory;
class AttrConstraint;
-class raw_mem_ostream;
/** \class InputBuilder
* \brief InputBuilder recieves InputActions and build the InputTree.
diff --git a/include/mcld/MC/InputFactory.h b/include/mcld/MC/InputFactory.h
index d644222..8c73d0b 100644
--- a/include/mcld/MC/InputFactory.h
+++ b/include/mcld/MC/InputFactory.h
@@ -6,13 +6,13 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_INPUT_FACTORY_H
-#define MCLD_INPUT_FACTORY_H
+#ifndef MCLD_MC_INPUTFACTORY_H
+#define MCLD_MC_INPUTFACTORY_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <mcld/Support/GCFactory.h>
-#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/Input.h>
namespace mcld {
diff --git a/include/mcld/MC/MCLDDirectory.h b/include/mcld/MC/MCLDDirectory.h
index 988f9d3..77692c0 100644
--- a/include/mcld/MC/MCLDDirectory.h
+++ b/include/mcld/MC/MCLDDirectory.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_MCLDDIRECTORY_H
-#define MCLD_MCLDDIRECTORY_H
+#ifndef MCLD_MC_MCLDDIRECTORY_H
+#define MCLD_MC_MCLDDIRECTORY_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/MC/SearchDirs.h b/include/mcld/MC/SearchDirs.h
index 0c0c657..a3bcf39 100644
--- a/include/mcld/MC/SearchDirs.h
+++ b/include/mcld/MC/SearchDirs.h
@@ -12,7 +12,7 @@
#include <gtest.h>
#endif
#include <mcld/ADT/Uncopyable.h>
-#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/Input.h>
#include <mcld/Support/Path.h>
#include <llvm/ADT/StringRef.h>
diff --git a/include/mcld/MC/SymbolCategory.h b/include/mcld/MC/SymbolCategory.h
index 61c015e..9ecc5b9 100644
--- a/include/mcld/MC/SymbolCategory.h
+++ b/include/mcld/MC/SymbolCategory.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_SYMBOL_CATEGORY_H
-#define MCLD_SYMBOL_CATEGORY_H
+#ifndef MCLD_MC_SYMBOLCATEGORY_H
+#define MCLD_MC_SYMBOLCATEGORY_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/MC/ZOption.h b/include/mcld/MC/ZOption.h
index e451734..d9cd635 100644
--- a/include/mcld/MC/ZOption.h
+++ b/include/mcld/MC/ZOption.h
@@ -6,15 +6,15 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ZOPTION_H
-#define MCLD_ZOPTION_H
+#ifndef MCLD_MC_ZOPTION_H
+#define MCLD_MC_ZOPTION_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
+
#include <llvm/Support/DataTypes.h>
-namespace mcld
-{
+namespace mcld {
/** \class ZOption
* \brief The -z options for GNU ld compatibility.
@@ -50,19 +50,13 @@
public:
ZOption();
- ~ZOption();
+ Kind kind() const { return m_Kind; }
- Kind kind() const
- { return m_Kind; }
+ void setKind(Kind pKind) { m_Kind = pKind; }
- uint64_t pageSize() const
- { return m_PageSize; }
+ uint64_t pageSize() const { return m_PageSize; }
- void setKind(Kind pKind)
- { m_Kind = pKind; }
-
- void setPageSize(uint64_t pPageSize)
- { m_PageSize = pPageSize; }
+ void setPageSize(uint64_t pPageSize) { m_PageSize = pPageSize; }
private:
Kind m_Kind;
diff --git a/include/mcld/Module.h b/include/mcld/Module.h
index 9ea9812..9dfb59e 100644
--- a/include/mcld/Module.h
+++ b/include/mcld/Module.h
@@ -16,25 +16,18 @@
#include <gtest.h>
#endif
-#include <vector>
-#include <string>
-#include <map>
-
-#include <mcld/LinkerScript.h>
#include <mcld/InputTree.h>
-#include <mcld/ADT/HashTable.h>
-#include <mcld/ADT/HashEntry.h>
-#include <mcld/Support/GCFactoryListTraits.h>
-#include <mcld/Fragment/Fragment.h>
#include <mcld/LD/NamePool.h>
#include <mcld/LD/SectionSymbolSet.h>
#include <mcld/MC/SymbolCategory.h>
-#include <mcld/MC/MCLDInput.h>
-#include <llvm/ADT/ilist.h>
+#include <vector>
+#include <string>
namespace mcld {
+class Input;
+class LinkerScript;
class LDSection;
class LDSymbol;
diff --git a/include/mcld/Object/ObjectBuilder.h b/include/mcld/Object/ObjectBuilder.h
index 79f81a5..ec80528 100644
--- a/include/mcld/Object/ObjectBuilder.h
+++ b/include/mcld/Object/ObjectBuilder.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_OBJECT_OBJECT_BUILDER_H
-#define MCLD_OBJECT_OBJECT_BUILDER_H
+#ifndef MCLD_OBJECT_OBJECTBUILDER_H
+#define MCLD_OBJECT_OBJECTBUILDER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -27,6 +27,7 @@
class RelocData;
class Fragment;
class Relocation;
+class Input;
/** \class ObjectBuilder
* \brief ObjectBuilder recieve ObjectAction and build the mcld::Module.
@@ -67,7 +68,7 @@
/// @param [in] pInputSection The merged input section.
/// @return The merged output section. If the corresponding output sections
/// is not defined, return NULL.
- LDSection* MergeSection(LDSection& pInputSection);
+ LDSection* MergeSection(const Input& pInputFile, LDSection& pInputSection);
/// MoveSectionData - move the fragment of pFrom to pTo section data.
static bool MoveSectionData(SectionData& pFrom, SectionData& pTo);
diff --git a/include/mcld/Object/ObjectLinker.h b/include/mcld/Object/ObjectLinker.h
index 128cf64..5c8c5cc 100644
--- a/include/mcld/Object/ObjectLinker.h
+++ b/include/mcld/Object/ObjectLinker.h
@@ -6,39 +6,34 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-//
-// ObjectLinker plays the same role as GNU collect2 to prepare all implicit
-// parameters for FragmentLinker.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_OBJECT_OBJECT_LINKER_H
-#define MCLD_OBJECT_OBJECT_LINKER_H
+#ifndef MCLD_OBJECT_OBJECTLINKER_H
+#define MCLD_OBJECT_OBJECTLINKER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
-#include <stddef.h>
+#include <llvm/Support/DataTypes.h>
namespace mcld {
class Module;
class LinkerConfig;
class IRBuilder;
-class FragmentLinker;
class TargetLDBackend;
-class MemoryArea;
-class MemoryAreaFactory;
+class FileOutputBuffer;
class ObjectReader;
class DynObjReader;
class ArchiveReader;
class GroupReader;
class BinaryReader;
+class ScriptReader;
class ObjectWriter;
class DynObjWriter;
class ExecWriter;
class BinaryWriter;
+class Relocation;
+class ResolveInfo;
/** \class ObjectLinker
- * \brief ObjectLinker prepares parameters for FragmentLinker.
*/
class ObjectLinker
{
@@ -48,11 +43,7 @@
~ObjectLinker();
- void setup(Module& pModule, IRBuilder& pBuilder);
-
- /// initFragmentLinker - initialize FragmentLinker
- /// Connect all components in FragmentLinker
- bool initFragmentLinker();
+ bool initialize(Module& pModule, IRBuilder& pBuilder);
/// initStdSections - initialize standard sections of the output file.
bool initStdSections();
@@ -69,9 +60,16 @@
/// readRelocations - read all relocation entries
bool readRelocations();
+ /// dataStrippingOpt - optimizations for reducing code size
+ void dataStrippingOpt();
+
/// mergeSections - put allinput sections into output sections
bool mergeSections();
+ /// addSymbolsToOutput - after all symbols has been resolved, add the symbol
+ /// to output
+ void addSymbolsToOutput(Module& pModule);
+
/// allocateCommonSymobols - allocate fragments for common symbols to the
/// corresponding sections
bool allocateCommonSymbols();
@@ -122,18 +120,10 @@
bool finalizeSymbolValue();
/// emitOutput - emit the output file.
- bool emitOutput(MemoryArea& pOutput);
+ bool emitOutput(FileOutputBuffer& pOutput);
/// postProcessing - do modificatiion after all processes
- bool postProcessing(MemoryArea& pOutput);
-
- /// getLinker - get internal FragmentLinker object
- const FragmentLinker* getLinker() const { return m_pLinker; }
- FragmentLinker* getLinker() { return m_pLinker; }
-
- /// hasInitLinker - has Linker been initialized?
- bool hasInitLinker() const
- { return (NULL != m_pLinker); }
+ bool postProcessing(FileOutputBuffer& pOutput);
// ----- readers and writers ----- //
const ObjectReader* getObjectReader () const { return m_pObjectReader; }
@@ -151,12 +141,31 @@
const BinaryReader* getBinaryReader () const { return m_pBinaryReader; }
BinaryReader* getBinaryReader () { return m_pBinaryReader; }
+ const ScriptReader* getScriptReader () const { return m_pScriptReader; }
+ ScriptReader* getScriptReader () { return m_pScriptReader; }
+
const ObjectWriter* getWriter () const { return m_pWriter; }
ObjectWriter* getWriter () { return m_pWriter; }
private:
+ /// normalSyncRelocationResult - sync relocation result when producing shared
+ /// objects or executables
+ void normalSyncRelocationResult(FileOutputBuffer& pOutput);
+
+ /// partialSyncRelocationResult - sync relocation result when doing partial
+ /// link
+ void partialSyncRelocationResult(FileOutputBuffer& pOutput);
+
+ /// writeRelocationResult - helper function of syncRelocationResult, write
+ /// relocation target data to output
+ void writeRelocationResult(Relocation& pReloc, uint8_t* pOutput);
+
+ /// addSymbolToOutput - add a symbol to output symbol table if it's not a
+ /// section symbol and not defined in the discarded section
+ void addSymbolToOutput(ResolveInfo& pInfo, Module& pModule);
+
+private:
const LinkerConfig& m_Config;
- FragmentLinker* m_pLinker;
Module* m_pModule;
IRBuilder* m_pBuilder;
@@ -168,6 +177,7 @@
ArchiveReader* m_pArchiveReader;
GroupReader* m_pGroupReader;
BinaryReader* m_pBinaryReader;
+ ScriptReader* m_pScriptReader;
ObjectWriter* m_pWriter;
};
diff --git a/include/mcld/Object/SectionMap.h b/include/mcld/Object/SectionMap.h
index 37df4a3..e6e779d 100644
--- a/include/mcld/Object/SectionMap.h
+++ b/include/mcld/Object/SectionMap.h
@@ -6,82 +6,206 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_SECTION_MAP_H
-#define MCLD_SECTION_MAP_H
+#ifndef MCLD_OBJECT_SECTIONMAP_H
+#define MCLD_OBJECT_SECTIONMAP_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
+#include <mcld/Script/OutputSectDesc.h>
+#include <mcld/Script/InputSectDesc.h>
+#include <mcld/Script/Assignment.h>
+#include <llvm/Support/DataTypes.h>
#include <vector>
#include <string>
-#include <llvm/Support/DataTypes.h>
-
namespace mcld {
+class Fragment;
+class LDSection;
+
/** \class SectionMap
- * \brief descirbe the mappings of input section's name (or prefix) to
- * its associated output section's name and offset
+ * \brief descirbe how to map input sections into output sections
*/
class SectionMap
{
public:
- // a mapping in SectionMap is the triple of
- // {input substr, output section's name, output section's offset}
- struct NamePair
- {
+ class Input {
public:
- NamePair();
- NamePair(const std::string& pFrom, const std::string& pTo);
+ typedef std::vector<std::pair<Fragment*, Assignment> > DotAssignments;
+ typedef DotAssignments::const_iterator const_dot_iterator;
+ typedef DotAssignments::iterator dot_iterator;
- bool isNull() const;
+ Input(const std::string& pName, InputSectDesc::KeepPolicy pPolicy);
+ Input(const InputSectDesc& pInputDesc);
- public:
- unsigned int hash;
- std::string from;
- std::string to;
+ InputSectDesc::KeepPolicy policy() const { return m_Policy; }
+
+ const InputSectDesc::Spec& spec() const { return m_Spec; }
+
+ const LDSection* getSection() const { return m_pSection; }
+ LDSection* getSection() { return m_pSection; }
+
+ const_dot_iterator dot_begin() const { return m_DotAssignments.begin(); }
+ dot_iterator dot_begin() { return m_DotAssignments.begin(); }
+ const_dot_iterator dot_end () const { return m_DotAssignments.end(); }
+ dot_iterator dot_end () { return m_DotAssignments.end(); }
+
+ const DotAssignments& dotAssignments() const { return m_DotAssignments; }
+ DotAssignments& dotAssignments() { return m_DotAssignments; }
+
+ private:
+ InputSectDesc::KeepPolicy m_Policy;
+ InputSectDesc::Spec m_Spec;
+ LDSection* m_pSection;
+ DotAssignments m_DotAssignments;
};
- typedef std::vector<NamePair> NamePairList;
- typedef NamePairList::iterator iterator;
- typedef NamePairList::const_iterator const_iterator;
+ class Output {
+ public:
+ typedef std::vector<Input*> InputList;
+ typedef InputList::const_iterator const_iterator;
+ typedef InputList::iterator iterator;
+ typedef InputList::const_reference const_reference;
+ typedef InputList::reference reference;
- /// NullName - the null object of NamePair
- static NamePair NullName;
+ typedef std::vector<Assignment> DotAssignments;
+ typedef DotAssignments::const_iterator const_dot_iterator;
+ typedef DotAssignments::iterator dot_iterator;
+
+ Output(const std::string& pName);
+ Output(const OutputSectDesc& pOutputDesc);
+
+ const std::string& name() const { return m_Name; }
+
+ const OutputSectDesc::Prolog& prolog() const { return m_Prolog; }
+ OutputSectDesc::Prolog& prolog() { return m_Prolog; }
+
+ const OutputSectDesc::Epilog& epilog() const { return m_Epilog; }
+ OutputSectDesc::Epilog& epilog() { return m_Epilog; }
+
+ size_t order() const { return m_Order; }
+
+ void setOrder(size_t pOrder) { m_Order = pOrder; }
+
+ bool hasContent() const;
+
+ const LDSection* getSection() const { return m_pSection; }
+ LDSection* getSection() { return m_pSection; }
+
+ void setSection(LDSection* pSection) { m_pSection = pSection; }
+
+ const_iterator begin() const { return m_InputList.begin(); }
+ iterator begin() { return m_InputList.begin(); }
+ const_iterator end () const { return m_InputList.end(); }
+ iterator end () { return m_InputList.end(); }
+
+ const_reference front() const { return m_InputList.front(); }
+ reference front() { return m_InputList.front(); }
+ const_reference back () const { return m_InputList.back(); }
+ reference back () { return m_InputList.back(); }
+
+ size_t size() const { return m_InputList.size(); }
+
+ bool empty() const { return m_InputList.empty(); }
+
+ bool isDiscard() const { return m_bIsDiscard; }
+
+ void append(Input* pInput) { m_InputList.push_back(pInput); }
+
+ const_dot_iterator dot_begin() const { return m_DotAssignments.begin(); }
+ dot_iterator dot_begin() { return m_DotAssignments.begin(); }
+ const_dot_iterator dot_end () const { return m_DotAssignments.end(); }
+ dot_iterator dot_end () { return m_DotAssignments.end(); }
+
+ const_dot_iterator find_first_explicit_dot() const;
+ dot_iterator find_first_explicit_dot();
+
+ const_dot_iterator find_last_explicit_dot() const;
+ dot_iterator find_last_explicit_dot();
+
+ const DotAssignments& dotAssignments() const { return m_DotAssignments; }
+ DotAssignments& dotAssignments() { return m_DotAssignments; }
+
+ private:
+ std::string m_Name;
+ OutputSectDesc::Prolog m_Prolog;
+ OutputSectDesc::Epilog m_Epilog;
+ LDSection* m_pSection;
+ size_t m_Order;
+ bool m_bIsDiscard;
+ InputList m_InputList;
+ DotAssignments m_DotAssignments;
+ };
+
+ struct SHOCompare
+ {
+ bool operator()(const Output* LHS, const Output* RHS) const
+ { return LHS->order() < RHS->order(); }
+ };
+
+ typedef std::pair<const Output*, const Input*> const_mapping;
+ typedef std::pair<Output*, Input*> mapping;
+
+ typedef std::vector<Output*> OutputDescList;
+ typedef OutputDescList::const_iterator const_iterator;
+ typedef OutputDescList::iterator iterator;
+ typedef OutputDescList::const_reference const_reference;
+ typedef OutputDescList::reference reference;
+
+ typedef OutputDescList::const_reverse_iterator const_reverse_iterator;
+ typedef OutputDescList::reverse_iterator reverse_iterator;
public:
- // get the possible output section name based on the mapping table
- // return NullPair if not found
- const NamePair& find(const std::string& pFrom) const;
- NamePair& find(const std::string& pFrom);
+ ~SectionMap();
- const NamePair& find(const std::string& pFrom, unsigned int pHash) const;
- NamePair& find(const std::string& pFrom, unsigned int pHash);
+ const_mapping find(const std::string& pInputFile,
+ const std::string& pInputSection) const;
+ mapping find(const std::string& pInputFile,
+ const std::string& pInputSection);
- // add a mapping from input sub-string to output name.
- // @param [in] pFrom the given input sub-string
- // @param [in] pTo the mapped output string
- // @param [out] pExist does pFrom exist?
- NamePair& append(const std::string& pFrom,
- const std::string& pTo,
- bool& pExist);
+ const_iterator find(const std::string& pOutputSection) const;
+ iterator find(const std::string& pOutputSection);
- const_iterator begin() const { return m_NamePairList.begin(); }
- iterator begin() { return m_NamePairList.begin(); }
- const_iterator end () const { return m_NamePairList.end(); }
- iterator end () { return m_NamePairList.end(); }
+ std::pair<mapping, bool>
+ insert(const std::string& pInputSection,
+ const std::string& pOutputSection,
+ InputSectDesc::KeepPolicy pPolicy = InputSectDesc::NoKeep);
+ std::pair<mapping, bool>
+ insert(const InputSectDesc& pInputDesc, const OutputSectDesc& pOutputDesc);
- bool empty() const { return m_NamePairList.empty(); }
- size_t size () const { return m_NamePairList.size(); }
+ bool empty() const { return m_OutputDescList.empty(); }
+ size_t size () const { return m_OutputDescList.size(); }
- static unsigned int hash(const std::string& pString);
+ const_iterator begin() const { return m_OutputDescList.begin(); }
+ iterator begin() { return m_OutputDescList.begin(); }
+ const_iterator end () const { return m_OutputDescList.end(); }
+ iterator end () { return m_OutputDescList.end(); }
+
+ const_reference front() const { return m_OutputDescList.front(); }
+ reference front() { return m_OutputDescList.front(); }
+ const_reference back () const { return m_OutputDescList.back(); }
+ reference back () { return m_OutputDescList.back(); }
+
+ const_reverse_iterator rbegin() const { return m_OutputDescList.rbegin(); }
+ reverse_iterator rbegin() { return m_OutputDescList.rbegin(); }
+ const_reverse_iterator rend () const { return m_OutputDescList.rend(); }
+ reverse_iterator rend () { return m_OutputDescList.rend(); }
+
+ iterator insert(iterator pPosition, LDSection* pSection);
+
+ // fixupDotSymbols - ensure the dot assignments are valid
+ void fixupDotSymbols();
private:
- bool matched(const NamePair& pNamePair,
- const std::string& pInput,
- unsigned int pHash) const;
+ bool matched(const Input& pInput,
+ const std::string& pInputFile,
+ const std::string& pInputSection) const;
+
+ bool matched(const WildcardPattern& pPattern, const std::string& pName) const;
+
private:
- NamePairList m_NamePairList;
+ OutputDescList m_OutputDescList;
};
} // namespace of mcld
diff --git a/include/mcld/Script/AssertCmd.h b/include/mcld/Script/AssertCmd.h
new file mode 100644
index 0000000..1e57375
--- /dev/null
+++ b/include/mcld/Script/AssertCmd.h
@@ -0,0 +1,58 @@
+//===- AssertCmd.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_ASSERTCMD_H
+#define MCLD_SCRIPT_ASSERTCMD_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/ScriptCommand.h>
+#include <string>
+
+namespace mcld
+{
+
+class RpnExpr;
+class Module;
+
+/** \class AssertCmd
+ * \brief This class defines the interfaces to assert command.
+ */
+
+class AssertCmd : public ScriptCommand
+{
+public:
+ AssertCmd(RpnExpr& pRpnExpr, const std::string& pMessage);
+
+ ~AssertCmd();
+
+ AssertCmd& operator=(const AssertCmd& pAssertCmd);
+
+ const RpnExpr& getRpnExpr() const { return m_RpnExpr; }
+ RpnExpr& getRpnExpr() { return m_RpnExpr; }
+
+ const std::string& message() const { return m_Message; }
+
+ void dump() const;
+
+ static bool classof(const ScriptCommand* pCmd)
+ {
+ return pCmd->getKind() == ScriptCommand::ASSERT;
+ }
+
+ void activate(Module& pModule);
+
+private:
+ RpnExpr& m_RpnExpr;
+ std::string m_Message;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Script/Assignment.h b/include/mcld/Script/Assignment.h
new file mode 100644
index 0000000..068735d
--- /dev/null
+++ b/include/mcld/Script/Assignment.h
@@ -0,0 +1,87 @@
+//===- Assignment.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_ASSIGNMENT_H
+#define MCLD_SCRIPT_ASSIGNMENT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/ScriptCommand.h>
+
+namespace mcld
+{
+
+class Module;
+class RpnExpr;
+class SymOperand;
+class RpnEvaluator;
+
+/** \class Assignment
+ * \brief This class defines the interfaces to assignment command.
+ */
+
+class Assignment : public ScriptCommand
+{
+public:
+ enum Level {
+ OUTSIDE_SECTIONS, // outside SECTIONS command
+ OUTPUT_SECTION, // related to an output section
+ INPUT_SECTION // related to an input section
+ };
+
+ enum Type {
+ DEFAULT,
+ HIDDEN,
+ PROVIDE,
+ PROVIDE_HIDDEN
+ };
+
+public:
+ Assignment(Level pLevel,
+ Type pType,
+ SymOperand& pSymbol,
+ RpnExpr& pRpnExpr);
+
+ ~Assignment();
+
+ Assignment& operator=(const Assignment& pAssignment);
+
+ Level level() const { return m_Level; }
+
+ Type type() const { return m_Type; }
+
+ const SymOperand& symbol() const { return m_Symbol; }
+ SymOperand& symbol() { return m_Symbol; }
+
+ const RpnExpr& getRpnExpr() const { return m_RpnExpr; }
+ RpnExpr& getRpnExpr() { return m_RpnExpr; }
+
+ void dump() const;
+
+ static bool classof(const ScriptCommand* pCmd)
+ {
+ return pCmd->getKind() == ScriptCommand::ASSIGNMENT;
+ }
+
+ void activate(Module& pModule);
+
+ /// assign - evaluate the rhs and assign the result to lhs.
+ bool assign(RpnEvaluator& pEvaluator);
+
+private:
+ Level m_Level;
+ Type m_Type;
+ SymOperand& m_Symbol;
+ RpnExpr& m_RpnExpr;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/BinaryOp.h b/include/mcld/Script/BinaryOp.h
new file mode 100644
index 0000000..884c0c1
--- /dev/null
+++ b/include/mcld/Script/BinaryOp.h
@@ -0,0 +1,135 @@
+//===- BinaryOp.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_BINARYOP_H
+#define MCLD_SCRIPT_BINARYOP_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/Operator.h>
+#include <cstddef>
+
+namespace mcld
+{
+
+class Operand;
+class IntOperand;
+class Module;
+class TargetLDBackend;
+
+/** \class BinaryOP
+ * \brief This class defines the interfaces to an binary operator token.
+ */
+
+template<Operator::Type TYPE>
+class BinaryOp : public Operator
+{
+private:
+ friend class Operator;
+
+ BinaryOp()
+ : Operator(Operator::BINARY, TYPE), m_Size(0)
+ {
+ m_pOperand[0] = m_pOperand[1] = NULL;
+ }
+
+public:
+ ~BinaryOp()
+ {}
+
+ IntOperand* eval(const Module& pModule, const TargetLDBackend& pBackend);
+
+ void appendOperand(Operand* pOperand)
+ {
+ m_pOperand[m_Size++] = pOperand;
+ if (m_Size == 2)
+ m_Size = 0;
+ }
+
+private:
+ size_t m_Size;
+ Operand* m_pOperand[2];
+};
+
+template<>
+IntOperand* BinaryOp<Operator::MUL>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::DIV>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::MOD>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::ADD>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::SUB>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::LSHIFT>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::RSHIFT>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::LT>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::LE>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::GT>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::GE>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::EQ>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::NE>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::BITWISE_AND>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::BITWISE_XOR>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::BITWISE_OR>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::LOGICAL_AND>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::LOGICAL_OR>::eval(const Module&,
+ const TargetLDBackend&);
+
+template<>
+IntOperand* BinaryOp<Operator::ALIGN>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand*
+BinaryOp<Operator::DATA_SEGMENT_RELRO_END>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::MAX>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::MIN>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* BinaryOp<Operator::SEGMENT_START>::eval(const Module&,
+ const TargetLDBackend&);
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/EntryCmd.h b/include/mcld/Script/EntryCmd.h
new file mode 100644
index 0000000..acbdd10
--- /dev/null
+++ b/include/mcld/Script/EntryCmd.h
@@ -0,0 +1,49 @@
+//===- EntryCmd.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_ENTRYCMD_H
+#define MCLD_SCRIPT_ENTRYCMD_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/ScriptCommand.h>
+#include <string>
+
+namespace mcld
+{
+
+class Module;
+
+/** \class EntryCmd
+ * \brief This class defines the interfaces to Entry command.
+ */
+
+class EntryCmd : public ScriptCommand
+{
+public:
+ EntryCmd(const std::string& pEntry);
+ ~EntryCmd();
+
+ void dump() const;
+
+ static bool classof(const ScriptCommand* pCmd)
+ {
+ return pCmd->getKind() == ScriptCommand::ENTRY;
+ }
+
+ void activate(Module& pModule);
+
+private:
+ std::string m_Entry;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/ExprToken.h b/include/mcld/Script/ExprToken.h
new file mode 100644
index 0000000..be248d5
--- /dev/null
+++ b/include/mcld/Script/ExprToken.h
@@ -0,0 +1,50 @@
+//===- ExprToken.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_EXPRTOKEN_H
+#define MCLD_SCRIPT_EXPRTOKEN_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+/** \class ExprToken
+ * \brief This class defines the interfaces to an expression token.
+ */
+
+class ExprToken
+{
+public:
+ enum Kind {
+ OPERATOR,
+ OPERAND
+ };
+
+protected:
+ ExprToken(Kind pKind)
+ : m_Kind(pKind)
+ {}
+
+public:
+ virtual ~ExprToken()
+ {}
+
+ virtual void dump() const = 0;
+
+ Kind kind() const { return m_Kind; }
+
+private:
+ Kind m_Kind;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/FileToken.h b/include/mcld/Script/FileToken.h
new file mode 100644
index 0000000..92faab4
--- /dev/null
+++ b/include/mcld/Script/FileToken.h
@@ -0,0 +1,50 @@
+//===- FileToken.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_FILETOKEN_H
+#define MCLD_SCRIPT_FILETOKEN_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/InputToken.h>
+#include <mcld/Support/Allocators.h>
+#include <mcld/Config/Config.h>
+
+namespace mcld
+{
+
+/** \class FileToken
+ * \brief This class defines the interfaces to a filename in INPUT/GROUP
+ * command.
+ */
+
+class FileToken : public InputToken
+{
+private:
+ friend class Chunk<FileToken, MCLD_SYMBOLS_PER_INPUT>;
+ FileToken();
+ FileToken(const std::string& pName, bool pAsNeeded);
+
+public:
+ ~FileToken();
+
+ static bool classof(const InputToken* pToken)
+ {
+ return pToken->type() == InputToken::File;
+ }
+
+ /* factory method */
+ static FileToken* create(const std::string& pName, bool pAsNeeded);
+ static void destroy(FileToken*& pToken);
+ static void clear();
+};
+
+} // namepsace of mcld
+
+#endif
diff --git a/include/mcld/Script/FlexLexer.h b/include/mcld/Script/FlexLexer.h
new file mode 100644
index 0000000..f09ab20
--- /dev/null
+++ b/include/mcld/Script/FlexLexer.h
@@ -0,0 +1,215 @@
+//===- FlexLexer.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// -*-C++-*-
+// FlexLexer.h -- define interfaces for lexical analyzer classes generated
+// by flex
+
+// Copyright (c) 1993 The Regents of the University of California.
+// All rights reserved.
+//
+// This code is derived from software contributed to Berkeley by
+// Kent Williams and Tom Epperly.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+
+// Neither the name of the University nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+// IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE.
+
+// This file defines FlexLexer, an abstract class which specifies the
+// external interface provided to flex C++ lexer objects, and yyFlexLexer,
+// which defines a particular lexer class.
+//
+// If you want to create multiple lexer classes, you use the -P flag
+// to rename each yyFlexLexer to some other xxFlexLexer. You then
+// include <FlexLexer.h> in your other sources once per lexer class:
+//
+// #undef yyFlexLexer
+// #define yyFlexLexer xxFlexLexer
+// #include <FlexLexer.h>
+//
+// #undef yyFlexLexer
+// #define yyFlexLexer zzFlexLexer
+// #include <FlexLexer.h>
+// ...
+
+#ifndef __FLEX_LEXER_H
+// Never included before - need to define base class.
+#define __FLEX_LEXER_H
+
+#include <iostream>
+# ifndef FLEX_STD
+# define FLEX_STD std::
+# endif
+
+extern "C++" {
+
+struct yy_buffer_state;
+typedef int yy_state_type;
+
+class FlexLexer {
+public:
+ virtual ~FlexLexer() { }
+
+ const char* YYText() const { return yytext; }
+ int YYLeng() const { return yyleng; }
+
+ virtual void
+ yy_switch_to_buffer( struct yy_buffer_state* new_buffer ) = 0;
+ virtual struct yy_buffer_state*
+ yy_create_buffer( FLEX_STD istream* s, int size ) = 0;
+ virtual void yy_delete_buffer( struct yy_buffer_state* b ) = 0;
+ virtual void yyrestart( FLEX_STD istream* s ) = 0;
+
+ virtual int yylex() = 0;
+
+ // Call yylex with new input/output sources.
+ int yylex( FLEX_STD istream* new_in, FLEX_STD ostream* new_out = 0 )
+ {
+ switch_streams( new_in, new_out );
+ return yylex();
+ }
+
+ // Switch to new input/output streams. A nil stream pointer
+ // indicates "keep the current one".
+ virtual void switch_streams( FLEX_STD istream* new_in = 0,
+ FLEX_STD ostream* new_out = 0 ) = 0;
+
+ int lineno() const { return yylineno; }
+
+ int debug() const { return yy_flex_debug; }
+ void set_debug( int flag ) { yy_flex_debug = flag; }
+
+protected:
+ char* yytext;
+ int yyleng;
+ int yylineno; // only maintained if you use %option yylineno
+ int yy_flex_debug; // only has effect with -d or "%option debug"
+};
+
+}
+#endif // FLEXLEXER_H
+
+#if defined(yyFlexLexer) || ! defined(yyFlexLexerOnce)
+// Either this is the first time through (yyFlexLexerOnce not defined),
+// or this is a repeated include to define a different flavor of
+// yyFlexLexer, as discussed in the flex manual.
+#define yyFlexLexerOnce
+
+extern "C++" {
+
+class yyFlexLexer : public FlexLexer {
+public:
+ // arg_yyin and arg_yyout default to the cin and cout, but we
+ // only make that assignment when initializing in yylex().
+ yyFlexLexer( FLEX_STD istream* arg_yyin = 0, FLEX_STD ostream* arg_yyout = 0 );
+
+ virtual ~yyFlexLexer();
+
+ void yy_switch_to_buffer( struct yy_buffer_state* new_buffer );
+ struct yy_buffer_state* yy_create_buffer( FLEX_STD istream* s, int size );
+ void yy_delete_buffer( struct yy_buffer_state* b );
+ void yyrestart( FLEX_STD istream* s );
+
+ void yypush_buffer_state( struct yy_buffer_state* new_buffer );
+ void yypop_buffer_state();
+
+ virtual int yylex();
+ virtual void switch_streams( FLEX_STD istream* new_in, FLEX_STD ostream* new_out = 0 );
+ virtual int yywrap();
+
+protected:
+ virtual int LexerInput( char* buf, int max_size );
+ virtual void LexerOutput( const char* buf, int size );
+ virtual void LexerError( const char* msg );
+
+ void yyunput( int c, char* buf_ptr );
+ int yyinput();
+
+ void yy_load_buffer_state();
+ void yy_init_buffer( struct yy_buffer_state* b, FLEX_STD istream* s );
+ void yy_flush_buffer( struct yy_buffer_state* b );
+
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int* yy_start_stack;
+
+ void yy_push_state( int new_state );
+ void yy_pop_state();
+ int yy_top_state();
+
+ yy_state_type yy_get_previous_state();
+ yy_state_type yy_try_NUL_trans( yy_state_type current_state );
+ int yy_get_next_buffer();
+
+ FLEX_STD istream* yyin; // input source for default LexerInput
+ FLEX_STD ostream* yyout; // output sink for default LexerOutput
+
+ // yy_hold_char holds the character lost when yytext is formed.
+ char yy_hold_char;
+
+ // Number of characters read into yy_ch_buf.
+ int yy_n_chars;
+
+ // Points to current character in buffer.
+ char* yy_c_buf_p;
+
+ int yy_init; // whether we need to initialize
+ int yy_start; // start state number
+
+ // Flag which is used to allow yywrap()'s to do buffer switches
+ // instead of setting up a fresh yyin. A bit of a hack ...
+ int yy_did_buffer_switch_on_eof;
+
+
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ struct yy_buffer_state ** yy_buffer_stack; /**< Stack as an array. */
+ void yyensure_buffer_stack(void);
+
+ // The following are not always needed, but may be depending
+ // on use of certain flex features (like REJECT or yymore()).
+
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ yy_state_type* yy_state_buf;
+ yy_state_type* yy_state_ptr;
+
+ char* yy_full_match;
+ int* yy_full_state;
+ int yy_full_lp;
+
+ int yy_lp;
+ int yy_looking_for_trail_begin;
+
+ int yy_more_flag;
+ int yy_more_len;
+ int yy_more_offset;
+ int yy_prev_more_offset;
+};
+
+}
+
+#endif // yyFlexLexer || ! yyFlexLexerOnce
+
diff --git a/include/mcld/Script/GroupCmd.h b/include/mcld/Script/GroupCmd.h
new file mode 100644
index 0000000..3006c79
--- /dev/null
+++ b/include/mcld/Script/GroupCmd.h
@@ -0,0 +1,60 @@
+//===- GroupCmd.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_GROUPCMD_H
+#define MCLD_SCRIPT_GROUPCMD_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/ScriptCommand.h>
+
+namespace mcld
+{
+
+class StringList;
+class InputTree;
+class InputBuilder;
+class GroupReader;
+class LinkerConfig;
+
+/** \class GroupCmd
+ * \brief This class defines the interfaces to Group command.
+ */
+
+class GroupCmd : public ScriptCommand
+{
+public:
+ GroupCmd(StringList& pStringList,
+ InputTree& pInputTree,
+ InputBuilder& pBuilder,
+ GroupReader& m_GroupReader,
+ const LinkerConfig& pConfig);
+ ~GroupCmd();
+
+ void dump() const;
+
+ static bool classof(const ScriptCommand* pCmd)
+ {
+ return pCmd->getKind() == ScriptCommand::GROUP;
+ }
+
+ void activate(Module& pModule);
+
+private:
+ StringList& m_StringList;
+ InputTree& m_InputTree;
+ InputBuilder& m_Builder;
+ GroupReader& m_GroupReader;
+ const LinkerConfig& m_Config;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/InputSectDesc.h b/include/mcld/Script/InputSectDesc.h
new file mode 100644
index 0000000..e2bbf8d
--- /dev/null
+++ b/include/mcld/Script/InputSectDesc.h
@@ -0,0 +1,105 @@
+//===- InputSectDesc.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_INPUTSECTDESC_H
+#define MCLD_SCRIPT_INPUTSECTDESC_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/ScriptCommand.h>
+#include <mcld/Script/StringList.h>
+#include <cassert>
+
+namespace mcld
+{
+
+class WildcardPattern;
+class OutputSectDesc;
+
+/** \class InputSectDesc
+ * \brief This class defines the interfaces to input section description.
+ */
+
+class InputSectDesc : public ScriptCommand
+{
+public:
+ enum KeepPolicy {
+ Keep,
+ NoKeep
+ };
+
+ struct Spec {
+ bool hasFile() const { return m_pWildcardFile != NULL; }
+ const WildcardPattern& file() const {
+ assert(hasFile());
+ return *m_pWildcardFile;
+ }
+
+ bool hasExcludeFiles() const {
+ return m_pExcludeFiles != NULL && !m_pExcludeFiles->empty();
+ }
+ const StringList& excludeFiles() const {
+ assert(hasExcludeFiles());
+ return *m_pExcludeFiles;
+ }
+
+ bool hasSections() const {
+ return m_pWildcardSections != NULL && !m_pWildcardSections->empty();
+ }
+ const StringList& sections() const {
+ assert(hasSections());
+ return *m_pWildcardSections;
+ }
+
+ bool operator==(const Spec& pRHS) const {
+ /* FIXME: currently I don't check the real content */
+ if (this == &pRHS)
+ return true;
+ if (m_pWildcardFile != pRHS.m_pWildcardFile)
+ return false;
+ if (m_pExcludeFiles != pRHS.m_pExcludeFiles)
+ return false;
+ if (m_pWildcardSections != pRHS.m_pWildcardSections)
+ return false;
+ return true;
+ }
+
+ WildcardPattern* m_pWildcardFile;
+ StringList* m_pExcludeFiles;
+ StringList* m_pWildcardSections;
+ };
+
+public:
+ InputSectDesc(KeepPolicy pPolicy,
+ const Spec& pSpec,
+ const OutputSectDesc& pOutputDesc);
+ ~InputSectDesc();
+
+ KeepPolicy policy() const { return m_KeepPolicy; }
+
+ const Spec& spec() const { return m_Spec; }
+
+ void dump() const;
+
+ static bool classof(const ScriptCommand* pCmd)
+ {
+ return pCmd->getKind() == ScriptCommand::INPUT_SECT_DESC;
+ }
+
+ void activate(Module& pModule);
+
+private:
+ KeepPolicy m_KeepPolicy;
+ Spec m_Spec;
+ const OutputSectDesc& m_OutputSectDesc;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Script/InputToken.h b/include/mcld/Script/InputToken.h
new file mode 100644
index 0000000..8d89022
--- /dev/null
+++ b/include/mcld/Script/InputToken.h
@@ -0,0 +1,56 @@
+//===- InputToken.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_INPUTTOKEN_H
+#define MCLD_SCRIPT_INPUTTOKEN_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/StrToken.h>
+
+namespace mcld
+{
+
+/** \class InputToken
+ * \brief This class defines the interfaces to a file/namespec token.
+ */
+
+class InputToken : public StrToken
+{
+public:
+ enum Type {
+ Unknown,
+ File,
+ NameSpec
+ };
+
+protected:
+ InputToken();
+ InputToken(Type pType, const std::string& pName, bool pAsNeeded);
+
+public:
+ virtual ~InputToken();
+
+ Type type() const { return m_Type; }
+
+ bool asNeeded() const { return m_bAsNeeded; }
+
+ static bool classof(const StrToken* pToken)
+ {
+ return pToken->kind() == StrToken::Input;
+ }
+
+private:
+ Type m_Type;
+ bool m_bAsNeeded;
+};
+
+} // namepsace of mcld
+
+#endif
diff --git a/include/mcld/Script/NameSpec.h b/include/mcld/Script/NameSpec.h
new file mode 100644
index 0000000..96cf95c
--- /dev/null
+++ b/include/mcld/Script/NameSpec.h
@@ -0,0 +1,50 @@
+//===- NameSpec.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_NAMESPEC_H
+#define MCLD_SCRIPT_NAMESPEC_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/InputToken.h>
+#include <mcld/Support/Allocators.h>
+#include <mcld/Config/Config.h>
+
+namespace mcld
+{
+
+/** \class NameSpec
+ * \brief This class defines the interfaces to a namespec in INPUT/GROUP
+ * command.
+ */
+
+class NameSpec : public InputToken
+{
+private:
+ friend class Chunk<NameSpec, MCLD_SYMBOLS_PER_INPUT>;
+ NameSpec();
+ NameSpec(const std::string& pName, bool pAsNeeded);
+
+public:
+ ~NameSpec();
+
+ static bool classof(const InputToken* pToken)
+ {
+ return pToken->type() == InputToken::NameSpec;
+ }
+
+ /* factory method */
+ static NameSpec* create(const std::string& pName, bool pAsNeeded);
+ static void destroy(NameSpec*& pToken);
+ static void clear();
+};
+
+} // namepsace of mcld
+
+#endif
diff --git a/include/mcld/Script/NullaryOp.h b/include/mcld/Script/NullaryOp.h
new file mode 100644
index 0000000..95fdc18
--- /dev/null
+++ b/include/mcld/Script/NullaryOp.h
@@ -0,0 +1,65 @@
+//===- NullaryOp.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_NULLOP_H
+#define MCLD_SCRIPT_NULLOP_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/Operator.h>
+#include <cassert>
+
+namespace mcld
+{
+
+class Operand;
+class IntOperand;
+class Module;
+class TargetLDBackend;
+
+/** \class NullaryOp
+ * \brief This class defines the interfaces to an nullary operator token.
+ */
+
+template<Operator::Type TYPE>
+class NullaryOp : public Operator
+{
+private:
+ friend class Operator;
+
+ NullaryOp()
+ : Operator(Operator::NULLARY, TYPE)
+ {}
+
+public:
+ ~NullaryOp()
+ {}
+
+ IntOperand* eval(const Module& pModule, const TargetLDBackend& pBackend);
+
+ void appendOperand(Operand* pOperand)
+ {
+ assert(0);
+ }
+};
+
+template<>
+IntOperand* NullaryOp<Operator::SIZEOF_HEADERS>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* NullaryOp<Operator::MAXPAGESIZE>::eval(const Module&,
+ const TargetLDBackend&);
+
+template<>
+IntOperand* NullaryOp<Operator::COMMONPAGESIZE>::eval(const Module&,
+ const TargetLDBackend&);
+
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Script/Operand.h b/include/mcld/Script/Operand.h
new file mode 100644
index 0000000..403701c
--- /dev/null
+++ b/include/mcld/Script/Operand.h
@@ -0,0 +1,241 @@
+//===- Operand.h ----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_OPERAND_H
+#define MCLD_SCRIPT_OPERAND_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/ExprToken.h>
+#include <mcld/Object/SectionMap.h>
+#include <mcld/Support/Allocators.h>
+#include <mcld/Config/Config.h>
+#include <llvm/Support/DataTypes.h>
+#include <string>
+#include <cassert>
+
+namespace mcld
+{
+
+/** \class Operand
+ * \brief This class defines the interfaces to an operand token.
+ */
+
+class Operand : public ExprToken
+{
+public:
+ enum Type {
+ SYMBOL,
+ INTEGER,
+ SECTION,
+ SECTION_DESC,
+ FRAGMENT
+ };
+
+protected:
+ Operand(Type pType);
+ virtual ~Operand();
+
+public:
+ Type type() const { return m_Type; }
+
+ virtual bool isDot() const { return false; }
+
+ virtual uint64_t value() const = 0;
+
+ static bool classof(const ExprToken* pToken)
+ {
+ return pToken->kind() == ExprToken::OPERAND;
+ }
+
+private:
+ Type m_Type;
+};
+
+/** \class SymOperand
+ * \brief This class defines the interfaces to a symbol operand.
+ */
+
+class SymOperand : public Operand
+{
+private:
+ friend class Chunk<SymOperand, MCLD_SYMBOLS_PER_INPUT>;
+ SymOperand();
+ SymOperand(const std::string& pName);
+
+public:
+ void dump() const;
+
+ const std::string& name() const { return m_Name; }
+
+ bool isDot() const;
+
+ uint64_t value() const { return m_Value; }
+
+ void setValue(uint64_t pValue) { m_Value = pValue; }
+
+ static bool classof(const Operand* pOperand)
+ {
+ return pOperand->type() == Operand::SYMBOL;
+ }
+
+ /* factory method */
+ static SymOperand* create(const std::string& pName);
+ static void destroy(SymOperand*& pOperand);
+ static void clear();
+
+private:
+ std::string m_Name;
+ uint64_t m_Value;
+};
+
+/** \class IntOperand
+ * \brief This class defines the interfaces to an integer operand.
+ */
+
+class IntOperand : public Operand
+{
+private:
+ friend class Chunk<IntOperand, MCLD_SYMBOLS_PER_INPUT>;
+ IntOperand();
+ IntOperand(uint64_t pValue);
+
+public:
+ void dump() const;
+
+ uint64_t value() const { return m_Value; }
+
+ void setValue(uint64_t pValue) { m_Value = pValue; }
+
+ static bool classof(const Operand* pOperand)
+ {
+ return pOperand->type() == Operand::INTEGER;
+ }
+
+ /* factory method */
+ static IntOperand* create(uint64_t pValue);
+ static void destroy(IntOperand*& pOperand);
+ static void clear();
+
+private:
+ uint64_t m_Value;
+};
+
+/** \class SectOperand
+ * \brief This class defines the interfaces to an section name operand.
+ */
+class LDSection;
+
+class SectOperand : public Operand
+{
+private:
+ friend class Chunk<SectOperand, MCLD_SECTIONS_PER_INPUT>;
+ SectOperand();
+ SectOperand(const std::string& pName);
+
+public:
+ void dump() const;
+
+ const std::string& name() const { return m_Name; }
+
+ uint64_t value() const
+ {
+ assert(0);
+ return 0;
+ }
+
+ static bool classof(const Operand* pOperand)
+ {
+ return pOperand->type() == Operand::SECTION;
+ }
+
+ /* factory method */
+ static SectOperand* create(const std::string& pName);
+ static void destroy(SectOperand*& pOperand);
+ static void clear();
+
+private:
+ std::string m_Name;
+};
+
+/** \class SectDescOperand
+ * \brief This class defines the interfaces to an section name operand.
+ */
+
+class SectDescOperand : public Operand
+{
+private:
+ friend class Chunk<SectDescOperand, MCLD_SECTIONS_PER_INPUT>;
+ SectDescOperand();
+ SectDescOperand(const SectionMap::Output* pOutputDesc);
+
+public:
+ void dump() const;
+
+ const SectionMap::Output* outputDesc() const { return m_pOutputDesc; }
+
+ uint64_t value() const
+ {
+ assert(0);
+ return 0;
+ }
+
+ static bool classof(const Operand* pOperand)
+ {
+ return pOperand->type() == Operand::SECTION_DESC;
+ }
+
+ /* factory method */
+ static SectDescOperand* create(const SectionMap::Output* pOutputDesc);
+ static void destroy(SectDescOperand*& pOperand);
+ static void clear();
+
+private:
+ const SectionMap::Output* m_pOutputDesc;
+};
+
+/** \class FragOperand
+ * \brief This class defines the interfaces to a fragment operand.
+ */
+
+class Fragment;
+
+class FragOperand : public Operand
+{
+private:
+ friend class Chunk<FragOperand, MCLD_SYMBOLS_PER_INPUT>;
+ FragOperand();
+ FragOperand(Fragment& pFragment);
+
+public:
+ void dump() const;
+
+ const Fragment* frag() const { return m_pFragment; }
+ Fragment* frag() { return m_pFragment; }
+
+ uint64_t value() const;
+
+ static bool classof(const Operand* pOperand)
+ {
+ return pOperand->type() == Operand::FRAGMENT;
+ }
+
+ /* factory method */
+ static FragOperand* create(Fragment& pFragment);
+ static void destroy(FragOperand*& pOperand);
+ static void clear();
+
+private:
+ Fragment* m_pFragment;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/Operator.h b/include/mcld/Script/Operator.h
new file mode 100644
index 0000000..1fe8118
--- /dev/null
+++ b/include/mcld/Script/Operator.h
@@ -0,0 +1,231 @@
+//===- Operator.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_OPERATOR_INTERFACE_H
+#define MCLD_SCRIPT_OPERATOR_INTERFACE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/ExprToken.h>
+#include <llvm/Support/DataTypes.h>
+
+namespace mcld
+{
+
+class Operand;
+class IntOperand;
+class Module;
+class TargetLDBackend;
+
+/** \class Operator
+ * \brief This class defines the interfaces to an operator token.
+ */
+
+class Operator : public ExprToken
+{
+public:
+ enum Arity {
+ NULLARY,
+ UNARY,
+ BINARY,
+ TERNARY
+ };
+
+ enum Type {
+ /* arithmetic operator */
+ UNARY_PLUS = 0,
+ UNARY_MINUS = 1,
+ LOGICAL_NOT = 2,
+ BITWISE_NOT = 3,
+ MUL = 4,
+ DIV = 5,
+ MOD = 6,
+ ADD = 7,
+ SUB = 8,
+ LSHIFT = 9,
+ RSHIFT = 10,
+ LT = 11,
+ LE = 12,
+ GT = 13,
+ GE = 14,
+ EQ = 15,
+ NE = 16,
+ BITWISE_AND = 17,
+ BITWISE_XOR = 18,
+ BITWISE_OR = 19,
+ LOGICAL_AND = 20,
+ LOGICAL_OR = 21,
+ TERNARY_IF = 22,
+ ASSIGN = 23,
+ ADD_ASSIGN = 24,
+ SUB_ASSIGN = 25,
+ MUL_ASSIGN = 26,
+ DIV_ASSIGN = 27,
+ AND_ASSIGN = 28,
+ OR_ASSIGN = 29,
+ LS_ASSIGN = 30,
+ RS_ASSIGN = 31,
+ /* function */
+ ABSOLUTE = 32,
+ ADDR = 33,
+ ALIGN = 34,
+ ALIGNOF = 35,
+ BLOCK = 36,
+ DATA_SEGMENT_ALIGN = 37,
+ DATA_SEGMENT_END = 38,
+ DATA_SEGMENT_RELRO_END = 39,
+ DEFINED = 40,
+ LENGTH = 41,
+ LOADADDR = 42,
+ MAX = 43,
+ MIN = 44,
+ NEXT = 45,
+ ORIGIN = 46,
+ SEGMENT_START = 47,
+ SIZEOF = 48,
+ SIZEOF_HEADERS = 49,
+ MAXPAGESIZE = 50,
+ COMMONPAGESIZE = 51
+ };
+
+ static const char* OpNames[];
+
+protected:
+ Operator(Arity pArity, Type pType);
+
+ const IntOperand* result() const { return m_pIntOperand; }
+ IntOperand* result() { return m_pIntOperand; }
+
+public:
+ virtual ~Operator();
+
+ Arity arity() const { return m_Arity; }
+
+ Type type() const { return m_Type; }
+
+ virtual void dump() const;
+
+ virtual IntOperand* eval(const Module& pModule,
+ const TargetLDBackend& pBackend) = 0;
+
+ virtual void appendOperand(Operand* pOperand) = 0;
+
+ static bool classof(const ExprToken* pToken)
+ {
+ return pToken->kind() == ExprToken::OPERATOR;
+ }
+
+ template<Operator::Type TYPE>
+ static Operator& create();
+
+private:
+ Arity m_Arity;
+ Type m_Type;
+ IntOperand* m_pIntOperand;
+};
+
+/* Nullary operator */
+template<>
+Operator& Operator::create<Operator::SIZEOF_HEADERS>();
+template<>
+Operator& Operator::create<Operator::MAXPAGESIZE>();
+template<>
+Operator& Operator::create<Operator::COMMONPAGESIZE>();
+
+/* Unary operator */
+template<>
+Operator& Operator::create<Operator::UNARY_PLUS>();
+template<>
+Operator& Operator::create<Operator::UNARY_MINUS>();
+template<>
+Operator& Operator::create<Operator::LOGICAL_NOT>();
+template<>
+Operator& Operator::create<Operator::BITWISE_NOT>();
+
+template<>
+Operator& Operator::create<Operator::ABSOLUTE>();
+template<>
+Operator& Operator::create<Operator::ADDR>();
+template<>
+Operator& Operator::create<Operator::ALIGNOF>();
+template<>
+Operator& Operator::create<Operator::DATA_SEGMENT_END>();
+template<>
+Operator& Operator::create<Operator::DEFINED>();
+template<>
+Operator& Operator::create<Operator::LENGTH>();
+template<>
+Operator& Operator::create<Operator::LOADADDR>();
+template<>
+Operator& Operator::create<Operator::NEXT>();
+template<>
+Operator& Operator::create<Operator::ORIGIN>();
+template<>
+Operator& Operator::create<Operator::SIZEOF>();
+
+/* Binary operator */
+template<>
+Operator& Operator::create<Operator::MUL>();
+template<>
+Operator& Operator::create<Operator::DIV>();
+template<>
+Operator& Operator::create<Operator::MOD>();
+template<>
+Operator& Operator::create<Operator::ADD>();
+template<>
+Operator& Operator::create<Operator::SUB>();
+template<>
+Operator& Operator::create<Operator::LSHIFT>();
+template<>
+Operator& Operator::create<Operator::RSHIFT>();
+template<>
+Operator& Operator::create<Operator::LT>();
+template<>
+Operator& Operator::create<Operator::LE>();
+template<>
+Operator& Operator::create<Operator::GT>();
+template<>
+Operator& Operator::create<Operator::GE>();
+template<>
+Operator& Operator::create<Operator::EQ>();
+template<>
+Operator& Operator::create<Operator::NE>();
+template<>
+Operator& Operator::create<Operator::BITWISE_AND>();
+template<>
+Operator& Operator::create<Operator::BITWISE_XOR>();
+template<>
+Operator& Operator::create<Operator::BITWISE_OR>();
+template<>
+Operator& Operator::create<Operator::LOGICAL_AND>();
+template<>
+Operator& Operator::create<Operator::LOGICAL_OR>();
+
+template<>
+Operator& Operator::create<Operator::ALIGN>();
+template<>
+Operator& Operator::create<Operator::DATA_SEGMENT_RELRO_END>();
+template<>
+Operator& Operator::create<Operator::MAX>();
+template<>
+Operator& Operator::create<Operator::MIN>();
+template<>
+Operator& Operator::create<Operator::SEGMENT_START>();
+
+/* Ternary operator */
+template<>
+Operator& Operator::create<Operator::TERNARY_IF>();
+
+template<>
+Operator&
+Operator::create<Operator::DATA_SEGMENT_ALIGN>();
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/OutputArchCmd.h b/include/mcld/Script/OutputArchCmd.h
new file mode 100644
index 0000000..51b75cc
--- /dev/null
+++ b/include/mcld/Script/OutputArchCmd.h
@@ -0,0 +1,49 @@
+//===- OutputArchCmd.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_OUTPUTARCHCMD_H
+#define MCLD_SCRIPT_OUTPUTARCHCMD_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/ScriptCommand.h>
+#include <string>
+
+namespace mcld
+{
+
+class Module;
+
+/** \class OutputArchCmd
+ * \brief This class defines the interfaces to OutputArch command.
+ */
+
+class OutputArchCmd : public ScriptCommand
+{
+public:
+ OutputArchCmd(const std::string& pArch);
+ ~OutputArchCmd();
+
+ void dump() const;
+
+ static bool classof(const ScriptCommand* pCmd)
+ {
+ return pCmd->getKind() == ScriptCommand::OUTPUT_ARCH;
+ }
+
+ void activate(Module& pModule);
+
+private:
+ std::string m_Arch;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/OutputCmd.h b/include/mcld/Script/OutputCmd.h
new file mode 100644
index 0000000..0a63891
--- /dev/null
+++ b/include/mcld/Script/OutputCmd.h
@@ -0,0 +1,50 @@
+//===- OutputCmd.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_OUTPUTCMD_H
+#define MCLD_SCRIPT_OUTPUTCMD_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/ScriptCommand.h>
+#include <string>
+
+namespace mcld
+{
+
+class Module;
+
+/** \class OutputCmd
+ * \brief This class defines the interfaces to Output command.
+ */
+
+class OutputCmd : public ScriptCommand
+{
+public:
+ OutputCmd(const std::string& pOutputFile);
+
+ ~OutputCmd();
+
+ void dump() const;
+
+ static bool classof(const ScriptCommand* pCmd)
+ {
+ return pCmd->getKind() == ScriptCommand::OUTPUT;
+ }
+
+ void activate(Module& pModule);
+
+private:
+ std::string m_OutputFile;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/OutputFormatCmd.h b/include/mcld/Script/OutputFormatCmd.h
new file mode 100644
index 0000000..b716e81
--- /dev/null
+++ b/include/mcld/Script/OutputFormatCmd.h
@@ -0,0 +1,63 @@
+//===- OutputFormatCmd.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_OUTPUTFORMATCMD_H
+#define MCLD_SCRIPT_OUTPUTFORMATCMD_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/ScriptCommand.h>
+#include <string>
+#include <vector>
+
+namespace mcld
+{
+
+class Module;
+
+/** \class OutputFormatCmd
+ * \brief This class defines the interfaces to OutputFormat command.
+ */
+
+class OutputFormatCmd : public ScriptCommand
+{
+public:
+ typedef std::vector<std::string> FormatList;
+ typedef FormatList::const_iterator const_iterator;
+ typedef FormatList::iterator iterator;
+
+public:
+ OutputFormatCmd(const std::string& pFormat);
+ OutputFormatCmd(const std::string& pDefault,
+ const std::string& pBig,
+ const std::string& pLittle);
+ ~OutputFormatCmd();
+
+ const_iterator begin() const { return m_FormatList.begin(); }
+ iterator begin() { return m_FormatList.begin(); }
+ const_iterator end() const { return m_FormatList.end(); }
+ iterator end() { return m_FormatList.end(); }
+
+ void dump() const;
+
+ static bool classof(const ScriptCommand* pCmd)
+ {
+ return pCmd->getKind() == ScriptCommand::OUTPUT_FORMAT;
+ }
+
+ void activate(Module& pModule);
+
+private:
+ FormatList m_FormatList;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/OutputSectDesc.h b/include/mcld/Script/OutputSectDesc.h
new file mode 100644
index 0000000..3c5187b
--- /dev/null
+++ b/include/mcld/Script/OutputSectDesc.h
@@ -0,0 +1,214 @@
+//===- OutputSectDesc.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_OUTPUTSECTDESC_H
+#define MCLD_SCRIPT_OUTPUTSECTDESC_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/ScriptCommand.h>
+#include <vector>
+#include <string>
+#include <cassert>
+
+namespace mcld
+{
+
+class RpnExpr;
+class StringList;
+
+/** \class OutputSectDesc
+ * \brief This class defines the interfaces to output section description.
+ */
+
+class OutputSectDesc : public ScriptCommand
+{
+public:
+ enum Type {
+ LOAD, // ALLOC
+ NOLOAD,
+ DSECT,
+ COPY,
+ INFO,
+ OVERLAY
+ };
+
+ enum Constraint {
+ NO_CONSTRAINT,
+ ONLY_IF_RO,
+ ONLY_IF_RW
+ };
+
+ struct Prolog {
+ bool hasVMA() const { return m_pVMA != NULL; }
+ const RpnExpr& vma() const {
+ assert(hasVMA());
+ return *m_pVMA;
+ }
+ RpnExpr& vma() {
+ assert(hasVMA());
+ return *m_pVMA;
+ }
+
+ void setType(Type pType) {
+ m_Type = pType;
+ }
+
+ Type type() const { return m_Type; }
+
+ bool hasLMA() const { return m_pLMA != NULL; }
+ const RpnExpr& lma() const {
+ assert(hasLMA());
+ return *m_pLMA;
+ }
+ RpnExpr& lma() {
+ assert(hasLMA());
+ return *m_pLMA;
+ }
+
+ bool hasAlign() const { return m_pAlign != NULL; }
+ const RpnExpr& align() const {
+ assert(hasAlign());
+ return *m_pAlign;
+ }
+
+ bool hasSubAlign() const { return m_pSubAlign != NULL; }
+ const RpnExpr& subAlign() const {
+ assert(hasSubAlign());
+ return *m_pSubAlign;
+ }
+
+ Constraint constraint() const { return m_Constraint; }
+
+ bool operator==(const Prolog& pRHS) const {
+ /* FIXME: currently I don't check the real content */
+ if (this == &pRHS)
+ return true;
+ if (m_pVMA != pRHS.m_pVMA)
+ return false;
+ if (m_Type != pRHS.m_Type)
+ return false;
+ if (m_pLMA!= pRHS.m_pLMA)
+ return false;
+ if (m_pAlign != pRHS.m_pAlign)
+ return false;
+ if (m_pSubAlign != pRHS.m_pSubAlign)
+ return false;
+ if (m_Constraint != pRHS.m_Constraint)
+ return false;
+ return true;
+ }
+
+ RpnExpr* m_pVMA;
+ Type m_Type;
+ RpnExpr* m_pLMA;
+ RpnExpr* m_pAlign;
+ RpnExpr* m_pSubAlign;
+ Constraint m_Constraint;
+ };
+
+ struct Epilog {
+ bool hasRegion() const { return m_pRegion != NULL; }
+ const std::string& region() const {
+ assert(hasRegion());
+ return *m_pRegion;
+ }
+
+ bool hasLMARegion() const { return m_pLMARegion != NULL; }
+ const std::string& lmaRegion() const {
+ assert(hasLMARegion());
+ return *m_pLMARegion;
+ }
+
+ bool hasPhdrs() const { return m_pPhdrs != NULL; }
+ const StringList& phdrs() const {
+ assert(hasPhdrs());
+ return *m_pPhdrs;
+ }
+
+ bool hasFillExp() const { return m_pFillExp != NULL; }
+ const RpnExpr& fillExp() const {
+ assert(hasFillExp());
+ return *m_pFillExp;
+ }
+
+ bool operator==(const Epilog& pRHS) const {
+ /* FIXME: currently I don't check the real content */
+ if (this == &pRHS)
+ return true;
+ if (m_pRegion != pRHS.m_pRegion)
+ return false;
+ if (m_pLMARegion != pRHS.m_pLMARegion)
+ return false;
+ if (m_pPhdrs != pRHS.m_pPhdrs)
+ return false;
+ if (m_pFillExp != pRHS.m_pFillExp)
+ return false;
+ return true;
+ }
+
+ const std::string* m_pRegion;
+ const std::string* m_pLMARegion;
+ StringList* m_pPhdrs;
+ RpnExpr* m_pFillExp;
+ };
+
+ typedef std::vector<ScriptCommand*> OutputSectCmds;
+ typedef OutputSectCmds::const_iterator const_iterator;
+ typedef OutputSectCmds::iterator iterator;
+ typedef OutputSectCmds::const_reference const_reference;
+ typedef OutputSectCmds::reference reference;
+
+public:
+ OutputSectDesc(const std::string& pName, const Prolog& pProlog);
+ ~OutputSectDesc();
+
+ const_iterator begin() const { return m_OutputSectCmds.begin(); }
+ iterator begin() { return m_OutputSectCmds.begin(); }
+ const_iterator end() const { return m_OutputSectCmds.end(); }
+ iterator end() { return m_OutputSectCmds.end(); }
+
+ const_reference front() const { return m_OutputSectCmds.front(); }
+ reference front() { return m_OutputSectCmds.front(); }
+ const_reference back() const { return m_OutputSectCmds.back(); }
+ reference back() { return m_OutputSectCmds.back(); }
+
+ const std::string& name() const { return m_Name; }
+
+ size_t size() const { return m_OutputSectCmds.size(); }
+
+ bool empty() const { return m_OutputSectCmds.empty(); }
+
+ void dump() const;
+
+ static bool classof(const ScriptCommand* pCmd)
+ {
+ return pCmd->getKind() == ScriptCommand::OUTPUT_SECT_DESC;
+ }
+
+ void activate(Module& pModule);
+
+ void push_back(ScriptCommand* pCommand);
+
+ void setEpilog(const Epilog& pEpilog);
+
+ const Prolog& prolog() const { return m_Prolog; }
+
+ const Epilog& epilog() const { return m_Epilog; }
+
+private:
+ OutputSectCmds m_OutputSectCmds;
+ std::string m_Name;
+ Prolog m_Prolog;
+ Epilog m_Epilog;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Script/RpnEvaluator.h b/include/mcld/Script/RpnEvaluator.h
new file mode 100644
index 0000000..7e35e86
--- /dev/null
+++ b/include/mcld/Script/RpnEvaluator.h
@@ -0,0 +1,36 @@
+//===- RpnEvaluator.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_RPNEVALUATOR_H
+#define MCLD_SCRIPT_RPNEVALUATOR_H
+
+namespace mcld {
+
+class RpnExpr;
+class Module;
+class TargetLDBackend;
+
+/** \class RpnEvaluator
+ * \brief RpnEvaluator evaluate a rpn expression
+ */
+class RpnEvaluator
+{
+public:
+ RpnEvaluator(const Module& pModule, const TargetLDBackend& pBackend);
+
+ // evaluate a valid expression and set the value in the second parameter
+ bool eval(const RpnExpr& pExpr, uint64_t& pResult);
+
+private:
+ const Module& m_Module;
+ const TargetLDBackend& m_Backend;
+};
+
+} // mcld
+
+#endif
diff --git a/include/mcld/Script/RpnExpr.h b/include/mcld/Script/RpnExpr.h
new file mode 100644
index 0000000..96b11e9
--- /dev/null
+++ b/include/mcld/Script/RpnExpr.h
@@ -0,0 +1,81 @@
+//===- RPNExpr.h ----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_RPNEXPR_H
+#define MCLD_SCRIPT_RPNEXPR_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Support/Allocators.h>
+#include <mcld/Config/Config.h>
+#include <mcld/Object/SectionMap.h>
+#include <vector>
+
+namespace mcld
+{
+
+class ExprToken;
+class Fragment;
+
+/** \class RpnExpr
+ * \brief This class defines the interfaces to a rpn expression.
+ */
+
+class RpnExpr
+{
+public:
+ typedef std::vector<ExprToken*> TokenQueue;
+ typedef TokenQueue::const_iterator const_iterator;
+ typedef TokenQueue::iterator iterator;
+
+private:
+ friend class Chunk<RpnExpr, MCLD_SYMBOLS_PER_INPUT>;
+ RpnExpr();
+
+public:
+ ~RpnExpr();
+
+ const_iterator begin() const { return m_TokenQueue.begin(); }
+ iterator begin() { return m_TokenQueue.begin(); }
+ const_iterator end() const { return m_TokenQueue.end(); }
+ iterator end() { return m_TokenQueue.end(); }
+
+ size_t size() const { return m_TokenQueue.size(); }
+
+ bool empty() const { return m_TokenQueue.empty(); }
+
+ bool hasDot() const;
+
+ void dump() const;
+
+ void push_back(ExprToken* pToken);
+
+ iterator insert(iterator pPosition, ExprToken* pToken);
+
+ void erase(iterator pPosition);
+
+ /* factory methods */
+ static RpnExpr* create();
+ static void destroy(RpnExpr*& pRpnExpr);
+ static void clear();
+
+ // buildHelperExpr - build the helper expr:
+ // ADDR ( `output_sect' ) + SIZEOF ( `output_sect' )
+ static RpnExpr* buildHelperExpr(SectionMap::iterator pIter);
+ // buildHelperExpr - build the helper expr: `fragment'
+ static RpnExpr* buildHelperExpr(Fragment& pFrag);
+
+private:
+ TokenQueue m_TokenQueue;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/ScriptCommand.h b/include/mcld/Script/ScriptCommand.h
new file mode 100644
index 0000000..06e07eb
--- /dev/null
+++ b/include/mcld/Script/ScriptCommand.h
@@ -0,0 +1,60 @@
+//===- ScriptCommand.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_COMMAND_H
+#define MCLD_SCRIPT_COMMAND_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld {
+
+class Module;
+
+/** \class ScriptCommand
+ * \brief This class defines the interfaces to a script command.
+ */
+class ScriptCommand
+{
+public:
+ enum Kind {
+ ENTRY,
+ OUTPUT_FORMAT,
+ GROUP,
+ OUTPUT,
+ SEARCH_DIR,
+ OUTPUT_ARCH,
+ ASSERT,
+ ASSIGNMENT,
+ SECTIONS,
+ OUTPUT_SECT_DESC,
+ INPUT_SECT_DESC
+ };
+
+protected:
+ ScriptCommand(Kind pKind)
+ : m_Kind(pKind)
+ {}
+
+public:
+ virtual ~ScriptCommand() = 0;
+
+ virtual void dump() const = 0;
+
+ virtual void activate(Module&) = 0;
+
+ Kind getKind() const { return m_Kind; }
+
+private:
+ Kind m_Kind;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/ScriptFile.h b/include/mcld/Script/ScriptFile.h
new file mode 100644
index 0000000..03662e3
--- /dev/null
+++ b/include/mcld/Script/ScriptFile.h
@@ -0,0 +1,165 @@
+//===- ScriptFile.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_SCRIPTFILE_H
+#define MCLD_SCRIPT_SCRIPTFILE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/Assignment.h>
+#include <mcld/Script/OutputSectDesc.h>
+#include <mcld/Script/InputSectDesc.h>
+#include <vector>
+#include <string>
+
+namespace mcld
+{
+
+class ScriptCommand;
+class Input;
+class InputTree;
+class InputBuilder;
+class GroupReader;
+class LinkerConfig;
+class RpnExpr;
+class StringList;
+class Module;
+
+/** \class ScriptFile
+ * \brief This class defines the interfaces to a linker script file.
+ */
+
+class ScriptFile
+{
+public:
+ enum Kind {
+ LDScript, // -T
+ Expression, // --defsym
+ VersionScript, // --version-script
+ DynamicList, // --dynamic-list
+ Unknown
+ };
+
+ typedef std::vector<ScriptCommand*> CommandQueue;
+ typedef CommandQueue::const_iterator const_iterator;
+ typedef CommandQueue::iterator iterator;
+ typedef CommandQueue::const_reference const_reference;
+ typedef CommandQueue::reference reference;
+
+public:
+ ScriptFile(Kind pKind, Input& pInput, InputBuilder& pBuilder);
+ ~ScriptFile();
+
+ const_iterator begin() const { return m_CommandQueue.begin(); }
+ iterator begin() { return m_CommandQueue.begin(); }
+ const_iterator end() const { return m_CommandQueue.end(); }
+ iterator end() { return m_CommandQueue.end(); }
+
+ const_reference front() const { return m_CommandQueue.front(); }
+ reference front() { return m_CommandQueue.front(); }
+ const_reference back() const { return m_CommandQueue.back(); }
+ reference back() { return m_CommandQueue.back(); }
+
+ const Input& input() const { return m_Input; }
+ Input& input() { return m_Input; }
+
+ size_t size() const { return m_CommandQueue.size(); }
+
+ Kind getKind() const { return m_Kind; }
+
+ const InputTree& inputs() const { return *m_pInputTree; }
+ InputTree& inputs() { return *m_pInputTree; }
+
+ const std::string& name() const { return m_Name; }
+ std::string& name() { return m_Name; }
+
+ void dump() const;
+ void activate(Module& pModule);
+
+ /// ENTRY(symbol)
+ void addEntryPoint(const std::string& pSymbol);
+
+ /// OUTPUT_FORMAT(bfdname)
+ /// OUTPUT_FORMAT(default, big, little)
+ void addOutputFormatCmd(const std::string& pFormat);
+ void addOutputFormatCmd(const std::string& pDefault,
+ const std::string& pBig,
+ const std::string& pLittle);
+
+ /// GROUP(file, file, ...)
+ /// GROUP(file file ...)
+ void addGroupCmd(StringList& pStringList,
+ GroupReader& pGroupReader,
+ const LinkerConfig& pConfig);
+
+ /// OUTPUT(filename)
+ void addOutputCmd(const std::string& pFileName);
+
+ /// SEARCH_DIR(path)
+ void addSearchDirCmd(const std::string& pPath);
+
+ /// OUTPUT_ARCH(bfdarch)
+ void addOutputArchCmd(const std::string& pArch);
+
+ /// ASSERT(exp, message)
+ void addAssertCmd(RpnExpr& pRpnExpr, const std::string& pMessage);
+
+ /// assignment
+ void addAssignment(const std::string& pSymbol,
+ RpnExpr& pRpnExpr,
+ Assignment::Type pType = Assignment::DEFAULT);
+
+ bool hasSectionsCmd() const;
+
+ void enterSectionsCmd();
+
+ void leaveSectionsCmd();
+
+ void enterOutputSectDesc(const std::string& pName,
+ const OutputSectDesc::Prolog& pProlog);
+
+ void leaveOutputSectDesc(const OutputSectDesc::Epilog& pEpilog);
+
+ void addInputSectDesc(InputSectDesc::KeepPolicy pPolicy,
+ const InputSectDesc::Spec& pSpec);
+
+ RpnExpr* createRpnExpr();
+ const RpnExpr* getCurrentRpnExpr() const { return m_pRpnExpr; }
+ RpnExpr* getCurrentRpnExpr() { return m_pRpnExpr; }
+
+ StringList* createStringList();
+ const StringList* getCurrentStringList() const { return m_pStringList; }
+ StringList* getCurrentStringList() { return m_pStringList; }
+
+ void setAsNeeded(bool pEnable = true);
+ bool asNeeded() const { return m_bAsNeeded; }
+
+ static const std::string& createParserStr(const char* pText, size_t pLength);
+
+ static void clearParserStrPool();
+
+private:
+ Kind m_Kind;
+ Input& m_Input;
+ std::string m_Name;
+ InputTree* m_pInputTree;
+ InputBuilder& m_Builder;
+ CommandQueue m_CommandQueue;
+ bool m_bHasSectionsCmd;
+ bool m_bInSectionsCmd;
+ bool m_bInOutputSectDesc;
+ RpnExpr* m_pRpnExpr;
+ StringList* m_pStringList;
+ bool m_bAsNeeded;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/ScriptReader.h b/include/mcld/Script/ScriptReader.h
new file mode 100644
index 0000000..14a667f
--- /dev/null
+++ b/include/mcld/Script/ScriptReader.h
@@ -0,0 +1,49 @@
+//===- ScriptReader.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_SCRIPTREADER_H
+#define MCLD_SCRIPT_SCRIPTREADER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/LDReader.h>
+
+namespace mcld {
+
+class Module;
+class ScriptFile;
+class Input;
+class GroupReader;
+class LinkerConfig;
+class LinkerScript;
+class TargetLDBackend;
+
+class ScriptReader : public LDReader
+{
+public:
+ ScriptReader(GroupReader& pGroupReader);
+
+ ~ScriptReader();
+
+ /// readScript
+ bool readScript(const LinkerConfig& pConfig, ScriptFile& pScriptFile);
+
+ /// isMyFormat
+ bool isMyFormat(Input& pInput, bool &pContinue) const;
+
+ GroupReader& getGroupReader() { return m_GroupReader; }
+
+private:
+ GroupReader& m_GroupReader;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/ScriptScanner.h b/include/mcld/Script/ScriptScanner.h
new file mode 100644
index 0000000..43897e5
--- /dev/null
+++ b/include/mcld/Script/ScriptScanner.h
@@ -0,0 +1,62 @@
+//===- ScriptScanner.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_SCRIPTSCANNER_H
+#define MCLD_SCRIPT_SCRIPTSCANNER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#ifndef __FLEX_LEXER_H
+#include "FlexLexer.h"
+#endif
+
+#ifndef YY_DECL
+#define YY_DECL \
+ mcld::ScriptParser::token_type \
+ mcld::ScriptScanner::lex(mcld::ScriptParser::semantic_type* yylval, \
+ mcld::ScriptParser::location_type* yylloc, \
+ const mcld::ScriptFile& pScriptFile)
+#endif
+
+#include <mcld/Script/ScriptFile.h>
+#include "ScriptParser.h"
+#include <stack>
+
+namespace mcld {
+
+/** \class ScriptScanner
+ *
+ */
+class ScriptScanner : public yyFlexLexer
+{
+public:
+ ScriptScanner(std::istream* yyin = NULL, std::ostream* yyout = NULL);
+
+ virtual ~ScriptScanner();
+
+ virtual ScriptParser::token_type lex(ScriptParser::semantic_type* yylval,
+ ScriptParser::location_type* yylloc,
+ const ScriptFile& pScriptFile);
+
+ void setLexState(ScriptFile::Kind pKind);
+
+ void popLexState();
+
+private:
+ void enterComments(ScriptParser::location_type& pLocation);
+
+private:
+ ScriptFile::Kind m_Kind;
+ std::stack<ScriptFile::Kind> m_StateStack;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/SearchDirCmd.h b/include/mcld/Script/SearchDirCmd.h
new file mode 100644
index 0000000..f695a76
--- /dev/null
+++ b/include/mcld/Script/SearchDirCmd.h
@@ -0,0 +1,49 @@
+//===- SearchDirCmd.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_SEARCHDIRCMD_H
+#define MCLD_SCRIPT_SEARCHDIRCMD_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/ScriptCommand.h>
+#include <string>
+
+namespace mcld
+{
+
+class Module;
+
+/** \class SearchDirCmd
+ * \brief This class defines the interfaces to SEARCH_DIR command.
+ */
+
+class SearchDirCmd : public ScriptCommand
+{
+public:
+ SearchDirCmd(const std::string& pPath);
+ ~SearchDirCmd();
+
+ void dump() const;
+
+ void activate(Module& pModule);
+
+ static bool classof(const ScriptCommand* pCmd)
+ {
+ return pCmd->getKind() == ScriptCommand::SEARCH_DIR;
+ }
+
+private:
+ std::string m_Path;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/SectionsCmd.h b/include/mcld/Script/SectionsCmd.h
new file mode 100644
index 0000000..afff1b1
--- /dev/null
+++ b/include/mcld/Script/SectionsCmd.h
@@ -0,0 +1,72 @@
+//===- SectionsCmd.h ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_SECTIONSCMD_H
+#define MCLD_SCRIPT_SECTIONSCMD_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/ScriptCommand.h>
+#include <llvm/Support/DataTypes.h>
+#include <vector>
+
+namespace mcld
+{
+
+class Module;
+
+/** \class SectionsCmd
+ * \brief This class defines the interfaces to SECTIONS command.
+ */
+
+class SectionsCmd : public ScriptCommand
+{
+public:
+ typedef std::vector<ScriptCommand*> SectionCommands;
+ typedef SectionCommands::const_iterator const_iterator;
+ typedef SectionCommands::iterator iterator;
+ typedef SectionCommands::const_reference const_reference;
+ typedef SectionCommands::reference reference;
+
+public:
+ SectionsCmd();
+ ~SectionsCmd();
+
+ const_iterator begin() const { return m_SectionCommands.begin(); }
+ iterator begin() { return m_SectionCommands.begin(); }
+ const_iterator end() const { return m_SectionCommands.end(); }
+ iterator end() { return m_SectionCommands.end(); }
+
+ const_reference front() const { return m_SectionCommands.front(); }
+ reference front() { return m_SectionCommands.front(); }
+ const_reference back() const { return m_SectionCommands.back(); }
+ reference back() { return m_SectionCommands.back(); }
+
+ size_t size() const { return m_SectionCommands.size(); }
+
+ bool empty() const { return m_SectionCommands.empty(); }
+
+ void dump() const;
+
+ static bool classof(const ScriptCommand* pCmd)
+ {
+ return pCmd->getKind() == ScriptCommand::SECTIONS;
+ }
+
+ void activate(Module& pModule);
+
+ void push_back(ScriptCommand* pCommand);
+
+private:
+ SectionCommands m_SectionCommands;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Script/StrToken.h b/include/mcld/Script/StrToken.h
new file mode 100644
index 0000000..359b0be
--- /dev/null
+++ b/include/mcld/Script/StrToken.h
@@ -0,0 +1,67 @@
+//===- StrToken.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_STRTOKEN_H
+#define MCLD_SCRIPT_STRTOKEN_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Support/Allocators.h>
+#include <mcld/Config/Config.h>
+#include <string>
+
+namespace mcld
+{
+
+/** \class StrToken
+ * \brief This class defines the interfaces to a element in EXCLUDE_FILE list
+ * or in Output Section Phdr, or be a base class of other str token.
+ */
+
+class StrToken
+{
+public:
+ enum Kind {
+ Unknown,
+ String,
+ Input,
+ Wildcard
+ };
+
+private:
+ friend class Chunk<StrToken, MCLD_SYMBOLS_PER_INPUT>;
+protected:
+ StrToken();
+ StrToken(Kind pKind, const std::string& pString);
+
+public:
+ virtual ~StrToken();
+
+ Kind kind() const { return m_Kind; }
+
+ const std::string& name() const { return m_Name; }
+
+ static bool classof(const StrToken* pToken)
+ {
+ return pToken->kind() == StrToken::String;
+ }
+
+ /* factory method */
+ static StrToken* create(const std::string& pString);
+ static void destroy(StrToken*& pToken);
+ static void clear();
+
+private:
+ Kind m_Kind;
+ std::string m_Name;
+};
+
+} // namepsace of mcld
+
+#endif
diff --git a/include/mcld/Script/StringList.h b/include/mcld/Script/StringList.h
new file mode 100644
index 0000000..da27e41
--- /dev/null
+++ b/include/mcld/Script/StringList.h
@@ -0,0 +1,72 @@
+//===- StringList.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_STRINGLIST_H
+#define MCLD_SCRIPT_STRINGLIST_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Config/Config.h>
+#include <mcld/Support/Allocators.h>
+#include <vector>
+
+namespace mcld
+{
+
+class StrToken;
+
+/** \class StringList
+ * \brief This class defines the interfaces to StringList.
+ */
+
+class StringList
+{
+public:
+ typedef std::vector<StrToken*> Tokens;
+ typedef Tokens::const_iterator const_iterator;
+ typedef Tokens::iterator iterator;
+ typedef Tokens::const_reference const_reference;
+ typedef Tokens::reference reference;
+
+private:
+ friend class Chunk<StringList, MCLD_SYMBOLS_PER_INPUT>;
+ StringList();
+
+public:
+ ~StringList();
+
+ const_iterator begin() const { return m_Tokens.begin(); }
+ iterator begin() { return m_Tokens.begin(); }
+ const_iterator end() const { return m_Tokens.end(); }
+ iterator end() { return m_Tokens.end(); }
+
+ const_reference front() const { return m_Tokens.front(); }
+ reference front() { return m_Tokens.front(); }
+ const_reference back() const { return m_Tokens.back(); }
+ reference back() { return m_Tokens.back(); }
+
+ bool empty() const { return m_Tokens.empty(); }
+
+ void push_back(StrToken* pToken);
+
+ void dump() const;
+
+ /* factory methods */
+ static StringList* create();
+ static void destroy(StringList*& pStringList);
+ static void clear();
+
+private:
+ Tokens m_Tokens;
+};
+
+} // namepsace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/TernaryOp.h b/include/mcld/Script/TernaryOp.h
new file mode 100644
index 0000000..0517b4a
--- /dev/null
+++ b/include/mcld/Script/TernaryOp.h
@@ -0,0 +1,71 @@
+//===- TernaryOp.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_TERNARYOP_H
+#define MCLD_SCRIPT_TERNARYOP_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/Operator.h>
+#include <cstddef>
+
+namespace mcld
+{
+
+class Operand;
+class IntOperand;
+class Module;
+class TargetLDBackend;
+
+/** \class TernaryOP
+ * \brief This class defines the interfaces to an binary operator token.
+ */
+
+template<Operator::Type TYPE>
+class TernaryOp : public Operator
+{
+private:
+ friend class Operator;
+
+ TernaryOp()
+ : Operator(Operator::TERNARY, TYPE)
+ {
+ m_pOperand[0] = m_pOperand[1] = m_pOperand[2] = NULL;
+ }
+
+public:
+ ~TernaryOp()
+ {}
+
+ IntOperand* eval(const Module& pModule, const TargetLDBackend& pBackend);
+
+ void appendOperand(Operand* pOperand)
+ {
+ m_pOperand[m_Size++] = pOperand;
+ if (m_Size == 3)
+ m_Size = 0;
+ }
+
+private:
+ size_t m_Size;
+ Operand* m_pOperand[3];
+};
+
+template<>
+IntOperand* TernaryOp<Operator::TERNARY_IF>::eval(const Module&,
+ const TargetLDBackend&);
+
+template<>
+IntOperand*
+TernaryOp<Operator::DATA_SEGMENT_ALIGN>::eval(const Module&,
+ const TargetLDBackend&);
+
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Script/UnaryOp.h b/include/mcld/Script/UnaryOp.h
new file mode 100644
index 0000000..6b79b3c
--- /dev/null
+++ b/include/mcld/Script/UnaryOp.h
@@ -0,0 +1,102 @@
+//===- UnaryOp.h ----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_UNARYOP_H
+#define MCLD_SCRIPT_UNARYOP_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/Operator.h>
+#include <cstddef>
+
+namespace mcld
+{
+
+class Operand;
+class IntOperand;
+class Module;
+class TargetLDBackend;
+
+/** \class UnaryOp
+ * \brief This class defines the interfaces to an unary operator token.
+ */
+
+template<Operator::Type TYPE>
+class UnaryOp : public Operator
+{
+private:
+ friend class Operator;
+
+ UnaryOp()
+ : Operator(Operator::UNARY, TYPE), m_pOperand(NULL)
+ {}
+
+public:
+ ~UnaryOp()
+ {}
+
+ IntOperand* eval(const Module& pModule, const TargetLDBackend& pBackend);
+
+ void appendOperand(Operand* pOperand)
+ {
+ m_pOperand = pOperand;
+ }
+
+private:
+ Operand* m_pOperand;
+};
+
+template<>
+IntOperand* UnaryOp<Operator::UNARY_PLUS>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* UnaryOp<Operator::UNARY_MINUS>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* UnaryOp<Operator::LOGICAL_NOT>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* UnaryOp<Operator::BITWISE_NOT>::eval(const Module&,
+ const TargetLDBackend&);
+
+template<>
+IntOperand* UnaryOp<Operator::ABSOLUTE>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* UnaryOp<Operator::ADDR>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* UnaryOp<Operator::ALIGNOF>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* UnaryOp<Operator::DATA_SEGMENT_END>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* UnaryOp<Operator::DEFINED>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* UnaryOp<Operator::LENGTH>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* UnaryOp<Operator::LOADADDR>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* UnaryOp<Operator::NEXT>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* UnaryOp<Operator::ORIGIN>::eval(const Module&,
+ const TargetLDBackend&);
+template<>
+IntOperand* UnaryOp<Operator::SIZEOF>::eval(const Module&,
+ const TargetLDBackend&);
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Script/WildcardPattern.h b/include/mcld/Script/WildcardPattern.h
new file mode 100644
index 0000000..0c91435
--- /dev/null
+++ b/include/mcld/Script/WildcardPattern.h
@@ -0,0 +1,71 @@
+//===- WildcardPattern.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SCRIPT_WILDCARDPATTERN_H
+#define MCLD_SCRIPT_WILDCARDPATTERN_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Script/StrToken.h>
+#include <mcld/Support/Allocators.h>
+#include <mcld/Config/Config.h>
+#include <llvm/ADT/StringRef.h>
+
+namespace mcld
+{
+
+/** \class WildcardPattern
+ * \brief This class defines the interfaces to Input Section Wildcard Patterns
+ */
+
+class WildcardPattern : public StrToken
+{
+public:
+ enum SortPolicy {
+ SORT_NONE,
+ SORT_BY_NAME,
+ SORT_BY_ALIGNMENT,
+ SORT_BY_NAME_ALIGNMENT,
+ SORT_BY_ALIGNMENT_NAME,
+ SORT_BY_INIT_PRIORITY
+ };
+
+private:
+ friend class Chunk<WildcardPattern, MCLD_SYMBOLS_PER_INPUT>;
+ WildcardPattern();
+ WildcardPattern(const std::string& pPattern, SortPolicy pPolicy);
+
+public:
+ ~WildcardPattern();
+
+ SortPolicy sortPolicy() const { return m_SortPolicy; }
+
+ bool isPrefix() const { return m_bIsPrefix; }
+
+ llvm::StringRef prefix() const;
+
+ static bool classof(const StrToken* pToken)
+ {
+ return pToken->kind() == StrToken::Wildcard;
+ }
+
+ /* factory method */
+ static WildcardPattern* create(const std::string& pPattern,
+ SortPolicy pPolicy);
+ static void destroy(WildcardPattern*& pToken);
+ static void clear();
+
+private:
+ SortPolicy m_SortPolicy;
+ bool m_bIsPrefix;
+};
+
+} // namepsace of mcld
+
+#endif
diff --git a/include/mcld/Support/CommandLine.h b/include/mcld/Support/CommandLine.h
index 00907fe..6cb0fae 100644
--- a/include/mcld/Support/CommandLine.h
+++ b/include/mcld/Support/CommandLine.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_COMMANDLINE_H
-#define MCLD_COMMANDLINE_H
+#ifndef MCLD_SUPPORT_COMMANDLINE_H
+#define MCLD_SUPPORT_COMMANDLINE_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Support/DefSymParser.h b/include/mcld/Support/DefSymParser.h
deleted file mode 100644
index a721b48..0000000
--- a/include/mcld/Support/DefSymParser.h
+++ /dev/null
@@ -1,34 +0,0 @@
-//===- DefSymParser.h -----------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_DEFSYM_PARSER_H
-#define MCLD_DEFSYM_PARSER_H
-
-#include <mcld/Module.h>
-#include <llvm/ADT/StringRef.h>
-
-namespace mcld {
-
-/** \class DefSymParser
- * \brief DefSymParser parses --defsym option.
- */
-class DefSymParser
-{
-public:
- DefSymParser(const Module& pModule);
-
- // parse a valid expression and set the value in the second parameter
- bool parse(llvm::StringRef, uint64_t&);
-
-private:
- const Module& m_Module;
-};
-
-} // mcld
-
-#endif
diff --git a/include/mcld/Support/Directory.h b/include/mcld/Support/Directory.h
index 66ba118..2bf8f06 100644
--- a/include/mcld/Support/Directory.h
+++ b/include/mcld/Support/Directory.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_DIRECTORY_H
-#define MCLD_DIRECTORY_H
+#ifndef MCLD_SUPPORT_DIRECTORY_H
+#define MCLD_SUPPORT_DIRECTORY_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Support/FileHandle.h b/include/mcld/Support/FileHandle.h
index f9fe73a..9f551b9 100644
--- a/include/mcld/Support/FileHandle.h
+++ b/include/mcld/Support/FileHandle.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_FILE_HANDLE_H
-#define MCLD_FILE_HANDLE_H
+#ifndef MCLD_SUPPORT_FILEHANDLE_H
+#define MCLD_SUPPORT_FILEHANDLE_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Support/FileOutputBuffer.h b/include/mcld/Support/FileOutputBuffer.h
new file mode 100644
index 0000000..a49ffb7
--- /dev/null
+++ b/include/mcld/Support/FileOutputBuffer.h
@@ -0,0 +1,72 @@
+//===- FileOutputBuffer.h -------------------------------------------------===//
+//
+// the mclinker project
+//
+// this file is distributed under the university of illinois open source
+// license. see license.txt for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SUPPORT_FILEOUTPUTBUFFER_H
+#define MCLD_SUPPORT_FILEOUTPUTBUFFER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Support/MemoryRegion.h>
+#include <llvm/ADT/OwningPtr.h>
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/DataTypes.h>
+#include <llvm/Support/FileSystem.h>
+#include <llvm/Support/system_error.h>
+
+namespace mcld {
+
+class FileHandle;
+
+/// FileOutputBuffer - This interface is borrowed from llvm bassically, and we
+/// may use ostream to emit output later.
+class FileOutputBuffer {
+public:
+ /// Factory method to create an OutputBuffer object which manages a read/write
+ /// buffer of the specified size. When committed, the buffer will be written
+ /// to the file at the specified path.
+ static llvm::error_code create(FileHandle& pFileHandle,
+ size_t pSize,
+ llvm::OwningPtr<FileOutputBuffer>& pResult);
+
+ /// Returns a pointer to the start of the buffer.
+ uint8_t* getBufferStart() {
+ return (uint8_t*)m_pRegion->data();
+ }
+
+ /// Returns a pointer to the end of the buffer.
+ uint8_t* getBufferEnd() {
+ return (uint8_t*)m_pRegion->data() + m_pRegion->size();
+ }
+
+ /// Returns size of the buffer.
+ size_t getBufferSize() const {
+ return m_pRegion->size();
+ }
+
+ MemoryRegion request(size_t pOffset, size_t pLength);
+
+ /// Returns path where file will show up if buffer is committed.
+ llvm::StringRef getPath() const;
+
+ ~FileOutputBuffer();
+
+private:
+ FileOutputBuffer(const FileOutputBuffer &);
+ FileOutputBuffer &operator=(const FileOutputBuffer &);
+
+ FileOutputBuffer(llvm::sys::fs::mapped_file_region* pRegion,
+ FileHandle& pFileHandle);
+
+ llvm::OwningPtr<llvm::sys::fs::mapped_file_region> m_pRegion;
+ FileHandle& m_FileHandle;
+};
+
+} // namespace mcld
+
+#endif
diff --git a/include/mcld/Support/FileSystem.h b/include/mcld/Support/FileSystem.h
index 927346e..e0dddd7 100644
--- a/include/mcld/Support/FileSystem.h
+++ b/include/mcld/Support/FileSystem.h
@@ -11,8 +11,8 @@
// path class.
//===----------------------------------------------------------------------===//
-#ifndef MCLD_FILE_SYSTEM_H
-#define MCLD_FILE_SYSTEM_H
+#ifndef MCLD_SUPPORT_FILESYSTEM_H
+#define MCLD_SUPPORT_FILESYSTEM_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Support/GCFactory.h b/include/mcld/Support/GCFactory.h
index 6679f41..9ae8650 100644
--- a/include/mcld/Support/GCFactory.h
+++ b/include/mcld/Support/GCFactory.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_GC_FACTORY_H
-#define MCLD_GC_FACTORY_H
+#ifndef MCLD_SUPPORT_GCFACTORY_H
+#define MCLD_SUPPORT_GCFACTORY_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Support/GCFactoryListTraits.h b/include/mcld/Support/GCFactoryListTraits.h
index 986f6f6..b7d44d3 100644
--- a/include/mcld/Support/GCFactoryListTraits.h
+++ b/include/mcld/Support/GCFactoryListTraits.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_GC_FACTORY_LIST_TRAITS_H
-#define MCLD_GC_FACTORY_LIST_TRAITS_H
+#ifndef MCLD_SUPPORT_GCFACTORYLISTTRAITS_H
+#define MCLD_SUPPORT_GCFACTORYLISTTRAITS_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Support/HandleToArea.h b/include/mcld/Support/HandleToArea.h
deleted file mode 100644
index 8c24db7..0000000
--- a/include/mcld/Support/HandleToArea.h
+++ /dev/null
@@ -1,118 +0,0 @@
-//===- HandleToArea.h -----------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_FILE_HANDLE_TO_MEMORY_AREA_H
-#define MCLD_FILE_HANDLE_TO_MEMORY_AREA_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-#include <mcld/ADT/Uncopyable.h>
-#include <mcld/ADT/TypeTraits.h>
-#include <mcld/ADT/StringHash.h>
-#include <mcld/Support/Path.h>
-#include <mcld/Support/FileHandle.h>
-#include <vector>
-
-namespace mcld {
-
-class MemoryArea;
-
-/** \class HandleToArea
- *
- * Special double-key associative container. Keys are Path and file handler,
- * associative value is MemoryArea.
- *
- * For high performance, HandleToArea is not designed to contain unique
- * <key, value> pair. The key and value may be duplicated.
- *
- * Like FileHandle, HandleToArea should neither throw exception nor call
- * expressive diagnostic.
- */
-class HandleToArea : private Uncopyable
-{
-private:
- struct Bucket {
- unsigned int hash_value;
- FileHandle* handle;
- MemoryArea* area;
- };
-
- // the best data structure is a binary search tree.
- // However, by the shrinking time-to-market constraint, I used
- // vector and sequential search here.
- typedef std::vector<Bucket> HandleToAreaMap;
-
- typedef hash::StringHash<hash::BKDR> HashFunction;
-
-public:
- typedef HandleToAreaMap::iterator iterator;
- typedef HandleToAreaMap::const_iterator const_iterator;
-
-public:
- struct Result {
- public:
- Result(FileHandle* pHandle, MemoryArea* pArea)
- : handle(pHandle), area(pArea) { }
-
- public:
- FileHandle* handle;
- MemoryArea* area;
- };
-
- struct ConstResult {
- public:
- ConstResult(const FileHandle* pHandle, const MemoryArea* pArea)
- : handle(pHandle), area(pArea) { }
-
- public:
- const FileHandle* handle;
- const MemoryArea* area;
- };
-
-public:
- bool push_back(FileHandle* pHandle, MemoryArea* pArea);
-
- bool erase(MemoryArea* pArea);
-
- bool erase(const sys::fs::Path& pPath);
-
- Result findFirst(const sys::fs::Path& pPath);
-
- ConstResult findFirst(const sys::fs::Path& pPath) const;
-
- iterator begin()
- { return m_AreaMap.begin(); }
-
- iterator end()
- { return m_AreaMap.end(); }
-
- const_iterator begin() const
- { return m_AreaMap.begin(); }
-
- const_iterator end() const
- { return m_AreaMap.end(); }
-
- // ----- capacity ----- //
- bool empty() const
- { return m_AreaMap.empty(); }
-
- size_t size() const
- { return m_AreaMap.size(); }
-
- HandleToArea() : m_AreaMap() { }
-
- ~HandleToArea() { }
-
-private:
- HandleToAreaMap m_AreaMap;
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/Support/LEB128.h b/include/mcld/Support/LEB128.h
index 816ed72..e44966a 100644
--- a/include/mcld/Support/LEB128.h
+++ b/include/mcld/Support/LEB128.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_LEB128_H
-#define MCLD_LEB128_H
+#ifndef MCLD_SUPPORT_LEB128_H
+#define MCLD_SUPPORT_LEB128_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Support/MemoryArea.h b/include/mcld/Support/MemoryArea.h
index d3ae9b7..18ea985 100644
--- a/include/mcld/Support/MemoryArea.h
+++ b/include/mcld/Support/MemoryArea.h
@@ -6,43 +6,22 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_SUPPORT_MEMORY_AREA_H
-#define MCLD_SUPPORT_MEMORY_AREA_H
+#ifndef MCLD_SUPPORT_MEMORYAREA_H
+#define MCLD_SUPPORT_MEMORYAREA_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <mcld/ADT/Uncopyable.h>
-#include <cstddef>
-#include <map>
-#if defined(ENABLE_UNITTEST)
-namespace mcldtest {
- class MemoryAreaTest;
-} // namespace of mcldtest
-#endif
+#include <llvm/ADT/OwningPtr.h>
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/MemoryBuffer.h>
namespace mcld {
-class Space;
-class FileHandle;
-class MemoryRegion;
-
/** \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.
+ * \brief MemoryArea is used to manage input read-only memory space.
*/
class MemoryArea : private Uncopyable
{
@@ -52,72 +31,22 @@
// If the given file handler is read-only, client can not request a region
// that out of the file size.
// @param pFileHandle - file handler
- explicit MemoryArea(FileHandle& pFileHandle);
+ explicit MemoryArea(llvm::StringRef pFilename);
- // constructor by set universal space.
- // Client can not request a region that out of the universal space.
- // @param pUniverse - file handler
- explicit MemoryArea(Space& pUniverse);
-
- // destructor
- ~MemoryArea();
+ explicit MemoryArea(const char* pMemBuffer, size_t pSize);
// 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);
+ llvm::StringRef request(size_t pOffset, size_t pLength);
- // release - release a MemoryRegion.
- // release a MemoryRegion does not cause
- void release(MemoryRegion* pRegion);
-
- // clear - release all memory regions.
- void clear();
-
- const FileHandle* handler() const { return m_pFileHandle; }
- FileHandle* handler() { return m_pFileHandle; }
-
- bool hasHandler() const { return (NULL != m_pFileHandle); }
-
- // ----- space list methods ----- //
- Space* find(size_t pOffset, size_t pLength);
-
- const Space* find(size_t pOffset, size_t pLength) const;
+ size_t size() const;
private:
- class Key {
- public:
- Key(size_t pOffset, size_t pLength)
- : m_Offset(pOffset), m_Length(pLength)
- { }
-
- size_t offset() const { return m_Offset; }
-
- size_t length() const { return m_Length; }
-
- struct Compare {
- bool operator()(const Key& KEY1, const Key& KEY2) const
- {
- return KEY1.offset() + KEY1.length() < KEY2.offset() ||
- (KEY1.offset() < KEY2.offset() &&
- (KEY1.offset() + KEY1.length() < KEY2.offset() + KEY2.length()));
- }
- };
-
- private:
- size_t m_Offset;
- size_t m_Length;
- };
-
- typedef std::multimap<Key, Space*, Key::Compare> SpaceMapType;
-
-private:
- SpaceMapType m_SpaceMap;
- FileHandle* m_pFileHandle;
+ llvm::OwningPtr<llvm::MemoryBuffer> m_pMemoryBuffer;
};
} // namespace of mcld
#endif
-
diff --git a/include/mcld/Support/MemoryAreaFactory.h b/include/mcld/Support/MemoryAreaFactory.h
index b28f096..302fbd1 100644
--- a/include/mcld/Support/MemoryAreaFactory.h
+++ b/include/mcld/Support/MemoryAreaFactory.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_SUPPORT_MEMORY_AREA_FACTORY_H
-#define MCLD_SUPPORT_MEMORY_AREA_FACTORY_H
+#ifndef MCLD_SUPPORT_MEMORYAREAFACTORY_H
+#define MCLD_SUPPORT_MEMORYAREAFACTORY_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -15,7 +15,7 @@
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/Path.h>
#include <mcld/Support/FileHandle.h>
-#include <mcld/Support/HandleToArea.h>
+#include <llvm/ADT/StringMap.h>
namespace mcld
{
@@ -63,12 +63,10 @@
MemoryArea* produce(int pFD, FileHandle::OpenMode pMode);
void destruct(MemoryArea* pArea);
-
private:
- HandleToArea m_HandleToArea;
+ llvm::StringMap<MemoryArea*> m_AreaMap;
};
} // namespace of mcld
#endif
-
diff --git a/include/mcld/Support/MemoryRegion.h b/include/mcld/Support/MemoryRegion.h
index 0984873..0d18f59 100644
--- a/include/mcld/Support/MemoryRegion.h
+++ b/include/mcld/Support/MemoryRegion.h
@@ -6,112 +6,24 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef LD_MEMORY_REGION_H
-#define LD_MEMORY_REGION_H
+#ifndef MCLD_SUPPORT_MEMORYREGION_H
+#define MCLD_SUPPORT_MEMORYREGION_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
-#include <mcld/Config/Config.h>
-#include <mcld/ADT/Uncopyable.h>
-#include <mcld/Support/Allocators.h>
-#include <mcld/Support/Space.h>
+#include <mcld/ADT/TypeTraits.h>
+#include <llvm/ADT/ArrayRef.h>
+#include <llvm/Support/DataTypes.h>
namespace mcld {
-class MemoryArea;
+typedef NonConstTraits<uint8_t>::pointer Address;
+typedef ConstTraits<uint8_t>::pointer ConstAddress;
-/** \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 Chunk<MemoryRegion, MCLD_REGION_CHUNK_SIZE>;
-friend class RegionFactory;
-friend class MemoryArea;
+typedef llvm::ArrayRef<uint8_t> ConstMemoryRegion;
+typedef llvm::MutableArrayRef<uint8_t> MemoryRegion;
-public:
- typedef Space::Address Address;
- typedef Space::ConstAddress ConstAddress;
-
-private:
- MemoryRegion();
-
- MemoryRegion(const Address pVMAStart, size_t pSize);
-
- ~MemoryRegion();
-
- void setParent(Space& pSpace) { m_pParent = &pSpace; }
-
-public:
- /// Create - To wrap a piece of memory and to create a new region.
- /// This function wraps a piece of memory and to create a new region. Region
- /// is just a wraper, it is not responsible for deallocate the given memory.
- ///
- /// @param pStart [in] The start address of a piece of memory
- /// @param pSize [in] The size of the given memory
- static MemoryRegion* Create(void* pStart, size_t pSize);
-
- /// Create - To wrap a piece of memory and to create a new region.
- /// This function wraps a piece of memory and to create a new region. Region
- /// is just a wraper, it is not responsible for deallocate the given memory.
- ///
- /// If a wrapped memory comes from a Space, then we say the space is the
- /// parent of the region. pSpace is a memory counting container. It remembers
- /// the number of regions in it. A space which has no region will be removed
- /// quickly.
- ///
- /// The wrapped memory will be deallocated by Space when the space has no
- /// region used it.
- ///
- /// @param pStart [in] The start address of a piece of memory
- /// @param pSize [in] The size of the given memory
- /// @param pSpace [in] The parent space.
- static MemoryRegion* Create(void* pStart, size_t pSize, Space& pSpace);
-
- /// Destroy - To destroy the region
- /// If the region has a parent space, it will be also remove from the space.
- ///
- /// @param pRegion [in, out] pRegion is set to NULL if the destruction is
- /// success.
- static void Destroy(MemoryRegion*& pRegion);
-
- const Space* parent() const { return m_pParent; }
- Space* parent() { return m_pParent; }
-
- bool hasParent() const { return (NULL != m_pParent); }
-
- ConstAddress start() const { return m_VMAStart; }
- Address start() { return m_VMAStart; }
-
- ConstAddress end() const { return m_VMAStart+m_Length; }
- Address end() { return m_VMAStart+m_Length; }
-
- size_t size() const { return m_Length; }
-
- ConstAddress getBuffer(size_t pOffset = 0) const
- { return m_VMAStart+pOffset; }
-
- Address getBuffer(size_t pOffset = 0)
- { return m_VMAStart+pOffset; }
-
-private:
- Space* m_pParent;
- Address m_VMAStart;
- size_t m_Length;
-};
-
-} // namespace of mcld
+} // namespace mcld
#endif
-
diff --git a/include/mcld/Support/MsgHandling.h b/include/mcld/Support/MsgHandling.h
index d00132c..778ec68 100644
--- a/include/mcld/Support/MsgHandling.h
+++ b/include/mcld/Support/MsgHandling.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_MESSAGE_HANDLING_H
-#define MCLD_MESSAGE_HANDLING_H
+#ifndef MCLD_SUPPORT_MSGHANDLING_H
+#define MCLD_SUPPORT_MSGHANDLING_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Support/Path.h b/include/mcld/Support/Path.h
index 13e8ddb..fe7914e 100644
--- a/include/mcld/Support/Path.h
+++ b/include/mcld/Support/Path.h
@@ -10,8 +10,8 @@
// filesystem (v3), but modified to remove exception handling and the
// path class.
//===----------------------------------------------------------------------===//
-#ifndef MCLD_PATH_H
-#define MCLD_PATH_H
+#ifndef MCLD_SUPPORT_PATH_H
+#define MCLD_SUPPORT_PATH_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Support/PathCache.h b/include/mcld/Support/PathCache.h
index 50c6984..37857dc 100644
--- a/include/mcld/Support/PathCache.h
+++ b/include/mcld/Support/PathCache.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_PATHCACHE_H
-#define MCLD_PATHCACHE_H
+#ifndef MCLD_SUPPORT_PATHCACHE_H
+#define MCLD_SUPPORT_PATHCACHE_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Support/RealPath.h b/include/mcld/Support/RealPath.h
index 6c0cd40..0369f25 100644
--- a/include/mcld/Support/RealPath.h
+++ b/include/mcld/Support/RealPath.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_REAL_PATH_H
-#define MCLD_REAL_PATH_H
+#ifndef MCLD_SUPPORT_REALPATH_H
+#define MCLD_SUPPORT_REALPATH_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Support/RegionFactory.h b/include/mcld/Support/RegionFactory.h
deleted file mode 100644
index fd90186..0000000
--- a/include/mcld/Support/RegionFactory.h
+++ /dev/null
@@ -1,42 +0,0 @@
-//===- RegionFactory.h ----------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_SUPPORT_REGION_FACTORY_H
-#define MCLD_SUPPORT_REGION_FACTORY_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-#include <mcld/Config/Config.h>
-#include <mcld/Support/GCFactory.h>
-#include <mcld/Support/MemoryRegion.h>
-
-namespace mcld {
-
-class MemoryArea;
-
-/** \class RegionFactory
- * \brief RegionFactory produces and destroys MemoryRegions
- *
- */
-class RegionFactory : public GCFactory<MemoryRegion, MCLD_REGION_CHUNK_SIZE>
-{
-public:
- typedef GCFactory<MemoryRegion, MCLD_REGION_CHUNK_SIZE> Alloc;
- typedef MemoryRegion::Address Address;
- typedef MemoryRegion::ConstAddress ConstAddress;
-
-public:
- MemoryRegion* produce(Address pVMAStart, size_t pSize);
-
- void destruct(MemoryRegion* pRegion);
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/Support/Space.h b/include/mcld/Support/Space.h
deleted file mode 100644
index cdf69b0..0000000
--- a/include/mcld/Support/Space.h
+++ /dev/null
@@ -1,99 +0,0 @@
-//===- Space.h ------------------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_MEMORY_SPACE_H
-#define MCLD_MEMORY_SPACE_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-#include <llvm/Support/DataTypes.h>
-#include <mcld/ADT/TypeTraits.h>
-
-namespace mcld {
-
-class FileHandle;
-class MemoryRegion;
-
-/** \class Space
- * \brief Space contains a chunk of memory space that does not overlap with
- * the other Space.
- *
- */
-class Space
-{
-public:
- enum Type
- {
- ALLOCATED_ARRAY,
- MMAPED,
- EXTERNAL,
- UNALLOCATED
- };
-
- typedef NonConstTraits<uint8_t>::pointer Address;
- typedef ConstTraits<uint8_t>::pointer ConstAddress;
-
-private:
- Space();
-
- ~Space();
-
- Space(Type pType, void* pMemBuffer, size_t pSize);
-
-public:
- void setStart(size_t pOffset)
- { m_StartOffset = pOffset; }
-
- Address memory()
- { return m_Data; }
-
- ConstAddress memory() const
- { return m_Data; }
-
- size_t start() const
- { return m_StartOffset; }
-
- size_t size() const
- { return m_Size; }
-
- Type type() const
- { return m_Type; }
-
- void addRegion(MemoryRegion& pRegion)
- { ++m_RegionCount; }
-
- void removeRegion(MemoryRegion& pRegion)
- { --m_RegionCount; }
-
- size_t numOfRegions() const
- { return m_RegionCount; }
-
- /// Create - Create a Space from external memory
- static Space* Create(void* pMemBuffer, size_t pSize);
-
- /// Create - Create a Space from FileHandler
- static Space* Create(FileHandle& pHandler, size_t pOffset, size_t pSize);
-
- static void Destroy(Space*& pSpace);
-
- static void Release(Space* pSpace, FileHandle& pHandler);
-
- static void Sync(Space* pSpace, FileHandle& pHandler);
-
-private:
- Address m_Data;
- uint32_t m_StartOffset;
- uint32_t m_Size;
- uint16_t m_RegionCount;
- Type m_Type : 2;
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/Support/SystemUtils.h b/include/mcld/Support/SystemUtils.h
index 8f8507a..f15fccf 100644
--- a/include/mcld/Support/SystemUtils.h
+++ b/include/mcld/Support/SystemUtils.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_SYSTEM_UTILS_H
-#define MCLD_SYSTEM_UTILS_H
+#ifndef MCLD_SUPPORT_SYSTEMUTILS_H
+#define MCLD_SUPPORT_SYSTEMUTILS_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Support/Target.h b/include/mcld/Support/Target.h
new file mode 100644
index 0000000..021fc2e
--- /dev/null
+++ b/include/mcld/Support/Target.h
@@ -0,0 +1,105 @@
+//===- Target.h -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SUPPORT_TARGET_H
+#define MCLD_SUPPORT_TARGET_H
+#include <string>
+#include <list>
+
+namespace llvm {
+class Target;
+class Triple;
+class TargetMachine;
+} // namespace of llvm
+
+namespace mcld {
+
+class MCLDTargetMachine;
+class TargetRegistry;
+class MCLinker;
+class LinkerScript;
+class LinkerConfig;
+class Module;
+class FileHandle;
+class DiagnosticLineInfo;
+class TargetLDBackend;
+
+/** \class Target
+ * \brief Target collects target specific information
+ */
+class Target
+{
+ friend class mcld::MCLDTargetMachine;
+ friend class mcld::TargetRegistry;
+
+public:
+ typedef unsigned int (*TripleMatchQualityFnTy)(const llvm::Triple& pTriple);
+
+ typedef MCLDTargetMachine *(*TargetMachineCtorTy)(const llvm::Target &,
+ const mcld::Target &,
+ llvm::TargetMachine &,
+ const std::string&);
+
+ typedef MCLinker *(*MCLinkerCtorTy)(const std::string& pTriple,
+ LinkerConfig&,
+ Module&,
+ FileHandle& pFileHandle);
+
+ typedef bool (*EmulationFnTy)(LinkerScript&, LinkerConfig&);
+
+ typedef TargetLDBackend *(*TargetLDBackendCtorTy)(const LinkerConfig&);
+
+ typedef DiagnosticLineInfo *(*DiagnosticLineInfoCtorTy)(const mcld::Target&,
+ const std::string&);
+
+public:
+ Target();
+
+ /// getName - get the target name
+ const char* name() const { return Name; }
+
+ unsigned int getTripleQuality(const llvm::Triple& pTriple) const;
+
+ /// createTargetMachine - create target-specific TargetMachine
+ MCLDTargetMachine* createTargetMachine(const std::string& pTriple,
+ const llvm::Target& pTarget,
+ llvm::TargetMachine& pTM) const;
+
+ /// createMCLinker - create target-specific MCLinker
+ MCLinker *createMCLinker(const std::string &pTriple,
+ LinkerConfig& pConfig,
+ Module& pModule,
+ FileHandle& pFileHandle) const;
+
+ /// emulate - given MCLinker default values for the other aspects of the
+ /// target system.
+ bool emulate(LinkerScript& pScript, LinkerConfig& pConfig) const;
+
+ /// createLDBackend - create target-specific LDBackend
+ TargetLDBackend* createLDBackend(const LinkerConfig& pConfig) const;
+
+ /// createDiagnosticLineInfo - create target-specific DiagnosticLineInfo
+ DiagnosticLineInfo* createDiagnosticLineInfo(const mcld::Target& pTarget,
+ const std::string& pTriple) const;
+
+private:
+ /// Name - The target name
+ const char* Name;
+
+ TripleMatchQualityFnTy TripleMatchQualityFn;
+ TargetMachineCtorTy TargetMachineCtorFn;
+ MCLinkerCtorTy MCLinkerCtorFn;
+ EmulationFnTy EmulationFn;
+ TargetLDBackendCtorTy TargetLDBackendCtorFn;
+ DiagnosticLineInfoCtorTy DiagnosticLineInfoCtorFn;
+};
+
+} //end namespace mcld
+
+#endif
+
diff --git a/include/mcld/Support/TargetRegistry.h b/include/mcld/Support/TargetRegistry.h
index aabb06d..1ae6245 100644
--- a/include/mcld/Support/TargetRegistry.h
+++ b/include/mcld/Support/TargetRegistry.h
@@ -6,9 +6,11 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_TARGET_REGISTRY_H
-#define MCLD_TARGET_REGISTRY_H
-#include <llvm/Support/TargetRegistry.h>
+#ifndef MCLD_SUPPORT_TARGETREGISTRY_H
+#define MCLD_SUPPORT_TARGETREGISTRY_H
+#include <mcld/Support/Target.h>
+#include <llvm/ADT/Triple.h>
+
#include <string>
#include <list>
@@ -21,122 +23,9 @@
namespace mcld {
-class Module;
-class LinkerConfig;
-class LinkerScript;
-class MemoryArea;
-class MCLDTargetMachine;
-class TargetRegistry;
-class MCLinker;
-class TargetLDBackend;
-class AttributeFactory;
-class InputFactory;
-class ContextFactory;
-class DiagnosticLineInfo;
-
-//===----------------------------------------------------------------------===//
-/// Target - mcld::Target is an object adapter of llvm::Target
-//===----------------------------------------------------------------------===//
-class Target
-{
- friend class mcld::MCLDTargetMachine;
- friend class mcld::TargetRegistry;
-public:
- typedef mcld::MCLDTargetMachine *(*TargetMachineCtorTy)(const mcld::Target &,
- llvm::TargetMachine &,
- const std::string&);
-
- typedef MCLinker *(*MCLinkerCtorTy)(const std::string& pTriple,
- LinkerConfig&,
- Module&,
- MemoryArea& pOutput);
-
- typedef bool (*EmulationFnTy)(LinkerScript&, LinkerConfig&);
-
- typedef TargetLDBackend *(*TargetLDBackendCtorTy)(const llvm::Target&,
- const LinkerConfig&);
-
- typedef DiagnosticLineInfo *(*DiagnosticLineInfoCtorTy)(const mcld::Target&,
- const std::string&);
-
-public:
- Target();
-
- void setTarget(const llvm::Target& pTarget)
- { m_pT = &pTarget; }
-
- mcld::MCLDTargetMachine *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 NULL;
- }
-
- /// createMCLinker - create target-specific MCLinker
- ///
- /// @return created MCLinker
- MCLinker *createMCLinker(const std::string &pTriple,
- LinkerConfig& pConfig,
- Module& pModule,
- MemoryArea& pOutput) const {
- if (!MCLinkerCtorFn)
- return NULL;
- return MCLinkerCtorFn(pTriple, pConfig, pModule, pOutput);
- }
-
- /// emulate - given MCLinker default values for the other aspects of the
- /// target system.
- bool emulate(LinkerScript& pScript, LinkerConfig& pConfig) const {
- if (!EmulationFn)
- return false;
- return EmulationFn(pScript, pConfig);
- }
-
- /// createLDBackend - create target-specific LDBackend
- ///
- /// @return created TargetLDBackend
- TargetLDBackend* createLDBackend(const LinkerConfig& pConfig) const
- {
- if (!TargetLDBackendCtorFn)
- return NULL;
- return TargetLDBackendCtorFn(*get(), pConfig);
- }
-
- /// createDiagnosticLineInfo - create target-specific DiagnosticLineInfo
- DiagnosticLineInfo* createDiagnosticLineInfo(const mcld::Target& pTarget,
- const std::string& pTriple) const
- {
- if (!DiagnosticLineInfoCtorFn)
- return NULL;
- return DiagnosticLineInfoCtorFn(pTarget, pTriple);
- }
-
- const llvm::Target* get() const { return m_pT; }
-
-private:
- // ----- function pointers ----- //
- TargetMachineCtorTy TargetMachineCtorFn;
- MCLinkerCtorTy MCLinkerCtorFn;
- EmulationFnTy EmulationFn;
- TargetLDBackendCtorTy TargetLDBackendCtorFn;
- DiagnosticLineInfoCtorTy DiagnosticLineInfoCtorFn;
-
- // ----- adapted llvm::Target ----- //
- const llvm::Target* m_pT;
-};
-
-//===----------------------------------------------------------------------===//
-/// TargetRegistry - mcld::TargetRegistry is an object adapter of
-/// llvm::TargetRegistry
-///
+/** \class TargetRegistry
+ * \brief TargetRegistry is an object adapter of llvm::TargetRegistry
+ */
class TargetRegistry
{
public:
@@ -161,7 +50,9 @@
/// this is done by initializing all targets at program startup.
///
/// @param T - The target being registered.
- static void RegisterTarget(mcld::Target &T);
+ static void RegisterTarget(Target& pTarget,
+ const char* pName,
+ Target::TripleMatchQualityFnTy pQualityFn);
/// RegisterTargetMachine - Register a TargetMachine implementation for the
/// given target.
@@ -221,16 +112,23 @@
T.DiagnosticLineInfoCtorFn = 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
+ /// lookupTarget - Look up MCLinker target
///
/// @param Triple - The Triple string
/// @param Error - The returned error message
- static const mcld::Target *lookupTarget(const std::string &Triple,
+ static const mcld::Target *lookupTarget(const std::string& pTriple,
+ std::string& pError);
+
+ /// lookupTarget - Look up MCLinker target by an architecture name
+ /// and a triple. If the architecture name is not empty, then the
+ /// the lookup is done mainly by architecture. Otherwise, the target
+ /// triple is used.
+ ///
+ /// @param pArch - The architecture name
+ /// @param pTriple - The target triple
+ /// @param pError - The returned error message
+ static const mcld::Target *lookupTarget(const std::string& pArchName,
+ llvm::Triple& pTriple,
std::string &Error);
};
@@ -240,22 +138,27 @@
/// Target TheFooTarget; // The global target instance.
///
/// extern "C" void MCLDInitializeFooTargetInfo() {
-/// RegisterTarget X(TheFooTarget, "foo", "Foo description");
+/// RegisterTarget<llvm::Foo> X(TheFooTarget, "foo", "Foo description");
/// }
+template<llvm::Triple::ArchType TargetArchType = llvm::Triple::UnknownArch>
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;
+public:
+ RegisterTarget(mcld::Target &pTarget, const char* pName) {
+ // if we've registered one, then return immediately.
+ TargetRegistry::iterator target, ie = TargetRegistry::end();
+ for (target = TargetRegistry::begin(); target != ie; ++target) {
+ if (0 == strcmp((*target)->name(), pName))
+ return;
}
- if (TIter != TEnd)
- T.setTarget(*TIter);
+ TargetRegistry::RegisterTarget(pTarget, pName, &getTripleMatchQuality);
+ }
- TargetRegistry::RegisterTarget(T);
+ static unsigned int getTripleMatchQuality(const llvm::Triple& pTriple) {
+ if (pTriple.getArch() == TargetArchType)
+ return 20;
+ return 0;
}
};
@@ -275,10 +178,11 @@
}
private:
- static mcld::MCLDTargetMachine *Allocator(const mcld::Target &T,
- llvm::TargetMachine& TM,
- const std::string &Triple) {
- return new TargetMachineImpl(TM, T, Triple);
+ static MCLDTargetMachine *Allocator(const llvm::Target& pLLVMTarget,
+ const mcld::Target& pMCLDTarget,
+ llvm::TargetMachine& pTM,
+ const std::string& pTriple) {
+ return new TargetMachineImpl(pTM, pLLVMTarget, pMCLDTarget, pTriple);
}
};
diff --git a/include/mcld/Support/TargetSelect.h b/include/mcld/Support/TargetSelect.h
index 7fcb74a..0b2be2a 100644
--- a/include/mcld/Support/TargetSelect.h
+++ b/include/mcld/Support/TargetSelect.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_TARGET_SELECT_H
-#define MCLD_TARGET_SELECT_H
+#ifndef MCLD_SUPPORT_TARGETSELECT_H
+#define MCLD_SUPPORT_TARGETSELECT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Support/ToolOutputFile.h b/include/mcld/Support/ToolOutputFile.h
index 4dfc4e6..f1186c3 100644
--- a/include/mcld/Support/ToolOutputFile.h
+++ b/include/mcld/Support/ToolOutputFile.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_SUPPORT_TOOL_OUTPUT_FILE_H
-#define MCLD_SUPPORT_TOOL_OUTPUT_FILE_H
+#ifndef MCLD_SUPPORT_TOOLOUTPUTFILE_H
+#define MCLD_SUPPORT_TOOLOUTPUTFILE_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -23,12 +23,9 @@
class Path;
class FileHandle;
-class MemoryArea;
-class raw_mem_ostream;
/** \class ToolOutputFile
- * \brief ToolOutputFile contains a raw_mem_ostream and adds extra new
- * features:
+ * \brief ToolOutputFile has the following features:
* - The file is automatically deleted if the process is killed.
* - The file is automatically deleted when the TooOutputFile object is
* destoryed unless the client calls keep().
@@ -36,21 +33,21 @@
class ToolOutputFile
{
public:
- ToolOutputFile(const std::string& pPath,
+ ToolOutputFile(const sys::fs::Path& pPath,
FileHandle::OpenMode pMode,
FileHandle::Permission pPermission);
~ToolOutputFile();
- /// mem_os - Return the contained raw_mem_ostream.
- raw_mem_ostream &mem_os();
+ /// fd - Retutn the output file handle
+ FileHandle& fd() { return m_FileHandle; }
- /// os - Return the contained formatted_raw_ostream
+ /// os - Return the contained raw_fd_ostream
+ llvm::raw_fd_ostream& os();
+
+ /// formatted_os - Return the contained formatted_raw_ostream
llvm::formatted_raw_ostream& formatted_os();
- /// memory - Return the contained MemoryArea.
- MemoryArea& memory();
-
/// keep - Indicate that the tool's job wrt this output file has been
/// successful and the file should not be deleted.
void keep();
@@ -59,7 +56,7 @@
class CleanupInstaller
{
public:
- explicit CleanupInstaller(const std::string& pPath);
+ explicit CleanupInstaller(const sys::fs::Path& pPath);
~CleanupInstaller();
@@ -67,19 +64,16 @@
bool Keep;
private:
- std::string m_Path;
+ sys::fs::Path m_Path;
};
private:
FileHandle m_FileHandle;
CleanupInstaller m_Installer;
- MemoryArea* m_pMemoryArea;
- raw_mem_ostream* m_pOStream;
- llvm::formatted_raw_ostream* m_pFOStream;
-
+ llvm::raw_fd_ostream* m_pFdOstream;
+ llvm::formatted_raw_ostream* m_pFormattedOstream;
};
} // namespace of mcld
#endif
-
diff --git a/include/mcld/Support/UniqueGCFactory.h b/include/mcld/Support/UniqueGCFactory.h
index 3147bab..73c1110 100644
--- a/include/mcld/Support/UniqueGCFactory.h
+++ b/include/mcld/Support/UniqueGCFactory.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_UNIQUE_GCFACTORY_H
-#define MCLD_UNIQUE_GCFACTORY_H
+#ifndef MCLD_SUPPORT_UNIQUEGCFACTORY_H
+#define MCLD_SUPPORT_UNIQUEGCFACTORY_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Support/raw_mem_ostream.h b/include/mcld/Support/raw_mem_ostream.h
deleted file mode 100644
index b2db64a..0000000
--- a/include/mcld/Support/raw_mem_ostream.h
+++ /dev/null
@@ -1,51 +0,0 @@
-//===- raw_mem_ostream.h --------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_RAW_MEMORY_AREA_OSTREAM_H
-#define MCLD_RAW_MEMORY_AREA_OSTREAM_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-#include <string>
-
-#include <llvm/Support/raw_ostream.h>
-
-namespace mcld {
-
-class MemoryArea;
-
-class raw_mem_ostream : public llvm::raw_ostream
-{
-public:
- /// constructor - pMemoryArea must be writable.
- explicit raw_mem_ostream(MemoryArea &pMemoryArea);
-
- ~raw_mem_ostream();
-
- MemoryArea& getMemoryArea() {
- flush();
- return m_MemoryArea;
- }
-
-private:
- /// write_impl - See raw_ostream::write_impl.
- virtual void write_impl(const char *pPtr, size_t pSize);
-
- /// current_pos - Return the current position within the stream, not
- /// counting the bytes currently in the buffer.
- virtual uint64_t current_pos() const;
-
-private:
- MemoryArea& m_MemoryArea;
- uint64_t m_Position;
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/Support/raw_ostream.h b/include/mcld/Support/raw_ostream.h
index 0e2cc40..6274e49 100644
--- a/include/mcld/Support/raw_ostream.h
+++ b/include/mcld/Support/raw_ostream.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_RAW_OSTREAM_H
-#define MCLD_RAW_OSTREAM_H
+#ifndef MCLD_SUPPORT_RAWOSTREAM_H
+#define MCLD_SUPPORT_RAWOSTREAM_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Target/DarwinLDBackend.h b/include/mcld/Target/DarwinLDBackend.h
index d55055a..9003812 100644
--- a/include/mcld/Target/DarwinLDBackend.h
+++ b/include/mcld/Target/DarwinLDBackend.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef DARWINLDBACKEND_H
-#define DARWINLDBACKEND_H
+#ifndef MCLD_TARGET_DARWINLDBACKEND_H
+#define MCLD_TARGET_DARWINLDBACKEND_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Target/ELFAttribute.h b/include/mcld/Target/ELFAttribute.h
new file mode 100644
index 0000000..7d9d30d
--- /dev/null
+++ b/include/mcld/Target/ELFAttribute.h
@@ -0,0 +1,125 @@
+//===- ELFAttribute.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TARGET_ELFATTRIBUTE_H
+#define MCLD_TARGET_ELFATTRIBUTE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Target/ELFAttributeData.h>
+
+#include <llvm/ADT/SmallVector.h>
+#include <llvm/ADT/StringRef.h>
+
+namespace mcld {
+
+class ELFAttributeData;
+class GNULDBackend;
+class Input;
+class LDSection;
+class LinkerConfig;
+
+/** \class ELFAttribute
+ * \brief ELFAttribute is the attribute section in an ELF file.
+ */
+class ELFAttribute
+{
+public:
+ // ARM [ABI-addenda], 2.2.3.
+ static const char FormatVersion = 'A';
+ static const size_t FormatVersionFieldSize = sizeof(FormatVersion); // a byte
+ static const size_t SubsectionLengthFieldSize = 4; // a 4-byte integer
+
+ // MinimalELFAttributeSubsectionSize is the minimal number of bytes a valid
+ // subsection in ELF attribute section should have.
+ static const size_t MinimalELFAttributeSubsectionSize
+ = 1 /* Tag_File, see ARM [ABI-addenda], 2.2.4 */ +
+ 4 /* byte-size, see ARM [ABI-addenda], 2.2.4 */;
+
+ // MinimalELFAttributeSectionSize is the minimal number of bytes a valid ELF
+ // attribute section should have.
+ static const size_t MinimalELFAttributeSectionSize
+ = FormatVersionFieldSize + SubsectionLengthFieldSize +
+ 2 /* vendor-name, a char plus '\0', see ARM [ABI-addenda], 2.2.3 */ +
+ 1 * MinimalELFAttributeSubsectionSize;
+
+public:
+ ELFAttribute(const GNULDBackend &pBackend, const LinkerConfig& pConfig)
+ : m_Backend(pBackend), m_Config(pConfig) { }
+
+ ~ELFAttribute();
+
+public:
+ /// merge - merge attributes from input (attribute) section
+ bool merge(const Input &pInput, LDSection &pInputAttrSectHdr);
+
+ /// sizeOutput - calculate the number of bytes required to encode this
+ /// attribute data section
+ size_t sizeOutput() const;
+
+ /// emit - encode and write out this attribute section
+ size_t emit(MemoryRegion &pRegion) const;
+
+ inline const GNULDBackend &backend() const { return m_Backend; }
+
+ inline const LinkerConfig &config() const { return m_Config; }
+
+ // Place vendor's attribute data under the management.
+ void registerAttributeData(ELFAttributeData& pAttrData);
+
+private:
+ /** \class Subsection
+ * \brief A helper class to wrap ELFAttributeData and to provide general
+ * interfaces for ELFAttribute to operate on
+ */
+ class Subsection {
+ public:
+ Subsection(ELFAttribute &pParent, ELFAttributeData &pAttrData)
+ : m_Parent(pParent), m_AttrData(pAttrData) { }
+
+ public:
+ bool isMyAttribute(llvm::StringRef pVendorName) const
+ {
+ return (m_AttrData.getVendorName() == pVendorName);
+ }
+
+ /// merge - Merge the attributes from the section in the input data.
+ bool merge(const Input &pInput, ConstAddress pData, size_t pSize);
+
+ /// sizeOutput - calculate the number of bytes required to encode this
+ /// subsection
+ size_t sizeOutput() const;
+
+ /// emit - write out this attribute subsection to the buffer.
+ size_t emit(char *pBuf) const;
+
+ private:
+ // The attribute section this subsection belongs to
+ ELFAttribute &m_Parent;
+
+ // The attribute data containing in this subsection
+ ELFAttributeData &m_AttrData;
+ };
+
+ // Obtain the corresponding subsection of the specified vendor
+ Subsection *getSubsection(llvm::StringRef pVendorName) const;
+
+private:
+ const GNULDBackend &m_Backend;
+
+ const LinkerConfig &m_Config;
+
+ // There is at most two subsections ("aeabi" and "gnu") in most cases.
+ llvm::SmallVector<Subsection*, 2> m_Subsections;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Target/ELFAttributeData.h b/include/mcld/Target/ELFAttributeData.h
new file mode 100644
index 0000000..1cb9ad7
--- /dev/null
+++ b/include/mcld/Target/ELFAttributeData.h
@@ -0,0 +1,114 @@
+//===- ELFAttributeData.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TARGET_ELFATTRIBUTEDATA_H
+#define MCLD_TARGET_ELFATTRIBUTEDATA_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <stdint.h>
+#include <string>
+#include <utility>
+
+namespace mcld {
+
+class ELFAttributeValue;
+class Input;
+class LinkerConfig;
+
+/** \class ELFAttributeData
+ * \brief ELFAttributeData handles data in vendor attribute subsection.
+ */
+class ELFAttributeData
+{
+public:
+ typedef uint32_t TagType;
+
+ // Generic attribute tags shared between all vendors
+ enum {
+ Tag_NULL = 0,
+ Tag_File = 1,
+ Tag_Section = 2,
+ Tag_Symbol = 3,
+ };
+
+public:
+ ELFAttributeData(const char* pVendor) : m_Vendor(pVendor) { }
+
+ virtual ~ELFAttributeData() { }
+
+public:
+ inline const std::string &getVendorName() const { return m_Vendor; }
+
+ /// getAttributeValue - query the data store for the attribute value of the
+ /// given tag.
+ virtual const ELFAttributeValue *getAttributeValue(TagType pTag) const = 0;
+
+ /// getOrCreateAttributeValue - obtain attribute value for the given tag and
+ /// create if it does not exist.
+ ///
+ /// It returns a pair containing the attribute value instance (guaranteed to
+ /// be non-NULL) and a boolean value indicating whether the instance is newly
+ /// created (true) or not (false.)
+ virtual std::pair<ELFAttributeValue*, bool>
+ getOrCreateAttributeValue(TagType pTag) = 0;
+
+ /// preMerge - hooks to call before starting merge the attribute data in an
+ /// input.
+ virtual bool preMerge(const Input &pInput) { return true; }
+
+ /// merge - implement logics to merge input attribute to the output.
+ virtual bool merge(const LinkerConfig& pConfig, const Input &pInput,
+ TagType pTag, const ELFAttributeValue& pInAttr) = 0;
+
+ /// postMerge - hooks to call after finishing merge the attribute data from an
+ /// input.
+ virtual bool postMerge(const LinkerConfig& pConfig, const Input &pInput)
+ { return true; }
+
+ /// sizeOutput - obtain number of bytes required to encode the attribute data.
+ virtual size_t sizeOutput() const = 0;
+
+ /// emit - write out attribute data to the buffer and return the number of
+ /// bytes written
+ virtual size_t emit(char *pBuf) const = 0;
+
+public:
+ /// ReadTag - read an attribute tag from input buffer.
+ ///
+ /// If the read succeeds, pBuf moves to the new position just pass the end of
+ /// the tag in the buffer and pBufSize decreases the size of tag in the
+ /// buffer. Otherwise, this function will return false and change nothing
+ /// except leaving undefined value in pTag.
+ static bool ReadTag(TagType& pTag, const char* &pBuf, size_t &pBufSize);
+
+ /// ReadValue - read an attribute value from input buffer
+ ///
+ /// Similar with ReadTag() while this reads attribute value from the input
+ /// buffer. Note that the value type of the attribute must be properly set in
+ /// pValue prior the call.
+ static bool ReadValue(ELFAttributeValue& pValue, const char* &pBuf,
+ size_t &pBufSize);
+
+ /// WriteAttribute - write an attribute tag plus value to buffer.
+ ///
+ /// On success, the pBuf moves to the new position just pass the end of the
+ /// attribute data just written. Otherwise, it returns false and leaves pBuf
+ /// in an undefined position. Note that buffer is guaranteed to be able to
+ /// contain the attribute data.
+ static bool WriteAttribute(TagType pTag, const ELFAttributeValue& pValue,
+ char* &pBuf);
+
+private:
+ const std::string m_Vendor;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Target/ELFAttributeValue.h b/include/mcld/Target/ELFAttributeValue.h
new file mode 100644
index 0000000..0af3c97
--- /dev/null
+++ b/include/mcld/Target/ELFAttributeValue.h
@@ -0,0 +1,125 @@
+//===- ELFAttributeValue.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TARGET_ELFATTRIBUTEVALUE_H
+#define MCLD_TARGET_ELFATTRIBUTEVALUE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <string>
+
+namespace mcld
+{
+
+/** \class ELFAttributeValue
+ * \brief ELFAttributeValue stroes the value of an attribute tag. The attribtue
+ * tag itself is not stored in this object.
+ */
+class ELFAttributeValue
+{
+public:
+ // Type of value that an attribute tag holds.
+ enum Type {
+ // The value contains no data and has unknown type.
+ Uninitialized = 0,
+
+ // The value contains integer data.
+ Int = 1L << 0,
+
+ // The value contains string data.
+ String = 1L << 1,
+
+ // This is for attribute in which "default value" (0 for int type and empty
+ // string for string type) has special meaning for them. That is, the
+ // default value is "disabled" and meaningful for those attribute.
+ NoDefault = 1L << 2,
+ };
+
+public:
+ ELFAttributeValue()
+ : m_Type(Uninitialized), m_IntValue(0), m_StringValue() { }
+
+ ~ELFAttributeValue() { }
+
+public:
+ unsigned int type() const
+ { return m_Type; }
+
+ void setType(unsigned int pType)
+ { m_Type = pType; }
+
+ unsigned int getIntValue() const
+ { return m_IntValue; }
+
+ void setIntValue(unsigned int pIntValue)
+ { m_IntValue = pIntValue; }
+
+ const std::string &getStringValue() const
+ { return m_StringValue; }
+
+ void setStringValue(const std::string &pStringValue)
+ { m_StringValue = pStringValue; }
+
+ void setStringValue(const char *pStringValue, size_t pSize)
+ { m_StringValue.assign(pStringValue, pSize); }
+
+ void setStringValue(const char *pStringValue)
+ { m_StringValue.assign(pStringValue); }
+
+ size_t getSize() const;
+
+ inline bool isUninitialized() const
+ { return (m_Type == Uninitialized); }
+
+ inline bool isInitialized() const
+ { return !isUninitialized(); }
+
+ inline bool isIntValue() const
+ { return (m_Type & Int); }
+
+ inline bool isStringValue() const
+ { return (m_Type & String); }
+
+ inline bool hasNoDefault() const
+ { return (m_Type & NoDefault); }
+
+ bool isDefaultValue() const;
+
+ // Returns true if this attribute value should be emitted to the output.
+ inline bool shouldEmit() const {
+ // Attribute with non-default value should be emitted.
+ return !isDefaultValue();
+ }
+
+ bool equals(const ELFAttributeValue& pValue) const;
+
+ bool operator==(const ELFAttributeValue& pValue) const
+ { return equals(pValue); }
+ bool operator!=(const ELFAttributeValue& pValue) const
+ { return !equals(pValue); }
+
+ /// reset - reset this value to the uninitialized state
+ void reset()
+ {
+ m_Type = Uninitialized;
+ m_IntValue = 0;
+ m_StringValue.clear();
+ return;
+ }
+
+private:
+ unsigned int m_Type;
+
+ unsigned int m_IntValue;
+ std::string m_StringValue;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Target/ELFDynamic.h b/include/mcld/Target/ELFDynamic.h
index 62f534d..c9b257f 100644
--- a/include/mcld/Target/ELFDynamic.h
+++ b/include/mcld/Target/ELFDynamic.h
@@ -6,14 +6,15 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ELF_DYNAMIC_SECTION_H
-#define MCLD_ELF_DYNAMIC_SECTION_H
+#ifndef MCLD_TARGET_ELFDYNAMIC_H
+#define MCLD_TARGET_ELFDYNAMIC_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
-#include <llvm/Support/ELF.h>
#include <mcld/LD/LDSection.h>
+#include <mcld/Support/FileOutputBuffer.h>
+#include <llvm/Support/ELF.h>
#include <vector>
#include <cstring>
@@ -22,7 +23,6 @@
class ELFFileFormat;
class GNULDBackend;
class LinkerConfig;
-class MemoryRegion;
namespace elf_dynamic {
diff --git a/include/mcld/Target/ELFEmulation.h b/include/mcld/Target/ELFEmulation.h
index 9d35792..2a79f11 100644
--- a/include/mcld/Target/ELFEmulation.h
+++ b/include/mcld/Target/ELFEmulation.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ELF_EMULATION_H
-#define MCLD_ELF_EMULATION_H
+#ifndef MCLD_TARGET_ELFEMULATION_H
+#define MCLD_TARGET_ELFEMULATION_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/include/mcld/Target/ELFMCLinker.h b/include/mcld/Target/ELFMCLinker.h
index 76f46e8..2cead3b 100644
--- a/include/mcld/Target/ELFMCLinker.h
+++ b/include/mcld/Target/ELFMCLinker.h
@@ -11,8 +11,8 @@
// This pass set up default parameters for ELF.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ELF_SECTION_LINKER_H
-#define MCLD_ELF_SECTION_LINKER_H
+#ifndef MCLD_TARGET_ELFMCLINKER_H
+#define MCLD_TARGET_ELFMCLINKER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -22,13 +22,14 @@
class Module;
class Output;
+class FileHandle;
class ELFMCLinker : public MCLinker
{
public:
ELFMCLinker(LinkerConfig& pConfig,
mcld::Module& pModule,
- MemoryArea& pOutput);
+ FileHandle& pFileHandle);
virtual ~ELFMCLinker();
};
diff --git a/include/mcld/Target/GNUInfo.h b/include/mcld/Target/GNUInfo.h
index 86a29ba..247d817 100644
--- a/include/mcld/Target/GNUInfo.h
+++ b/include/mcld/Target/GNUInfo.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_TARGET_GNU_INFO_H
-#define MCLD_TARGET_GNU_INFO_H
+#ifndef MCLD_TARGET_GNUINFO_H
+#define MCLD_TARGET_GNUINFO_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -36,7 +36,7 @@
uint8_t OSABI() const;
/// ABIVersion - the value of e_ident[EI_ABIVRESION]
- uint8_t ABIVersion() const { return 0x0; }
+ virtual uint8_t ABIVersion() const { return 0x0; }
/// defaultTextSegmentAddr - target should specify its own default start address
/// of the text segment. esp. for exec.
@@ -65,7 +65,7 @@
/// here. If target favors the different size, please override this function
virtual uint64_t abiPageSize() const { return 0x1000; }
-private:
+protected:
const llvm::Triple& m_Triple;
};
diff --git a/include/mcld/Target/GNULDBackend.h b/include/mcld/Target/GNULDBackend.h
index 3384eae..0d23964 100644
--- a/include/mcld/Target/GNULDBackend.h
+++ b/include/mcld/Target/GNULDBackend.h
@@ -6,31 +6,21 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_TARGET_GNU_LDBACKEND_H
-#define MCLD_TARGET_GNU_LDBACKEND_H
+#ifndef MCLD_TARGET_GNULDBACKEND_H
+#define MCLD_TARGET_GNULDBACKEND_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <mcld/Target/TargetLDBackend.h>
-#include <llvm/Support/ELF.h>
-#include <mcld/ADT/HashTable.h>
-#include <mcld/ADT/HashEntry.h>
-#include <mcld/LD/ELFDynObjFileFormat.h>
-#include <mcld/LD/ELFExecFileFormat.h>
-#include <mcld/LD/ELFObjectFileFormat.h>
+#include <mcld/Module.h>
#include <mcld/LD/GNUArchiveReader.h>
-#include <mcld/LD/ELFObjectReader.h>
#include <mcld/LD/ELFDynObjReader.h>
#include <mcld/LD/ELFBinaryReader.h>
+#include <mcld/LD/ELFObjectReader.h>
#include <mcld/LD/ELFObjectWriter.h>
-#include <mcld/LD/ELFSegment.h>
-#include <mcld/LD/ELFSegmentFactory.h>
-#include <mcld/Target/ELFDynamic.h>
-#include <mcld/Target/GNUInfo.h>
-#include <mcld/Support/GCFactory.h>
-#include <mcld/Module.h>
+#include <llvm/Support/ELF.h>
namespace mcld {
@@ -42,6 +32,15 @@
class BranchIslandFactory;
class StubFactory;
class GNUInfo;
+class ELFFileFormat;
+class ELFSegmentFactory;
+class ELFAttribute;
+class ELFDynamic;
+class ELFDynObjFileFormat;
+class ELFExecFileFormat;
+class ELFObjectFileFormat;
+class LinkerScript;
+class Relocation;
/** \class GNULDBackend
* \brief GNULDBackend provides a common interface for all GNU Unix-OS
@@ -110,6 +109,9 @@
/// getSegmentStartAddr - this function returns the start address of the segment
uint64_t getSegmentStartAddr(const LinkerScript& pScript) const;
+ /// sizeShstrtab - compute the size of .shstrtab
+ void sizeShstrtab(Module& pModule);
+
/// sizeNamePools - compute the size of regular name pools
/// In ELF executable files, regular name pools are .symtab, .strtab.,
/// .dynsym, .dynstr, and .hash
@@ -120,25 +122,25 @@
MemoryRegion& pRegion) const = 0;
/// emitRegNamePools - emit regular name pools - .symtab, .strtab
- virtual void emitRegNamePools(const Module& pModule, MemoryArea& pOutput);
+ virtual void emitRegNamePools(const Module& pModule, FileOutputBuffer& pOutput);
/// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash
- virtual void emitDynNamePools(Module& pModule, MemoryArea& pOutput);
+ virtual void emitDynNamePools(Module& pModule, FileOutputBuffer& pOutput);
/// emitELFHashTab - emit .hash
virtual void emitELFHashTab(const Module::SymbolTable& pSymtab,
- MemoryArea& pOutput);
+ FileOutputBuffer& pOutput);
/// emitGNUHashTab - emit .gnu.hash
virtual void emitGNUHashTab(Module::SymbolTable& pSymtab,
- MemoryArea& pOutput);
+ FileOutputBuffer& pOutput);
/// sizeInterp - compute the size of program interpreter's name
/// In ELF executables, this is the length of dynamic linker's path name
virtual void sizeInterp();
/// emitInterp - emit the .interp
- virtual void emitInterp(MemoryArea& pOutput);
+ virtual void emitInterp(FileOutputBuffer& pOutput);
/// hasEntryInStrTab - symbol has an entry in a .strtab
virtual bool hasEntryInStrTab(const LDSymbol& pSym) const;
@@ -169,16 +171,11 @@
virtual unsigned int getTargetSectionOrder(const LDSection& pSectHdr) const
{ return (unsigned int)-1; }
- /// numOfSegments - return the number of segments
- /// if the target favors other ways to emit program header, please override
- /// this function
- size_t numOfSegments() const { return m_ELFSegmentTable.size(); }
+ /// elfSegmentTable - return the reference of the elf segment table
+ ELFSegmentFactory& elfSegmentTable();
/// elfSegmentTable - return the reference of the elf segment table
- ELFSegmentFactory& elfSegmentTable() { return m_ELFSegmentTable; }
-
- /// elfSegmentTable - return the reference of the elf segment table
- const ELFSegmentFactory& elfSegmentTable() const { return m_ELFSegmentTable; }
+ const ELFSegmentFactory& elfSegmentTable() const;
/// commonPageSize - the common page size of the target machine
uint64_t commonPageSize() const;
@@ -198,6 +195,58 @@
/// update the output section flags based on input section flags.
virtual bool updateSectionFlags(LDSection& pTo, const LDSection& pFrom);
+ /// readRelocation - read ELF32_Rel entry
+ virtual bool readRelocation(const llvm::ELF::Elf32_Rel& pRel,
+ uint32_t& pType,
+ uint32_t& pSymIdx,
+ uint32_t& pOffset) const;
+
+ /// readRelocation - read ELF32_Rela entry
+ virtual bool readRelocation(const llvm::ELF::Elf32_Rela& pRel,
+ uint32_t& pType,
+ uint32_t& pSymIdx,
+ uint32_t& pOffset,
+ int32_t& pAddend) const;
+
+ /// readRelocation - read ELF64_Rel entry
+ virtual bool readRelocation(const llvm::ELF::Elf64_Rel& pRel,
+ uint32_t& pType,
+ uint32_t& pSymIdx,
+ uint64_t& pOffset) const;
+
+ /// readRel - read ELF64_Rela entry
+ virtual bool readRelocation(const llvm::ELF::Elf64_Rela& pRel,
+ uint32_t& pType,
+ uint32_t& pSymIdx,
+ uint64_t& pOffset,
+ int64_t& pAddend) const;
+
+ /// emitRelocation - write data to the ELF32_Rel entry
+ virtual void emitRelocation(llvm::ELF::Elf32_Rel& pRel,
+ uint32_t pType,
+ uint32_t pSymIdx,
+ uint32_t pOffset) const;
+
+ /// emitRelocation - write data to the ELF32_Rela entry
+ virtual void emitRelocation(llvm::ELF::Elf32_Rela& pRel,
+ uint32_t pType,
+ uint32_t pSymIdx,
+ uint32_t pOffset,
+ int32_t pAddend) const;
+
+ /// emitRelocation - write data to the ELF64_Rel entry
+ virtual void emitRelocation(llvm::ELF::Elf64_Rel& pRel,
+ uint32_t pType,
+ uint32_t pSymIdx,
+ uint64_t pOffset) const;
+
+ /// emitRelocation - write data to the ELF64_Rela entry
+ virtual void emitRelocation(llvm::ELF::Elf64_Rela& pRel,
+ uint32_t pType,
+ uint32_t pSymIdx,
+ uint64_t pOffset,
+ int64_t pAddend) const;
+
/// symbolNeedsPLT - return whether the symbol needs a PLT entry
/// @ref Google gold linker, symtab.h:596
bool symbolNeedsPLT(const ResolveInfo& pSym) const;
@@ -223,11 +272,11 @@
/// isDynamicSymbol
/// @ref Google gold linker: symtab.cc:311
- bool isDynamicSymbol(const LDSymbol& pSymbol);
+ bool isDynamicSymbol(const LDSymbol& pSymbol) const;
/// isDynamicSymbol
/// @ref Google gold linker: symtab.cc:311
- bool isDynamicSymbol(const ResolveInfo& pResolveInfo);
+ bool isDynamicSymbol(const ResolveInfo& pResolveInfo) const;
virtual ResolveInfo::Desc getSymDesc(uint16_t pShndx) const {
return ResolveInfo::Define;
@@ -247,6 +296,9 @@
LDSymbol& getTBSSSymbol();
const LDSymbol& getTBSSSymbol() const;
+ /// getEntry - get the entry point name
+ llvm::StringRef getEntry(const Module& pModule) const;
+
// ----- relaxation ----- //
/// initBRIslandFactory - initialize the branch island factory for relaxation
bool initBRIslandFactory();
@@ -267,7 +319,27 @@
/// checkAndSetHasTextRel - check pSection flag to set HasTextRel
void checkAndSetHasTextRel(const LDSection& pSection);
+ /// sortRelocation - sort the dynamic relocations to let dynamic linker
+ /// process relocations more efficiently
+ void sortRelocation(LDSection& pSection);
+
+ /// createAndSizeEhFrameHdr - This is seperated since we may add eh_frame
+ /// entry in the middle
+ void createAndSizeEhFrameHdr(Module& pModule);
+
+ /// attribute - the attribute section data.
+ ELFAttribute& attribute() { return *m_pAttribute; }
+
+ /// attribute - the attribute section data.
+ const ELFAttribute& attribute() const { return *m_pAttribute; }
+
protected:
+ /// getRelEntrySize - the size in BYTE of rel type relocation
+ virtual size_t getRelEntrySize() = 0;
+
+ /// getRelEntrySize - the size in BYTE of rela type relocation
+ virtual size_t getRelaEntrySize() = 0;
+
uint64_t getSymbolSize(const LDSymbol& pSymbol) const;
uint64_t getSymbolInfo(const LDSymbol& pSymbol) const;
@@ -315,33 +387,19 @@
/// 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;
- }
+ inline uint32_t getSegmentFlag(const uint32_t pSectionFlag);
/// setupGNUStackInfo - setup the section flag of .note.GNU-stack in output
void setupGNUStackInfo(Module& pModule);
- /// setupRelro - setup the offset constraint of PT_RELRO
- void setupRelro(Module& pModule);
+ /// setOutputSectionOffset - helper function to set output sections' offset.
+ void setOutputSectionOffset(Module& pModule);
- /// setOutputSectionOffset - helper function to set a group of output sections'
- /// offset, and set pSectBegin to pStartOffset if pStartOffset is not -1U.
- void setOutputSectionOffset(Module& pModule,
- Module::iterator pSectBegin,
- Module::iterator pSectEnd,
- uint64_t pStartOffset = -1U);
+ /// setOutputSectionAddress - helper function to set output sections' address.
+ void setOutputSectionAddress(Module& pModule);
- /// setOutputSectionOffset - helper function to set output sections' address.
- void setOutputSectionAddress(Module& pModule,
- Module::iterator pSectBegin,
- Module::iterator pSectEnd);
+ /// placeOutputSections - place output sections based on SectionMap
+ void placeOutputSections(Module& pModule);
/// layout - layout method
void layout(Module& pModule);
@@ -359,7 +417,7 @@
virtual void doPostLayout(Module& pModule, IRBuilder& pLinker) = 0;
/// postProcessing - Backend can do any needed modification in the final stage
- void postProcessing(MemoryArea& pOutput);
+ void postProcessing(FileOutputBuffer& pOutput);
/// dynamic - the dynamic section of the target machine.
virtual ELFDynamic& dynamic() = 0;
@@ -380,56 +438,48 @@
virtual bool doRelax(Module& pModule, IRBuilder& pBuilder, bool& pFinished)
{ return false; }
- /// getRelEntrySize - the size in BYTE of rel type relocation
- virtual size_t getRelEntrySize() = 0;
-
- /// getRelEntrySize - the size in BYTE of rela type relocation
- virtual size_t getRelaEntrySize() = 0;
-
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_EXCEPTION, // .eh_frame_hdr, .eh_frame, .gcc_except_table
- 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, // default order
- SHO_STRTAB // .strtab
+ SHO_NULL = 0, // NULL
+ SHO_INTERP, // .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_EXCEPTION, // .eh_frame_hdr, .eh_frame, .gcc_except_table
+ 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, // default order
+ SHO_STRTAB // .strtab
};
- typedef std::pair<LDSection*, unsigned int> SHOEntry;
-
- struct SHOCompare
+ // for -z combreloc
+ struct RelocCompare
{
- bool operator()(const SHOEntry& X, const SHOEntry& Y) const
- { return X.second < Y.second; }
- };
-
- struct SymCompare
- {
- bool operator()(const LDSymbol* X, const LDSymbol* Y) const
- { return (X==Y); }
+ RelocCompare(const GNULDBackend& pBackend)
+ : m_Backend(pBackend) {
+ }
+ bool operator()(const Relocation* X, const Relocation* Y) const;
+ private:
+ const GNULDBackend& m_Backend;
};
// for gnu style hash table
@@ -440,6 +490,12 @@
bool operator()(const LDSymbol* X, const LDSymbol* Y) const;
};
+ struct SymCompare
+ {
+ bool operator()(const LDSymbol* X, const LDSymbol* Y) const
+ { return (X==Y); }
+ };
+
struct SymPtrHash
{
size_t operator()(const LDSymbol* pKey) const
@@ -467,7 +523,7 @@
GNUInfo* m_pInfo;
// ELF segment factory
- ELFSegmentFactory m_ELFSegmentTable;
+ ELFSegmentFactory* m_pELFSegmentTable;
// branch island factory
BranchIslandFactory* m_pBRIslandFactory;
@@ -481,6 +537,9 @@
// section .eh_frame_hdr
EhFrameHdr* m_pEhFrameHdr;
+ // attribute section
+ ELFAttribute* m_pAttribute;
+
// ----- dynamic flags ----- //
// DF_TEXTREL of DT_FLAGS
bool m_bHasTextRel;
diff --git a/include/mcld/Target/GOT.h b/include/mcld/Target/GOT.h
index 9b61bcd..eb73741 100644
--- a/include/mcld/Target/GOT.h
+++ b/include/mcld/Target/GOT.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_GLOBAL_OFFSET_TABLE_H
-#define MCLD_GLOBAL_OFFSET_TABLE_H
+#ifndef MCLD_TARGET_GOT_H
+#define MCLD_TARGET_GOT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -80,13 +80,6 @@
// finalizeSectionSize - set LDSection size
virtual void finalizeSectionSize();
- /// reserve - 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 reserve(size_t pNum = 1) = 0;
-
protected:
LDSection& m_Section;
SectionData* m_SectionData;
diff --git a/include/mcld/Target/KeyEntryMap.h b/include/mcld/Target/KeyEntryMap.h
new file mode 100644
index 0000000..8136687
--- /dev/null
+++ b/include/mcld/Target/KeyEntryMap.h
@@ -0,0 +1,204 @@
+//===- KeyEntryMap.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TARGET_KEYENTRYMAP_H
+#define MCLD_TARGET_KEYENTRYMAP_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <vector>
+#include <list>
+
+namespace mcld {
+
+/** \class KeyEntryMap
+ * \brief KeyEntryMap is a <const KeyType*, ENTRY*> map.
+ */
+template<typename KEY, typename ENTRY>
+class KeyEntryMap
+{
+public:
+ typedef KEY KeyType;
+ typedef ENTRY EntryType;
+
+private:
+ struct EntryPair {
+ EntryPair(EntryType* pEntry1, EntryType* pEntry2)
+ : entry1(pEntry1), entry2(pEntry2)
+ {}
+
+ EntryType* entry1;
+ EntryType* entry2;
+ };
+
+ /// EntryOrPair - A key may mapping to a signal entry or a pair of entries,
+ /// user is responsible for the type of Mapping.entry
+ union EntryOrPair {
+ EntryType* entry_ptr;
+ EntryPair* pair_ptr;
+ };
+
+ struct Mapping {
+ const KeyType* key;
+ EntryOrPair entry;
+ };
+
+ typedef std::vector<Mapping> KeyEntryPool;
+ typedef std::list<EntryPair> PairListType;
+
+public:
+ typedef typename KeyEntryPool::iterator iterator;
+ typedef typename KeyEntryPool::const_iterator const_iterator;
+
+public:
+ /// lookUp - look up the entry mapping to pKey
+ const EntryType* lookUp(const KeyType& pKey) const;
+ EntryType* lookUp(const KeyType& pKey);
+
+ /// lookUpFirstEntry - look up the first entry mapping to pKey
+ const EntryType* lookUpFirstEntry(const KeyType& pKey) const;
+ EntryType* lookUpFirstEntry(const KeyType& pKey);
+
+ /// lookUpSecondEntry - look up the second entry mapping to pKey
+ const EntryType* lookUpSecondEntry(const KeyType& pKey) const;
+ EntryType* lookUpSecondEntry(const KeyType& pKey);
+
+ void record(const KeyType& pKey, EntryType& pEntry);
+ void record(const KeyType& pKey,
+ EntryType& pEntry1,
+ EntryType& pEntry2);
+
+ bool empty() const { return m_Pool.empty(); }
+ size_t size () const { return m_Pool.size(); }
+
+ const_iterator begin() const { return m_Pool.begin(); }
+ iterator begin() { return m_Pool.begin(); }
+ const_iterator end () const { return m_Pool.end(); }
+ iterator end () { return m_Pool.end(); }
+
+ void reserve(size_t pSize) { m_Pool.reserve(pSize); }
+
+private:
+ KeyEntryPool m_Pool;
+
+ /// m_Pairs - the EntryPairs
+ PairListType m_Pairs;
+};
+
+template<typename KeyType, typename EntryType>
+const EntryType*
+KeyEntryMap<KeyType, EntryType>::lookUp(const KeyType& pKey) const
+{
+ const_iterator mapping, mEnd = m_Pool.end();
+ for (mapping = m_Pool.begin(); mapping != mEnd; ++mapping) {
+ if (mapping->key == &pKey) {
+ return mapping->entry.entry_ptr;
+ }
+ }
+
+ return NULL;
+}
+
+template<typename KeyType, typename EntryType>
+EntryType*
+KeyEntryMap<KeyType, EntryType>::lookUp(const KeyType& pKey)
+{
+ iterator mapping, mEnd = m_Pool.end();
+ for (mapping = m_Pool.begin(); mapping != mEnd; ++mapping) {
+ if (mapping->key == &pKey) {
+ return mapping->entry.entry_ptr;
+ }
+ }
+
+ return NULL;
+}
+
+template<typename KeyType, typename EntryType>
+const EntryType*
+KeyEntryMap<KeyType, EntryType>::lookUpFirstEntry(const KeyType& pKey) const
+{
+ const_iterator mapping, mEnd = m_Pool.end();
+ for (mapping = m_Pool.begin(); mapping != mEnd; ++mapping) {
+ if (mapping->key == &pKey) {
+ return mapping->entry.pair_ptr->entry1;
+ }
+ }
+
+ return NULL;
+}
+
+template<typename KeyType, typename EntryType>
+EntryType*
+KeyEntryMap<KeyType, EntryType>::lookUpFirstEntry(const KeyType& pKey)
+{
+ const_iterator mapping, mEnd = m_Pool.end();
+ for (mapping = m_Pool.begin(); mapping != mEnd; ++mapping) {
+ if (mapping->key == &pKey) {
+ return mapping->entry.pair_ptr->entry1;
+ }
+ }
+
+ return NULL;
+}
+
+template<typename KeyType, typename EntryType>
+const EntryType*
+KeyEntryMap<KeyType, EntryType>::lookUpSecondEntry(const KeyType& pKey) const
+{
+ const_iterator mapping, mEnd = m_Pool.end();
+ for (mapping = m_Pool.begin(); mapping != mEnd; ++mapping) {
+ if (mapping->key == &pKey) {
+ return mapping->entry.pair_ptr->entry2;
+ }
+ }
+
+ return NULL;
+}
+
+template<typename KeyType, typename EntryType>
+EntryType*
+KeyEntryMap<KeyType, EntryType>::lookUpSecondEntry(const KeyType& pKey)
+{
+ const_iterator mapping, mEnd = m_Pool.end();
+ for (mapping = m_Pool.begin(); mapping != mEnd; ++mapping) {
+ if (mapping->key == &pKey) {
+ return mapping->entry.pair_ptr->entry2;
+ }
+ }
+
+ return NULL;
+}
+
+template<typename KeyType, typename EntryType>
+void
+KeyEntryMap<KeyType, EntryType>::record(const KeyType& pKey, EntryType& pEntry)
+{
+ Mapping mapping;
+ mapping.key = &pKey;
+ mapping.entry.entry_ptr = &pEntry;
+ m_Pool.push_back(mapping);
+}
+
+template<typename KeyType, typename EntryType>
+void
+KeyEntryMap<KeyType, EntryType>::record(const KeyType& pKey,
+ EntryType& pEntry1,
+ EntryType& pEntry2)
+{
+ Mapping mapping;
+ mapping.key = &pKey;
+ m_Pairs.push_back(EntryPair(&pEntry1, &pEntry2));
+ mapping.entry.pair_ptr = &m_Pairs.back();
+ m_Pool.push_back(mapping);
+}
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/OutputRelocSection.h b/include/mcld/Target/OutputRelocSection.h
index b0f8f2d..a109843 100644
--- a/include/mcld/Target/OutputRelocSection.h
+++ b/include/mcld/Target/OutputRelocSection.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_OUTPUT_RELOCATION_SECTION_H
-#define MCLD_OUTPUT_RELOCATION_SECTION_H
+#ifndef MCLD_TARGET_OUTPUTRELOCSECTION_H
+#define MCLD_TARGET_OUTPUTRELOCSECTION_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -32,6 +32,9 @@
~OutputRelocSection();
+ /// create - create an dynamic relocation entry
+ Relocation* create();
+
void reserveEntry(size_t pNum=1);
Relocation* consumeEntry();
diff --git a/include/mcld/Target/PLT.h b/include/mcld/Target/PLT.h
index 5d91446..7305a74 100644
--- a/include/mcld/Target/PLT.h
+++ b/include/mcld/Target/PLT.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_PROCEDURE_LINKAGE_TABLE_H
-#define MCLD_PROCEDURE_LINKAGE_TABLE_H
+#ifndef MCLD_TARGET_PLT_H
+#define MCLD_TARGET_PLT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -22,7 +22,7 @@
class ResolveInfo;
/** \class PLTEntryDefaultBase
- * \brief PLTEntryDefaultBase provides the default interface for PLE Entry
+ * \brief PLTEntryDefaultBase provides the default interface for PLT Entry
*/
class PLTEntryBase : public TargetFragment
{
@@ -33,7 +33,7 @@
virtual ~PLTEntryBase()
{
- delete m_pValue;
+ free(m_pValue);
}
void setValue(unsigned char* pValue)
@@ -81,10 +81,6 @@
virtual ~PLT();
- /// 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;
-
// finalizeSectionSize - set LDSection size
virtual void finalizeSectionSize() = 0;
diff --git a/include/mcld/Target/SymbolEntryMap.h b/include/mcld/Target/SymbolEntryMap.h
deleted file mode 100644
index fc5ea93..0000000
--- a/include/mcld/Target/SymbolEntryMap.h
+++ /dev/null
@@ -1,104 +0,0 @@
-//===- SymbolEntryMap.h ---------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_TARGET_SYMBOL_ENTRY_MAP_H
-#define MCLD_TARGET_SYMBOL_ENTRY_MAP_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-
-#include <vector>
-
-namespace mcld {
-
-class ResolveInfo;
-
-/** \class SymbolEntryMap
- * \brief SymbolEntryMap is a <const ResolveInfo*, ENTRY*> map.
- */
-template<typename ENTRY>
-class SymbolEntryMap
-{
-public:
- typedef ENTRY EntryType;
-
-private:
- struct Mapping {
- const ResolveInfo* symbol;
- EntryType* entry;
- };
-
- typedef std::vector<Mapping> SymbolEntryPool;
-
-public:
- typedef typename SymbolEntryPool::iterator iterator;
- typedef typename SymbolEntryPool::const_iterator const_iterator;
-
-public:
- const EntryType* lookUp(const ResolveInfo& pSymbol) const;
- EntryType* lookUp(const ResolveInfo& pSymbol);
-
- void record(const ResolveInfo& pSymbol, EntryType& pEntry);
-
- bool empty() const { return m_Pool.empty(); }
- size_t size () const { return m_Pool.size(); }
-
- const_iterator begin() const { return m_Pool.begin(); }
- iterator begin() { return m_Pool.begin(); }
- const_iterator end () const { return m_Pool.end(); }
- iterator end () { return m_Pool.end(); }
-
- void reserve(size_t pSize) { m_Pool.reserve(pSize); }
-
-private:
- SymbolEntryPool m_Pool;
-
-};
-
-template<typename EntryType>
-const EntryType*
-SymbolEntryMap<EntryType>::lookUp(const ResolveInfo& pSymbol) const
-{
- const_iterator mapping, mEnd = m_Pool.end();
- for (mapping = m_Pool.begin(); mapping != mEnd; ++mapping) {
- if (mapping->symbol == &pSymbol) {
- return mapping->entry;
- }
- }
-
- return NULL;
-}
-
-template<typename EntryType>
-EntryType*
-SymbolEntryMap<EntryType>::lookUp(const ResolveInfo& pSymbol)
-{
- iterator mapping, mEnd = m_Pool.end();
- for (mapping = m_Pool.begin(); mapping != mEnd; ++mapping) {
- if (mapping->symbol == &pSymbol) {
- return mapping->entry;
- }
- }
-
- return NULL;
-}
-
-template<typename EntryType>
-void
-SymbolEntryMap<EntryType>::record(const ResolveInfo& pSymbol, EntryType& pEntry)
-{
- Mapping mapping;
- mapping.symbol = &pSymbol;
- mapping.entry = &pEntry;
- m_Pool.push_back(mapping);
-}
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/Target/TargetLDBackend.h b/include/mcld/Target/TargetLDBackend.h
index d3f14b2..29fb395 100644
--- a/include/mcld/Target/TargetLDBackend.h
+++ b/include/mcld/Target/TargetLDBackend.h
@@ -1,4 +1,4 @@
-//===-- llvm/Target/TargetLDBackend.h - Target LD Backend -----*- C++ -*-===//
+//===-- TargetLDBackend.h - Target LD Backend -------------------*- C++ -*-===//
//
// The MCLinker Project
//
@@ -9,36 +9,34 @@
#ifndef MCLD_TARGET_TARGETLDBACKEND_H
#define MCLD_TARGET_TARGETLDBACKEND_H
+#include <llvm/ADT/StringRef.h>
#include <llvm/Support/DataTypes.h>
+#include <mcld/LD/GarbageCollection.h>
namespace mcld {
-class Module;
-class LinkerConfig;
-class IRBuilder;
-class Relocation;
-class RelocationFactory;
-class Relocator;
-class Layout;
class ArchiveReader;
-class ObjectReader;
-class DynObjReader;
class BinaryReader;
-class ObjectWriter;
+class BinaryWriter;
+class BranchIslandFactory;
+class DynObjReader;
class DynObjWriter;
class ExecWriter;
-class BinaryWriter;
-class LDFileFormat;
-class LDSymbol;
-class LDSection;
-class SectionData;
+class FileOutputBuffer;
+class SectionReachedListMap;
+class IRBuilder;
class Input;
-class GOT;
-class MemoryArea;
-class MemoryAreaFactory;
-class BranchIslandFactory;
-class StubFactory;
+class LDSection;
+class LDSymbol;
+class Layout;
+class LinkerConfig;
+class Module;
class ObjectBuilder;
+class ObjectReader;
+class ObjectWriter;
+class Relocator;
+class SectionData;
+class StubFactory;
//===----------------------------------------------------------------------===//
/// TargetLDBackend - Generic interface to target specific assembler backends.
@@ -84,7 +82,7 @@
virtual void postLayout(Module& pModule, IRBuilder& pBuilder) = 0;
/// postProcessing - Backend can do any needed modification in the final stage
- virtual void postProcessing(MemoryArea& pOutput) = 0;
+ virtual void postProcessing(FileOutputBuffer& pOutput) = 0;
/// section start offset in the output file
virtual size_t sectionStartOffset() const = 0;
@@ -112,9 +110,17 @@
virtual bool allocateCommonSymbols(Module& pModule) = 0;
/// mergeSection - merge target dependent sections.
- virtual bool mergeSection(Module& pModule, LDSection& pInputSection)
+ virtual bool mergeSection(Module& pModule,
+ const Input& pInputFile,
+ LDSection& pInputSection)
{ return true; }
+ /// setUpReachedSectionsForGC - set the reference between two sections for
+ /// some special target sections. GC will set up the reference for the Regular
+ /// and BSS sections. Backends can also set up the reference if need.
+ virtual void setUpReachedSectionsForGC(const Module& pModule,
+ GarbageCollection::SectionReachedListMap& pSectReachedListMap) const { }
+
/// updateSectionFlags - update pTo's flags when merging pFrom
/// update the output section flags based on input section flags.
/// FIXME: (Luba) I know ELF need to merge flags, but I'm not sure if
@@ -130,6 +136,9 @@
/// In ELF executables, this is the length of dynamic linker's path name
virtual void sizeInterp() = 0;
+ /// getEntry - get the entry point name
+ virtual llvm::StringRef getEntry(const Module& pModule) const = 0;
+
// ----- relaxation ----- //
virtual bool initBRIslandFactory() = 0;
virtual bool initStubFactory() = 0;
@@ -144,6 +153,20 @@
/// mayRelax - return true if the backend needs to do relaxation
virtual bool mayRelax() = 0;
+ /// commonPageSize - the common page size of the target machine
+ virtual uint64_t commonPageSize() const = 0;
+
+ /// abiPageSize - the abi page size of the target machine
+ virtual uint64_t abiPageSize() const = 0;
+
+ /// sortRelocation - sort the dynamic relocations to let dynamic linker
+ /// process relocations more efficiently
+ virtual void sortRelocation(LDSection& pSection) = 0;
+
+ /// createAndSizeEhFrameHdr - This is seperated since we may add eh_frame
+ /// entry in the middle
+ virtual void createAndSizeEhFrameHdr(Module& pModule) = 0;
+
protected:
const LinkerConfig& config() const { return m_Config; }
diff --git a/include/mcld/TargetOptions.h b/include/mcld/TargetOptions.h
index dfdd773..5f7e339 100644
--- a/include/mcld/TargetOptions.h
+++ b/include/mcld/TargetOptions.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_TARGET_OPTIONS_H
-#define MCLD_TARGET_OPTIONS_H
+#ifndef MCLD_TARGETOPTIONS_H
+#define MCLD_TARGETOPTIONS_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -44,6 +44,10 @@
void setTriple(const llvm::Triple& pTriple);
+ const std::string& getArch() const { return m_ArchName; }
+
+ void setArch(const std::string& pArchName);
+
const std::string& getTargetCPU() const { return m_TargetCPU; }
void setTargetCPU(const std::string& pCPU);
@@ -68,6 +72,7 @@
private:
llvm::Triple m_Triple;
+ std::string m_ArchName;
std::string m_TargetCPU;
std::string m_TargetFS;
Endian m_Endian;
diff --git a/lib/ADT/GraphLite/Digraph.cpp b/lib/ADT/GraphLite/Digraph.cpp
new file mode 100644
index 0000000..301f9fa
--- /dev/null
+++ b/lib/ADT/GraphLite/Digraph.cpp
@@ -0,0 +1,88 @@
+//===- Digraph.cpp --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/ADT/GraphLite/Digraph.h>
+
+using namespace mcld::graph;
+
+//===----------------------------------------------------------------------===//
+// Digraph::Arc
+//===----------------------------------------------------------------------===//
+Digraph::Arc::Arc()
+{
+}
+
+bool Digraph::Arc::operator==(const Digraph::Node& pOther) const
+{
+ return true;
+}
+
+bool Digraph::Arc::operator!=(const Digraph::Node& pOther) const
+{
+ return true;
+}
+
+Digraph::Node Digraph::Arc::source() const
+{
+ return Node();
+}
+
+Digraph::Node Digraph::Arc::target() const
+{
+ return Node();
+}
+
+Digraph::Arc::Arc(Digraph& pParent)
+{
+}
+
+
+//===----------------------------------------------------------------------===//
+// Digraph
+//===----------------------------------------------------------------------===//
+Digraph::Digraph()
+{
+}
+
+
+Digraph::Node Digraph::addNode()
+{
+ return Node();
+}
+
+
+Digraph::Arc
+Digraph::addArc(const Digraph::Node& pSource, const Digraph::Node& pTarget)
+{
+ return Arc();
+}
+
+
+void Digraph::erase(const Digraph::Node& pNode)
+{
+}
+
+
+void Digraph::erase(const Digraph::Arc& pArc)
+{
+}
+
+
+void Digraph::clear()
+{
+}
+
+unsigned int Digraph::numOfNodes() const
+{
+ return 0;
+}
+
+unsigned int Digraph::numOfArcs() const
+{
+ return 0;
+}
diff --git a/lib/ADT/GraphLite/ListDigraph.cpp b/lib/ADT/GraphLite/ListDigraph.cpp
new file mode 100644
index 0000000..fcf957b
--- /dev/null
+++ b/lib/ADT/GraphLite/ListDigraph.cpp
@@ -0,0 +1,178 @@
+//===- ListDigraph.cpp ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/ADT/GraphLite/ListDigraph.h>
+
+using namespace mcld::graph;
+
+//===----------------------------------------------------------------------===//
+// ListDigraph::Node
+//===----------------------------------------------------------------------===//
+ListDigraph::Node::Node()
+ : prev(NULL), next(NULL), first_in(NULL), first_out(NULL) {
+}
+
+//===----------------------------------------------------------------------===//
+// ListDigraph::Arc
+//===----------------------------------------------------------------------===//
+ListDigraph::Arc::Arc()
+ : target(NULL), source(NULL),
+ prev_in(NULL), next_in(NULL), prev_out(NULL), next_out(NULL) {
+}
+
+//===----------------------------------------------------------------------===//
+// ListDigraph
+//===----------------------------------------------------------------------===//
+ListDigraph::ListDigraph()
+ : m_pNodeHead(NULL), m_pFreeNodeHead(NULL), m_pFreeArcHead(NULL),
+ m_NodeList(32), m_ArcList(32) {
+}
+
+
+ListDigraph::Node* ListDigraph::addNode()
+{
+ // 1. find an available free node
+ Node* result = NULL;
+ if (NULL == m_pFreeNodeHead) {
+ result = m_NodeList.allocate();
+ new (result) Node();
+ }
+ else {
+ result = m_pFreeNodeHead;
+ m_pFreeNodeHead = m_pFreeNodeHead->next;
+ }
+
+ // 2. set up linkages
+ result->prev = NULL;
+ result->next = m_pNodeHead;
+
+ // 3. reset head node
+ if (NULL != m_pNodeHead) {
+ m_pNodeHead->prev = result;
+ }
+ m_pNodeHead = result;
+
+ return result;
+}
+
+
+ListDigraph::Arc* ListDigraph::addArc(Node& pU, Node& pV)
+{
+ // 1. find an available free arc
+ Arc* result = NULL;
+ if (NULL == m_pFreeArcHead) {
+ result = m_ArcList.allocate();
+ new (result) Arc();
+ }
+ else {
+ result = m_pFreeArcHead;
+ m_pFreeArcHead = m_pFreeArcHead->next_in;
+ }
+
+ // 2. set up arc
+ result->source = &pU;
+ result->target = &pV;
+
+ // 3. set up fan-out linked list
+ result->next_out = pU.first_out;
+ if (NULL != pU.first_out) {
+ pU.first_out->prev_out = result;
+ }
+ pU.first_out = result;
+
+ // 4. set up fan-in linked list
+ result->next_in = pV.first_in;
+ if (NULL != pV.first_in) {
+ pV.first_in->prev_in = result;
+ }
+ pV.first_in = result;
+
+ return result;
+}
+
+void ListDigraph::erase(ListDigraph::Node& pNode)
+{
+ // 1. connect previous node and next node.
+ if (NULL != pNode.next) {
+ pNode.next->prev = pNode.prev;
+ }
+
+ if (NULL != pNode.prev) {
+ pNode.prev->next = pNode.next;
+ }
+ else { // pNode.prev is NULL => pNode is the head
+ m_pNodeHead = pNode.next;
+ }
+
+ // 2. remove all fan-in arcs
+ Arc* fan_in = pNode.first_in;
+ while(NULL != fan_in) {
+ Arc* next_in = fan_in->next_in;
+ erase(*fan_in);
+ fan_in = next_in;
+ }
+
+ // 3. remove all fan-out arcs
+ Arc* fan_out = pNode.first_out;
+ while(NULL != fan_out) {
+ Arc* next_out = fan_out->next_out;
+ erase(*fan_out);
+ fan_out = next_out;
+ }
+
+ // 4. put pNode in the free node list
+ pNode.next = m_pFreeNodeHead;
+ pNode.prev = NULL;
+ if (NULL != m_pFreeNodeHead)
+ m_pFreeNodeHead->prev = &pNode;
+ m_pFreeNodeHead = &pNode;
+}
+
+
+void ListDigraph::erase(ListDigraph::Arc& pArc)
+{
+ // 1. remove from the fan-out list
+ if (NULL != pArc.prev_out) {
+ pArc.prev_out->next_out = pArc.next_out;
+ }
+ else { // pArc.prev_out is NULL => pArc is the first_out of the source
+ pArc.source->first_out = pArc.next_out;
+ }
+
+ if (NULL != pArc.next_out) {
+ pArc.next_out->prev_out = pArc.prev_out;
+ }
+
+ // 2. remove from the fan-in list
+ if (NULL != pArc.prev_in) {
+ pArc.prev_in->next_in = pArc.next_in;
+ }
+ else {
+ pArc.target->first_in = pArc.next_in;
+ }
+
+ if (NULL != pArc.next_in) {
+ pArc.next_in->prev_in = pArc.prev_in;
+ }
+
+ // 3. put pArc in the free arc list
+ // Use fan-in links to chain the free list
+ pArc.next_in = m_pFreeArcHead;
+ m_pFreeArcHead = &pArc;
+}
+
+
+void ListDigraph::clear()
+{
+ m_pNodeHead = NULL;
+ m_pFreeNodeHead = NULL;
+ m_pFreeArcHead = NULL;
+ m_NodeList.clear();
+ m_ArcList.clear();
+}
+
diff --git a/lib/CodeGen/MCLDTargetMachine.cpp b/lib/CodeGen/MCLDTargetMachine.cpp
index a695f29..272e775 100644
--- a/lib/CodeGen/MCLDTargetMachine.cpp
+++ b/lib/CodeGen/MCLDTargetMachine.cpp
@@ -6,15 +6,13 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include <mcld/Target/TargetMachine.h>
+#include <mcld/CodeGen/TargetMachine.h>
#include <mcld/Module.h>
#include <mcld/LinkerConfig.h>
#include <mcld/CodeGen/MCLinker.h>
-#include <mcld/Support/raw_mem_ostream.h>
#include <mcld/Support/TargetRegistry.h>
#include <mcld/Support/ToolOutputFile.h>
-#include <mcld/Support/MemoryArea.h>
#include <mcld/Target/TargetLDBackend.h>
#include <llvm/ADT/OwningPtr.h>
@@ -59,7 +57,6 @@
// Enable or disable FastISel. Both options are needed, because
// FastISel is enabled by default with -fast, and we wish to be
// able to enable or disable fast-isel independently from -O0.
-
static cl::opt<cl::boolOrDefault>
ArgEnableFastISelOption("lfast-isel", cl::Hidden,
cl::desc("Enable the \"fast\" instruction selector"));
@@ -90,28 +87,34 @@
}
-//===---------------------------------------------------------------------===//
-/// MCLDTargetMachine
+//===----------------------------------------------------------------------===//
+// MCLDTargetMachine
//===----------------------------------------------------------------------===//
mcld::MCLDTargetMachine::MCLDTargetMachine(llvm::TargetMachine &pTM,
- const mcld::Target& pTarget,
+ const llvm::Target& pLLVMTarget,
+ const mcld::Target& pMCLDTarget,
const std::string& pTriple)
- : m_TM(pTM), m_pTarget(&pTarget), m_Triple(pTriple) {
+ : m_TM(pTM),
+ m_pLLVMTarget(&pLLVMTarget),
+ m_pMCLDTarget(&pMCLDTarget),
+ m_Triple(pTriple) {
}
-mcld::MCLDTargetMachine::~MCLDTargetMachine() {
- m_pTarget = 0;
+mcld::MCLDTargetMachine::~MCLDTargetMachine()
+{
+ m_pLLVMTarget = NULL;
+ m_pMCLDTarget = NULL;
}
const mcld::Target& mcld::MCLDTargetMachine::getTarget() const
{
- return *m_pTarget;
+ return *m_pMCLDTarget;
}
/// Turn exception handling constructs into something the code generators can
/// handle.
static void addPassesToHandleExceptions(llvm::TargetMachine *TM,
- PassManagerBase &PM) {
+ llvm::legacy::PassManagerBase &PM) {
switch (TM->getMCAsmInfo()->getExceptionHandlingType()) {
case llvm::ExceptionHandling::SjLj:
// SjLj piggy-backs on dwarf for this bit. The cleanups done apply to both
@@ -137,9 +140,10 @@
}
-static llvm::MCContext *addPassesToGenerateCode(llvm::LLVMTargetMachine *TM,
- PassManagerBase &PM,
- bool DisableVerify)
+static llvm::MCContext *
+addPassesToGenerateCode(llvm::LLVMTargetMachine *TM,
+ llvm::legacy::PassManagerBase &PM,
+ bool DisableVerify)
{
// Targets may override createPassConfig to provide a target-specific sublass.
TargetPassConfig *PassConfig = TM->createPassConfig(PM);
@@ -184,7 +188,8 @@
}
-bool mcld::MCLDTargetMachine::addPassesToEmitFile(PassManagerBase &pPM,
+bool
+mcld::MCLDTargetMachine::addPassesToEmitFile(llvm::legacy::PassManagerBase &pPM,
mcld::ToolOutputFile& pOutput,
mcld::CodeGenFileType pFileType,
CodeGenOpt::Level pOptLvl,
@@ -222,7 +227,7 @@
if (getTM().hasMCSaveTempLabels())
Context->setAllowTemporaryLabels(false);
if (addAssemblerPasses(pPM,
- pOutput.mem_os(),
+ pOutput.formatted_os(),
Context))
return true;
break;
@@ -232,7 +237,7 @@
if (addLinkerPasses(pPM,
pConfig,
pModule,
- pOutput.memory(),
+ pOutput.fd(),
Context))
return true;
break;
@@ -242,7 +247,7 @@
if (addLinkerPasses(pPM,
pConfig,
pModule,
- pOutput.memory(),
+ pOutput.fd(),
Context))
return true;
break;
@@ -252,7 +257,7 @@
if (addLinkerPasses(pPM,
pConfig,
pModule,
- pOutput.memory(),
+ pOutput.fd(),
Context))
return true;
break;
@@ -262,7 +267,7 @@
if (addLinkerPasses(pPM,
pConfig,
pModule,
- pOutput.memory(),
+ pOutput.fd(),
Context))
return true;
break;
@@ -271,9 +276,10 @@
return false;
}
-bool mcld::MCLDTargetMachine::addCompilerPasses(PassManagerBase &pPM,
- llvm::formatted_raw_ostream &pOutput,
- llvm::MCContext *&Context)
+bool
+mcld::MCLDTargetMachine::addCompilerPasses(llvm::legacy::PassManagerBase &pPM,
+ llvm::formatted_raw_ostream &pOutput,
+ llvm::MCContext *&Context)
{
const MCAsmInfo &MAI = *getTM().getMCAsmInfo();
const MCInstrInfo &MII = *getTM().getInstrInfo();
@@ -281,32 +287,31 @@
const MCSubtargetInfo &STI = getTM().getSubtarget<MCSubtargetInfo>();
MCInstPrinter *InstPrinter =
- getTarget().get()->createMCInstPrinter(MAI.getAssemblerDialect(), MAI,
- MII,
- *Context->getRegisterInfo(), STI);
+ m_pLLVMTarget->createMCInstPrinter(MAI.getAssemblerDialect(), MAI,
+ MII, *Context->getRegisterInfo(), STI);
MCCodeEmitter* MCE = 0;
MCAsmBackend *MAB = 0;
if (ArgShowMCEncoding) {
- MCE = getTarget().get()->createMCCodeEmitter(MII, MRI, STI, *Context);
- MAB = getTarget().get()->createMCAsmBackend(m_Triple,
- getTM().getTargetCPU());
+ MCE = m_pLLVMTarget->createMCCodeEmitter(MII, MRI, STI, *Context);
+ MAB = m_pLLVMTarget->createMCAsmBackend(MRI, m_Triple,
+ getTM().getTargetCPU());
}
// now, we have MCCodeEmitter and MCAsmBackend, we can create AsmStreamer.
OwningPtr<MCStreamer> AsmStreamer(
- getTarget().get()->createAsmStreamer(*Context, pOutput,
- getVerboseAsm(),
- getTM().hasMCUseLoc(),
- getTM().hasMCUseCFI(),
- getTM().hasMCUseDwarfDirectory(),
- InstPrinter,
- MCE, MAB,
- ArgShowMCInst));
+ m_pLLVMTarget->createAsmStreamer(*Context, pOutput,
+ getVerboseAsm(),
+ getTM().hasMCUseLoc(),
+ getTM().hasMCUseCFI(),
+ getTM().hasMCUseDwarfDirectory(),
+ InstPrinter,
+ MCE, MAB,
+ ArgShowMCInst));
llvm::MachineFunctionPass* funcPass =
- getTarget().get()->createAsmPrinter(getTM(), *AsmStreamer.get());
+ m_pLLVMTarget->createAsmPrinter(getTM(), *AsmStreamer.get());
if (funcPass == 0)
return true;
@@ -316,35 +321,32 @@
return false;
}
-bool mcld::MCLDTargetMachine::addAssemblerPasses(PassManagerBase &pPM,
- llvm::raw_ostream &pOutput,
- llvm::MCContext *&Context)
+bool
+mcld::MCLDTargetMachine::addAssemblerPasses(llvm::legacy::PassManagerBase &pPM,
+ llvm::raw_ostream &pOutput,
+ llvm::MCContext *&Context)
{
// MCCodeEmitter
const MCInstrInfo &MII = *getTM().getInstrInfo();
const MCRegisterInfo &MRI = *getTM().getRegisterInfo();
const MCSubtargetInfo &STI = getTM().getSubtarget<MCSubtargetInfo>();
MCCodeEmitter* MCE =
- getTarget().get()->createMCCodeEmitter(MII, MRI, STI, *Context);
+ m_pLLVMTarget->createMCCodeEmitter(MII, MRI, STI, *Context);
// MCAsmBackend
MCAsmBackend* MAB =
- getTarget().get()->createMCAsmBackend(m_Triple,getTM().getTargetCPU());
+ m_pLLVMTarget->createMCAsmBackend(MRI, m_Triple, getTM().getTargetCPU());
if (MCE == 0 || MAB == 0)
return true;
// now, we have MCCodeEmitter and MCAsmBackend, we can create AsmStreamer.
- OwningPtr<MCStreamer> AsmStreamer(getTarget().get()->createMCObjectStreamer(
- m_Triple,
- *Context,
- *MAB,
- pOutput,
- MCE,
- getTM().hasMCRelaxAll(),
- getTM().hasMCNoExecStack()));
+ OwningPtr<MCStreamer> AsmStreamer(m_pLLVMTarget->createMCObjectStreamer(
+ m_Triple, *Context, *MAB, pOutput, MCE, getTM().hasMCRelaxAll(),
+ getTM().hasMCNoExecStack()));
+
AsmStreamer.get()->InitSections();
- MachineFunctionPass *funcPass = getTarget().get()->createAsmPrinter(getTM(),
- *AsmStreamer.get());
+ MachineFunctionPass *funcPass =
+ m_pLLVMTarget->createAsmPrinter(getTM(), *AsmStreamer.get());
if (funcPass == 0)
return true;
// If successful, createAsmPrinter took ownership of AsmStreamer
@@ -353,29 +355,27 @@
return false;
}
-bool mcld::MCLDTargetMachine::addLinkerPasses(PassManagerBase &pPM,
- LinkerConfig& pConfig,
- mcld::Module& pModule,
- mcld::MemoryArea& pOutput,
- llvm::MCContext *&Context)
+bool
+mcld::MCLDTargetMachine::addLinkerPasses(llvm::legacy::PassManagerBase &pPM,
+ LinkerConfig& pConfig,
+ mcld::Module& pModule,
+ mcld::FileHandle& pFileHandle,
+ llvm::MCContext *&Context)
{
- if (NULL == pOutput.handler())
- return true;
-
// set up output's SOName
if (pConfig.options().soname().empty()) {
// if the output is a shared object, and the option -soname was not
// enable, set soname as the output file name. soname must be UTF-8 string.
- pModule.setName(pOutput.handler()->path().filename().native());
- }
- else {
- pModule.setName(pConfig.options().soname());
+ pConfig.options().setSOName(pFileHandle.path().filename().native());
}
- MachineFunctionPass* funcPass = getTarget().createMCLinker(m_Triple,
- pConfig,
- pModule,
- pOutput);
+ // set up output module name
+ pModule.setName(pFileHandle.path().filename().native());
+
+ MachineFunctionPass* funcPass = m_pMCLDTarget->createMCLinker(m_Triple,
+ pConfig,
+ pModule,
+ pFileHandle);
if (NULL == funcPass)
return true;
diff --git a/lib/CodeGen/MCLinker.cpp b/lib/CodeGen/MCLinker.cpp
index 683cc89..471b0af 100644
--- a/lib/CodeGen/MCLinker.cpp
+++ b/lib/CodeGen/MCLinker.cpp
@@ -14,6 +14,7 @@
#include <mcld/Module.h>
#include <mcld/LinkerConfig.h>
+#include <mcld/LinkerScript.h>
#include <mcld/InputTree.h>
#include <mcld/Linker.h>
#include <mcld/IRBuilder.h>
@@ -26,7 +27,6 @@
#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/FileHandle.h>
#include <mcld/Support/raw_ostream.h>
-#include <mcld/Support/MemoryArea.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/CommandLine.h>
@@ -186,15 +186,24 @@
cl::aliasopt(ArgEndGroupList));
//===----------------------------------------------------------------------===//
+// --defsym
+//===----------------------------------------------------------------------===//
+static cl::list<std::string>
+ArgDefSymList("defsym",
+ cl::ZeroOrMore,
+ cl::desc("Define a symbol"),
+ cl::value_desc("symbol=expression"));
+
+//===----------------------------------------------------------------------===//
// MCLinker
//===----------------------------------------------------------------------===//
MCLinker::MCLinker(LinkerConfig& pConfig,
mcld::Module& pModule,
- MemoryArea& pOutput)
+ FileHandle& pFileHandle)
: MachineFunctionPass(m_ID),
m_Config(pConfig),
m_Module(pModule),
- m_Output(pOutput),
+ m_FileHandle(pFileHandle),
m_pBuilder(NULL),
m_pLinker(NULL) {
}
@@ -225,7 +234,7 @@
if (!m_pLinker->link(m_Module, *m_pBuilder))
return true;
- if (!m_pLinker->emit(m_Output))
+ if (!m_pLinker->emit(m_Module, m_FileHandle.handler()))
return true;
return false;
@@ -258,10 +267,34 @@
ArgBStaticList.size() +
ArgStartGroupList.size() +
ArgEndGroupList.size() +
+ ArgDefSymList.size() +
1; // bitcode
std::vector<InputAction*> actions;
actions.reserve(num_actions);
+ // ----- scripts ----- //
+ /// -T
+ if (!m_Config.options().getScriptList().empty()) {
+ GeneralOptions::const_script_iterator ii, ie = m_Config.options().script_end();
+ for (ii = m_Config.options().script_begin(); ii != ie; ++ii) {
+ actions.push_back(new ScriptAction(0x0,
+ *ii,
+ ScriptFile::LDScript,
+ m_Module.getScript().directories()));
+ actions.push_back(new ContextAction(0x0));
+ actions.push_back(new MemoryAreaAction(0x0, FileHandle::ReadOnly));
+ }
+ }
+
+ /// --defsym
+ cl::list<std::string>::iterator defsym, dsBegin, dsEnd;
+ dsBegin = ArgDefSymList.begin();
+ dsEnd = ArgDefSymList.end();
+ for (defsym = dsBegin; defsym != dsEnd; ++defsym) {
+ unsigned int pos = ArgDefSymList.getPosition(defsym - dsBegin);
+ actions.push_back(new DefSymAction(pos, *defsym));
+ }
+
// ----- inputs ----- //
cl::list<mcld::sys::fs::Path>::iterator input, inBegin, inEnd;
inBegin = ArgInputObjectFiles.begin();
@@ -277,11 +310,10 @@
cl::list<std::string>::iterator namespec, nsBegin, nsEnd;
nsBegin = ArgNameSpecList.begin();
nsEnd = ArgNameSpecList.end();
- mcld::Module& module = pBuilder.getModule();
for (namespec = nsBegin; namespec != nsEnd; ++namespec) {
unsigned int pos = ArgNameSpecList.getPosition(namespec - nsBegin);
actions.push_back(new NamespecAction(pos, *namespec,
- module.getScript().directories()));
+ m_Module.getScript().directories()));
actions.push_back(new ContextAction(pos));
actions.push_back(new MemoryAreaAction(pos, FileHandle::ReadOnly));
}
diff --git a/lib/Core/Environment.cpp b/lib/Core/Environment.cpp
index 0aa7536..5755fe7 100644
--- a/lib/Core/Environment.cpp
+++ b/lib/Core/Environment.cpp
@@ -9,8 +9,6 @@
#include <mcld/Environment.h>
#include <mcld/Support/TargetSelect.h>
-#include <llvm/Support/TargetSelect.h>
-
void mcld::Initialize()
{
static bool is_initialized = false;
@@ -18,7 +16,6 @@
if (is_initialized)
return;
- llvm::InitializeAllTargets();
mcld::InitializeAllTargets();
mcld::InitializeAllEmulations();
mcld::InitializeAllDiagnostics();
diff --git a/lib/Core/GeneralOptions.cpp b/lib/Core/GeneralOptions.cpp
index 71dcb95..442ae51 100644
--- a/lib/Core/GeneralOptions.cpp
+++ b/lib/Core/GeneralOptions.cpp
@@ -7,7 +7,8 @@
//
//===----------------------------------------------------------------------===//
#include <mcld/GeneralOptions.h>
-#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/Input.h>
+#include <mcld/MC/ZOption.h>
using namespace mcld;
@@ -20,14 +21,14 @@
m_MaxErrorNum(-1),
m_MaxWarnNum(-1),
m_ExecStack(Unknown),
+ m_NoUndefined(Unknown),
+ m_MulDefs(Unknown),
m_CommPageSize(0x0),
m_MaxPageSize(0x0),
m_bCombReloc(true),
- m_bNoUndefined(false),
m_bInitFirst(false),
m_bInterPose(false),
m_bLoadFltr(false),
- m_bMulDefs(false),
m_bNoCopyReloc(false),
m_bNoDefaultLib(false),
m_bNoDelete(false),
@@ -52,6 +53,9 @@
m_bFatalWarnings(false),
m_bNewDTags(false),
m_bNoStdlib(false),
+ m_bWarnMismatch(true),
+ m_bGCSections(false),
+ m_bGenUnwindInfo(true),
m_GPSize(8),
m_StripSymbols(KeepAllSymbols),
m_HashStyle(SystemV) {
@@ -61,20 +65,6 @@
{
}
-bool GeneralOptions::hasDefaultLDScript() const
-{
- return true;
-}
-
-const char* GeneralOptions::defaultLDScript() const
-{
- return NULL;
-}
-
-void GeneralOptions::setDefaultLDScript(const std::string& pFilename)
-{
-}
-
void GeneralOptions::setSOName(const std::string& pName)
{
size_t pos = pName.find_last_of(sys::fs::separator);
@@ -94,7 +84,7 @@
m_bCombReloc = false;
break;
case ZOption::Defs:
- m_bNoUndefined = true;
+ m_NoUndefined = YES;
break;
case ZOption::ExecStack:
m_ExecStack = YES;
@@ -112,7 +102,7 @@
m_bLoadFltr = true;
break;
case ZOption::MulDefs:
- m_bMulDefs = true;
+ m_MulDefs = YES;
break;
case ZOption::NoCopyReloc:
m_bNoCopyReloc = true;
diff --git a/lib/Core/IRBuilder.cpp b/lib/Core/IRBuilder.cpp
index 1b9747e..080a122 100644
--- a/lib/Core/IRBuilder.cpp
+++ b/lib/Core/IRBuilder.cpp
@@ -7,14 +7,17 @@
//
//===----------------------------------------------------------------------===//
#include <mcld/IRBuilder.h>
+#include <mcld/LinkerScript.h>
#include <mcld/LD/ELFReader.h>
#include <mcld/Object/ObjectBuilder.h>
#include <mcld/LD/SectionData.h>
#include <mcld/LD/EhFrame.h>
#include <mcld/LD/RelocData.h>
#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/ELF.h>
#include <mcld/Fragment/FragmentRef.h>
+#include <llvm/ADT/StringRef.h>
using namespace mcld;
@@ -66,6 +69,7 @@
case llvm::ELF::SHT_STRTAB:
case llvm::ELF::SHT_HASH:
case llvm::ELF::SHT_DYNAMIC:
+ case llvm::ELF::SHT_SYMTAB_SHNDX:
return LDFileFormat::NamePool;
case llvm::ELF::SHT_RELA:
case llvm::ELF::SHT_REL:
@@ -92,22 +96,6 @@
return LDFileFormat::MetaData;
}
-bool ShouldForceLocal(const ResolveInfo& pInfo, const LinkerConfig& pConfig)
-{
- // forced local symbol matches all rules:
- // 1. We are not doing incremental linking.
- // 2. The symbol is with Hidden or Internal visibility.
- // 3. The symbol should be global or weak. Otherwise, local symbol is local.
- // 4. The symbol is defined or common
- if (LinkerConfig::Object != pConfig.codeGenType() &&
- (pInfo.visibility() == ResolveInfo::Hidden ||
- pInfo.visibility() == ResolveInfo::Internal) &&
- (pInfo.isGlobal() || pInfo.isWeak()) &&
- (pInfo.isDefine() || pInfo.isCommon()))
- return true;
- return false;
-}
-
//===----------------------------------------------------------------------===//
// IRBuilder
//===----------------------------------------------------------------------===//
@@ -197,29 +185,6 @@
}
/// ReadInput - To read an input file and append it to the input tree.
-Input* IRBuilder::ReadInput(raw_mem_ostream& pMemOStream)
-{
- Input* input = NULL;
- if (pMemOStream.getMemoryArea().hasHandler()) {
- m_InputBuilder.createNode<InputTree::Positional>(
- "memory ostream",
- pMemOStream.getMemoryArea().handler()->path());
-
- input = *m_InputBuilder.getCurrentNode();
- m_InputBuilder.setContext(*input);
- input->setMemArea(&pMemOStream.getMemoryArea());
- }
- else {
- m_InputBuilder.createNode<InputTree::Positional>("memory ostream", "NAN");
- input = *m_InputBuilder.getCurrentNode();
- m_InputBuilder.setContext(*input, false);
- input->setMemArea(&pMemOStream.getMemoryArea());
- }
-
- return input;
-}
-
-/// ReadInput - To read an input file and append it to the input tree.
Input* IRBuilder::ReadInput(FileHandle& pFileHandle)
{
m_InputBuilder.createNode<InputTree::Positional>("file handler",
@@ -377,12 +342,8 @@
if (0 == pLength)
return new FillFragment(0x0, 0, 0);
- MemoryRegion* region = pInput.memArea()->request(pOffset, pLength);
-
- if (NULL == region)
- return new FillFragment(0x0, 0, 0);
-
- return new RegionFragment(*region);
+ llvm::StringRef region = pInput.memArea()->request(pOffset, pLength);
+ return new RegionFragment(region);
}
/// CreateRegion - To create a region fragment wrapping the given memory
@@ -391,11 +352,8 @@
if (0 == pLength)
return new FillFragment(0x0, 0, 0);
- MemoryRegion* region = MemoryRegion::Create(pMemory, pLength);
- if (NULL == region)
- return new FillFragment(0x0, 0, 0);
-
- return new RegionFragment(*region);
+ llvm::StringRef region(reinterpret_cast<const char*>(pMemory), pLength);
+ return new RegionFragment(region);
}
/// AppendFragment - To append pFrag to the given SectionData pSD
@@ -527,7 +485,7 @@
else {
// if the symbol is not local, insert and resolve it immediately
m_Module.getNamePool().insertSymbol(pName, false, pType, pDesc, pBinding,
- pSize, pVisibility,
+ pSize, pValue, pVisibility,
&old_info, resolved_result);
}
@@ -566,36 +524,6 @@
output_sym->setFragmentRef(pFragmentRef);
output_sym->setValue(pValue);
}
-
- // Step 4. Adjust the position of output LDSymbol.
- // After symbol resolution, visibility is changed to the most restrict one.
- // we need to arrange its position in the output symbol. We arrange the
- // positions by sorting symbols in SymbolCategory.
- if (pType != ResolveInfo::Section) {
- if (!has_output_sym) {
- // We merge sections when reading them. So we do not need to output symbols
- // with section type
-
- // No matter the symbol is already in the output or not, add it if it
- // should be forcefully set local.
- if (ShouldForceLocal(*resolved_result.info, m_Config))
- m_Module.getSymbolTable().forceLocal(*output_sym);
- else {
- // the symbol should not be forcefully local.
- m_Module.getSymbolTable().add(*output_sym);
- }
- }
- else if (resolved_result.overriden) {
- if (!ShouldForceLocal(old_info, m_Config) ||
- !ShouldForceLocal(*resolved_result.info, m_Config)) {
- // If the old info and the new info are both forcefully local, then
- // we should keep the output_sym in forcefully local category. Else,
- // we should re-sort the output_sym
- m_Module.getSymbolTable().arrange(*output_sym, old_info);
- }
- }
- }
-
return input_sym;
}
@@ -628,7 +556,7 @@
// resolved_result is a triple <resolved_info, existent, override>
Resolver::Result resolved_result;
m_Module.getNamePool().insertSymbol(pName, true, pType, pDesc,
- pBinding, pSize, pVisibility,
+ pBinding, pSize, pValue, pVisibility,
NULL, resolved_result);
// the return ResolveInfo should not NULL
@@ -642,25 +570,13 @@
input_sym->setFragmentRef(FragmentRef::Null());
input_sym->setValue(pValue);
- LDSymbol* output_sym = NULL;
+ // this symbol is seen in a dynamic object, set the InDyn flag
+ resolved_result.info->setInDyn();
+
if (!resolved_result.existent) {
// we get a new symbol, leave it as NULL
resolved_result.info->setSymPtr(NULL);
}
- else {
- // we saw the symbol before, but the output_sym still may be NULL.
- output_sym = resolved_result.info->outSymbol();
- }
-
- if (output_sym != NULL) {
- // After symbol resolution, visibility is changed to the most restrict one.
- // If we are not doing incremental linking, then any symbol with hidden
- // or internal visibility is forcefully set as a local symbol.
- if (ShouldForceLocal(*resolved_result.info, m_Config)) {
- m_Module.getSymbolTable().forceLocal(*output_sym);
- }
- }
-
return input_sym;
}
@@ -673,20 +589,11 @@
uint32_t pOffset,
Relocation::Address pAddend)
{
- // FIXME: we should dicard sections and symbols first instead
- // if the symbol is in the discarded input section, then we also need to
- // discard this relocation.
- ResolveInfo* resolve_info = pSym.resolveInfo();
- if (!pSym.hasFragRef() &&
- ResolveInfo::Section == resolve_info->type() &&
- ResolveInfo::Undefined == resolve_info->desc())
- return NULL;
-
FragmentRef* frag_ref = FragmentRef::Create(*pSection.getLink(), pOffset);
Relocation* relocation = Relocation::Create(pType, *frag_ref, pAddend);
- relocation->setSymInfo(resolve_info);
+ relocation->setSymInfo(pSym.resolveInfo());
pSection.getRelocData()->append(*relocation);
return relocation;
@@ -711,7 +618,7 @@
// create a ResolveInfo
Resolver::Result result;
m_Module.getNamePool().insertSymbol(pName, false, pType, pDesc,
- pBinding, pSize, pVisibility,
+ pBinding, pSize, pValue, pVisibility,
NULL, result);
assert(!result.existent);
@@ -719,7 +626,7 @@
output_sym = LDSymbol::Create(*result.info);
result.info->setSymPtr(output_sym);
- if (ShouldForceLocal(*result.info, m_Config))
+ if (result.info->shouldForceLocal(m_Config))
m_Module.getSymbolTable().forceLocal(*output_sym);
else
m_Module.getSymbolTable().add(*output_sym);
@@ -822,7 +729,7 @@
Resolver::Result result;
ResolveInfo old_info;
m_Module.getNamePool().insertSymbol(pName, false, pType, pDesc, pBinding,
- pSize, pVisibility,
+ pSize, pValue, pVisibility,
&old_info, result);
LDSymbol* output_sym = result.info->outSymbol();
@@ -840,7 +747,7 @@
// After symbol resolution, the visibility is changed to the most restrict.
// arrange the output position
- if (ShouldForceLocal(*result.info, m_Config))
+ if (result.info->shouldForceLocal(m_Config))
m_Module.getSymbolTable().forceLocal(*output_sym);
else if (has_output_sym)
m_Module.getSymbolTable().arrange(*output_sym, old_info);
diff --git a/lib/Core/InputTree.cpp b/lib/Core/InputTree.cpp
index 15f6f5e..5df91d8 100644
--- a/lib/Core/InputTree.cpp
+++ b/lib/Core/InputTree.cpp
@@ -24,7 +24,7 @@
return *this;
if (!pTree.empty()) {
- pMover.connect(pRoot, iterator(pTree.m_Root.node.right));
+ pMover.connect(pRoot, pTree.m_Root.node.right);
BinaryTreeBase<Input>::m_Root.summon(
pTree.BinaryTreeBase<Input>::m_Root);
BinaryTreeBase<Input>::m_Root.delegate(pTree.m_Root);
@@ -37,7 +37,7 @@
const InputTree::Mover& pMover)
{
NodeBase* node = createNode();
- pMover.connect(pRoot, iterator(node));
+ pMover.connect(pRoot, node);
return *this;
}
@@ -47,7 +47,7 @@
{
BinaryTree<Input>::node_type* node = createNode();
node->data = &pInput;
- pMover.connect(pRoot, iterator(node));
+ pMover.connect(pRoot, node);
return *this;
}
diff --git a/lib/Core/Linker.cpp b/lib/Core/Linker.cpp
index 1361402..464f039 100644
--- a/lib/Core/Linker.cpp
+++ b/lib/Core/Linker.cpp
@@ -14,7 +14,7 @@
#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/TargetRegistry.h>
#include <mcld/Support/FileHandle.h>
-#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/FileOutputBuffer.h>
#include <mcld/Support/raw_ostream.h>
#include <mcld/Object/ObjectLinker.h>
@@ -24,9 +24,12 @@
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/SectionData.h>
#include <mcld/LD/RelocData.h>
+#include <mcld/LD/ObjectWriter.h>
#include <mcld/Fragment/Relocation.h>
#include <mcld/Fragment/FragmentRef.h>
+#include <llvm/ADT/OwningPtr.h>
+
#include <cassert>
using namespace mcld;
@@ -67,7 +70,7 @@
if (!normalize(pModule, pBuilder))
return false;
- if (!resolve())
+ if (!resolve(pModule))
return false;
return layout();
@@ -82,10 +85,8 @@
m_pObjLinker = new ObjectLinker(*m_pConfig, *m_pBackend);
- m_pObjLinker->setup(pModule, pBuilder);
-
- // 2. - initialize FragmentLinker
- if (!m_pObjLinker->initFragmentLinker())
+ // 2. - initialize ObjectLinker
+ if (!m_pObjLinker->initialize(pModule, pBuilder))
return false;
// 3. - initialize output's standard sections
@@ -159,7 +160,7 @@
return true;
}
-bool Linker::resolve()
+bool Linker::resolve(Module& pModule)
{
assert(NULL != m_pConfig);
assert(m_pObjLinker != NULL);
@@ -172,7 +173,11 @@
// To collect all edges in the reference graph.
m_pObjLinker->readRelocations();
- // 7. - merge all sections
+
+ // 7. - data stripping optimizations
+ m_pObjLinker->dataStrippingOpt();
+
+ // 8. - merge all sections
// Push sections into Module's SectionTable.
// Merge sections that have the same name.
// Maintain them as fragments in the section.
@@ -181,10 +186,16 @@
if (!m_pObjLinker->mergeSections())
return false;
- // 8. - allocateCommonSymbols
+ // 9.a - add symbols to output
+ // After all input symbols have been resolved, add them to output symbol
+ // table at once
+ m_pObjLinker->addSymbolsToOutput(pModule);
+
+ // 9.b - allocateCommonSymbols
// Allocate fragments for common symbols to the corresponding sections.
if (!m_pObjLinker->allocateCommonSymbols())
return false;
+
return true;
}
@@ -192,38 +203,38 @@
{
assert(NULL != m_pConfig && NULL != m_pObjLinker);
- // 9. - add standard symbols, target-dependent symbols and script symbols
+ // 10. - add standard symbols, target-dependent symbols and script symbols
// m_pObjLinker->addUndefSymbols();
if (!m_pObjLinker->addStandardSymbols() ||
!m_pObjLinker->addTargetSymbols() ||
!m_pObjLinker->addScriptSymbols())
return false;
- // 10. - scan all relocation entries by output symbols.
+ // 11. - scan all relocation entries by output symbols.
// reserve GOT space for layout.
// the space info is needed by pre-layout to compute the section size
m_pObjLinker->scanRelocations();
- // 11.a - init relaxation stuff.
+ // 12.a - init relaxation stuff.
m_pObjLinker->initStubs();
- // 11.b - pre-layout
+ // 12.b - pre-layout
m_pObjLinker->prelayout();
- // 11.c - linear layout
+ // 12.c - linear layout
// Decide which sections will be left in. Sort the sections according to
// a given order. Then, create program header accordingly.
// Finally, set the offset for sections (@ref LDSection)
// according to the new order.
m_pObjLinker->layout();
- // 11.d - post-layout (create segment, instruction relaxing)
+ // 12.d - post-layout (create segment, instruction relaxing)
m_pObjLinker->postlayout();
- // 12. - finalize symbol value
+ // 13. - finalize symbol value
m_pObjLinker->finalizeSymbolValue();
- // 13. - apply relocations
+ // 14. - apply relocations
m_pObjLinker->relocation();
if (!Diagnose())
@@ -231,12 +242,12 @@
return true;
}
-bool Linker::emit(MemoryArea& pOutput)
+bool Linker::emit(FileOutputBuffer& pOutput)
{
- // 13. - write out output
+ // 15. - write out output
m_pObjLinker->emitOutput(pOutput);
- // 14. - post processing
+ // 16. - post processing
m_pObjLinker->postProcessing(pOutput);
if (!Diagnose())
@@ -245,10 +256,23 @@
return true;
}
-bool Linker::emit(const std::string& pPath)
+bool Linker::emit(const Module& pModule, const std::string& pPath)
{
FileHandle file;
- FileHandle::Permission perm = FileHandle::Permission(0x755);
+ FileHandle::Permission perm;
+ switch (m_pConfig->codeGenType()) {
+ case mcld::LinkerConfig::Unknown:
+ case mcld::LinkerConfig::Object:
+ perm = mcld::FileHandle::Permission(0x644);
+ break;
+ case mcld::LinkerConfig::DynObj:
+ case mcld::LinkerConfig::Exec:
+ case mcld::LinkerConfig::Binary:
+ perm = mcld::FileHandle::Permission(0x755);
+ break;
+ default: assert(0 && "Unknown file type");
+ }
+
if (!file.open(pPath,
FileHandle::ReadWrite | FileHandle::Truncate | FileHandle::Create,
perm)) {
@@ -256,25 +280,28 @@
return false;
}
- MemoryArea* output = new MemoryArea(file);
+ llvm::OwningPtr<FileOutputBuffer> output;
+ FileOutputBuffer::create(file,
+ m_pObjLinker->getWriter()->getOutputSize(pModule),
+ output);
- bool result = emit(*output);
-
- delete output;
+ bool result = emit(*output.get());
file.close();
return result;
}
-bool Linker::emit(int pFileDescriptor)
+bool Linker::emit(const Module& pModule, int pFileDescriptor)
{
FileHandle file;
file.delegate(pFileDescriptor);
- MemoryArea* output = new MemoryArea(file);
- bool result = emit(*output);
+ llvm::OwningPtr<FileOutputBuffer> output;
+ FileOutputBuffer::create(file,
+ m_pObjLinker->getWriter()->getOutputSize(pModule),
+ output);
- delete output;
- file.close();
+ bool result = emit(*output.get());
+
return result;
}
@@ -308,9 +335,14 @@
assert(NULL != m_pConfig);
std::string error;
- m_pTarget = mcld::TargetRegistry::lookupTarget(m_pConfig->targets().triple().str(), error);
+ llvm::Triple triple(m_pConfig->targets().triple());
+
+ m_pTarget = mcld::TargetRegistry::lookupTarget(m_pConfig->targets().getArch(),
+ triple, error);
+ m_pConfig->targets().setTriple(triple);
+
if (NULL == m_pTarget) {
- fatal(diag::fatal_cannot_init_target) << m_pConfig->targets().triple().str() << error;
+ fatal(diag::fatal_cannot_init_target) << triple.str() << error;
return false;
}
return true;
diff --git a/lib/Core/LinkerScript.cpp b/lib/Core/LinkerScript.cpp
index 4bee579..2e891e2 100644
--- a/lib/Core/LinkerScript.cpp
+++ b/lib/Core/LinkerScript.cpp
@@ -36,3 +36,32 @@
return !sysroot().empty();
}
+const std::string& LinkerScript::entry() const
+{
+ return m_Entry;
+}
+
+void LinkerScript::setEntry(const std::string& pEntry)
+{
+ m_Entry = pEntry;
+}
+
+bool LinkerScript::hasEntry() const
+{
+ return !m_Entry.empty();
+}
+
+const std::string& LinkerScript::outputFile() const
+{
+ return m_OutputFile;
+}
+
+void LinkerScript::setOutputFile(const std::string& pOutputFile)
+{
+ m_OutputFile = pOutputFile;
+}
+
+bool LinkerScript::hasOutputFile() const
+{
+ return !m_OutputFile.empty();
+}
diff --git a/lib/Core/TargetOptions.cpp b/lib/Core/TargetOptions.cpp
index 4f2cea2..710899c 100644
--- a/lib/Core/TargetOptions.cpp
+++ b/lib/Core/TargetOptions.cpp
@@ -38,6 +38,11 @@
m_Triple.setTriple(pTriple);
}
+void TargetOptions::setArch(const std::string& pArchName)
+{
+ m_ArchName = pArchName;
+}
+
void TargetOptions::setTargetCPU(const std::string& pCPU)
{
m_TargetCPU = pCPU;
diff --git a/lib/Fragment/Android.mk b/lib/Fragment/Android.mk
index 6e875a8..743232f 100644
--- a/lib/Fragment/Android.mk
+++ b/lib/Fragment/Android.mk
@@ -2,10 +2,8 @@
mcld_fragment_SRC_FILES := \
AlignFragment.cpp \
- FGNode.cpp \
FillFragment.cpp \
Fragment.cpp \
- FragmentLinker.cpp \
FragmentRef.cpp \
NullFragment.cpp \
RegionFragment.cpp \
diff --git a/lib/Fragment/FGNode.cpp b/lib/Fragment/FGNode.cpp
deleted file mode 100644
index 92706ba..0000000
--- a/lib/Fragment/FGNode.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-//===- FGNode.cpp ---------------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/Fragment/FGNode.h>
-
-using namespace mcld;
-
-//===----------------------------------------------------------------------===//
-// FGNode
-//===----------------------------------------------------------------------===//
-FGNode::FGNode()
- : m_Index(0x0)
-{
-}
-
-FGNode::FGNode(uint32_t pIndex)
- : m_Index(pIndex)
-{
-}
-
-void FGNode::addFragment(Fragment* pFrag)
-{
- m_Fragments.push_back(pFrag);
-}
-
-void FGNode::addSignal(Signal pSignal)
-{
- m_Signals.push_back(pSignal);
-}
-
-void FGNode::addSlot(Slot pSlot)
-{
- m_Slots.push_back(pSlot);
-}
-
diff --git a/lib/Fragment/FragmentGraph.cpp b/lib/Fragment/FragmentGraph.cpp
deleted file mode 100644
index 3140447..0000000
--- a/lib/Fragment/FragmentGraph.cpp
+++ /dev/null
@@ -1,412 +0,0 @@
-//===- FragmentGraph.cpp --------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/Fragment/FragmentGraph.h>
-#include <mcld/Fragment/Fragment.h>
-#include <mcld/Fragment/Relocation.h>
-#include <mcld/LD/LDContext.h>
-#include <mcld/LD/LDFileFormat.h>
-#include <mcld/LD/LDSection.h>
-#include <mcld/LD/LDSymbol.h>
-#include <mcld/LD/SectionData.h>
-#include <mcld/LD/RelocData.h>
-#include <mcld/LinkerConfig.h>
-#include <mcld/Module.h>
-#include <mcld/Support/MsgHandling.h>
-
-#include <llvm/Support/Casting.h>
-#include <llvm/Support/ELF.h>
-
-#include <iostream>
-
-using namespace mcld;
-
-//===----------------------------------------------------------------------===//
-// non-member functions
-//===----------------------------------------------------------------------===//
-static int get_state(Fragment::Type pKind)
-{
- switch(pKind) {
- case Fragment::Alignment:
- return 0;
- case Fragment::Fillment:
- case Fragment::Region:
- return 1;
- case Fragment::Null:
- return 2;
- default:
- unreachable(diag::unexpected_frag_type) << pKind;
- }
- return 0;
-}
-
-//===----------------------------------------------------------------------===//
-// ReachMatrix
-//===----------------------------------------------------------------------===//
-FragmentGraph::ReachMatrix::ReachMatrix(size_t pSize)
-{
- assert(pSize != 0);
- m_Data.assign(pSize * pSize, 0x0);
- m_N = pSize;
-}
-
-uint32_t& FragmentGraph::ReachMatrix::at(uint32_t pX, uint32_t pY)
-{
- return m_Data[pX * m_N + pY];
-}
-
-uint32_t FragmentGraph::ReachMatrix::at(uint32_t pX, uint32_t pY) const
-{
- return m_Data[pX * m_N + pY];
-}
-
-//===----------------------------------------------------------------------===//
-// FragmentGraph
-//===----------------------------------------------------------------------===//
-FragmentGraph::FragmentGraph()
- : m_pMatrix(NULL), m_NumOfPNodes(0x0), m_NumOfRNodes(0x0), m_NumOfEdges(0x0)
-{
- m_pPseudoNodeFactory = new NodeFactoryType();
- m_pRegularNodeFactory = new NodeFactoryType();
- m_pFragNodeMap = new FragHashTableType(256);
- m_pSymNodeMap = new SymHashTableType(256);
-}
-
-FragmentGraph::~FragmentGraph()
-{
- delete m_pPseudoNodeFactory;
- delete m_pRegularNodeFactory;
- delete m_pFragNodeMap;
-}
-
-FGNode* FragmentGraph::getNode(const Fragment& pFrag)
-{
- FragHashTableType::iterator entry = m_pFragNodeMap->find(&pFrag);
- if (entry == m_pFragNodeMap->end())
- return NULL;
- return entry.getEntry()->value();
-}
-
-const FGNode* FragmentGraph::getNode(const Fragment& pFrag) const
-{
- FragHashTableType::iterator entry = m_pFragNodeMap->find(&pFrag);
- if (entry == m_pFragNodeMap->end())
- return NULL;
- return entry.getEntry()->value();
-}
-
-FGNode* FragmentGraph::getNode(const ResolveInfo& pSym)
-{
- SymHashTableType::iterator entry = m_pSymNodeMap->find(&pSym);
- if (entry == m_pSymNodeMap->end())
- return NULL;
- return entry.getEntry()->value();
-}
-
-const FGNode* FragmentGraph::getNode(const ResolveInfo& pSym) const
-{
- SymHashTableType::iterator entry = m_pSymNodeMap->find(&pSym);
- if (entry == m_pSymNodeMap->end())
- return NULL;
- return entry.getEntry()->value();
-}
-
-FGNode* FragmentGraph::producePseudoNode()
-{
- FGNode* result = m_pPseudoNodeFactory->allocate();
- new (result) FGNode(m_NumOfPNodes + m_NumOfRNodes);
- ++m_NumOfPNodes;
- return result;
-}
-
-FGNode* FragmentGraph::produceRegularNode()
-{
- FGNode* result = m_pRegularNodeFactory->allocate();
- new (result) FGNode(m_NumOfPNodes + m_NumOfRNodes);
- ++m_NumOfRNodes;
- return result;
-}
-
-bool FragmentGraph::setNodeSlots(Module& pModule)
-{
- // symbols are the slots of nodes, push the symbols into the corresponding
- // nodes.
-
- // Traverse all defined symbols, including global and local symbols, to add
- // symbols into the corresponding nodes
- Module::SymbolTable& sym_tab = pModule.getSymbolTable();
- SymbolCategory::iterator sym_it, sym_end = sym_tab.end();
- for (sym_it = sym_tab.begin(); sym_it != sym_end; ++sym_it) {
- // only the defined symbols with FragmnentRef can form a slot. The defined
- // symbol with no FragmentRef such as ABS symbol should be skipped
- LDSymbol* sym = *sym_it;
- if (!sym->resolveInfo()->isDefine() ||
- !sym->hasFragRef())
- continue;
-
- // FIXME: judge by getNode() is NULL or not
- LDFileFormat::Kind sect_kind =
- sym->fragRef()->frag()->getParent()->getSection().kind();
- if (sect_kind != LDFileFormat::Regular &&
- sect_kind != LDFileFormat::BSS)
- continue;
-
- FGNode* node = getNode(*sym->fragRef()->frag());
- assert(NULL != node);
- node->addSlot(sym->resolveInfo());
- }
-
- return true;
-}
-
-bool FragmentGraph::createRegularEdges(Module& pModule)
-{
- // The reference between nodes are presented by the relocations. Set the
- // reachability matrix to present the connection
-
- // Traverse all input relocations to set connection
- Module::obj_iterator input, inEnd = pModule.obj_end();
- for (input = pModule.obj_begin(); input != inEnd; ++input) {
- LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
- for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
- // bypass the discarded relocations
- // 1. its section kind is changed to Ignore. (The target section is a
- // discarded group section.)
- // 2. it has no reloc data. (All symbols in the input relocs are in the
- // discarded group sections)
- if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData())
- continue;
- RelocData::iterator reloc_it, rEnd = (*rs)->getRelocData()->end();
- for (reloc_it = (*rs)->getRelocData()->begin(); reloc_it != rEnd;
- ++reloc_it) {
- Relocation* reloc = llvm::cast<Relocation>(reloc_it);
- ResolveInfo* sym = reloc->symInfo();
- // only the target symbols defined in the input fragments can make the
- // connection
- if (NULL == sym)
- continue;
- if (!sym->isDefine() || !sym->outSymbol()->hasFragRef())
- continue;
-
- // only the relocation target places which defined in the concerned
- // sections can make the connection
- // FIXME: judge by getNode() is NULL or not
- LDFileFormat::Kind sect_kind =
- reloc->targetRef().frag()->getParent()->getSection().kind();
- if (sect_kind != LDFileFormat::Regular &&
- sect_kind != LDFileFormat::BSS)
- continue;
-
- // only the target symbols defined in the concerned sections can make
- // the connection
- // FIXME: judge by getNode() is NULL or not
- sect_kind =
- sym->outSymbol()->fragRef()->frag()->getParent()->getSection().kind();
- if (sect_kind != LDFileFormat::Regular &&
- sect_kind != LDFileFormat::BSS)
- continue;
-
- connect(reloc, sym);
- }
- }
- }
- return true;
-}
-
-bool FragmentGraph::createPseudoEdges(Module& pModule)
-{
- // the pseudo edges are the edges from pseudo nodes to regular nodes, which
- // present the reference from out-side world when building shared library
-
- // Traverse all pseudo relocations in the pseudo nodes to set the connection
- node_iterator node_it, node_end = m_pPseudoNodeFactory->end();
- for (node_it = m_pPseudoNodeFactory->begin(); node_it != node_end; ++node_it) {
- FGNode& node = *node_it;
- FGNode::signal_iterator sig_it, sig_end = node.signal_end();
- for (sig_it = node.signal_begin(); sig_it != sig_end; ++sig_it) {
- connect(node, (*sig_it)->symInfo());
- }
- }
- return true;
-}
-
-bool FragmentGraph::connect(Signal pSignal, Slot pSlot)
-{
- FGNode* from = getNode(*pSignal->targetRef().frag());
- assert(NULL != from);
-
- FGNode* to = getNode(*pSlot->outSymbol()->fragRef()->frag());
- assert(NULL != to);
-
- // maintain edge counter
- if (0 == m_pMatrix->at(from->getIndex(), to->getIndex()))
- ++m_NumOfEdges;
- ++m_pMatrix->at(from->getIndex(), to->getIndex());
- return true;
-}
-
-bool FragmentGraph::connect(FGNode& pFrom, Slot pSlot)
-{
- FGNode* to = getNode(*pSlot->outSymbol()->fragRef()->frag());
- assert(NULL != to);
-
- // maintain edge counter
- if (0 == m_pMatrix->at(pFrom.getIndex(), to->getIndex()))
- ++m_NumOfEdges;
- ++m_pMatrix->at(pFrom.getIndex(), to->getIndex());
- return true;
-}
-
-bool FragmentGraph::createPseudoNodes(Module& pModule)
-{
- // when generating shared library, we need to create pseudo node for every
- // global defined symbols to present the fan-in of a regular node.
-
- // Traverse all global defined symbols to build the pseudo nodes.
- Module::SymbolTable& sym_tab = pModule.getSymbolTable();
- SymbolCategory::iterator sym_it, sym_end = sym_tab.dynamicEnd();
- for (sym_it = sym_tab.dynamicBegin(); sym_it != sym_end; ++sym_it) {
- ResolveInfo* sym = (*sym_it)->resolveInfo();
- if (!sym->isDefine() || !sym->outSymbol()->hasFragRef())
- continue;
- FGNode* node = producePseudoNode();
- // create the pseudo relocation to present the fan-out of the pseudo node
- Relocation* reloc = Relocation::Create();
- reloc->setSymInfo(sym);
-
- // set the signal of the pseudo node
- node->addSignal(reloc);
-
- // maintain the map for symbol to pseudo node
- SymHashTableType::entry_type* entry = 0;
- bool exist = false;
- entry = m_pSymNodeMap->insert(sym, exist);
- entry->setValue(node);
-
- }
- return true;
-}
-
-bool FragmentGraph::createRegularNodes(Module& pModule)
-{
- // Traverse all sections to build the Nodes. We build nodes only for Regular,
- // and BSS
- Module::iterator sect_it, sect_end = pModule.end();
- for (sect_it = pModule.begin(); sect_it != sect_end; ++sect_it) {
- LDSection* section = *sect_it;
- SectionData* sect_data = NULL;
-
- if (LDFileFormat::Regular != section->kind() &&
- LDFileFormat::BSS != section->kind())
- continue;
-
- sect_data = section->getSectionData();
- if (NULL == sect_data)
- continue;
-
- // Traverse all fragments in the sections, create Nodes and push the
- // fragments into Nodes. Each Region or Fillment fragment belongs to a
- // unique Node. The corresponding Align fragments and Null fragments belong
- // to the same Node as the Region or Fillment fragment.
- SectionData::iterator frag_it = sect_data->begin();
- SectionData::iterator frag_end = sect_data->end();
- if (frag_it == frag_end)
- continue;
-
- int cur_stat = 0;
- int last_stat = 0;
- // FIXME:
- // To prevent some cases that we add the redundant NULL or Align fragments
- // and lead a Region/Fillment fragment has more than one NULL or Align
- // fragment. We should put all of them into the same Node.
- static int stat_matrix[3][3] = {{0, 1, 1},
- {0, 1, 1},
- {0, 0, 0}};
-
- FragHashTableType::entry_type* entry = 0;
- bool exist = false;
-
- FGNode* node = produceRegularNode();
- Fragment* frag = NULL;
-
- frag = &(*frag_it);
- cur_stat = get_state(frag->getKind());
-
- node->addFragment(frag);
- // maintain the fragment to Node map
- entry = m_pFragNodeMap->insert(frag, exist);
- entry->setValue(node);
- ++frag_it;
-
- while (frag_it != frag_end) {
- last_stat = cur_stat;
- frag = &(*frag_it);
-
- cur_stat = get_state(frag->getKind());
-
- if (stat_matrix[cur_stat][last_stat]) {
- node = produceRegularNode();
- }
- node->addFragment(frag);
- // maintain the fragment to Node map
- entry = m_pFragNodeMap->insert(frag, exist);
- entry->setValue(node);
-
- ++frag_it;
- }
- }
- return true;
-}
-
-void FragmentGraph::initMatrix()
-{
- m_pMatrix = new ReachMatrix(m_NumOfPNodes + m_NumOfRNodes);
-}
-
-bool FragmentGraph::getEdges(FGNode& pNode, EdgeListType& pEdges)
-{
- // Traverse all regular nodes to find the connection to pNode
- node_iterator it, itEnd = m_pRegularNodeFactory->end();
- for (it = m_pRegularNodeFactory->begin(); it != itEnd; ++it) {
- FGNode& node_to = *it;
- uint32_t weight = m_pMatrix->at(pNode.getIndex(), node_to.getIndex());
- if (weight > 0) {
- // build an Edge
- pEdges.push_back(FGEdge(pNode, node_to, weight));
- }
- }
-
- return true;
-}
-
-bool FragmentGraph::construct(const LinkerConfig& pConfig, Module& pModule)
-{
- // create nodes - traverse all fragments to create the regular nodes, and
- // then traverse all global defined symbols to create pseudo nodes
- if (!createRegularNodes(pModule))
- return false;
- if (!createPseudoNodes(pModule))
- return false;
-
- // after all nodes created, we know the number of the nodes and then can
- // create the reachability matrix
- initMatrix();
-
- // set slots - traverse all symbols to set the slots of regular nodes
- if(!setNodeSlots(pModule))
- return false;
-
- // connect edges - traverse all relocations to set the edges
- if(!createRegularEdges(pModule))
- return false;
- if(!createPseudoEdges(pModule))
- return false;
-
- return true;
-}
-
diff --git a/lib/Fragment/FragmentLinker.cpp b/lib/Fragment/FragmentLinker.cpp
deleted file mode 100644
index 5a4b53f..0000000
--- a/lib/Fragment/FragmentLinker.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-//===- FragmentLinker.cpp -------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the FragmentLinker class
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/Fragment/FragmentLinker.h>
-
-#include <llvm/Support/Host.h>
-#include <llvm/Support/raw_ostream.h>
-#include <llvm/Support/Casting.h>
-
-#include <mcld/LinkerConfig.h>
-#include <mcld/Module.h>
-#include <mcld/LD/LDSection.h>
-#include <mcld/MC/MCLDInput.h>
-#include <mcld/LD/LDSection.h>
-#include <mcld/LD/BranchIslandFactory.h>
-#include <mcld/LD/Resolver.h>
-#include <mcld/LD/LDContext.h>
-#include <mcld/LD/RelocationFactory.h>
-#include <mcld/LD/RelocData.h>
-#include <mcld/LD/Relocator.h>
-#include <mcld/Support/MemoryRegion.h>
-#include <mcld/Support/MemoryArea.h>
-#include <mcld/Support/FileHandle.h>
-#include <mcld/Support/MsgHandling.h>
-#include <mcld/Target/TargetLDBackend.h>
-#include <mcld/Fragment/Relocation.h>
-
-using namespace mcld;
-
-//===----------------------------------------------------------------------===//
-// FragmentLinker
-//===----------------------------------------------------------------------===//
-/// Constructor
-FragmentLinker::FragmentLinker(const LinkerConfig& pConfig,
- Module& pModule,
- TargetLDBackend& pBackend)
-
- : m_Config(pConfig),
- m_Module(pModule),
- m_Backend(pBackend) {
-}
-
-/// Destructor
-FragmentLinker::~FragmentLinker()
-{
-}
-
-bool FragmentLinker::finalizeSymbols()
-{
- Module::sym_iterator symbol, symEnd = m_Module.sym_end();
- for (symbol = m_Module.sym_begin(); symbol != symEnd; ++symbol) {
-
- if ((*symbol)->resolveInfo()->isAbsolute() ||
- (*symbol)->resolveInfo()->type() == ResolveInfo::File) {
- // absolute symbols or symbols with function type should have
- // zero value
- (*symbol)->setValue(0x0);
- continue;
- }
-
- if ((*symbol)->resolveInfo()->type() == ResolveInfo::ThreadLocal) {
- m_Backend.finalizeTLSSymbol(**symbol);
- continue;
- }
-
- if ((*symbol)->hasFragRef()) {
- // set the virtual address of the symbol. If the output file is
- // relocatable object file, the section's virtual address becomes zero.
- // And the symbol's value become section relative offset.
- uint64_t value = (*symbol)->fragRef()->getOutputOffset();
- assert(NULL != (*symbol)->fragRef()->frag());
- uint64_t addr = (*symbol)->fragRef()->frag()->getParent()->getSection().addr();
- (*symbol)->setValue(value + addr);
- continue;
- }
- }
-
- return true;
-}
-
-//===----------------------------------------------------------------------===//
-// Relocation Operations
-//===----------------------------------------------------------------------===//
-bool FragmentLinker::applyRelocations()
-{
- // when producing relocatables, no need to apply relocation
- if (LinkerConfig::Object == m_Config.codeGenType())
- return true;
-
- // apply all relocations of all inputs
- Module::obj_iterator input, inEnd = m_Module.obj_end();
- for (input = m_Module.obj_begin(); input != inEnd; ++input) {
- m_Backend.getRelocator()->initializeApply(**input);
- LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
- for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
- // bypass the reloc section if
- // 1. its section kind is changed to Ignore. (The target section is a
- // discarded group section.)
- // 2. it has no reloc data. (All symbols in the input relocs are in the
- // discarded group sections)
- if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData())
- continue;
- RelocData::iterator reloc, rEnd = (*rs)->getRelocData()->end();
- for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) {
- Relocation* relocation = llvm::cast<Relocation>(reloc);
- relocation->apply(*m_Backend.getRelocator());
- } // for all relocations
- } // for all relocation section
- m_Backend.getRelocator()->finalizeApply(**input);
- } // for all inputs
-
- // apply relocations created by relaxation
- BranchIslandFactory* br_factory = m_Backend.getBRIslandFactory();
- BranchIslandFactory::iterator facIter, facEnd = br_factory->end();
- for (facIter = br_factory->begin(); facIter != facEnd; ++facIter) {
- BranchIsland& island = *facIter;
- BranchIsland::reloc_iterator iter, iterEnd = island.reloc_end();
- for (iter = island.reloc_begin(); iter != iterEnd; ++iter)
- (*iter)->apply(*m_Backend.getRelocator());
- }
- return true;
-}
-
-
-void FragmentLinker::syncRelocationResult(MemoryArea& pOutput)
-{
- if (LinkerConfig::Object != m_Config.codeGenType())
- normalSyncRelocationResult(pOutput);
- else
- partialSyncRelocationResult(pOutput);
- return;
-}
-
-void FragmentLinker::normalSyncRelocationResult(MemoryArea& pOutput)
-{
- MemoryRegion* region = pOutput.request(0, pOutput.handler()->size());
-
- uint8_t* data = region->getBuffer();
-
- // sync all relocations of all inputs
- Module::obj_iterator input, inEnd = m_Module.obj_end();
- for (input = m_Module.obj_begin(); input != inEnd; ++input) {
- LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
- for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
- // bypass the reloc section if
- // 1. its section kind is changed to Ignore. (The target section is a
- // discarded group section.)
- // 2. it has no reloc data. (All symbols in the input relocs are in the
- // discarded group sections)
- if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData())
- continue;
- RelocData::iterator reloc, rEnd = (*rs)->getRelocData()->end();
- for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) {
- Relocation* relocation = llvm::cast<Relocation>(reloc);
-
- // bypass the relocation with NONE type. This is to avoid overwrite the
- // target result by NONE type relocation if there is a place which has
- // two relocations to apply to, and one of it is NONE type. The result
- // we want is the value of the other relocation result. For example,
- // in .exidx, there are usually an R_ARM_NONE and R_ARM_PREL31 apply to
- // the same place
- if (0x0 == relocation->type())
- continue;
- writeRelocationResult(*relocation, data);
- } // for all relocations
- } // for all relocation section
- } // for all inputs
-
- // sync relocations created by relaxation
- BranchIslandFactory* br_factory = m_Backend.getBRIslandFactory();
- BranchIslandFactory::iterator facIter, facEnd = br_factory->end();
- for (facIter = br_factory->begin(); facIter != facEnd; ++facIter) {
- BranchIsland& island = *facIter;
- BranchIsland::reloc_iterator iter, iterEnd = island.reloc_end();
- for (iter = island.reloc_begin(); iter != iterEnd; ++iter) {
- Relocation* reloc = *iter;
- writeRelocationResult(*reloc, data);
- }
- }
-
- pOutput.clear();
-}
-
-void FragmentLinker::partialSyncRelocationResult(MemoryArea& pOutput)
-{
- MemoryRegion* region = pOutput.request(0, pOutput.handler()->size());
-
- uint8_t* data = region->getBuffer();
-
- // traverse outputs' LDSection to get RelocData
- Module::iterator sectIter, sectEnd = m_Module.end();
- for (sectIter = m_Module.begin(); sectIter != sectEnd; ++sectIter) {
- if (LDFileFormat::Relocation != (*sectIter)->kind())
- continue;
-
- RelocData* reloc_data = (*sectIter)->getRelocData();
- RelocData::iterator relocIter, relocEnd = reloc_data->end();
- for (relocIter = reloc_data->begin(); relocIter != relocEnd; ++relocIter) {
- Relocation* reloc = llvm::cast<Relocation>(relocIter);
-
- // bypass the relocation with NONE type. This is to avoid overwrite the
- // target result by NONE type relocation if there is a place which has
- // two relocations to apply to, and one of it is NONE type. The result
- // we want is the value of the other relocation result. For example,
- // in .exidx, there are usually an R_ARM_NONE and R_ARM_PREL31 apply to
- // the same place
- if (0x0 == reloc->type())
- continue;
- writeRelocationResult(*reloc, data);
- }
- }
-
- pOutput.clear();
-}
-
-void FragmentLinker::writeRelocationResult(Relocation& pReloc, uint8_t* pOutput)
-{
- // get output file offset
- size_t out_offset =
- pReloc.targetRef().frag()->getParent()->getSection().offset() +
- pReloc.targetRef().getOutputOffset();
-
- uint8_t* target_addr = pOutput + out_offset;
- // byte swapping if target and host has different endian, and then write back
- if(llvm::sys::IsLittleEndianHost != m_Config.targets().isLittleEndian()) {
- uint64_t tmp_data = 0;
-
- switch(pReloc.size(*m_Backend.getRelocator())) {
- case 8u:
- std::memcpy(target_addr, &pReloc.target(), 1);
- break;
-
- case 16u:
- tmp_data = mcld::bswap16(pReloc.target());
- std::memcpy(target_addr, &tmp_data, 2);
- break;
-
- case 32u:
- tmp_data = mcld::bswap32(pReloc.target());
- std::memcpy(target_addr, &tmp_data, 4);
- break;
-
- case 64u:
- tmp_data = mcld::bswap64(pReloc.target());
- std::memcpy(target_addr, &tmp_data, 8);
- break;
-
- default:
- break;
- }
- }
- else
- std::memcpy(target_addr, &pReloc.target(),
- pReloc.size(*m_Backend.getRelocator())/8);
-}
-
diff --git a/lib/Fragment/FragmentRef.cpp b/lib/Fragment/FragmentRef.cpp
index 9383e87..a22beca 100644
--- a/lib/Fragment/FragmentRef.cpp
+++ b/lib/Fragment/FragmentRef.cpp
@@ -8,21 +8,20 @@
//===----------------------------------------------------------------------===//
#include <mcld/Fragment/FragmentRef.h>
-#include <cstring>
-#include <cassert>
-
-#include <llvm/Support/Casting.h>
-#include <llvm/Support/ManagedStatic.h>
-
#include <mcld/Fragment/Fragment.h>
#include <mcld/LD/LDSection.h>
#include <mcld/LD/SectionData.h>
#include <mcld/LD/EhFrame.h>
#include <mcld/Support/GCFactory.h>
-#include <mcld/Support/MemoryRegion.h>
#include <mcld/Fragment/RegionFragment.h>
#include <mcld/Fragment/Stub.h>
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/Casting.h>
+#include <llvm/Support/ManagedStatic.h>
+
+#include <cassert>
+
using namespace mcld;
typedef GCFactory<FragmentRef, MCLD_SECTIONS_PER_INPUT> FragRefFactory;
@@ -61,13 +60,18 @@
break;
frag = frag->getNextNode();
}
-
+ if ((frag != NULL) && (frag->size() != 0)) {
+ if (offset == 0)
+ frag = frag->getNextNode();
+ else
+ offset += frag->size();
+ }
if (NULL == frag)
return Null();
FragmentRef* result = g_FragRefFactory->allocate();
- new (result) FragmentRef(*frag, offset + frag->size());
+ new (result) FragmentRef(*frag, offset);
return result;
}
@@ -132,7 +136,7 @@
if (total_length < (total_offset+pNBytes))
pNBytes = total_length - total_offset;
- std::memcpy(pDest, region_frag->getRegion().getBuffer(total_offset), pNBytes);
+ std::memcpy(pDest, region_frag->getRegion().begin() + total_offset, pNBytes);
return;
}
case Fragment::Stub: {
@@ -150,40 +154,6 @@
}
}
-FragmentRef::Address FragmentRef::deref()
-{
- if (NULL == m_pFragment)
- return NULL;
- Address base = NULL;
- switch(m_pFragment->getKind()) {
- case Fragment::Region:
- base = static_cast<RegionFragment*>(m_pFragment)->getRegion().getBuffer();
- break;
- case Fragment::Alignment:
- case Fragment::Fillment:
- default:
- return NULL;
- }
- return base + m_Offset;
-}
-
-FragmentRef::ConstAddress FragmentRef::deref() const
-{
- if (NULL == m_pFragment)
- return NULL;
- ConstAddress base = NULL;
- switch(m_pFragment->getKind()) {
- case Fragment::Region:
- base = static_cast<const RegionFragment*>(m_pFragment)->getRegion().getBuffer();
- break;
- case Fragment::Alignment:
- case Fragment::Fillment:
- default:
- return NULL;
- }
- return base + m_Offset;
-}
-
FragmentRef::Offset FragmentRef::getOutputOffset() const
{
Offset result = 0;
@@ -191,4 +161,3 @@
result = m_pFragment->getOffset();
return (result + m_Offset);
}
-
diff --git a/lib/Fragment/RegionFragment.cpp b/lib/Fragment/RegionFragment.cpp
index 363a0f2..c8971b8 100644
--- a/lib/Fragment/RegionFragment.cpp
+++ b/lib/Fragment/RegionFragment.cpp
@@ -7,14 +7,13 @@
//
//===----------------------------------------------------------------------===//
#include <mcld/Fragment/RegionFragment.h>
-#include <mcld/Support/MemoryRegion.h>
using namespace mcld;
//===----------------------------------------------------------------------===//
// RegionFragment
//===----------------------------------------------------------------------===//
-RegionFragment::RegionFragment(MemoryRegion& pRegion, SectionData* pSD)
+RegionFragment::RegionFragment(llvm::StringRef pRegion, SectionData* pSD)
: Fragment(Fragment::Region, pSD), m_Region(pRegion) {
}
diff --git a/lib/Fragment/Relocation.cpp b/lib/Fragment/Relocation.cpp
index fd042ea..1537c0c 100644
--- a/lib/Fragment/Relocation.cpp
+++ b/lib/Fragment/Relocation.cpp
@@ -91,8 +91,10 @@
Relocation::Address Relocation::symValue() const
{
if (m_pSymInfo->type() == ResolveInfo::Section &&
- m_pSymInfo->outSymbol()->hasFragRef()) {
- return m_pSymInfo->outSymbol()->fragRef()->frag()->getParent()->getSection().addr();
+ m_pSymInfo->outSymbol()->hasFragRef()) {
+ const FragmentRef* fragRef = m_pSymInfo->outSymbol()->fragRef();
+ return fragRef->frag()->getParent()->getSection().addr() +
+ fragRef->getOutputOffset();
}
return m_pSymInfo->outSymbol()->value();
}
@@ -156,4 +158,3 @@
m_Addend += offset;
}
}
-
diff --git a/lib/LD/Archive.cpp b/lib/LD/Archive.cpp
index ee2edea..864cedb 100644
--- a/lib/LD/Archive.cpp
+++ b/lib/LD/Archive.cpp
@@ -8,11 +8,8 @@
//===----------------------------------------------------------------------===//
#include <mcld/LD/Archive.h>
#include <mcld/MC/InputBuilder.h>
-#include <mcld/MC/MCLDInput.h>
-#include <mcld/MC/AttributeSet.h>
-#include <mcld/MC/ContextFactory.h>
+#include <mcld/MC/Input.h>
#include <llvm/ADT/StringRef.h>
-#include <mcld/Support/MemoryAreaFactory.h>
#include <mcld/Support/MsgHandling.h>
using namespace mcld;
@@ -23,6 +20,7 @@
const char Archive::THIN_MAGIC[] = "!<thin>\n";
const size_t Archive::MAGIC_LEN = sizeof(Archive::MAGIC) - 1;
const char Archive::SVR4_SYMTAB_NAME[] = "/ ";
+const char Archive::IRIX6_SYMTAB_NAME[]= "/SYM64/ ";
const char Archive::STRTAB_NAME[] = "// ";
const char Archive::PAD[] = "\n";
const char Archive::MEMBER_MAGIC[] = "`\n";
diff --git a/lib/LD/BSDArchiveReader.cpp b/lib/LD/BSDArchiveReader.cpp
index bd59844..57d3a52 100644
--- a/lib/LD/BSDArchiveReader.cpp
+++ b/lib/LD/BSDArchiveReader.cpp
@@ -6,7 +6,7 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/Input.h>
#include <mcld/LD/BSDArchiveReader.h>
#include <mcld/LD/Archive.h>
@@ -20,14 +20,16 @@
{
}
-bool BSDArchiveReader::readArchive(Archive& pArchive)
+bool BSDArchiveReader::readArchive(const LinkerConfig& pConfig,
+ Archive& pArchive)
{
// TODO
return true;
}
-bool BSDArchiveReader::isMyFormat(Input& pInput) const
+bool BSDArchiveReader::isMyFormat(Input& pInput, bool &pContinue) const
{
+ pContinue = true;
// TODO
return false;
}
diff --git a/lib/LD/BinaryReader.cpp b/lib/LD/BinaryReader.cpp
new file mode 100644
index 0000000..f5c439f
--- /dev/null
+++ b/lib/LD/BinaryReader.cpp
@@ -0,0 +1,19 @@
+//===- BinaryReader.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/BinaryReader.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// BinaryReader
+//===----------------------------------------------------------------------===//
+BinaryReader::~BinaryReader()
+{
+}
+
diff --git a/lib/LD/BranchIslandFactory.cpp b/lib/LD/BranchIslandFactory.cpp
index 6a61481..116f075 100644
--- a/lib/LD/BranchIslandFactory.cpp
+++ b/lib/LD/BranchIslandFactory.cpp
@@ -8,6 +8,9 @@
//===----------------------------------------------------------------------===//
#include <mcld/LD/BranchIslandFactory.h>
#include <mcld/Fragment/Fragment.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/SectionData.h>
+#include <mcld/Module.h>
using namespace mcld;
@@ -31,43 +34,40 @@
{
}
+/// group - group fragments and create islands when needed
+/// @param pSectionData - the SectionData holds fragments need to be grouped
+void BranchIslandFactory::group(Module& pModule)
+{
+ /* Currently only support relaxing .text section! */
+ LDSection* text = pModule.getSection(".text");
+ if (text != NULL && text->hasSectionData()) {
+ SectionData& sd = *text->getSectionData();
+ uint64_t group_end = m_MaxBranchRange - m_MaxIslandSize;
+ for (SectionData::iterator it = sd.begin(), ie = sd.end(); it != ie; ++it) {
+ if ((*it).getOffset() + (*it).size() > group_end) {
+ Fragment* frag = (*it).getPrevNode();
+ while (frag != NULL && frag->getKind() == Fragment::Alignment) {
+ frag = frag->getPrevNode();
+ }
+ if (frag != NULL) {
+ produce(*frag);
+ group_end = (*it).getOffset() + m_MaxBranchRange - m_MaxIslandSize;
+ }
+ }
+ }
+ if (find(sd.back()) == NULL)
+ produce(sd.back());
+ }
+}
+
/// produce - produce a island for the given fragment
/// @param pFragment - the fragment needs a branch island
BranchIsland* BranchIslandFactory::produce(Fragment& pFragment)
{
- assert(NULL == find(pFragment));
- uint64_t island_offset = pFragment.getOffset() + m_MaxBranchRange -
- (pFragment.getOffset() % m_MaxBranchRange);
-
- // find out the last fragment whose offset is smaller than the calculated
- // offset of the island
- Fragment* frag = &pFragment;
- while (NULL != frag->getNextNode()) {
- if (frag->getNextNode()->getOffset() > island_offset)
- break;
- frag = frag->getNextNode();
- }
-
- // fall back one step if needed
- if (NULL != frag &&
- (frag->getOffset() + frag->size()) > island_offset)
- frag = frag->getPrevNode();
-
- // check not to break the alignment constraint in the target section
- // (i.e., do not insert the island after a Alignment fragment)
- while (NULL != frag &&
- Fragment::Alignment == frag->getKind()) {
- frag = frag->getPrevNode();
- }
-
- // can not find an entry fragment to bridge the island
- if (NULL == frag)
- return NULL;
-
BranchIsland *island = allocate();
- new (island) BranchIsland(*frag, // entry fragment to the island
+ new (island) BranchIsland(pFragment, // entry fragment to the island
m_MaxIslandSize, // the max size of the island
- size() - 1u); // index in the island factory
+ size() - 1u); // index in the island factory
return island;
}
@@ -76,7 +76,7 @@
BranchIsland* BranchIslandFactory::find(const Fragment& pFragment)
{
// Currently we always find the island in a forward direction.
- // TODO: If we can search backward, then we may reduce the number of islands.
+ // TODO: If we can search backward, then we may reduce the number of stubs.
for (iterator it = begin(), ie = end(); it != ie; ++it) {
if ((pFragment.getOffset() < (*it).offset()) &&
((pFragment.getOffset() + m_MaxBranchRange) >= (*it).offset()))
diff --git a/lib/LD/DiagnosticInfos.cpp b/lib/LD/DiagnosticInfos.cpp
index 3219d4a..943b046 100644
--- a/lib/LD/DiagnosticInfos.cpp
+++ b/lib/LD/DiagnosticInfos.cpp
@@ -42,12 +42,14 @@
static const DiagStaticInfo DiagCommonInfo[] = {
#define DIAG(ENUM, CLASS, ADDRDESC, LOCDESC) \
{ diag::ENUM, CLASS, STR_SIZE(ADDRDESC, uint16_t), ADDRDESC },
+#include "mcld/LD/DiagAttribute.inc"
#include "mcld/LD/DiagCommonKinds.inc"
#include "mcld/LD/DiagReaders.inc"
#include "mcld/LD/DiagSymbolResolutions.inc"
#include "mcld/LD/DiagRelocations.inc"
#include "mcld/LD/DiagLayouts.inc"
#include "mcld/LD/DiagGOTPLT.inc"
+#include "mcld/LD/DiagLDScript.inc"
#undef DIAG
{ 0, DiagnosticEngine::None, 0, 0}
};
@@ -58,11 +60,14 @@
static const DiagStaticInfo DiagLoCInfo[] = {
#define DIAG(ENUM, CLASS, ADDRDESC, LOCDESC) \
{ diag::ENUM, CLASS, STR_SIZE(LOCDESC, uint16_t), LOCDESC },
+#include "mcld/LD/DiagAttribute.inc"
+#include "mcld/LD/DiagCommonKinds.inc"
#include "mcld/LD/DiagReaders.inc"
#include "mcld/LD/DiagSymbolResolutions.inc"
#include "mcld/LD/DiagRelocations.inc"
#include "mcld/LD/DiagLayouts.inc"
#include "mcld/LD/DiagGOTPLT.inc"
+#include "mcld/LD/DiagLDScript.inc"
#undef DIAG
{ 0, DiagnosticEngine::None, 0, 0}
};
@@ -114,12 +119,13 @@
switch (ID) {
case diag::multiple_definitions: {
- if (m_Config.options().hasMulDefs()) {
+ if (m_Config.options().isMulDefs()) {
severity = DiagnosticEngine::Ignore;
}
break;
}
- case diag::undefined_reference: {
+ case diag::undefined_reference:
+ case diag::undefined_reference_text: {
// we have not implement --unresolved-symbols=method yet. So far, MCLinker
// provides the easier --allow-shlib-undefined and --no-undefined (i.e. -z defs)
switch(m_Config.codeGenType()) {
diff --git a/lib/LD/DynObjReader.cpp b/lib/LD/DynObjReader.cpp
index 60b5cf7..552e893 100644
--- a/lib/LD/DynObjReader.cpp
+++ b/lib/LD/DynObjReader.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "mcld/LD/DynObjReader.h"
#include "mcld/Target/TargetLDBackend.h"
-#include "mcld/MC/MCLDInput.h"
+#include "mcld/MC/Input.h"
using namespace mcld;
diff --git a/lib/LD/ELFBinaryReader.cpp b/lib/LD/ELFBinaryReader.cpp
index 68deea0..ee537c2 100644
--- a/lib/LD/ELFBinaryReader.cpp
+++ b/lib/LD/ELFBinaryReader.cpp
@@ -10,9 +10,8 @@
#include <mcld/IRBuilder.h>
#include <mcld/LinkerConfig.h>
-#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/Input.h>
#include <mcld/Support/MemoryArea.h>
-#include <mcld/Target/GNULDBackend.h>
#include <llvm/Support/ELF.h>
@@ -24,13 +23,9 @@
// ELFBinaryReader
//===----------------------------------------------------------------------===//
/// constructor
-ELFBinaryReader::ELFBinaryReader(GNULDBackend& pBackend,
- IRBuilder& pBuilder,
+ELFBinaryReader::ELFBinaryReader(IRBuilder& pBuilder,
const LinkerConfig& pConfig)
- : BinaryReader(),
- m_Backend(pBackend),
- m_Builder(pBuilder),
- m_Config(pConfig) {
+ : m_Builder(pBuilder), m_Config(pConfig) {
}
/// destructor
@@ -38,6 +33,12 @@
{
}
+bool ELFBinaryReader::isMyFormat(Input& pInput, bool &pContinue) const
+{
+ pContinue = true;
+ return m_Config.options().isBinaryInput();
+}
+
bool ELFBinaryReader::readBinary(Input& pInput)
{
// section: NULL
@@ -57,7 +58,7 @@
SectionData* data = m_Builder.CreateSectionData(*data_sect);
- size_t data_size = pInput.memArea()->handler()->size();
+ size_t data_size = pInput.memArea()->size();
Fragment* frag = m_Builder.CreateRegion(pInput, 0x0, data_size);
m_Builder.AppendFragment(*frag, *data);
diff --git a/lib/LD/ELFDynObjReader.cpp b/lib/LD/ELFDynObjReader.cpp
index 4f8c7ba..ebeba63 100644
--- a/lib/LD/ELFDynObjReader.cpp
+++ b/lib/LD/ELFDynObjReader.cpp
@@ -11,10 +11,11 @@
#include <mcld/LinkerConfig.h>
#include <mcld/IRBuilder.h>
#include <mcld/LD/ELFReader.h>
-#include <mcld/MC/MCLDInput.h>
-#include <mcld/Support/MemoryRegion.h>
+#include <mcld/MC/Input.h>
#include <mcld/Target/GNULDBackend.h>
+#include <mcld/Support/MemoryArea.h>
+#include <llvm/ADT/StringRef.h>
#include <llvm/ADT/Twine.h>
#include <llvm/ADT/OwningPtr.h>
#include <llvm/Support/ErrorHandling.h>
@@ -44,27 +45,34 @@
}
/// isMyFormat
-bool ELFDynObjReader::isMyFormat(Input &pInput) const
+bool ELFDynObjReader::isMyFormat(Input &pInput, bool &pContinue) const
{
assert(pInput.hasMemArea());
// Don't warning about the frequently requests.
// MemoryArea has a list of cache to handle this.
size_t hdr_size = m_pELFReader->getELFHeaderSize();
- MemoryRegion* region = pInput.memArea()->request(pInput.fileOffset(),
- hdr_size);
+ if (pInput.memArea()->size() < hdr_size)
+ return false;
- uint8_t* ELF_hdr = region->start();
+ llvm::StringRef region = pInput.memArea()->request(pInput.fileOffset(),
+ hdr_size);
+
+ const char* ELF_hdr = region.begin();
bool result = true;
- if (!m_pELFReader->isELF(ELF_hdr))
+ if (!m_pELFReader->isELF(ELF_hdr)) {
+ pContinue = true;
result = false;
- else if (!m_pELFReader->isMyEndian(ELF_hdr))
+ } else if (Input::DynObj != m_pELFReader->fileType(ELF_hdr)) {
+ pContinue = true;
result = false;
- else if (!m_pELFReader->isMyMachine(ELF_hdr))
+ } else if (!m_pELFReader->isMyEndian(ELF_hdr)) {
+ pContinue = false;
result = false;
- else if (Input::DynObj != m_pELFReader->fileType(ELF_hdr))
+ } else if (!m_pELFReader->isMyMachine(ELF_hdr)) {
+ pContinue = false;
result = false;
- pInput.memArea()->release(region);
+ }
return result;
}
@@ -74,12 +82,11 @@
assert(pInput.hasMemArea());
size_t hdr_size = m_pELFReader->getELFHeaderSize();
- MemoryRegion* region = pInput.memArea()->request(pInput.fileOffset(),
- hdr_size);
- uint8_t* ELF_hdr = region->start();
+ llvm::StringRef region = pInput.memArea()->request(pInput.fileOffset(),
+ hdr_size);
+ const char* ELF_hdr = region.begin();
bool shdr_result = m_pELFReader->readSectionHeaders(pInput, ELF_hdr);
- pInput.memArea()->release(region);
// read .dynamic to get the correct SONAME
bool dyn_result = m_pELFReader->readDynamic(pInput);
@@ -108,17 +115,14 @@
return false;
}
- MemoryRegion* symtab_region = pInput.memArea()->request(
- pInput.fileOffset() + symtab_shdr->offset(), symtab_shdr->size());
+ llvm::StringRef symtab_region = pInput.memArea()->request(
+ pInput.fileOffset() + symtab_shdr->offset(), symtab_shdr->size());
- MemoryRegion* strtab_region = pInput.memArea()->request(
- pInput.fileOffset() + strtab_shdr->offset(), strtab_shdr->size());
- char* strtab = reinterpret_cast<char*>(strtab_region->start());
+ llvm::StringRef strtab_region = pInput.memArea()->request(
+ pInput.fileOffset() + strtab_shdr->offset(), strtab_shdr->size());
+ const char* strtab = strtab_region.begin();
bool result = m_pELFReader->readSymbols(pInput, m_Builder,
- *symtab_region, strtab);
- pInput.memArea()->release(symtab_region);
- pInput.memArea()->release(strtab_region);
-
+ symtab_region, strtab);
return result;
}
diff --git a/lib/LD/ELFObjectReader.cpp b/lib/LD/ELFObjectReader.cpp
index b645570..a34739a 100644
--- a/lib/LD/ELFObjectReader.cpp
+++ b/lib/LD/ELFObjectReader.cpp
@@ -8,21 +8,23 @@
//===----------------------------------------------------------------------===//
#include <mcld/LD/ELFObjectReader.h>
-#include <string>
-#include <cassert>
-
-#include <llvm/Support/ELF.h>
-#include <llvm/ADT/Twine.h>
-
#include <mcld/IRBuilder.h>
-#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/Input.h>
#include <mcld/LD/ELFReader.h>
#include <mcld/LD/EhFrameReader.h>
#include <mcld/LD/EhFrame.h>
#include <mcld/Target/GNULDBackend.h>
#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/MemoryArea.h>
#include <mcld/Object/ObjectBuilder.h>
+#include <llvm/Support/ELF.h>
+#include <llvm/ADT/Twine.h>
+#include <llvm/ADT/StringRef.h>
+
+#include <string>
+#include <cassert>
+
using namespace mcld;
//===----------------------------------------------------------------------===//
@@ -57,27 +59,34 @@
}
/// isMyFormat
-bool ELFObjectReader::isMyFormat(Input &pInput) const
+bool ELFObjectReader::isMyFormat(Input &pInput, bool &pContinue) const
{
assert(pInput.hasMemArea());
// Don't warning about the frequently requests.
// MemoryArea has a list of cache to handle this.
size_t hdr_size = m_pELFReader->getELFHeaderSize();
- MemoryRegion* region = pInput.memArea()->request(pInput.fileOffset(),
+ if (pInput.memArea()->size() < hdr_size)
+ return false;
+
+ llvm::StringRef region = pInput.memArea()->request(pInput.fileOffset(),
hdr_size);
- uint8_t* ELF_hdr = region->start();
+ const char* ELF_hdr = region.begin();
bool result = true;
- if (!m_pELFReader->isELF(ELF_hdr))
+ if (!m_pELFReader->isELF(ELF_hdr)) {
+ pContinue = true;
result = false;
- else if (!m_pELFReader->isMyEndian(ELF_hdr))
+ } else if (Input::Object != m_pELFReader->fileType(ELF_hdr)) {
+ pContinue = true;
result = false;
- else if (!m_pELFReader->isMyMachine(ELF_hdr))
+ } else if (!m_pELFReader->isMyEndian(ELF_hdr)) {
+ pContinue = false;
result = false;
- else if (Input::Object != m_pELFReader->fileType(ELF_hdr))
+ } else if (!m_pELFReader->isMyMachine(ELF_hdr)) {
+ pContinue = false;
result = false;
- pInput.memArea()->release(region);
+ }
return result;
}
@@ -87,11 +96,13 @@
assert(pInput.hasMemArea());
size_t hdr_size = m_pELFReader->getELFHeaderSize();
- MemoryRegion* region = pInput.memArea()->request(pInput.fileOffset(),
+ if (pInput.memArea()->size() < hdr_size)
+ return false;
+
+ llvm::StringRef region = pInput.memArea()->request(pInput.fileOffset(),
hdr_size);
- uint8_t* ELF_hdr = region->start();
+ const char* ELF_hdr = region.begin();
bool result = m_pELFReader->readSectionHeaders(pInput, ELF_hdr);
- pInput.memArea()->release(region);
return result;
}
@@ -110,9 +121,9 @@
case LDFileFormat::Group: {
assert(NULL != (*section)->getLink());
ResolveInfo* signature =
- m_pELFReader->readSignature(pInput,
- *(*section)->getLink(),
- (*section)->getInfo());
+ m_pELFReader->readSignature(pInput,
+ *(*section)->getLink(),
+ (*section)->getInfo());
bool exist = false;
if (0 == signature->nameSize() &&
@@ -127,18 +138,17 @@
if (exist) {
// if this is not the first time we see this group signature, then
// ignore all the members in this group (set Ignore)
- MemoryRegion* region = pInput.memArea()->request(
+ llvm::StringRef region = pInput.memArea()->request(
pInput.fileOffset() + (*section)->offset(), (*section)->size());
- llvm::ELF::Elf32_Word* value =
- reinterpret_cast<llvm::ELF::Elf32_Word*>(region->start());
+ const llvm::ELF::Elf32_Word* value =
+ reinterpret_cast<const llvm::ELF::Elf32_Word*>(region.begin());
- size_t size = region->size() / sizeof(llvm::ELF::Elf32_Word);
+ size_t size = region.size() / sizeof(llvm::ELF::Elf32_Word);
if (llvm::ELF::GRP_COMDAT == *value) {
for (size_t index = 1; index < size; ++index) {
pInput.context()->getSection(value[index])->setKind(LDFileFormat::Ignore);
}
}
- pInput.memArea()->release(region);
}
ResolveInfo::Destroy(signature);
break;
@@ -212,10 +222,9 @@
case LDFileFormat::EhFrame: {
EhFrame* eh_frame = IRBuilder::CreateEhFrame(**section);
- if (m_Config.options().hasEhFrameHdr() &&
+ // We don't really parse EhFrame if this is a partial linking
+ if ((m_Config.codeGenType() != LinkerConfig::Object) &&
(m_ReadFlag & ParseEhFrame)) {
-
- // if --eh-frame-hdr option is given, parse .eh_frame.
if (!m_pEhFrameReader->read<32, true>(pInput, *eh_frame)) {
// if we failed to parse a .eh_frame, we should not parse the rest
// .eh_frame.
@@ -284,17 +293,15 @@
return false;
}
- MemoryRegion* symtab_region = pInput.memArea()->request(
- pInput.fileOffset() + symtab_shdr->offset(), symtab_shdr->size());
- MemoryRegion* strtab_region = pInput.memArea()->request(
- pInput.fileOffset() + strtab_shdr->offset(), strtab_shdr->size());
- char* strtab = reinterpret_cast<char*>(strtab_region->start());
+ llvm::StringRef symtab_region = pInput.memArea()->request(
+ pInput.fileOffset() + symtab_shdr->offset(), symtab_shdr->size());
+ llvm::StringRef strtab_region = pInput.memArea()->request(
+ pInput.fileOffset() + strtab_shdr->offset(), strtab_shdr->size());
+ const char* strtab = strtab_region.begin();
bool result = m_pELFReader->readSymbols(pInput,
m_Builder,
- *symtab_region,
+ symtab_region,
strtab);
- pInput.memArea()->release(symtab_region);
- pInput.memArea()->release(strtab_region);
return result;
}
@@ -310,30 +317,26 @@
uint32_t offset = pInput.fileOffset() + (*rs)->offset();
uint32_t size = (*rs)->size();
- MemoryRegion* region = mem->request(offset, size);
+ llvm::StringRef region = mem->request(offset, size);
IRBuilder::CreateRelocData(**rs); ///< create relocation data for the header
switch ((*rs)->type()) {
case llvm::ELF::SHT_RELA: {
- if (!m_pELFReader->readRela(pInput, **rs, *region)) {
- mem->release(region);
+ if (!m_pELFReader->readRela(pInput, **rs, region)) {
return false;
}
break;
}
case llvm::ELF::SHT_REL: {
- if (!m_pELFReader->readRel(pInput, **rs, *region)) {
- mem->release(region);
+ if (!m_pELFReader->readRel(pInput, **rs, region)) {
return false;
}
break;
}
default: { ///< should not enter
- mem->release(region);
return false;
}
} // end of switch
- mem->release(region);
} // end of for all relocation data
return true;
diff --git a/lib/LD/ELFObjectWriter.cpp b/lib/LD/ELFObjectWriter.cpp
index ddd3551..dca6936 100644
--- a/lib/LD/ELFObjectWriter.cpp
+++ b/lib/LD/ELFObjectWriter.cpp
@@ -10,23 +10,24 @@
#include <mcld/Module.h>
#include <mcld/LinkerConfig.h>
+#include <mcld/LinkerScript.h>
#include <mcld/Target/GNULDBackend.h>
-#include <mcld/Support/MemoryArea.h>
-#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/ADT/SizeTraits.h>
-#include <mcld/Fragment/FragmentLinker.h>
#include <mcld/Fragment/AlignFragment.h>
#include <mcld/Fragment/FillFragment.h>
#include <mcld/Fragment/RegionFragment.h>
#include <mcld/Fragment/Stub.h>
#include <mcld/Fragment/NullFragment.h>
+#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/LDSection.h>
#include <mcld/LD/SectionData.h>
#include <mcld/LD/ELFSegment.h>
#include <mcld/LD/ELFSegmentFactory.h>
#include <mcld/LD/RelocData.h>
#include <mcld/LD/EhFrame.h>
+#include <mcld/LD/ELFFileFormat.h>
+#include <mcld/Target/GNUInfo.h>
#include <llvm/Support/ErrorHandling.h>
#include <llvm/Support/system_error.h>
@@ -50,9 +51,10 @@
{
}
-void ELFObjectWriter::writeSection(MemoryArea& pOutput, LDSection *section)
+void ELFObjectWriter::writeSection(Module& pModule,
+ FileOutputBuffer& pOutput, LDSection *section)
{
- MemoryRegion* region;
+ MemoryRegion region;
// Request output region
switch (section->kind()) {
case LDFileFormat::Note:
@@ -66,10 +68,8 @@
case LDFileFormat::GCCExceptTable:
case LDFileFormat::EhFrame: {
region = pOutput.request(section->offset(), section->size());
- if (NULL == region) {
- llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section `") +
- llvm::Twine(section->name()) +
- llvm::Twine("'.\n"));
+ if (region.size() == 0) {
+ return;
}
break;
}
@@ -94,19 +94,22 @@
// Write out sections with data
switch(section->kind()) {
case LDFileFormat::GCCExceptTable:
- case LDFileFormat::EhFrame:
case LDFileFormat::Regular:
case LDFileFormat::Debug:
case LDFileFormat::Note:
- // FIXME: if optimization of exception handling sections is enabled,
- // then we should emit these sections by the other way.
- emitSectionData(*section, *region);
+ emitSectionData(*section, region);
+ break;
+ case LDFileFormat::EhFrame:
+ emitEhFrame(pModule, *section->getEhFrame(), region);
break;
case LDFileFormat::Relocation:
- emitRelocation(m_Config, *section, *region);
+ // sort relocation for the benefit of the dynamic linker.
+ target().sortRelocation(*section);
+
+ emitRelocation(m_Config, *section, region);
break;
case LDFileFormat::Target:
- target().emitSectionData(*section, *region);
+ target().emitSectionData(*section, region);
break;
default:
llvm_unreachable("invalid section kind");
@@ -114,7 +117,7 @@
}
llvm::error_code ELFObjectWriter::writeObject(Module& pModule,
- MemoryArea& pOutput)
+ FileOutputBuffer& pOutput)
{
bool is_dynobj = m_Config.codeGenType() == LinkerConfig::DynObj;
bool is_exec = m_Config.codeGenType() == LinkerConfig::Exec;
@@ -144,17 +147,17 @@
ELFSegmentFactory::iterator seg, segEnd = target().elfSegmentTable().end();
for (seg = target().elfSegmentTable().begin(); seg != segEnd; ++seg) {
- if (llvm::ELF::PT_LOAD == (*seg).type()) {
- ELFSegment::sect_iterator sect, sectEnd = (*seg).end();
- for (sect = (*seg).begin(); sect != sectEnd; ++sect)
- writeSection(pOutput, *sect);
+ if (llvm::ELF::PT_LOAD == (*seg)->type()) {
+ ELFSegment::iterator sect, sectEnd = (*seg)->end();
+ for (sect = (*seg)->begin(); sect != sectEnd; ++sect)
+ writeSection(pModule, pOutput, *sect);
}
}
} else {
// Write out regular ELF sections
Module::iterator sect, sectEnd = pModule.end();
for (sect = pModule.begin(); sect != sectEnd; ++sect)
- writeSection(pOutput, *sect);
+ writeSection(pModule, pOutput, *sect);
emitShStrTab(target().getOutputFormat()->getShStrTab(), pModule, pOutput);
@@ -180,23 +183,37 @@
return make_error_code(errc::not_supported);
}
- pOutput.clear();
return llvm::make_error_code(llvm::errc::success);
}
+// getOutputSize - count the final output size
+size_t ELFObjectWriter::getOutputSize(const Module& pModule) const
+{
+ if (m_Config.targets().is32Bits()) {
+ return getLastStartOffset<32>(pModule) +
+ sizeof(ELFSizeTraits<32>::Shdr) * pModule.size();
+ } else if (m_Config.targets().is64Bits()) {
+ return getLastStartOffset<64>(pModule) +
+ sizeof(ELFSizeTraits<64>::Shdr) * pModule.size();
+ } else {
+ assert(0 && "Invalid ELF Class");
+ return 0;
+ }
+}
+
// writeELFHeader - emit ElfXX_Ehdr
template<size_t SIZE>
void ELFObjectWriter::writeELFHeader(const LinkerConfig& pConfig,
const Module& pModule,
- MemoryArea& pOutput) const
+ FileOutputBuffer& pOutput) const
{
typedef typename ELFSizeTraits<SIZE>::Ehdr ElfXX_Ehdr;
typedef typename ELFSizeTraits<SIZE>::Shdr ElfXX_Shdr;
typedef typename ELFSizeTraits<SIZE>::Phdr ElfXX_Phdr;
// ELF header must start from 0x0
- MemoryRegion *region = pOutput.request(0, sizeof(ElfXX_Ehdr));
- ElfXX_Ehdr* header = (ElfXX_Ehdr*)region->start();
+ MemoryRegion region = pOutput.request(0, sizeof(ElfXX_Ehdr));
+ ElfXX_Ehdr* header = (ElfXX_Ehdr*)region.begin();
memcpy(header->e_ident, ElfMagic, EI_MAG3+1);
@@ -235,7 +252,7 @@
header->e_flags = target().getInfo().flags();
header->e_ehsize = sizeof(ElfXX_Ehdr);
header->e_phentsize = sizeof(ElfXX_Phdr);
- header->e_phnum = target().numOfSegments();
+ header->e_phnum = target().elfSegmentTable().size();
header->e_shentsize = sizeof(ElfXX_Shdr);
header->e_shnum = pModule.size();
header->e_shstrndx = pModule.getSection(".shstrtab")->index();
@@ -245,15 +262,10 @@
uint64_t ELFObjectWriter::getEntryPoint(const LinkerConfig& pConfig,
const Module& pModule) const
{
- llvm::StringRef entry_name;
- if (pConfig.options().hasEntry())
- entry_name = pConfig.options().entry();
- else
- entry_name = target().getInfo().entry();
-
+ llvm::StringRef entry_name = target().getEntry(pModule);
uint64_t result = 0x0;
- bool issue_warning = (pConfig.options().hasEntry() &&
+ bool issue_warning = (pModule.getScript().hasEntry() &&
LinkerConfig::Object != pConfig.codeGenType() &&
LinkerConfig::DynObj != pConfig.codeGenType());
@@ -290,16 +302,16 @@
template<size_t SIZE>
void ELFObjectWriter::emitSectionHeader(const Module& pModule,
const LinkerConfig& pConfig,
- MemoryArea& pOutput) const
+ FileOutputBuffer& pOutput) const
{
typedef typename ELFSizeTraits<SIZE>::Shdr ElfXX_Shdr;
// emit section header
unsigned int sectNum = pModule.size();
unsigned int header_size = sizeof(ElfXX_Shdr) * sectNum;
- MemoryRegion* region = pOutput.request(getLastStartOffset<SIZE>(pModule),
- header_size);
- ElfXX_Shdr* shdr = (ElfXX_Shdr*)region->start();
+ MemoryRegion region = pOutput.request(getLastStartOffset<SIZE>(pModule),
+ header_size);
+ ElfXX_Shdr* shdr = (ElfXX_Shdr*)region.begin();
// Iterate the SectionTable in LDContext
unsigned int sectIdx = 0;
@@ -324,7 +336,7 @@
// emitProgramHeader - emit ElfXX_Phdr
template<size_t SIZE>
-void ELFObjectWriter::emitProgramHeader(MemoryArea& pOutput) const
+void ELFObjectWriter::emitProgramHeader(FileOutputBuffer& pOutput) const
{
typedef typename ELFSizeTraits<SIZE>::Ehdr ElfXX_Ehdr;
typedef typename ELFSizeTraits<SIZE>::Phdr ElfXX_Phdr;
@@ -334,24 +346,24 @@
start_offset = sizeof(ElfXX_Ehdr);
phdr_size = sizeof(ElfXX_Phdr);
// Program header must start directly after ELF header
- MemoryRegion *region = pOutput.request(start_offset,
- target().numOfSegments() * phdr_size);
+ MemoryRegion region = pOutput.request(start_offset,
+ target().elfSegmentTable().size() * phdr_size);
- ElfXX_Phdr* phdr = (ElfXX_Phdr*)region->start();
+ ElfXX_Phdr* phdr = (ElfXX_Phdr*)region.begin();
// Iterate the elf segment table in GNULDBackend
size_t index = 0;
ELFSegmentFactory::const_iterator seg = target().elfSegmentTable().begin(),
segEnd = target().elfSegmentTable().end();
for (; seg != segEnd; ++seg, ++index) {
- phdr[index].p_type = (*seg).type();
- phdr[index].p_flags = (*seg).flag();
- phdr[index].p_offset = (*seg).offset();
- phdr[index].p_vaddr = (*seg).vaddr();
- phdr[index].p_paddr = (*seg).paddr();
- phdr[index].p_filesz = (*seg).filesz();
- phdr[index].p_memsz = (*seg).memsz();
- phdr[index].p_align = (*seg).align();
+ phdr[index].p_type = (*seg)->type();
+ phdr[index].p_flags = (*seg)->flag();
+ phdr[index].p_offset = (*seg)->offset();
+ phdr[index].p_vaddr = (*seg)->vaddr();
+ phdr[index].p_paddr = (*seg)->paddr();
+ phdr[index].p_filesz = (*seg)->filesz();
+ phdr[index].p_memsz = (*seg)->memsz();
+ phdr[index].p_align = (*seg)->align();
}
}
@@ -359,11 +371,11 @@
void
ELFObjectWriter::emitShStrTab(const LDSection& pShStrTab,
const Module& pModule,
- MemoryArea& pOutput)
+ FileOutputBuffer& pOutput)
{
// write out data
- MemoryRegion* region = pOutput.request(pShStrTab.offset(), pShStrTab.size());
- unsigned char* data = region->start();
+ MemoryRegion region = pOutput.request(pShStrTab.offset(), pShStrTab.size());
+ char* data = (char*)region.begin();
size_t shstrsize = 0;
Module::const_iterator section, sectEnd = pModule.end();
for (section = pModule.begin(); section != sectEnd; ++section) {
@@ -394,6 +406,50 @@
emitSectionData(*sd, pRegion);
}
+/// emitEhFrame
+void ELFObjectWriter::emitEhFrame(Module& pModule,
+ EhFrame& pFrame, MemoryRegion& pRegion) const
+{
+ emitSectionData(*pFrame.getSectionData(), pRegion);
+
+ // Patch FDE field (offset to CIE)
+ for (EhFrame::cie_iterator i = pFrame.cie_begin(), e = pFrame.cie_end();
+ i != e; ++i) {
+ EhFrame::CIE& cie = **i;
+ for (EhFrame::fde_iterator fi = cie.begin(), fe = cie.end();
+ fi != fe; ++fi) {
+ EhFrame::FDE& fde = **fi;
+ if (fde.getRecordType() == EhFrame::RECORD_GENERATED) {
+ // Patch PLT offset
+ LDSection* plt_sect = pModule.getSection(".plt");
+ assert (plt_sect && "We have no plt but have corresponding eh_frame?");
+ uint64_t plt_offset = plt_sect->offset();
+ // FDE entry for PLT is always 32-bit
+ uint64_t fde_offset = pFrame.getSection().offset() + fde.getOffset() +
+ EhFrame::getDataStartOffset<32>();
+ int32_t offset = fde_offset - plt_offset;
+ if (plt_offset < fde_offset)
+ offset = -offset;
+ memcpy(pRegion.begin() + fde.getOffset() +
+ EhFrame::getDataStartOffset<32>(),
+ &offset, 4);
+ uint32_t size = plt_sect->size();
+ memcpy(pRegion.begin() + fde.getOffset() +
+ EhFrame::getDataStartOffset<32>() + 4,
+ &size, 4);
+ }
+ uint64_t fde_cie_ptr_offset = fde.getOffset() +
+ EhFrame::getDataStartOffset<32>() -
+ /*ID*/4;
+ uint64_t cie_start_offset = cie.getOffset();
+ int32_t offset = fde_cie_ptr_offset - cie_start_offset;
+ if (fde_cie_ptr_offset < cie_start_offset)
+ offset = -offset;
+ memcpy(pRegion.begin() + fde_cie_ptr_offset, &offset, 4);
+ } // for loop fde_iterator
+ } // for loop cie_iterator
+}
+
/// emitRelocation
void ELFObjectWriter::emitRelocation(const LinkerConfig& pConfig,
const LDSection& pSection,
@@ -435,34 +491,36 @@
typedef typename ELFSizeTraits<SIZE>::Addr ElfXX_Addr;
typedef typename ELFSizeTraits<SIZE>::Word ElfXX_Word;
- ElfXX_Rel* rel = reinterpret_cast<ElfXX_Rel*>(pRegion.start());
+ ElfXX_Rel* rel = reinterpret_cast<ElfXX_Rel*>(pRegion.begin());
const Relocation* relocation = 0;
const FragmentRef* frag_ref = 0;
for (RelocData::const_iterator it = pRelocData.begin(),
ie = pRelocData.end(); it != ie; ++it, ++rel) {
+ ElfXX_Addr r_offset = 0;
+ ElfXX_Word r_sym = 0;
relocation = &(llvm::cast<Relocation>(*it));
frag_ref = &(relocation->targetRef());
if(LinkerConfig::DynObj == pConfig.codeGenType() ||
LinkerConfig::Exec == pConfig.codeGenType()) {
- rel->r_offset = static_cast<ElfXX_Addr>(
+ r_offset = static_cast<ElfXX_Addr>(
frag_ref->frag()->getParent()->getSection().addr() +
frag_ref->getOutputOffset());
}
else {
- rel->r_offset = static_cast<ElfXX_Addr>(frag_ref->getOutputOffset());
+ r_offset = static_cast<ElfXX_Addr>(frag_ref->getOutputOffset());
}
- ElfXX_Word Index;
+
if( relocation->symInfo() == NULL )
- Index = 0;
+ r_sym = 0;
else
- Index = static_cast<ElfXX_Word>(
+ r_sym = static_cast<ElfXX_Word>(
target().getSymbolIdx(relocation->symInfo()->outSymbol()));
- rel->setSymbolAndType(Index, relocation->type());
+ target().emitRelocation(*rel, relocation->type(), r_sym, r_offset);
}
}
@@ -476,36 +534,37 @@
typedef typename ELFSizeTraits<SIZE>::Addr ElfXX_Addr;
typedef typename ELFSizeTraits<SIZE>::Word ElfXX_Word;
- ElfXX_Rela* rel = reinterpret_cast<ElfXX_Rela*>(pRegion.start());
+ ElfXX_Rela* rel = reinterpret_cast<ElfXX_Rela*>(pRegion.begin());
const Relocation* relocation = 0;
const FragmentRef* frag_ref = 0;
for (RelocData::const_iterator it = pRelocData.begin(),
ie = pRelocData.end(); it != ie; ++it, ++rel) {
+ ElfXX_Addr r_offset = 0;
+ ElfXX_Word r_sym = 0;
relocation = &(llvm::cast<Relocation>(*it));
frag_ref = &(relocation->targetRef());
if(LinkerConfig::DynObj == pConfig.codeGenType() ||
LinkerConfig::Exec == pConfig.codeGenType()) {
- rel->r_offset = static_cast<ElfXX_Addr>(
+ r_offset = static_cast<ElfXX_Addr>(
frag_ref->frag()->getParent()->getSection().addr() +
frag_ref->getOutputOffset());
}
else {
- rel->r_offset = static_cast<ElfXX_Addr>(frag_ref->getOutputOffset());
+ r_offset = static_cast<ElfXX_Addr>(frag_ref->getOutputOffset());
}
- ElfXX_Word Index;
if( relocation->symInfo() == NULL )
- Index = 0;
+ r_sym = 0;
else
- Index = static_cast<ElfXX_Word>(
+ r_sym = static_cast<ElfXX_Word>(
target().getSymbolIdx(relocation->symInfo()->outSymbol()));
- rel->setSymbolAndType(Index, relocation->type());
- rel->r_addend = relocation->addend();
+ target().emitRelocation(*rel, relocation->type(),
+ r_sym, r_offset, relocation->addend());
}
}
@@ -532,6 +591,12 @@
return sizeof(ElfXX_Word);
if (llvm::ELF::SHT_DYNAMIC == pSection.type())
return sizeof(ElfXX_Dyn);
+ // FIXME: We should get the entsize from input since the size of each
+ // character is specified in the section header's sh_entsize field.
+ // For example, traditional string is 0x1, UCS-2 is 0x2, ... and so on.
+ // Ref: http://www.sco.com/developers/gabi/2003-12-17/ch4.sheader.html
+ if (pSection.flag() & llvm::ELF::SHF_STRINGS)
+ return 0x1;
return 0x0;
}
@@ -607,8 +672,8 @@
switch(fragIter->getKind()) {
case Fragment::Region: {
const RegionFragment& region_frag = llvm::cast<RegionFragment>(*fragIter);
- const uint8_t* from = region_frag.getRegion().start();
- memcpy(pRegion.getBuffer(cur_offset), from, size);
+ const char* from = region_frag.getRegion().begin();
+ memcpy(pRegion.begin() + cur_offset, from, size);
break;
}
case Fragment::Alignment: {
@@ -617,7 +682,7 @@
uint64_t count = size / align_frag.getValueSize();
switch (align_frag.getValueSize()) {
case 1u:
- std::memset(pRegion.getBuffer(cur_offset),
+ std::memset(pRegion.begin() + cur_offset,
align_frag.getValue(),
count);
break;
@@ -638,7 +703,7 @@
uint64_t num_tiles = fill_frag.size() / fill_frag.getValueSize();
for (uint64_t i = 0; i != num_tiles; ++i) {
- std::memset(pRegion.getBuffer(cur_offset),
+ std::memset(pRegion.begin() + cur_offset,
fill_frag.getValue(),
fill_frag.getValueSize());
}
@@ -646,7 +711,7 @@
}
case Fragment::Stub: {
const Stub& stub_frag = llvm::cast<Stub>(*fragIter);
- memcpy(pRegion.getBuffer(cur_offset), stub_frag.getContent(), size);
+ memcpy(pRegion.begin() + cur_offset, stub_frag.getContent(), size);
break;
}
case Fragment::Null: {
diff --git a/lib/LD/ELFReader.cpp b/lib/LD/ELFReader.cpp
index f7b047f..119f8a7 100644
--- a/lib/LD/ELFReader.cpp
+++ b/lib/LD/ELFReader.cpp
@@ -13,8 +13,9 @@
#include <mcld/LD/EhFrame.h>
#include <mcld/LD/SectionData.h>
#include <mcld/Target/GNULDBackend.h>
-#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Target/GNUInfo.h>
#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/MemoryArea.h>
#include <mcld/Object/ObjectBuilder.h>
#include <cstring>
@@ -42,10 +43,10 @@
}
/// isELF - is this a ELF file
-bool ELFReader<32, true>::isELF(void* pELFHeader) const
+bool ELFReader<32, true>::isELF(const void* pELFHeader) const
{
- llvm::ELF::Elf32_Ehdr* hdr =
- reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(pELFHeader);
+ const llvm::ELF::Elf32_Ehdr* hdr =
+ reinterpret_cast<const llvm::ELF::Elf32_Ehdr*>(pELFHeader);
if (0 == memcmp(llvm::ELF::ElfMagic, hdr, 4))
return true;
return false;
@@ -66,13 +67,13 @@
/// readSymbols - read ELF symbols and create LDSymbol
bool ELFReader<32, true>::readSymbols(Input& pInput,
IRBuilder& pBuilder,
- const MemoryRegion& pRegion,
+ llvm::StringRef pRegion,
const char* pStrTab) const
{
// get number of symbols
size_t entsize = pRegion.size()/sizeof(llvm::ELF::Elf32_Sym);
const llvm::ELF::Elf32_Sym* symtab =
- reinterpret_cast<const llvm::ELF::Elf32_Sym*>(pRegion.start());
+ reinterpret_cast<const llvm::ELF::Elf32_Sym*>(pRegion.begin());
uint32_t st_name = 0x0;
uint32_t st_value = 0x0;
@@ -144,22 +145,22 @@
ld_name = std::string(pStrTab + st_name);
}
- LDSymbol *psym =
- pBuilder.AddSymbol(pInput,
- ld_name,
- ld_type,
- ld_desc,
- ld_binding,
- st_size,
- ld_value,
- section, ld_vis);
+ LDSymbol* psym = pBuilder.AddSymbol(pInput,
+ ld_name,
+ ld_type,
+ ld_desc,
+ ld_binding,
+ st_size,
+ ld_value,
+ section,
+ ld_vis);
- if ( is_dyn_obj
- && NULL!=psym
- && ResolveInfo::Undefined!=ld_desc
- && (ResolveInfo::Global==ld_binding ||
- ResolveInfo::Weak==ld_binding)
- && ResolveInfo::Object==ld_type ) {
+ if (is_dyn_obj
+ && NULL != psym
+ && ResolveInfo::Undefined != ld_desc
+ && (ResolveInfo::Global == ld_binding ||
+ ResolveInfo::Weak == ld_binding)
+ && ResolveInfo::Object == ld_type) {
AliasInfo p;
p.pt_alias = psym;
p.ld_binding = ld_binding;
@@ -174,9 +175,9 @@
// 1. eliminate code duplication
// 2. easy to know if a symbol is from .so
// (so that it may be a potential alias)
- if ( is_dyn_obj ) {
+ if (is_dyn_obj) {
// sort symbols by symbol value and then weak before strong
- std::sort( potential_aliases.begin(), potential_aliases.end(), less);
+ std::sort(potential_aliases.begin(), potential_aliases.end(), less);
// for each weak symbol, find out all its aliases, and
// then link them as a circular list in Module
@@ -189,16 +190,16 @@
Module& pModule = pBuilder.getModule();
std::vector<AliasInfo>::iterator alias_it = sym_it+1;
while(alias_it!=sym_e) {
- if ( sym_it->ld_value != alias_it->ld_value )
+ if (sym_it->ld_value != alias_it->ld_value)
break;
- if (sym_it+1==alias_it)
+ if (sym_it + 1 == alias_it)
pModule.CreateAliasList(*sym_it->pt_alias->resolveInfo());
pModule.addAlias(*alias_it->pt_alias->resolveInfo());
++alias_it;
}
- sym_it = alias_it-1;
+ sym_it = alias_it - 1;
}// end of for loop
}
@@ -211,30 +212,21 @@
/// ELFReader::readRela - read ELF rela and create Relocation
bool ELFReader<32, true>::readRela(Input& pInput,
LDSection& pSection,
- const MemoryRegion& pRegion) const
+ llvm::StringRef pRegion) const
{
// get the number of rela
size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf32_Rela);
const llvm::ELF::Elf32_Rela* relaTab =
- reinterpret_cast<const llvm::ELF::Elf32_Rela*>(pRegion.start());
+ reinterpret_cast<const llvm::ELF::Elf32_Rela*>(pRegion.begin());
for (size_t idx=0; idx < entsize; ++idx) {
+ Relocation::Type r_type = 0x0;
+ uint32_t r_sym = 0x0;
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 = mcld::bswap32(relaTab[idx].r_offset);
- r_info = mcld::bswap32(relaTab[idx].r_info);
- r_addend = mcld::bswap32(relaTab[idx].r_addend);
- }
+ if (!target().readRelocation(relaTab[idx], r_type, r_sym, r_offset, r_addend))
+ return false;
- 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) {
fatal(diag::err_cannot_read_symbol) << r_sym << pInput.path();
@@ -248,27 +240,20 @@
/// readRel - read ELF rel and create Relocation
bool ELFReader<32, true>::readRel(Input& pInput,
LDSection& pSection,
- const MemoryRegion& pRegion) const
+ llvm::StringRef pRegion) const
{
// get the number of rel
size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf32_Rel);
const llvm::ELF::Elf32_Rel* relTab =
- reinterpret_cast<const llvm::ELF::Elf32_Rel*>(pRegion.start());
+ reinterpret_cast<const llvm::ELF::Elf32_Rel*>(pRegion.begin());
for (size_t idx=0; idx < entsize; ++idx) {
+ Relocation::Type r_type = 0x0;
+ uint32_t r_sym = 0x0;
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 = mcld::bswap32(relTab[idx].r_offset);
- r_info = mcld::bswap32(relTab[idx].r_info);
- }
- uint8_t r_type = static_cast<unsigned char>(r_info);
- uint32_t r_sym = (r_info >> 8);
+ if (!target().readRelocation(relTab[idx], r_type, r_sym, r_offset))
+ return false;
LDSymbol* symbol = pInput.context()->getSymbol(r_sym);
if (NULL == symbol) {
@@ -281,19 +266,19 @@
}
/// isMyEndian - is this ELF file in the same endian to me?
-bool ELFReader<32, true>::isMyEndian(void* pELFHeader) const
+bool ELFReader<32, true>::isMyEndian(const void* pELFHeader) const
{
- llvm::ELF::Elf32_Ehdr* hdr =
- reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(pELFHeader);
+ const llvm::ELF::Elf32_Ehdr* hdr =
+ reinterpret_cast<const 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
+bool ELFReader<32, true>::isMyMachine(const void* pELFHeader) const
{
- llvm::ELF::Elf32_Ehdr* hdr =
- reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(pELFHeader);
+ const llvm::ELF::Elf32_Ehdr* hdr =
+ reinterpret_cast<const llvm::ELF::Elf32_Ehdr*>(pELFHeader);
if (llvm::sys::IsLittleEndianHost)
return (hdr->e_machine == target().getInfo().machine());
@@ -301,10 +286,10 @@
}
/// fileType - return the file type
-Input::Type ELFReader<32, true>::fileType(void* pELFHeader) const
+Input::Type ELFReader<32, true>::fileType(const void* pELFHeader) const
{
- llvm::ELF::Elf32_Ehdr* hdr =
- reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(pELFHeader);
+ const llvm::ELF::Elf32_Ehdr* hdr =
+ reinterpret_cast<const llvm::ELF::Elf32_Ehdr*>(pELFHeader);
uint32_t type = 0x0;
if (llvm::sys::IsLittleEndianHost)
type = hdr->e_type;
@@ -327,11 +312,11 @@
}
/// readSectionHeaders - read ELF section header table and create LDSections
-bool
-ELFReader<32, true>::readSectionHeaders(Input& pInput, void* pELFHeader) const
+bool ELFReader<32, true>::readSectionHeaders(Input& pInput,
+ const void* pELFHeader) const
{
- llvm::ELF::Elf32_Ehdr* ehdr =
- reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(pELFHeader);
+ const llvm::ELF::Elf32_Ehdr* ehdr =
+ reinterpret_cast<const llvm::ELF::Elf32_Ehdr*>(pELFHeader);
uint32_t shoff = 0x0;
uint16_t shentsize = 0x0;
@@ -355,8 +340,8 @@
if (0x0 == shoff)
return true;
- llvm::ELF::Elf32_Shdr *shdr = NULL;
- MemoryRegion* shdr_region = NULL;
+ const llvm::ELF::Elf32_Shdr *shdr = NULL;
+ llvm::StringRef shdr_region;
uint32_t sh_name = 0x0;
uint32_t sh_type = 0x0;
uint32_t sh_flags = 0x0;
@@ -370,7 +355,7 @@
if (shnum == llvm::ELF::SHN_UNDEF || shstrtab == llvm::ELF::SHN_XINDEX) {
shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff,
shentsize);
- shdr = reinterpret_cast<llvm::ELF::Elf32_Shdr*>(shdr_region->start());
+ shdr = reinterpret_cast<const llvm::ELF::Elf32_Shdr*>(shdr_region.begin());
if (llvm::sys::IsLittleEndianHost) {
sh_size = shdr->sh_size;
@@ -380,7 +365,6 @@
sh_size = mcld::bswap32(shdr->sh_size);
sh_link = mcld::bswap32(shdr->sh_link);
}
- pInput.memArea()->release(shdr_region);
if (shnum == llvm::ELF::SHN_UNDEF)
shnum = sh_size;
@@ -392,8 +376,8 @@
shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff,
shnum * shentsize);
- llvm::ELF::Elf32_Shdr * shdrTab =
- reinterpret_cast<llvm::ELF::Elf32_Shdr*>(shdr_region->start());
+ const llvm::ELF::Elf32_Shdr* shdrTab =
+ reinterpret_cast<const llvm::ELF::Elf32_Shdr*>(shdr_region.begin());
// get .shstrtab first
shdr = &shdrTab[shstrtab];
@@ -406,10 +390,9 @@
sh_size = mcld::bswap32(shdr->sh_size);
}
- MemoryRegion* sect_name_region = pInput.memArea()->request(
- pInput.fileOffset() + sh_offset, sh_size);
- const char* sect_name =
- reinterpret_cast<const char*>(sect_name_region->start());
+ llvm::StringRef sect_name_region = pInput.memArea()->request(
+ pInput.fileOffset() + sh_offset, sh_size);
+ const char* sect_name = sect_name_region.begin();
LinkInfoList link_info_list;
@@ -454,21 +437,12 @@
// 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() ||
- LDFileFormat::Note == info->section->kind()) {
- info->section->setLink(pInput.context()->getSection(info->sh_link));
- continue;
- }
- if (LDFileFormat::Relocation == info->section->kind()) {
+ if (LDFileFormat::Relocation == info->section->kind())
info->section->setLink(pInput.context()->getSection(info->sh_info));
- continue;
- }
+ else
+ info->section->setLink(pInput.context()->getSection(info->sh_link));
}
- pInput.memArea()->release(shdr_region);
- pInput.memArea()->release(sect_name_region);
-
return true;
}
@@ -484,10 +458,10 @@
uint32_t offset = pInput.fileOffset() + 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());
+ llvm::StringRef symbol_region =
+ pInput.memArea()->request(offset, sizeof(llvm::ELF::Elf32_Sym));
+ const llvm::ELF::Elf32_Sym* entry =
+ reinterpret_cast<const llvm::ELF::Elf32_Sym*>(symbol_region.begin());
uint32_t st_name = 0x0;
uint8_t st_info = 0x0;
@@ -504,12 +478,11 @@
st_shndx = mcld::bswap16(entry->st_shndx);
}
- MemoryRegion* strtab_region = pInput.memArea()->request(
- pInput.fileOffset() + strtab->offset(), strtab->size());
+ llvm::StringRef strtab_region = pInput.memArea()->request(
+ pInput.fileOffset() + strtab->offset(), strtab->size());
// get ld_name
- llvm::StringRef ld_name(
- reinterpret_cast<char*>(strtab_region->start() + st_name));
+ llvm::StringRef ld_name(strtab_region.begin() + st_name);
ResolveInfo* result = ResolveInfo::Create(ld_name);
result->setSource(pInput.type() == Input::DynObj);
@@ -518,10 +491,6 @@
result->setBinding(getSymBinding((st_info >> 4), st_shndx, st_other));
result->setVisibility(getSymVisibility(st_other));
- // release regions
- pInput.memArea()->release(symbol_region);
- pInput.memArea()->release(strtab_region);
-
return result;
}
@@ -538,17 +507,15 @@
fatal(diag::err_cannot_read_section) << ".dynstr";
}
- MemoryRegion* dynamic_region = pInput.memArea()->request(
- pInput.fileOffset() + dynamic_sect->offset(), dynamic_sect->size());
+ llvm::StringRef dynamic_region = pInput.memArea()->request(
+ pInput.fileOffset() + dynamic_sect->offset(), dynamic_sect->size());
- MemoryRegion* dynstr_region = pInput.memArea()->request(
- pInput.fileOffset() + dynstr_sect->offset(), dynstr_sect->size());
-
- assert(NULL != dynamic_region && NULL != dynstr_region);
+ llvm::StringRef dynstr_region = pInput.memArea()->request(
+ pInput.fileOffset() + dynstr_sect->offset(), dynstr_sect->size());
const llvm::ELF::Elf32_Dyn* dynamic =
- (llvm::ELF::Elf32_Dyn*) dynamic_region->start();
- const char* dynstr = (const char*) dynstr_region->start();
+ reinterpret_cast<const llvm::ELF::Elf32_Dyn*>(dynamic_region.begin());
+ const char* dynstr = dynstr_region.begin();
bool hasSOName = false;
size_t numOfEntries = dynamic_sect->size() / sizeof(llvm::ELF::Elf32_Dyn);
@@ -584,8 +551,6 @@
if (!hasSOName)
pInput.setName(pInput.path().filename().native());
- pInput.memArea()->release(dynamic_region);
- pInput.memArea()->release(dynstr_region);
return true;
}
@@ -603,10 +568,10 @@
}
/// isELF - is this a ELF file
-bool ELFReader<64, true>::isELF(void* pELFHeader) const
+bool ELFReader<64, true>::isELF(const void* pELFHeader) const
{
- llvm::ELF::Elf64_Ehdr* hdr =
- reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(pELFHeader);
+ const llvm::ELF::Elf64_Ehdr* hdr =
+ reinterpret_cast<const llvm::ELF::Elf64_Ehdr*>(pELFHeader);
if (0 == memcmp(llvm::ELF::ElfMagic, hdr, 4))
return true;
return false;
@@ -627,13 +592,13 @@
/// readSymbols - read ELF symbols and create LDSymbol
bool ELFReader<64, true>::readSymbols(Input& pInput,
IRBuilder& pBuilder,
- const MemoryRegion& pRegion,
+ llvm::StringRef pRegion,
const char* pStrTab) const
{
// get number of symbols
- size_t entsize = pRegion.size()/sizeof(llvm::ELF::Elf64_Sym);
+ size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf64_Sym);
const llvm::ELF::Elf64_Sym* symtab =
- reinterpret_cast<const llvm::ELF::Elf64_Sym*>(pRegion.start());
+ reinterpret_cast<const llvm::ELF::Elf64_Sym*>(pRegion.begin());
uint32_t st_name = 0x0;
uint64_t st_value = 0x0;
@@ -705,22 +670,22 @@
ld_name = std::string(pStrTab + st_name);
}
- LDSymbol *psym =
- pBuilder.AddSymbol(pInput,
- ld_name,
- ld_type,
- ld_desc,
- ld_binding,
- st_size,
- ld_value,
- section, ld_vis);
+ LDSymbol* psym = pBuilder.AddSymbol(pInput,
+ ld_name,
+ ld_type,
+ ld_desc,
+ ld_binding,
+ st_size,
+ ld_value,
+ section,
+ ld_vis);
- if ( is_dyn_obj
- && NULL!=psym
- && ResolveInfo::Undefined!=ld_desc
- && (ResolveInfo::Global==ld_binding ||
- ResolveInfo::Weak==ld_binding)
- && ResolveInfo::Object==ld_type ) {
+ if (is_dyn_obj
+ && NULL != psym
+ && ResolveInfo::Undefined != ld_desc
+ && (ResolveInfo::Global == ld_binding ||
+ ResolveInfo::Weak == ld_binding)
+ && ResolveInfo::Object == ld_type ) {
AliasInfo p;
p.pt_alias = psym;
p.ld_binding = ld_binding;
@@ -731,9 +696,9 @@
} // end of for loop
// analyze weak alias here
- if ( is_dyn_obj ) {
+ if (is_dyn_obj) {
// sort symbols by symbol value and then weak before strong
- std::sort( potential_aliases.begin(), potential_aliases.end(), less);
+ std::sort(potential_aliases.begin(), potential_aliases.end(), less);
// for each weak symbol, find out all its aliases, and
// then link them as a circular list in Module
@@ -746,16 +711,16 @@
Module& pModule = pBuilder.getModule();
std::vector<AliasInfo>::iterator alias_it = sym_it+1;
while(alias_it!=sym_e) {
- if ( sym_it->ld_value != alias_it->ld_value )
+ if (sym_it->ld_value != alias_it->ld_value)
break;
- if (sym_it+1==alias_it)
+ if (sym_it + 1 == alias_it)
pModule.CreateAliasList(*sym_it->pt_alias->resolveInfo());
pModule.addAlias(*alias_it->pt_alias->resolveInfo());
++alias_it;
}
- sym_it = alias_it-1;
+ sym_it = alias_it - 1;
}// end of for loop
}
return true;
@@ -767,30 +732,23 @@
/// ELFReader::readRela - read ELF rela and create Relocation
bool ELFReader<64, true>::readRela(Input& pInput,
LDSection& pSection,
- const MemoryRegion& pRegion) const
+ llvm::StringRef pRegion) const
{
// get the number of rela
size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf64_Rela);
const llvm::ELF::Elf64_Rela* relaTab =
- reinterpret_cast<const llvm::ELF::Elf64_Rela*>(pRegion.start());
+ reinterpret_cast<const llvm::ELF::Elf64_Rela*>(pRegion.begin());
for (size_t idx=0; idx < entsize; ++idx) {
+ Relocation::Type r_type = 0x0;
+ uint32_t r_sym = 0x0;
uint64_t r_offset = 0x0;
- uint64_t r_info = 0x0;
int64_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 = mcld::bswap64(relaTab[idx].r_offset);
- r_info = mcld::bswap64(relaTab[idx].r_info);
- r_addend = mcld::bswap64(relaTab[idx].r_addend);
+ if (!target().readRelocation(relaTab[idx],
+ r_type, r_sym, r_offset, r_addend)) {
+ return false;
}
- uint32_t r_type = static_cast<uint32_t>(r_info);
- uint32_t r_sym = (r_info >> 32);
LDSymbol* symbol = pInput.context()->getSymbol(r_sym);
if (NULL == symbol) {
fatal(diag::err_cannot_read_symbol) << r_sym << pInput.path();
@@ -804,27 +762,19 @@
/// readRel - read ELF rel and create Relocation
bool ELFReader<64, true>::readRel(Input& pInput,
LDSection& pSection,
- const MemoryRegion& pRegion) const
+ llvm::StringRef pRegion) const
{
// get the number of rel
size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf64_Rel);
const llvm::ELF::Elf64_Rel* relTab =
- reinterpret_cast<const llvm::ELF::Elf64_Rel*>(pRegion.start());
+ reinterpret_cast<const llvm::ELF::Elf64_Rel*>(pRegion.begin());
for (size_t idx=0; idx < entsize; ++idx) {
+ Relocation::Type r_type = 0x0;
+ uint32_t r_sym = 0x0;
uint64_t r_offset = 0x0;
- uint64_t r_info = 0x0;
- if (llvm::sys::IsLittleEndianHost) {
- r_offset = relTab[idx].r_offset;
- r_info = relTab[idx].r_info;
- }
- else {
- r_offset = mcld::bswap64(relTab[idx].r_offset);
- r_info = mcld::bswap64(relTab[idx].r_info);
- }
-
- uint32_t r_type = static_cast<uint32_t>(r_info);
- uint32_t r_sym = (r_info >> 32);
+ if (!target().readRelocation(relTab[idx], r_type, r_sym, r_offset))
+ return false;
LDSymbol* symbol = pInput.context()->getSymbol(r_sym);
if (NULL == symbol) {
@@ -837,19 +787,19 @@
}
/// isMyEndian - is this ELF file in the same endian to me?
-bool ELFReader<64, true>::isMyEndian(void* pELFHeader) const
+bool ELFReader<64, true>::isMyEndian(const void* pELFHeader) const
{
- llvm::ELF::Elf64_Ehdr* hdr =
- reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(pELFHeader);
+ const llvm::ELF::Elf64_Ehdr* hdr =
+ reinterpret_cast<const llvm::ELF::Elf64_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<64, true>::isMyMachine(void* pELFHeader) const
+bool ELFReader<64, true>::isMyMachine(const void* pELFHeader) const
{
- llvm::ELF::Elf64_Ehdr* hdr =
- reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(pELFHeader);
+ const llvm::ELF::Elf64_Ehdr* hdr =
+ reinterpret_cast<const llvm::ELF::Elf64_Ehdr*>(pELFHeader);
if (llvm::sys::IsLittleEndianHost)
return (hdr->e_machine == target().getInfo().machine());
@@ -857,10 +807,10 @@
}
/// fileType - return the file type
-Input::Type ELFReader<64, true>::fileType(void* pELFHeader) const
+Input::Type ELFReader<64, true>::fileType(const void* pELFHeader) const
{
- llvm::ELF::Elf64_Ehdr* hdr =
- reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(pELFHeader);
+ const llvm::ELF::Elf64_Ehdr* hdr =
+ reinterpret_cast<const llvm::ELF::Elf64_Ehdr*>(pELFHeader);
uint32_t type = 0x0;
if (llvm::sys::IsLittleEndianHost)
type = hdr->e_type;
@@ -883,11 +833,11 @@
}
/// readSectionHeaders - read ELF section header table and create LDSections
-bool
-ELFReader<64, true>::readSectionHeaders(Input& pInput, void* pELFHeader) const
+bool ELFReader<64, true>::readSectionHeaders(Input& pInput,
+ const void* pELFHeader) const
{
- llvm::ELF::Elf64_Ehdr* ehdr =
- reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(pELFHeader);
+ const llvm::ELF::Elf64_Ehdr* ehdr =
+ reinterpret_cast<const llvm::ELF::Elf64_Ehdr*>(pELFHeader);
uint64_t shoff = 0x0;
uint16_t shentsize = 0x0;
@@ -911,8 +861,8 @@
if (0x0 == shoff)
return true;
- llvm::ELF::Elf64_Shdr *shdr = NULL;
- MemoryRegion* shdr_region = NULL;
+ const llvm::ELF::Elf64_Shdr *shdr = NULL;
+ llvm::StringRef shdr_region;
uint32_t sh_name = 0x0;
uint32_t sh_type = 0x0;
uint64_t sh_flags = 0x0;
@@ -926,7 +876,7 @@
if (shnum == llvm::ELF::SHN_UNDEF || shstrtab == llvm::ELF::SHN_XINDEX) {
shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff,
shentsize);
- shdr = reinterpret_cast<llvm::ELF::Elf64_Shdr*>(shdr_region->start());
+ shdr = reinterpret_cast<const llvm::ELF::Elf64_Shdr*>(shdr_region.begin());
if (llvm::sys::IsLittleEndianHost) {
sh_size = shdr->sh_size;
@@ -936,7 +886,6 @@
sh_size = mcld::bswap64(shdr->sh_size);
sh_link = mcld::bswap32(shdr->sh_link);
}
- pInput.memArea()->release(shdr_region);
if (shnum == llvm::ELF::SHN_UNDEF)
shnum = sh_size;
@@ -948,8 +897,8 @@
shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff,
shnum * shentsize);
- llvm::ELF::Elf64_Shdr * shdrTab =
- reinterpret_cast<llvm::ELF::Elf64_Shdr*>(shdr_region->start());
+ const llvm::ELF::Elf64_Shdr* shdrTab =
+ reinterpret_cast<const llvm::ELF::Elf64_Shdr*>(shdr_region.begin());
// get .shstrtab first
shdr = &shdrTab[shstrtab];
@@ -962,10 +911,9 @@
sh_size = mcld::bswap64(shdr->sh_size);
}
- MemoryRegion* sect_name_region = pInput.memArea()->request(
- pInput.fileOffset() + sh_offset, sh_size);
- const char* sect_name =
- reinterpret_cast<const char*>(sect_name_region->start());
+ llvm::StringRef sect_name_region = pInput.memArea()->request(
+ pInput.fileOffset() + sh_offset, sh_size);
+ const char* sect_name = sect_name_region.begin();
LinkInfoList link_info_list;
@@ -1010,21 +958,12 @@
// 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() ||
- LDFileFormat::Note == info->section->kind()) {
- info->section->setLink(pInput.context()->getSection(info->sh_link));
- continue;
- }
- if (LDFileFormat::Relocation == info->section->kind()) {
+ if (LDFileFormat::Relocation == info->section->kind())
info->section->setLink(pInput.context()->getSection(info->sh_info));
- continue;
- }
+ else
+ info->section->setLink(pInput.context()->getSection(info->sh_link));
}
- pInput.memArea()->release(shdr_region);
- pInput.memArea()->release(sect_name_region);
-
return true;
}
@@ -1040,10 +979,10 @@
uint64_t offset = pInput.fileOffset() + symtab->offset() +
sizeof(llvm::ELF::Elf64_Sym) * pSymIdx;
- MemoryRegion* symbol_region =
- pInput.memArea()->request(offset, sizeof(llvm::ELF::Elf64_Sym));
- llvm::ELF::Elf64_Sym* entry =
- reinterpret_cast<llvm::ELF::Elf64_Sym*>(symbol_region->start());
+ llvm::StringRef symbol_region =
+ pInput.memArea()->request(offset, sizeof(llvm::ELF::Elf64_Sym));
+ const llvm::ELF::Elf64_Sym* entry =
+ reinterpret_cast<const llvm::ELF::Elf64_Sym*>(symbol_region.begin());
uint32_t st_name = 0x0;
uint8_t st_info = 0x0;
@@ -1060,12 +999,11 @@
st_shndx = mcld::bswap16(entry->st_shndx);
}
- MemoryRegion* strtab_region = pInput.memArea()->request(
- pInput.fileOffset() + strtab->offset(), strtab->size());
+ llvm::StringRef strtab_region = pInput.memArea()->request(
+ pInput.fileOffset() + strtab->offset(), strtab->size());
// get ld_name
- llvm::StringRef ld_name(
- reinterpret_cast<char*>(strtab_region->start() + st_name));
+ llvm::StringRef ld_name(strtab_region.begin() + st_name);
ResolveInfo* result = ResolveInfo::Create(ld_name);
result->setSource(pInput.type() == Input::DynObj);
@@ -1074,10 +1012,6 @@
result->setBinding(getSymBinding((st_info >> 4), st_shndx, st_other));
result->setVisibility(getSymVisibility(st_other));
- // release regions
- pInput.memArea()->release(symbol_region);
- pInput.memArea()->release(strtab_region);
-
return result;
}
@@ -1094,17 +1028,15 @@
fatal(diag::err_cannot_read_section) << ".dynstr";
}
- MemoryRegion* dynamic_region = pInput.memArea()->request(
- pInput.fileOffset() + dynamic_sect->offset(), dynamic_sect->size());
+ llvm::StringRef dynamic_region = pInput.memArea()->request(
+ pInput.fileOffset() + dynamic_sect->offset(), dynamic_sect->size());
- MemoryRegion* dynstr_region = pInput.memArea()->request(
- pInput.fileOffset() + dynstr_sect->offset(), dynstr_sect->size());
-
- assert(NULL != dynamic_region && NULL != dynstr_region);
+ llvm::StringRef dynstr_region = pInput.memArea()->request(
+ pInput.fileOffset() + dynstr_sect->offset(), dynstr_sect->size());
const llvm::ELF::Elf64_Dyn* dynamic =
- (llvm::ELF::Elf64_Dyn*) dynamic_region->start();
- const char* dynstr = (const char*) dynstr_region->start();
+ reinterpret_cast<const llvm::ELF::Elf64_Dyn*>(dynamic_region.begin());
+ const char* dynstr = dynstr_region.begin();
bool hasSOName = false;
size_t numOfEntries = dynamic_sect->size() / sizeof(llvm::ELF::Elf64_Dyn);
@@ -1140,8 +1072,5 @@
if (!hasSOName)
pInput.setName(pInput.path().filename().native());
- pInput.memArea()->release(dynamic_region);
- pInput.memArea()->release(dynstr_region);
return true;
}
-
diff --git a/lib/LD/ELFReaderIf.cpp b/lib/LD/ELFReaderIf.cpp
index 4d56b14..7d72596 100644
--- a/lib/LD/ELFReaderIf.cpp
+++ b/lib/LD/ELFReaderIf.cpp
@@ -13,10 +13,6 @@
#include <mcld/LD/EhFrame.h>
#include <mcld/LD/SectionData.h>
#include <mcld/Target/GNULDBackend.h>
-//#include <mcld/Support/MemoryArea.h>
-//#include <mcld/Support/MemoryRegion.h>
-//#include <mcld/Support/MsgHandling.h>
-//#include <mcld/Object/ObjectBuilder.h>
#include <cstring>
diff --git a/lib/LD/ELFSegment.cpp b/lib/LD/ELFSegment.cpp
index ae328ca..1c09514 100644
--- a/lib/LD/ELFSegment.cpp
+++ b/lib/LD/ELFSegment.cpp
@@ -7,61 +7,100 @@
//
//===----------------------------------------------------------------------===//
#include <mcld/LD/ELFSegment.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/Support/GCFactory.h>
+#include <mcld/Config/Config.h>
+#include <llvm/Support/ManagedStatic.h>
+#include <cassert>
using namespace mcld;
-//==========================
+typedef GCFactory<ELFSegment, MCLD_SEGMENTS_PER_OUTPUT> ELFSegmentFactory;
+static llvm::ManagedStatic<ELFSegmentFactory> g_ELFSegmentFactory;
+
+//===----------------------------------------------------------------------===//
// ELFSegment
-ELFSegment::ELFSegment(uint32_t pType,
- uint32_t pFlag,
- uint64_t pOffset,
- uint64_t pVaddr,
- uint64_t pPaddr,
- uint64_t pFilesz,
- uint64_t pMemsz,
- uint64_t pAlign,
- uint64_t pMaxSectAlign)
+//===----------------------------------------------------------------------===//
+ELFSegment::ELFSegment()
+ : m_Type(llvm::ELF::PT_NULL),
+ m_Flag(llvm::ELF::PF_R),
+ m_Offset(0x0),
+ m_Vaddr(0x0),
+ m_Paddr(0x0),
+ m_Filesz(0x0),
+ m_Memsz(0x0),
+ m_Align(0x0),
+ m_MaxSectionAlign(0x0)
+{
+}
+
+ELFSegment::ELFSegment(uint32_t pType, uint32_t pFlag)
: m_Type(pType),
m_Flag(pFlag),
- m_Offset(pOffset),
- m_Vaddr(pVaddr),
- m_Paddr(pPaddr),
- m_Filesz(pFilesz),
- m_Memsz(pMemsz),
- m_Align(pAlign),
- m_MaxSectionAlign(pMaxSectAlign) {
+ m_Offset(0x0),
+ m_Vaddr(0x0),
+ m_Paddr(0x0),
+ m_Filesz(0x0),
+ m_Memsz(0x0),
+ m_Align(0x0),
+ m_MaxSectionAlign(0x0)
+{
}
ELFSegment::~ELFSegment()
{
}
+bool ELFSegment::isLoadSegment() const
+{
+ return type() == llvm::ELF::PT_LOAD;
+}
+
bool ELFSegment::isDataSegment() const
{
- bool result = false;
- if ((type() == llvm::ELF::PT_LOAD) && (flag() & llvm::ELF::PF_W) != 0x0) {
- for (const_sect_iterator it = begin(), ie = end(); it != ie; ++it) {
- if ((*it)->kind() != LDFileFormat::BSS) {
- result = true;
- break;
- }
- }
- }
- return result;
+ return (type() == llvm::ELF::PT_LOAD) && ((flag() & llvm::ELF::PF_W) != 0x0);
}
bool ELFSegment::isBssSegment() const
{
- bool result = false;
- if ((type() == llvm::ELF::PT_LOAD) && (flag() & llvm::ELF::PF_W) != 0x0) {
- const_sect_iterator it = begin(), ie = end();
- for (; it != ie; ++it) {
- if ((*it)->kind() != LDFileFormat::BSS)
- break;
- }
- if (it == ie)
- result = true;
+ if (!isDataSegment())
+ return false;
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ if ((*it)->kind() != LDFileFormat::BSS)
+ return false;
}
- return result;
+ return true;
}
+ELFSegment::iterator ELFSegment::insert(ELFSegment::iterator pPos,
+ LDSection* pSection)
+{
+ return m_SectionList.insert(pPos, pSection);
+}
+
+void ELFSegment::append(LDSection* pSection)
+{
+ assert(NULL != pSection);
+ if (pSection->align() > m_MaxSectionAlign)
+ m_MaxSectionAlign = pSection->align();
+ m_SectionList.push_back(pSection);
+}
+
+ELFSegment* ELFSegment::Create(uint32_t pType, uint32_t pFlag)
+{
+ ELFSegment* seg = g_ELFSegmentFactory->allocate();
+ new (seg) ELFSegment(pType, pFlag);
+ return seg;
+}
+
+void ELFSegment::Destroy(ELFSegment*& pSegment)
+{
+ g_ELFSegmentFactory->destroy(pSegment);
+ g_ELFSegmentFactory->deallocate(pSegment);
+ pSegment = NULL;
+}
+
+void ELFSegment::Clear()
+{
+ g_ELFSegmentFactory->clear();
+}
diff --git a/lib/LD/ELFSegmentFactory.cpp b/lib/LD/ELFSegmentFactory.cpp
index af0f588..4d06629 100644
--- a/lib/LD/ELFSegmentFactory.cpp
+++ b/lib/LD/ELFSegmentFactory.cpp
@@ -7,58 +7,83 @@
//
//===----------------------------------------------------------------------===//
#include <mcld/LD/ELFSegmentFactory.h>
+#include <mcld/LD/ELFSegment.h>
using namespace mcld;
-//==========================
+//===----------------------------------------------------------------------===//
// ELFSegmentFactory
+//===----------------------------------------------------------------------===//
-ELFSegmentFactory::ELFSegmentFactory(size_t pNum)
- : GCFactory<ELFSegment, 0>(pNum)
-{
-}
-
-ELFSegmentFactory::~ELFSegmentFactory()
-{
-}
-
-/// produce - produce an empty ELF segment information.
-/// this function will create an ELF segment
-/// @param pType - p_type in ELF program header
-ELFSegment* ELFSegmentFactory::produce(uint32_t pType, uint32_t pFlag)
-{
- ELFSegment* segment = allocate();
- new (segment) ELFSegment(pType, pFlag);
- return segment;
-}
-
-ELFSegment*
+ELFSegmentFactory::iterator
ELFSegmentFactory::find(uint32_t pType, uint32_t pFlagSet, uint32_t pFlagClear)
{
iterator segment, segEnd = end();
for (segment = begin(); segment != segEnd; ++segment) {
- if ((*segment).type() == pType &&
- ((*segment).flag() & pFlagSet) == pFlagSet &&
- ((*segment).flag() & pFlagClear) == 0x0) {
- return &(*segment);
+ if ((*segment)->type() == pType &&
+ ((*segment)->flag() & pFlagSet) == pFlagSet &&
+ ((*segment)->flag() & pFlagClear) == 0x0) {
+ return segment;
}
}
- return NULL;
+ return segEnd;
}
-const ELFSegment*
+ELFSegmentFactory::const_iterator
ELFSegmentFactory::find(uint32_t pType,
uint32_t pFlagSet,
uint32_t pFlagClear) const
{
const_iterator segment, segEnd = end();
for (segment = begin(); segment != segEnd; ++segment) {
- if ((*segment).type() == pType &&
- ((*segment).flag() & pFlagSet) == pFlagSet &&
- ((*segment).flag() & pFlagClear) == 0x0) {
- return &(*segment);
+ if ((*segment)->type() == pType &&
+ ((*segment)->flag() & pFlagSet) == pFlagSet &&
+ ((*segment)->flag() & pFlagClear) == 0x0) {
+ return segment;
}
}
- return NULL;
+ return segEnd;
}
+ELFSegmentFactory::iterator
+ELFSegmentFactory::find(uint32_t pType, const LDSection* pSection)
+{
+ iterator segment, segEnd = end();
+ for (segment = begin(); segment != segEnd; ++segment) {
+ if ((*segment)->type() == pType) {
+ ELFSegment::iterator sect, sectEnd = (*segment)->end();
+ for (sect = (*segment)->begin(); sect != sectEnd; ++sect) {
+ if (*sect == pSection)
+ return segment;
+ } // for each section
+ }
+ } // for each segment
+ return segEnd;
+}
+
+ELFSegmentFactory::const_iterator
+ELFSegmentFactory::find(uint32_t pType, const LDSection* pSection) const
+{
+ const_iterator segment, segEnd = end();
+ for (segment = begin(); segment != segEnd; ++segment) {
+ if ((*segment)->type() == pType) {
+ ELFSegment::const_iterator sect, sectEnd = (*segment)->end();
+ for (sect = (*segment)->begin(); sect != sectEnd; ++sect) {
+ if (*sect == pSection)
+ return segment;
+ } // for each section
+ }
+ } // for each segment
+ return segEnd;
+}
+
+ELFSegment* ELFSegmentFactory::produce(uint32_t pType, uint32_t pFlag)
+{
+ m_Segments.push_back(ELFSegment::Create(pType, pFlag));
+ return back();
+}
+
+void ELFSegmentFactory::erase(iterator pSegment)
+{
+ m_Segments.erase(pSegment);
+}
diff --git a/lib/LD/EhFrame.cpp b/lib/LD/EhFrame.cpp
index 0bd6511..5ac3e72 100644
--- a/lib/LD/EhFrame.cpp
+++ b/lib/LD/EhFrame.cpp
@@ -6,11 +6,16 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include <mcld/Fragment/Relocation.h>
#include <mcld/LD/EhFrame.h>
+#include <mcld/LD/LDContext.h>
#include <mcld/LD/LDSection.h>
+#include <mcld/LD/LDSymbol.h>
+#include <mcld/LD/RelocData.h>
+#include <mcld/LD/ResolveInfo.h>
#include <mcld/LD/SectionData.h>
+#include <mcld/MC/Input.h>
#include <mcld/Object/ObjectBuilder.h>
-#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/GCFactory.h>
#include <llvm/Support/ManagedStatic.h>
@@ -22,21 +27,66 @@
static llvm::ManagedStatic<EhFrameFactory> g_EhFrameFactory;
//===----------------------------------------------------------------------===//
+// EhFrame::Record
+//===----------------------------------------------------------------------===//
+EhFrame::Record::Record(llvm::StringRef pRegion)
+ : RegionFragment(pRegion) {
+}
+
+EhFrame::Record::~Record()
+{
+ // llvm::iplist will manage and delete the fragments
+}
+
+//===----------------------------------------------------------------------===//
// EhFrame::CIE
//===----------------------------------------------------------------------===//
-EhFrame::CIE::CIE(MemoryRegion& pRegion)
- : RegionFragment(pRegion) {
+EhFrame::CIE::CIE(llvm::StringRef pRegion)
+ : EhFrame::Record(pRegion),
+ m_FDEEncode(0u), m_Mergeable(false), m_pReloc(0), m_PersonalityOffset(0) {
+}
+
+EhFrame::CIE::~CIE()
+{
}
//===----------------------------------------------------------------------===//
// EhFrame::FDE
//===----------------------------------------------------------------------===//
-EhFrame::FDE::FDE(MemoryRegion& pRegion,
- const EhFrame::CIE& pCIE,
- uint32_t pDataStart)
- : RegionFragment(pRegion),
- m_CIE(pCIE),
- m_DataStart(pDataStart) {
+EhFrame::FDE::FDE(llvm::StringRef pRegion, EhFrame::CIE& pCIE)
+ : EhFrame::Record(pRegion), m_pCIE(&pCIE) {
+}
+
+EhFrame::FDE::~FDE()
+{
+}
+
+void EhFrame::FDE::setCIE(EhFrame::CIE& pCIE)
+{
+ m_pCIE = &pCIE;
+ m_pCIE->add(*this);
+}
+
+//===----------------------------------------------------------------------===//
+// EhFrame::GeneratedCIE
+//===----------------------------------------------------------------------===//
+EhFrame::GeneratedCIE::GeneratedCIE(llvm::StringRef pRegion)
+ : EhFrame::CIE(pRegion) {
+}
+
+EhFrame::GeneratedCIE::~GeneratedCIE()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// EhFrame::GeneratedFDE
+//===----------------------------------------------------------------------===//
+EhFrame::GeneratedFDE::GeneratedFDE(llvm::StringRef pRegion, CIE &pCIE)
+ : EhFrame::FDE(pRegion, pCIE) {
+}
+
+EhFrame::GeneratedFDE::~GeneratedFDE()
+{
}
//===----------------------------------------------------------------------===//
@@ -54,8 +104,6 @@
EhFrame::~EhFrame()
{
- // Since all CIEs, FDEs and regular fragments are stored in iplist, iplist
- // will delete the fragments and we do not need to handle with it.
}
EhFrame* EhFrame::Create(LDSection& pSection)
@@ -89,52 +137,247 @@
return *m_pSection;
}
-void EhFrame::addFragment(RegionFragment& pFrag)
+void EhFrame::addFragment(Fragment& pFrag)
{
uint32_t offset = 0;
if (!m_pSectionData->empty())
offset = m_pSectionData->back().getOffset() + m_pSectionData->back().size();
m_pSectionData->getFragmentList().push_back(&pFrag);
+ pFrag.setParent(m_pSectionData);
pFrag.setOffset(offset);
}
-void EhFrame::addFragment(NullFragment& pFrag)
-{
- uint32_t offset = 0;
- if (!m_pSectionData->empty())
- offset = m_pSectionData->back().getOffset() + m_pSectionData->back().size();
-
- m_pSectionData->getFragmentList().push_back(&pFrag);
- pFrag.setOffset(offset);
-}
-
-void EhFrame::addCIE(EhFrame::CIE& pCIE)
+void EhFrame::addCIE(EhFrame::CIE& pCIE, bool pAlsoAddFragment)
{
m_CIEs.push_back(&pCIE);
- addFragment(pCIE);
+ if (pAlsoAddFragment)
+ addFragment(pCIE);
}
-void EhFrame::addFDE(EhFrame::FDE& pFDE)
+void EhFrame::addFDE(EhFrame::FDE& pFDE, bool pAlsoAddFragment)
{
- m_FDEs.push_back(&pFDE);
- addFragment(pFDE);
+ pFDE.getCIE().add(pFDE);
+ if (pAlsoAddFragment)
+ addFragment(pFDE);
}
-EhFrame& EhFrame::merge(EhFrame& pOther)
+size_t EhFrame::numOfFDEs() const
{
- ObjectBuilder::MoveSectionData(*pOther.getSectionData(), *m_pSectionData);
+ // FDE number only used by .eh_frame_hdr computation, and the number of CIE
+ // is usually not too many. It is worthy to compromise space by time
+ size_t size = 0u;
+ for (const_cie_iterator i = cie_begin(), e = cie_end(); i != e; ++i)
+ size += (*i)->numOfFDEs();
+ return size;
+}
- m_CIEs.reserve(pOther.numOfCIEs() + m_CIEs.size());
- for (cie_iterator cie = pOther.cie_begin(); cie != pOther.cie_end(); ++cie)
- m_CIEs.push_back(*cie);
+EhFrame& EhFrame::merge(const Input& pInput, EhFrame& pFrame)
+{
+ assert (this != &pFrame);
+ if (pFrame.emptyCIEs()) {
+ // May be a partial linking, or the eh_frame has no data.
+ // Just append the fragments.
+ moveInputFragments(pFrame);
+ return *this;
+ }
- m_FDEs.reserve(pOther.numOfFDEs() + m_FDEs.size());
- for (fde_iterator fde = pOther.fde_begin(); fde != pOther.fde_end(); ++fde)
- m_FDEs.push_back(*fde);
+ const LDContext& ctx = *pInput.context();
+ const LDSection* rel_sec = 0;
+ for (LDContext::const_sect_iterator ri = ctx.relocSectBegin(),
+ re = ctx.relocSectEnd(); ri != re; ++ri) {
+ if ((*ri)->getLink() == &pFrame.getSection()) {
+ rel_sec = *ri;
+ break;
+ }
+ }
+ pFrame.setupAttributes(rel_sec);
- pOther.m_CIEs.clear();
- pOther.m_FDEs.clear();
+ // Most CIE will be merged, so we don't reserve space first.
+ for (cie_iterator i = pFrame.cie_begin(), e = pFrame.cie_end(); i != e; ++i) {
+ CIE& input_cie = **i;
+ // CIE number is usually very few, so we just use vector sequential search.
+ if (!input_cie.getMergeable()) {
+ moveInputFragments(pFrame, input_cie);
+ addCIE(input_cie, /*AlsoAddFragment=*/false);
+ continue;
+ }
+
+ cie_iterator out_i = cie_begin();
+ for (cie_iterator out_e = cie_end(); out_i != out_e; ++out_i) {
+ CIE& output_cie = **out_i;
+ if (output_cie == input_cie) {
+ // This input CIE can be merged
+ moveInputFragments(pFrame, input_cie, &output_cie);
+ removeAndUpdateCIEForFDE(pFrame, input_cie, output_cie, rel_sec);
+ break;
+ }
+ }
+ if (out_i == cie_end()) {
+ moveInputFragments(pFrame, input_cie);
+ addCIE(input_cie, /*AlsoAddFragment=*/false);
+ }
+ }
return *this;
}
+void EhFrame::setupAttributes(const LDSection* rel_sec)
+{
+ for (cie_iterator i = cie_begin(), e = cie_end(); i != e; ++i) {
+ CIE* cie = *i;
+ removeDiscardedFDE(*cie, rel_sec);
+
+ if (cie->getPersonalityName().size() == 0) {
+ // There's no personality data encoding inside augmentation string.
+ cie->setMergeable();
+ } else {
+ if (!rel_sec) {
+ // No relocation to eh_frame section
+ assert (cie->getPersonalityName() != "" &&
+ "PR name should be a symbol address or offset");
+ continue;
+ }
+ const RelocData* reloc_data = rel_sec->getRelocData();
+ for (RelocData::const_iterator ri = reloc_data->begin(),
+ re = reloc_data->end(); ri != re; ++ri) {
+ const Relocation& rel = *ri;
+ if (rel.targetRef().getOutputOffset() == cie->getOffset() +
+ cie->getPersonalityOffset()) {
+ cie->setMergeable();
+ cie->setPersonalityName(rel.symInfo()->outSymbol()->name());
+ cie->setRelocation(rel);
+ break;
+ }
+ }
+
+ assert (cie->getPersonalityName() != "" &&
+ "PR name should be a symbol address or offset");
+ }
+ }
+}
+
+void EhFrame::removeDiscardedFDE(CIE& pCIE, const LDSection* pRelocSect)
+{
+ if (!pRelocSect)
+ return;
+
+ typedef std::vector<FDE*> FDERemoveList;
+ FDERemoveList to_be_removed_fdes;
+ const RelocData* reloc_data = pRelocSect->getRelocData();
+ for (fde_iterator i = pCIE.begin(), e = pCIE.end(); i != e; ++i) {
+ FDE& fde = **i;
+ for (RelocData::const_iterator ri = reloc_data->begin(),
+ re = reloc_data->end(); ri != re; ++ri) {
+ const Relocation& rel = *ri;
+ if (rel.targetRef().getOutputOffset() == fde.getOffset() +
+ getDataStartOffset<32>()) {
+ bool has_section = rel.symInfo()->outSymbol()->hasFragRef();
+ if (!has_section)
+ // The section was discarded, just ignore this FDE.
+ // This may happen when redundant group section was read.
+ to_be_removed_fdes.push_back(&fde);
+ break;
+ }
+ }
+ }
+
+ for (FDERemoveList::iterator i = to_be_removed_fdes.begin(),
+ e = to_be_removed_fdes.end(); i != e; ++i) {
+ FDE& fde = **i;
+ fde.getCIE().remove(fde);
+
+ // FIXME: This traverses relocations from the beginning on each FDE, which
+ // may cause performance degration. Actually relocations will be sequential
+ // order, so we can bookkeep the previously found relocation for next use.
+ // Note: We must ensure FDE order is ordered.
+ for (RelocData::const_iterator ri = reloc_data->begin(),
+ re = reloc_data->end(); ri != re; ) {
+ Relocation& rel = const_cast<Relocation&>(*ri++);
+ if (rel.targetRef().getOutputOffset() >= fde.getOffset() &&
+ rel.targetRef().getOutputOffset() < fde.getOffset() + fde.size()) {
+ const_cast<RelocData*>(reloc_data)->remove(rel);
+ }
+ }
+ }
+}
+
+void EhFrame::removeAndUpdateCIEForFDE(EhFrame& pInFrame, CIE& pInCIE,
+ CIE& pOutCIE, const LDSection* rel_sect)
+{
+ // Make this relocation to be ignored.
+ Relocation* rel = const_cast<Relocation*>(pInCIE.getRelocation());
+ if (rel && rel_sect)
+ const_cast<RelocData*>(rel_sect->getRelocData())->remove(*rel);
+
+ // Update the CIE-pointed FDEs
+ for (fde_iterator i = pInCIE.begin(), e = pInCIE.end(); i != e; ++i)
+ (*i)->setCIE(pOutCIE);
+
+ // We cannot know whether there are references to this fragment, so just
+ // keep it in input fragment list instead of memory deallocation
+ pInCIE.clearFDEs();
+}
+
+void EhFrame::moveInputFragments(EhFrame& pInFrame)
+{
+ SectionData& in_sd = *pInFrame.getSectionData();
+ SectionData::FragmentListType& in_frag_list = in_sd.getFragmentList();
+ SectionData& out_sd = *getSectionData();
+ SectionData::FragmentListType& out_frag_list = out_sd.getFragmentList();
+
+ while (!in_frag_list.empty()) {
+ Fragment* frag = in_frag_list.remove(in_frag_list.begin());
+ out_frag_list.push_back(frag);
+ frag->setParent(&out_sd);
+ }
+}
+
+void EhFrame::moveInputFragments(EhFrame& pInFrame,
+ CIE& pInCIE, CIE* pOutCIE)
+{
+ SectionData& in_sd = *pInFrame.getSectionData();
+ SectionData::FragmentListType& in_frag_list = in_sd.getFragmentList();
+ SectionData& out_sd = *getSectionData();
+ SectionData::FragmentListType& out_frag_list = out_sd.getFragmentList();
+
+ if (!pOutCIE) {
+ // Newly inserted
+ Fragment* frag = in_frag_list.remove(SectionData::iterator(pInCIE));
+ out_frag_list.push_back(frag);
+ frag->setParent(&out_sd);
+ for (fde_iterator i = pInCIE.begin(), e = pInCIE.end(); i != e; ++i) {
+ frag = in_frag_list.remove(SectionData::iterator(**i));
+ out_frag_list.push_back(frag);
+ frag->setParent(&out_sd);
+ }
+ return;
+ }
+
+ SectionData::iterator cur_iter(*pOutCIE);
+ assert (cur_iter != out_frag_list.end());
+ for (fde_iterator i = pInCIE.begin(), e = pInCIE.end(); i != e; ++i) {
+ Fragment* frag = in_frag_list.remove(SectionData::iterator(**i));
+ cur_iter = out_frag_list.insertAfter(cur_iter, frag);
+ frag->setParent(&out_sd);
+ }
+}
+
+size_t EhFrame::computeOffsetSize()
+{
+ size_t offset = 0u;
+ SectionData::FragmentListType& frag_list = getSectionData()->getFragmentList();
+ for (SectionData::iterator i = frag_list.begin(), e = frag_list.end();
+ i != e; ++i) {
+ Fragment& frag = *i;
+ frag.setOffset(offset);
+ offset += frag.size();
+ }
+ getSection().setSize(offset);
+ return offset;
+}
+
+bool mcld::operator==(const EhFrame::CIE& p1, const EhFrame::CIE& p2)
+{
+ return p1.getPersonalityName() == p2.getPersonalityName() &&
+ p1.getAugmentationData() == p2.getAugmentationData();
+}
diff --git a/lib/LD/EhFrameHdr.cpp b/lib/LD/EhFrameHdr.cpp
index 89b828f..74516d1 100644
--- a/lib/LD/EhFrameHdr.cpp
+++ b/lib/LD/EhFrameHdr.cpp
@@ -8,8 +8,6 @@
//===----------------------------------------------------------------------===//
#include <mcld/LD/EhFrameHdr.h>
-#include <mcld/Support/MemoryArea.h>
-#include <mcld/Support/MemoryRegion.h>
#include <mcld/LD/EhFrame.h>
#include <mcld/LD/LDSection.h>
@@ -39,16 +37,15 @@
//===----------------------------------------------------------------------===//
/// emitOutput<32> - write out eh_frame_hdr
template<>
-void EhFrameHdr::emitOutput<32>(MemoryArea& pOutput)
+void EhFrameHdr::emitOutput<32>(FileOutputBuffer& pOutput)
{
- MemoryRegion* ehframehdr_region =
- pOutput.request(m_EhFrameHdr.offset(), m_EhFrameHdr.size());
+ MemoryRegion ehframehdr_region = pOutput.request(m_EhFrameHdr.offset(),
+ m_EhFrameHdr.size());
- MemoryRegion* ehframe_region =
- pOutput.request(m_EhFrame.offset(),
- m_EhFrame.size());
+ MemoryRegion ehframe_region = pOutput.request(m_EhFrame.offset(),
+ m_EhFrame.size());
- uint8_t* data = (uint8_t*)ehframehdr_region->start();
+ uint8_t* data = ehframehdr_region.begin();
// version
data[0] = 1;
// eh_frame_ptr_enc
@@ -80,16 +77,21 @@
// prepare the binary search table
typedef std::vector<bit32::Entry> SearchTableType;
SearchTableType search_table;
- EhFrame::const_fde_iterator fde, fde_end = m_EhFrame.getEhFrame()->fde_end();
- for(fde = m_EhFrame.getEhFrame()->fde_begin(); fde != fde_end; ++fde) {
- assert(*fde != NULL);
- SizeTraits<32>::Offset offset;
- SizeTraits<32>::Address fde_pc;
- SizeTraits<32>::Address fde_addr;
- offset = (*fde)->getOffset();
- fde_pc = computePCBegin(**fde, *ehframe_region);
- fde_addr = m_EhFrame.addr() + offset;
- search_table.push_back(std::make_pair(fde_pc, fde_addr));
+
+ for (EhFrame::const_cie_iterator i = m_EhFrame.getEhFrame()->cie_begin(),
+ e = m_EhFrame.getEhFrame()->cie_end(); i != e; ++i) {
+ EhFrame::CIE& cie = **i;
+ for (EhFrame::const_fde_iterator fi = cie.begin(), fe = cie.end();
+ fi != fe; ++fi) {
+ EhFrame::FDE& fde = **fi;
+ SizeTraits<32>::Offset offset;
+ SizeTraits<32>::Address fde_pc;
+ SizeTraits<32>::Address fde_addr;
+ offset = fde.getOffset();
+ fde_pc = computePCBegin(fde, ehframe_region);
+ fde_addr = m_EhFrame.addr() + offset;
+ search_table.push_back(std::make_pair(fde_pc, fde_addr));
+ }
}
std::sort(search_table.begin(), search_table.end(), bit32::EntryCompare);
@@ -103,8 +105,6 @@
bst[id++] = (*entry).second - m_EhFrameHdr.addr();
}
}
- pOutput.release(ehframehdr_region);
- pOutput.release(ehframe_region);
}
//===----------------------------------------------------------------------===//
@@ -168,9 +168,9 @@
}
SizeTraits<32>::Address pc = 0x0;
- const uint8_t* offset = (const uint8_t*) pEhFrameRegion.start() +
+ const uint8_t* offset = (const uint8_t*) pEhFrameRegion.begin() +
pFDE.getOffset() +
- pFDE.getDataStart();
+ EhFrame::getDataStartOffset<32>();
std::memcpy(&pc, offset, pc_size);
// adjust the signed value
@@ -184,7 +184,8 @@
case DW_EH_PE_absptr:
break;
case DW_EH_PE_pcrel:
- pc += m_EhFrame.addr() + pFDE.getOffset() + pFDE.getDataStart();
+ pc += m_EhFrame.addr() + pFDE.getOffset() +
+ EhFrame::getDataStartOffset<32>();
break;
case DW_EH_PE_datarel:
// TODO
diff --git a/lib/LD/EhFrameReader.cpp b/lib/LD/EhFrameReader.cpp
index 69a7a05..49950a0 100644
--- a/lib/LD/EhFrameReader.cpp
+++ b/lib/LD/EhFrameReader.cpp
@@ -8,14 +8,15 @@
//===----------------------------------------------------------------------===//
#include <mcld/LD/EhFrameReader.h>
+#include <mcld/Fragment/NullFragment.h>
+#include <mcld/MC/Input.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/MemoryArea.h>
+
#include <llvm/ADT/StringRef.h>
#include <llvm/Support/Dwarf.h>
-
-#include <mcld/MC/MCLDInput.h>
-#include <mcld/LD/EhFrame.h>
-#include <mcld/LD/LDSection.h>
-#include <mcld/Support/MemoryArea.h>
-#include <mcld/Support/MsgHandling.h>
+#include <llvm/Support/LEB128.h>
using namespace mcld;
using namespace llvm::dwarf;
@@ -45,7 +46,7 @@
template<> EhFrameReader::Token
EhFrameReader::scan<true>(ConstAddress pHandler,
uint64_t pOffset,
- const MemoryRegion& pData) const
+ llvm::StringRef pData) const
{
Token result;
result.file_off = pOffset;
@@ -71,6 +72,8 @@
extended |= data[cur_idx++];
result.size = extended + 12;
result.data_off = 16;
+ // 64-bit obj file still uses 32-bit eh_frame.
+ assert (false && "We don't support 64-bit eh_frame.");
}
else {
result.size = length + 4;
@@ -129,17 +132,17 @@
// get file offset and address
uint64_t file_off = pInput.fileOffset() + section.offset();
- MemoryRegion* sect_reg =
- pInput.memArea()->request(file_off, section.size());
- ConstAddress handler = (ConstAddress)sect_reg->start();
+ llvm::StringRef sect_reg =
+ pInput.memArea()->request(file_off, section.size());
+ ConstAddress handler = (ConstAddress)sect_reg.begin();
State cur_state = Q0;
while (Reject != cur_state && Accept != cur_state) {
- Token token = scan<true>(handler, file_off, *sect_reg);
- MemoryRegion* entry = pInput.memArea()->request(token.file_off, token.size);
+ Token token = scan<true>(handler, file_off, sect_reg);
+ llvm::StringRef entry = pInput.memArea()->request(token.file_off, token.size);
- if (!transition[cur_state][token.kind](pEhFrame, *entry, token)) {
+ if (!transition[cur_state][token.kind](pEhFrame, entry, token)) {
// fail to scan
debug(diag::debug_cannot_scan_eh) << pInput.name();
return false;
@@ -148,9 +151,9 @@
file_off += token.size;
handler += token.size;
- if (handler == sect_reg->end())
+ if (handler == sect_reg.end())
cur_state = Accept;
- else if (handler > sect_reg->end()) {
+ else if (handler > sect_reg.end()) {
cur_state = Reject;
}
else
@@ -166,12 +169,14 @@
}
bool EhFrameReader::addCIE(EhFrame& pEhFrame,
- MemoryRegion& pRegion,
+ llvm::StringRef pRegion,
const EhFrameReader::Token& pToken)
{
// skip Length, Extended Length and CIE ID.
- ConstAddress handler = pRegion.start() + pToken.data_off;
+ ConstAddress handler = pRegion.begin() + pToken.data_off;
ConstAddress cie_end = pRegion.end();
+ ConstAddress handler_start = handler;
+ uint64_t pr_ptr_data_offset = pToken.data_off;
// the version should be 1 or 3
uint8_t version = *handler++;
@@ -211,6 +216,7 @@
EhFrame::CIE* cie = new EhFrame::CIE(pRegion);
cie->setFDEEncode(llvm::dwarf::DW_EH_PE_absptr);
pEhFrame.addCIE(*cie);
+ pEhFrame.getCIEMap().insert(std::make_pair(pToken.file_off, cie));
return true;
}
@@ -222,12 +228,13 @@
// parse the Augmentation String to get the FDE encodeing if 'z' existed
uint8_t fde_encoding = llvm::dwarf::DW_EH_PE_absptr;
+ std::string augdata;
+ std::string pr_ptr_data;
if ('z' == augment[0]) {
-
- // skip the Augumentation Data Length
- if (!skip_LEB128(&handler, cie_end)) {
- return false;
- }
+ unsigned offset;
+ size_t augdata_size = llvm::decodeULEB128((const uint8_t*)handler, &offset);
+ handler += offset;
+ augdata = std::string((const char*)handler, augdata_size);
// parse the Augmentation String
for (size_t i = 1; i < augment.size(); ++i) {
@@ -285,6 +292,8 @@
if (static_cast<uint32_t>(cie_end - handler) < per_length) {
return false;
}
+ pr_ptr_data_offset += handler - handler_start;
+ pr_ptr_data = std::string((const char*)handler, per_length);
handler += per_length;
break;
} // end of case 'P'
@@ -316,38 +325,46 @@
// create and push back the CIE entry
EhFrame::CIE* cie = new EhFrame::CIE(pRegion);
cie->setFDEEncode(fde_encoding);
+ cie->setPersonalityOffset(pr_ptr_data_offset);
+ cie->setPersonalityName(pr_ptr_data);
+ cie->setAugmentationData(augdata);
pEhFrame.addCIE(*cie);
+ pEhFrame.getCIEMap().insert(std::make_pair(pToken.file_off, cie));
return true;
}
bool EhFrameReader::addFDE(EhFrame& pEhFrame,
- MemoryRegion& pRegion,
+ llvm::StringRef pRegion,
const EhFrameReader::Token& pToken)
{
if (pToken.data_off == pRegion.size())
return false;
+ const int32_t offset = *(const int32_t*) (pRegion.begin() + pToken.data_off
+ - 4);
+ size_t cie_offset = (size_t) ((int64_t) (pToken.file_off + 4) -
+ (int32_t) offset);
+
+ EhFrame::CIEMap::iterator iter = pEhFrame.getCIEMap().find(cie_offset);
+ if (iter == pEhFrame.getCIEMap().end())
+ return false;
+
// create and push back the FDE entry
- EhFrame::FDE* fde = new EhFrame::FDE(pRegion,
- pEhFrame.cie_back(),
- pToken.data_off);
+ EhFrame::FDE* fde = new EhFrame::FDE(pRegion, *iter->second);
pEhFrame.addFDE(*fde);
return true;
}
bool EhFrameReader::addTerm(EhFrame& pEhFrame,
- MemoryRegion& pRegion,
+ llvm::StringRef pRegion,
const EhFrameReader::Token& pToken)
{
- RegionFragment* frag = new RegionFragment(pRegion);
- pEhFrame.addFragment(*frag);
return true;
}
bool EhFrameReader::reject(EhFrame& pEhFrame,
- MemoryRegion& pRegion,
+ llvm::StringRef pRegion,
const EhFrameReader::Token& pToken)
{
return true;
}
-
diff --git a/lib/LD/GNUArchiveReader.cpp b/lib/LD/GNUArchiveReader.cpp
index e391b20..3dc95a5 100644
--- a/lib/LD/GNUArchiveReader.cpp
+++ b/lib/LD/GNUArchiveReader.cpp
@@ -10,14 +10,14 @@
#include <mcld/Module.h>
#include <mcld/InputTree.h>
+#include <mcld/LinkerConfig.h>
#include <mcld/MC/Attribute.h>
-#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/Input.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/LD/ELFObjectReader.h>
#include <mcld/Support/FileSystem.h>
#include <mcld/Support/FileHandle.h>
#include <mcld/Support/MemoryArea.h>
-#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/Path.h>
#include <mcld/ADT/SizeTraits.h>
@@ -42,19 +42,22 @@
}
/// isMyFormat
-bool GNUArchiveReader::isMyFormat(Input& pInput) const
+bool GNUArchiveReader::isMyFormat(Input& pInput, bool &pContinue) const
{
assert(pInput.hasMemArea());
- MemoryRegion* region = pInput.memArea()->request(pInput.fileOffset(),
- Archive::MAGIC_LEN);
- const char* str = reinterpret_cast<const char*>(region->getBuffer());
+ if (pInput.memArea()->size() < Archive::MAGIC_LEN)
+ return false;
+
+ llvm::StringRef region =
+ pInput.memArea()->request(pInput.fileOffset(), Archive::MAGIC_LEN);
+ const char* str = region.begin();
bool result = false;
assert(NULL != str);
+ pContinue = true;
if (isArchive(str) || isThinArchive(str))
result = true;
- pInput.memArea()->release(region);
return result;
}
@@ -74,27 +77,27 @@
bool GNUArchiveReader::isThinArchive(Input& pInput) const
{
assert(pInput.hasMemArea());
- MemoryRegion* region = pInput.memArea()->request(pInput.fileOffset(),
- Archive::MAGIC_LEN);
- const char* str = reinterpret_cast<const char*>(region->getBuffer());
+ llvm::StringRef region =
+ pInput.memArea()->request(pInput.fileOffset(), Archive::MAGIC_LEN);
+ const char* str = region.begin();
bool result = false;
assert(NULL != str);
if (isThinArchive(str))
result = true;
- pInput.memArea()->release(region);
return result;
}
-bool GNUArchiveReader::readArchive(Archive& pArchive)
+bool GNUArchiveReader::readArchive(const LinkerConfig& pConfig,
+ Archive& pArchive)
{
// bypass the empty archive
- if (Archive::MAGIC_LEN == pArchive.getARFile().memArea()->handler()->size())
+ if (Archive::MAGIC_LEN == pArchive.getARFile().memArea()->size())
return true;
if (pArchive.getARFile().attribute()->isWholeArchive())
- return includeAllMembers(pArchive);
+ return includeAllMembers(pConfig, pArchive);
// if this is the first time read this archive, setup symtab and strtab
if (pArchive.getSymbolTable().empty()) {
@@ -133,7 +136,7 @@
if (Archive::Symbol::Include == status) {
// include the object member from the given offset
- includeMember(pArchive, pArchive.getObjFileOffset(idx));
+ includeMember(pConfig, pArchive, pArchive.getObjFileOffset(idx));
willSymResolved = true;
} // end of if
} // end of for
@@ -159,11 +162,11 @@
{
assert(pArchiveFile.hasMemArea());
- MemoryRegion* header_region =
+ llvm::StringRef header_region =
pArchiveFile.memArea()->request((pArchiveFile.fileOffset() + pFileOffset),
sizeof(Archive::MemberHeader));
const Archive::MemberHeader* header =
- reinterpret_cast<const Archive::MemberHeader*>(header_region->getBuffer());
+ reinterpret_cast<const Archive::MemberHeader*>(header_region.begin());
assert(0 == memcmp(header->fmag, Archive::MEMBER_MAGIC, sizeof(header->fmag)));
@@ -233,59 +236,71 @@
input_path);
}
- pArchiveFile.memArea()->release(header_region);
return member;
}
+template <size_t SIZE>
+static void readSymbolTableEntries(Archive& pArchive, llvm::StringRef pMemRegion)
+{
+ typedef typename SizeTraits<SIZE>::Offset Offset;
+
+ const Offset* data = reinterpret_cast<const Offset*>(pMemRegion.begin());
+
+ // read the number of symbols
+ Offset number = 0;
+ if (llvm::sys::IsLittleEndianHost)
+ number = mcld::bswap<SIZE>(*data);
+ else
+ number = *data;
+
+ // set up the pointers for file offset and name offset
+ ++data;
+ const char* name = reinterpret_cast<const char*>(data + number);
+
+ // add the archive symbols
+ for (Offset i = 0; i < number; ++i) {
+ if (llvm::sys::IsLittleEndianHost)
+ pArchive.addSymbol(name, mcld::bswap<SIZE>(*data));
+ else
+ pArchive.addSymbol(name, *data);
+ name += strlen(name) + 1;
+ ++data;
+ }
+}
+
/// readSymbolTable - read the archive symbol map (armap)
bool GNUArchiveReader::readSymbolTable(Archive& pArchive)
{
assert(pArchive.getARFile().hasMemArea());
- MemoryRegion* header_region =
+ llvm::StringRef header_region =
pArchive.getARFile().memArea()->request((pArchive.getARFile().fileOffset() +
Archive::MAGIC_LEN),
sizeof(Archive::MemberHeader));
const Archive::MemberHeader* header =
- reinterpret_cast<const Archive::MemberHeader*>(header_region->getBuffer());
+ reinterpret_cast<const Archive::MemberHeader*>(header_region.begin());
assert(0 == memcmp(header->fmag, Archive::MEMBER_MAGIC, sizeof(header->fmag)));
int symtab_size = atoi(header->size);
pArchive.setSymTabSize(symtab_size);
if (!pArchive.getARFile().attribute()->isWholeArchive()) {
- MemoryRegion* symtab_region =
- pArchive.getARFile().memArea()->request(
- (pArchive.getARFile().fileOffset() +
- Archive::MAGIC_LEN +
- sizeof(Archive::MemberHeader)),
- symtab_size);
- const uint32_t* data =
- reinterpret_cast<const uint32_t*>(symtab_region->getBuffer());
+ llvm::StringRef symtab_region = pArchive.getARFile().memArea()->request(
+ (pArchive.getARFile().fileOffset() +
+ Archive::MAGIC_LEN +
+ sizeof(Archive::MemberHeader)),
+ symtab_size);
- // read the number of symbols
- uint32_t number = 0;
- if (llvm::sys::IsLittleEndianHost)
- number = mcld::bswap32(*data);
+ if (0 == strncmp(header->name, Archive::SVR4_SYMTAB_NAME,
+ strlen(Archive::SVR4_SYMTAB_NAME)))
+ readSymbolTableEntries<32>(pArchive, symtab_region);
+ else if (0 == strncmp(header->name, Archive::IRIX6_SYMTAB_NAME,
+ strlen(Archive::IRIX6_SYMTAB_NAME)))
+ readSymbolTableEntries<64>(pArchive, symtab_region);
else
- number = *data;
+ unreachable(diag::err_unsupported_archive);
- // set up the pointers for file offset and name offset
- ++data;
- const char* name = reinterpret_cast<const char*>(data + number);
-
- // add the archive symbols
- for (uint32_t i = 0; i < number; ++i) {
- if (llvm::sys::IsLittleEndianHost)
- pArchive.addSymbol(name, mcld::bswap32(*data));
- else
- pArchive.addSymbol(name, *data);
- name += strlen(name) + 1;
- ++data;
- }
- pArchive.getARFile().memArea()->release(symtab_region);
}
- pArchive.getARFile().memArea()->release(header_region);
return true;
}
@@ -301,29 +316,26 @@
assert(pArchive.getARFile().hasMemArea());
- MemoryRegion* header_region =
+ llvm::StringRef header_region =
pArchive.getARFile().memArea()->request((pArchive.getARFile().fileOffset() +
offset),
sizeof(Archive::MemberHeader));
const Archive::MemberHeader* header =
- reinterpret_cast<const Archive::MemberHeader*>(header_region->getBuffer());
+ reinterpret_cast<const Archive::MemberHeader*>(header_region.begin());
assert(0 == memcmp(header->fmag, Archive::MEMBER_MAGIC, sizeof(header->fmag)));
if (0 == memcmp(header->name, Archive::STRTAB_NAME, sizeof(header->name))) {
// read the extended name table
int strtab_size = atoi(header->size);
- MemoryRegion* strtab_region =
+ llvm::StringRef strtab_region =
pArchive.getARFile().memArea()->request(
(pArchive.getARFile().fileOffset() +
offset + sizeof(Archive::MemberHeader)),
strtab_size);
- const char* strtab =
- reinterpret_cast<const char*>(strtab_region->getBuffer());
+ const char* strtab = strtab_region.begin();
pArchive.getStrTable().assign(strtab, strtab_size);
- pArchive.getARFile().memArea()->release(strtab_region);
}
- pArchive.getARFile().memArea()->release(header_region);
return true;
}
@@ -346,9 +358,12 @@
/// includeMember - include the object member in the given file offset, and
/// return the size of the object
+/// @param pConfig - LinkerConfig
/// @param pArchiveRoot - the archive root
/// @param pFileOffset - file offset of the member header in the archive
-size_t GNUArchiveReader::includeMember(Archive& pArchive, uint32_t pFileOffset)
+size_t GNUArchiveReader::includeMember(const LinkerConfig& pConfig,
+ Archive& pArchive,
+ uint32_t pFileOffset)
{
Input* cur_archive = &(pArchive.getARFile());
Input* member = NULL;
@@ -382,8 +397,9 @@
// direction to Afterward for next insertion in this subtree
parent->move->move(parent->lastPos);
parent->move = &InputTree::Afterward;
+ bool doContinue = false;
- if (m_ELFObjectReader.isMyFormat(*member)) {
+ if (m_ELFObjectReader.isMyFormat(*member, doContinue)) {
member->setType(Input::Object);
pArchive.addObjectMember(pFileOffset, parent->lastPos);
m_ELFObjectReader.readHeader(*member);
@@ -391,7 +407,7 @@
m_ELFObjectReader.readSymbols(*member);
m_Module.getObjectList().push_back(member);
}
- else if (isMyFormat(*member)) {
+ else if (doContinue && isMyFormat(*member, doContinue)) {
member->setType(Input::Archive);
// when adding a new archive node, set the iterator to archive
// itself, and set the direction to Downward
@@ -401,13 +417,18 @@
cur_archive = member;
file_offset = nested_offset;
}
+ else {
+ warning(diag::warn_unrecognized_input_file) << member->path()
+ << pConfig.targets().triple().str();
+ }
} while (Input::Object != member->type());
return size;
}
/// includeAllMembers - include all object members. This is called if
/// --whole-archive is the attribute for this archive file.
-bool GNUArchiveReader::includeAllMembers(Archive& pArchive)
+bool GNUArchiveReader::includeAllMembers(const LinkerConfig& pConfig,
+ Archive& pArchive)
{
// read the symtab of the archive
readSymbolTable(pArchive);
@@ -431,12 +452,12 @@
begin_offset += sizeof(Archive::MemberHeader) +
pArchive.getStrTable().size();
}
- uint32_t end_offset = pArchive.getARFile().memArea()->handler()->size();
+ uint32_t end_offset = pArchive.getARFile().memArea()->size();
for (uint32_t offset = begin_offset;
offset < end_offset;
offset += sizeof(Archive::MemberHeader)) {
- size_t size = includeMember(pArchive, offset);
+ size_t size = includeMember(pConfig, pArchive, offset);
if (!isThinAR) {
offset += size;
diff --git a/lib/LD/GarbageCollection.cpp b/lib/LD/GarbageCollection.cpp
new file mode 100644
index 0000000..4ea40ac
--- /dev/null
+++ b/lib/LD/GarbageCollection.cpp
@@ -0,0 +1,343 @@
+//===- GarbageCollection.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Fragment/Fragment.h>
+#include <mcld/Fragment/Relocation.h>
+#include <mcld/LD/GarbageCollection.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/LDSymbol.h>
+#include <mcld/LD/SectionData.h>
+#include <mcld/LD/RelocData.h>
+#include <mcld/LinkerConfig.h>
+#include <mcld/LinkerScript.h>
+#include <mcld/Module.h>
+#include <mcld/Target/TargetLDBackend.h>
+
+#include <llvm/Support/Casting.h>
+
+#include <queue>
+#if !defined(MCLD_ON_WIN32)
+#include <fnmatch.h>
+#define fnmatch0(pattern,string) (fnmatch(pattern,string,0) == 0)
+#else
+#include <windows.h>
+#include <shlwapi.h>
+#define fnmatch0(pattern,string) (PathMatchSpec(string, pattern) == true)
+#endif
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// Non-member functions
+//===----------------------------------------------------------------------===//
+// FIXME: these rules should be added into SectionMap, while currently adding to
+// SectionMap will cause the output order change in .text section and leads to
+// the .ARM.exidx order incorrect. We should sort the .ARM.exidx.
+static const char* pattern_to_keep[] =
+{
+ ".text*personality*",
+ ".data*personality*",
+ ".gnu.linkonce.d*personality*",
+ ".sdata*personality*"
+};
+
+/// shouldKeep - check the section name for the keep sections
+static bool shouldKeep(const std::string& pName)
+{
+ static const unsigned int pattern_size =
+ sizeof(pattern_to_keep) / sizeof(pattern_to_keep[0]);
+ for (unsigned int i=0; i < pattern_size; ++i) {
+ if (fnmatch0(pattern_to_keep[i], pName.c_str()))
+ return true;
+ }
+ return false;
+}
+
+/// shouldProcessGC - check if the section kind is handled in GC
+static bool mayProcessGC(const LDSection& pSection)
+{
+ if (pSection.kind() == LDFileFormat::Regular ||
+ pSection.kind() == LDFileFormat::BSS ||
+ pSection.kind() == LDFileFormat::GCCExceptTable)
+ return true;
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// GarbageCollection::SectionReachedListMap
+//===----------------------------------------------------------------------===//
+void
+GarbageCollection::SectionReachedListMap::addReference(const LDSection& pFrom,
+ const LDSection& pTo)
+{
+ m_ReachedSections[&pFrom].insert(&pTo);
+}
+
+GarbageCollection::SectionListTy&
+GarbageCollection::SectionReachedListMap::getReachedList(
+ const LDSection& pSection)
+{
+ return m_ReachedSections[&pSection];
+}
+
+GarbageCollection::SectionListTy*
+GarbageCollection::SectionReachedListMap::findReachedList(
+ const LDSection& pSection)
+{
+ ReachedSectionsTy::iterator it = m_ReachedSections.find(&pSection);
+ if (it == m_ReachedSections.end())
+ return NULL;
+ return &it->second;
+}
+
+//===----------------------------------------------------------------------===//
+// GarbageCollection
+//===----------------------------------------------------------------------===//
+GarbageCollection::GarbageCollection(const LinkerConfig& pConfig,
+ const TargetLDBackend& pBackend,
+ Module& pModule)
+ : m_Config(pConfig), m_Backend(pBackend), m_Module(pModule)
+{
+}
+
+GarbageCollection::~GarbageCollection()
+{
+}
+
+bool GarbageCollection::run()
+{
+ // 1. traverse all the relocations to set up the reached sections of each
+ // section
+ setUpReachedSections();
+ m_Backend.setUpReachedSectionsForGC(m_Module, m_SectionReachedListMap);
+
+ // 2. get all sections defined the entry point
+ SectionVecTy entry;
+ getEntrySections(entry);
+
+ // 3. find all the referenced sections those can be reached by entry
+ findReferencedSections(entry);
+
+ // 4. stripSections - set the unreached sections to Ignore
+ stripSections();
+ return true;
+}
+
+void GarbageCollection::setUpReachedSections()
+{
+ // traverse all the input relocations to setup the reached sections
+ Module::obj_iterator input, inEnd = m_Module.obj_end();
+ for (input = m_Module.obj_begin(); input != inEnd; ++input) {
+ LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
+ for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
+ // bypass the discarded relocation section
+ // 1. its section kind is changed to Ignore. (The target section is a
+ // discarded group section.)
+ // 2. it has no reloc data. (All symbols in the input relocs are in the
+ // discarded group sections)
+ LDSection* reloc_sect = *rs;
+ LDSection* apply_sect = reloc_sect->getLink();
+ if ((LDFileFormat::Ignore == reloc_sect->kind()) ||
+ (!reloc_sect->hasRelocData()))
+ continue;
+
+ // bypass the apply target sections which are not handled by gc
+ if (!mayProcessGC(*apply_sect))
+ continue;
+
+ bool add_first = false;
+ SectionListTy* reached_sects = NULL;
+ RelocData::iterator reloc_it, rEnd = reloc_sect->getRelocData()->end();
+ for (reloc_it = reloc_sect->getRelocData()->begin(); reloc_it != rEnd;
+ ++reloc_it) {
+ Relocation* reloc = llvm::cast<Relocation>(reloc_it);
+ ResolveInfo* sym = reloc->symInfo();
+ // only the target symbols defined in the input fragments can make the
+ // reference
+ if (NULL == sym)
+ continue;
+ if (!sym->isDefine() || !sym->outSymbol()->hasFragRef())
+ continue;
+
+ // only the target symbols defined in the concerned sections can make
+ // the reference
+ const LDSection* target_sect =
+ &sym->outSymbol()->fragRef()->frag()->getParent()->getSection();
+ if (!mayProcessGC(*target_sect))
+ continue;
+
+ // setup the reached list, if we first add the element to reached list
+ // of this section, create an entry in ReachedSections map
+ if (!add_first) {
+ reached_sects = &m_SectionReachedListMap.getReachedList(*apply_sect);
+ add_first = true;
+ }
+ reached_sects->insert(target_sect);
+ }
+ reached_sects = NULL;
+ add_first = false;
+ }
+ }
+}
+
+void GarbageCollection::getEntrySections(SectionVecTy& pEntry)
+{
+ // all the KEEP sections defined in ldscript are entries, traverse all the
+ // input sections and check the SectionMap to find the KEEP sections
+ Module::obj_iterator obj, objEnd = m_Module.obj_end();
+ SectionMap& sect_map = m_Module.getScript().sectionMap();
+ for (obj = m_Module.obj_begin(); obj != objEnd; ++obj) {
+ const std::string input_name = (*obj)->name();
+ LDContext::sect_iterator sect, sectEnd = (*obj)->context()->sectEnd();
+ for (sect = (*obj)->context()->sectBegin(); sect != sectEnd; ++sect) {
+ LDSection* section = *sect;
+ if (!mayProcessGC(*section))
+ continue;
+
+ SectionMap::Input* sm_input =
+ sect_map.find(input_name, section->name()).second;
+ if (((sm_input != NULL) && (InputSectDesc::Keep == sm_input->policy())) ||
+ shouldKeep(section->name()))
+ pEntry.push_back(section);
+ }
+ }
+
+ // get the sections those the entry symbols defined in
+ if (LinkerConfig::Exec == m_Config.codeGenType() ||
+ m_Config.options().isPIE()) {
+ // when building executable
+ // 1. the entry symbol is the entry
+ LDSymbol* entry_sym =
+ m_Module.getNamePool().findSymbol(m_Backend.getEntry(m_Module));
+ assert(NULL != entry_sym);
+ pEntry.push_back(&entry_sym->fragRef()->frag()->getParent()->getSection());
+
+ // 2. the symbols have been seen in dynamice objects are entries
+ NamePool::syminfo_iterator info_it,
+ info_end = m_Module.getNamePool().syminfo_end();
+ for (info_it = m_Module.getNamePool().syminfo_begin(); info_it != info_end;
+ ++info_it) {
+ ResolveInfo* info = info_it.getEntry();
+ if (!info->isDefine() || info->isLocal())
+ continue;
+
+ if (!info->isInDyn())
+ continue;
+
+ LDSymbol* sym = info->outSymbol();
+ if (NULL == sym || !sym->hasFragRef())
+ continue;
+
+ // only the target symbols defined in the concerned sections can be
+ // entries
+ const LDSection* sect =
+ &sym->fragRef()->frag()->getParent()->getSection();
+ if (!mayProcessGC(*sect))
+ continue;
+
+ pEntry.push_back(sect);
+ }
+ }
+
+ else {
+ // when building shared objects, the global define symbols are entries
+ NamePool::syminfo_iterator info_it,
+ info_end = m_Module.getNamePool().syminfo_end();
+ for (info_it = m_Module.getNamePool().syminfo_begin(); info_it != info_end;
+ ++info_it) {
+ ResolveInfo* info = info_it.getEntry();
+ if (!info->isDefine() ||
+ info->isLocal() ||
+ info->shouldForceLocal(m_Config))
+ continue;
+ LDSymbol* sym = info->outSymbol();
+ if (NULL == sym || !sym->hasFragRef())
+ continue;
+
+ // only the target symbols defined in the concerned sections can be
+ // entries
+ const LDSection* sect =
+ &sym->fragRef()->frag()->getParent()->getSection();
+ if (!mayProcessGC(*sect))
+ continue;
+ pEntry.push_back(sect);
+ }
+ }
+}
+
+void GarbageCollection::findReferencedSections(SectionVecTy& pEntry)
+{
+ // list of sections waiting to be processed
+ typedef std::queue<const LDSection*> WorkListTy;
+ WorkListTy work_list;
+ // start from each entry, resolve the transitive closure
+ SectionVecTy::iterator entry_it, entry_end = pEntry.end();
+ for (entry_it = pEntry.begin(); entry_it != entry_end; ++entry_it) {
+ // add entry point to work list
+ work_list.push(*entry_it);
+
+ // add section from the work_list to the referencedSections until every
+ // reached sections are added
+ while (!work_list.empty()) {
+ const LDSection* sect = work_list.front();
+ work_list.pop();
+ // add section to the ReferencedSections, if the section has been put into
+ // referencedSections, skip this section
+ if (!m_ReferencedSections.insert(sect).second)
+ continue;
+
+ // get the section reached list, if the section do not has one, which
+ // means no referenced between it and other sections, then skip it
+ SectionListTy* reach_list =
+ m_SectionReachedListMap.findReachedList(*sect);
+ if (NULL == reach_list)
+ continue;
+
+ // put the reached sections to work list, skip the one already be in
+ // referencedSections
+ SectionListTy::iterator it, end = reach_list->end();
+ for (it = reach_list->begin(); it != end; ++it) {
+ if (m_ReferencedSections.find(*it) == m_ReferencedSections.end())
+ work_list.push(*it);
+ }
+ }
+ }
+}
+
+void GarbageCollection::stripSections()
+{
+ // Traverse all the input Regular and BSS sections, if a section is not found
+ // in the ReferencedSections, then it should be garbage collected
+ Module::obj_iterator obj, objEnd = m_Module.obj_end();
+ for (obj = m_Module.obj_begin(); obj != objEnd; ++obj) {
+ LDContext::sect_iterator sect, sectEnd = (*obj)->context()->sectEnd();
+ for (sect = (*obj)->context()->sectBegin(); sect != sectEnd; ++sect) {
+ LDSection* section = *sect;
+ if (!mayProcessGC(*section))
+ continue;
+
+ if (m_ReferencedSections.find(section) == m_ReferencedSections.end())
+ section->setKind(LDFileFormat::Ignore);
+ }
+ }
+
+ // Traverse all the relocation sections, if its target section is set to
+ // Ignore, then set the relocation section to Ignore as well
+ Module::obj_iterator input, inEnd = m_Module.obj_end();
+ for (input = m_Module.obj_begin(); input != inEnd; ++input) {
+ LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
+ for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
+ LDSection* reloc_sect = *rs;
+ if (LDFileFormat::Ignore == reloc_sect->getLink()->kind())
+ reloc_sect->setKind(LDFileFormat::Ignore);
+ }
+ }
+}
+
diff --git a/lib/LD/GroupReader.cpp b/lib/LD/GroupReader.cpp
index a5b612b..b3e6f9e 100644
--- a/lib/LD/GroupReader.cpp
+++ b/lib/LD/GroupReader.cpp
@@ -36,6 +36,7 @@
}
bool GroupReader::readGroup(Module::input_iterator pRoot,
+ Module::input_iterator pEnd,
InputBuilder& pBuilder,
const LinkerConfig& pConfig)
{
@@ -50,12 +51,8 @@
Module::input_iterator input = --pRoot;
- // Since the end of a sub-tree is the same node to the end of whole tree, we
- // take the end of the whole input tree for conventience.
- Module::input_iterator input_end = m_Module.input_end();
-
// first time read the sub-tree
- while (input != input_end) {
+ while (input != pEnd) {
// already got type - for example, bitcode or external OIR (object
// intermediate representation)
if ((*input)->type() == Input::Script ||
@@ -75,25 +72,26 @@
continue;
}
+ bool doContinue = false;
// is an archive
- if (m_ArchiveReader.isMyFormat(**input)) {
+ if (m_ArchiveReader.isMyFormat(**input, doContinue)) {
(*input)->setType(Input::Archive);
// record the Archive used by each archive node
Archive* ar = new Archive(**input, pBuilder);
ArchiveListEntry* entry = new ArchiveListEntry(*ar, input);
ar_list.push_back(entry);
// read archive
- m_ArchiveReader.readArchive(*ar);
+ m_ArchiveReader.readArchive(pConfig, *ar);
cur_obj_cnt += ar->numOfObjectMember();
}
// read input as a binary file
- else if (pConfig.options().isBinaryInput()) {
+ else if (doContinue && m_BinaryReader.isMyFormat(**input, doContinue)) {
(*input)->setType(Input::Object);
m_BinaryReader.readBinary(**input);
m_Module.getObjectList().push_back(*input);
}
// is a relocatable object file
- else if (m_ObjectReader.isMyFormat(**input)) {
+ else if (doContinue && m_ObjectReader.isMyFormat(**input, doContinue)) {
(*input)->setType(Input::Object);
m_ObjectReader.readHeader(**input);
m_ObjectReader.readSections(**input);
@@ -103,15 +101,15 @@
++non_ar_obj_cnt;
}
// is a shared object file
- else if (m_DynObjReader.isMyFormat(**input)) {
+ else if (doContinue && m_DynObjReader.isMyFormat(**input, doContinue)) {
(*input)->setType(Input::DynObj);
m_DynObjReader.readHeader(**input);
m_DynObjReader.readSymbols(**input);
m_Module.getLibraryList().push_back(*input);
}
else {
- fatal(diag::err_unrecognized_input_file) << (*input)->path()
- << pConfig.targets().triple().str();
+ warning(diag::warn_unrecognized_input_file) << (*input)->path()
+ << pConfig.targets().triple().str();
}
++input;
}
@@ -128,7 +126,7 @@
// if --whole-archive is given to this archive, no need to read it again
if ( ar.getARFile().attribute()->isWholeArchive())
continue;
- m_ArchiveReader.readArchive(ar);
+ m_ArchiveReader.readArchive(pConfig, ar);
cur_obj_cnt += ar.numOfObjectMember();
}
}
diff --git a/lib/LD/LDFileFormat.cpp b/lib/LD/LDFileFormat.cpp
index bb878b8..d1f0b80 100644
--- a/lib/LD/LDFileFormat.cpp
+++ b/lib/LD/LDFileFormat.cpp
@@ -7,7 +7,6 @@
//
//===----------------------------------------------------------------------===//
#include <mcld/LD/LDFileFormat.h>
-#include <mcld/Fragment/FragmentLinker.h>
using namespace mcld;
diff --git a/lib/LD/NamePool.cpp b/lib/LD/NamePool.cpp
index 7fb8688..151b1dd 100644
--- a/lib/LD/NamePool.cpp
+++ b/lib/LD/NamePool.cpp
@@ -59,6 +59,7 @@
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBinding,
ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
ResolveInfo::Visibility pVisibility,
ResolveInfo* pOldInfo,
Resolver::Result& pResult)
@@ -102,7 +103,7 @@
// symbol resolution
bool override = false;
unsigned int action = Resolver::LastAction;
- if (m_pResolver->resolve(*old_symbol, *new_symbol, override)) {
+ if (m_pResolver->resolve(*old_symbol, *new_symbol, override, pValue)) {
pResult.info = old_symbol;
pResult.existent = true;
pResult.overriden = override;
diff --git a/lib/LD/RelocData.cpp b/lib/LD/RelocData.cpp
index 1c9411d..8379872 100644
--- a/lib/LD/RelocData.cpp
+++ b/lib/LD/RelocData.cpp
@@ -53,3 +53,9 @@
return *this;
}
+Relocation& RelocData::remove(Relocation& pRelocation)
+{
+ iterator iter(pRelocation);
+ Relocation* rel = m_Relocations.remove(iter);
+ return *rel;
+}
diff --git a/lib/LD/Relocator.cpp b/lib/LD/Relocator.cpp
index 767588a..dc9445b 100644
--- a/lib/LD/Relocator.cpp
+++ b/lib/LD/Relocator.cpp
@@ -6,16 +6,48 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include <mcld/Config/Config.h>
#include <mcld/Fragment/Fragment.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/LD/LDSection.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/Relocator.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/LD/SectionData.h>
+#include <mcld/Support/MsgHandling.h>
#include <mcld/Module.h>
+#if HAVE_CXXABI_H
+#include <cxxabi.h>
+#endif
+#include <sstream>
using namespace mcld;
//===----------------------------------------------------------------------===//
+// Helper functions
+//===----------------------------------------------------------------------===//
+std::string demangleSymbol(const std::string& mangled_name) {
+#if HAVE_CXXABI_H
+ // __cxa_demangle needs manually handle the memory release, so we wrap
+ // it into this helper function.
+ size_t output_leng;
+ int status;
+ char* buffer = abi::__cxa_demangle(mangled_name.c_str(), /*buffer=*/0,
+ &output_leng, &status);
+ if (status != 0) { // Failed
+ return mangled_name;
+ }
+ std::string demangled_name(buffer);
+ free(buffer);
+
+ return demangled_name;
+#else
+ return mangled_name;
+#endif
+}
+
+
+//===----------------------------------------------------------------------===//
// Relocator
//===----------------------------------------------------------------------===//
Relocator::~Relocator()
@@ -46,3 +78,52 @@
}
}
+void Relocator::issueUndefRef(Relocation& pReloc,
+ LDSection& pSection,
+ Input& pInput)
+{
+ FragmentRef::Offset undef_sym_pos = pReloc.targetRef().offset();
+ std::string sect_name(pSection.name());
+ sect_name = sect_name.substr(sect_name.find('.', /*pos=*/1)); // Drop .rel(a) prefix
+
+ std::string reloc_sym(pReloc.symInfo()->name());
+ if (reloc_sym.substr(0, 2) == "_Z")
+ reloc_sym = demangleSymbol(reloc_sym);
+
+ std::stringstream ss;
+ ss << "0x" << std::hex << undef_sym_pos;
+ std::string undef_sym_pos_hex(ss.str());
+
+ if (sect_name.substr(0, 5) != ".text") {
+ // Function name is only valid for text section
+ fatal(diag::undefined_reference) << reloc_sym
+ << pInput.path()
+ << sect_name
+ << undef_sym_pos_hex;
+ return;
+ }
+
+ std::string caller_file_name;
+ std::string caller_func_name;
+ for (LDContext::sym_iterator i = pInput.context()->symTabBegin(),
+ e = pInput.context()->symTabEnd(); i != e; ++i) {
+ LDSymbol& sym = **i;
+ if (sym.resolveInfo()->type() == ResolveInfo::File)
+ caller_file_name = sym.resolveInfo()->name();
+
+ if (sym.resolveInfo()->type() == ResolveInfo::Function &&
+ sym.value() <= undef_sym_pos &&
+ sym.value() + sym.size() > undef_sym_pos) {
+ caller_func_name = sym.name();
+ break;
+ }
+ }
+
+ if (caller_func_name.substr(0, 2) == "_Z")
+ caller_func_name = demangleSymbol(caller_func_name);
+
+ fatal(diag::undefined_reference_text) << reloc_sym
+ << pInput.path()
+ << caller_file_name
+ << caller_func_name;
+}
diff --git a/lib/LD/ResolveInfo.cpp b/lib/LD/ResolveInfo.cpp
index 4d1f72b..ca26d63 100644
--- a/lib/LD/ResolveInfo.cpp
+++ b/lib/LD/ResolveInfo.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include <mcld/LD/ResolveInfo.h>
#include <mcld/LD/LDSection.h>
+#include <mcld/LinkerConfig.h>
#include <mcld/Support/GCFactory.h>
#include <llvm/Support/ManagedStatic.h>
#include <cstdlib>
@@ -90,6 +91,11 @@
m_BitField &= (~dynamic_flag);
}
+void ResolveInfo::setInDyn()
+{
+ m_BitField |= indyn_flag;
+}
+
void ResolveInfo::setType(uint32_t pType)
{
m_BitField &= ~TYPE_MASK;
@@ -200,6 +206,11 @@
return (string_flag == (m_BitField & SYMBOL_MASK));
}
+bool ResolveInfo::isInDyn() const
+{
+ return (indyn_flag == (m_BitField & IN_DYN_MASK));
+}
+
uint32_t ResolveInfo::type() const
{
return (m_BitField & TYPE_MASK) >> TYPE_OFFSET;
@@ -239,22 +250,37 @@
return (0 == std::memcmp(m_Name, pKey.data(), length));
}
+bool ResolveInfo::shouldForceLocal(const LinkerConfig& pConfig)
+{
+ // forced local symbol matches all rules:
+ // 1. We are not doing incremental linking.
+ // 2. The symbol is with Hidden or Internal visibility.
+ // 3. The symbol should be global or weak. Otherwise, local symbol is local.
+ // 4. The symbol is defined or common
+ if (LinkerConfig::Object != pConfig.codeGenType() &&
+ (visibility() == ResolveInfo::Hidden ||
+ visibility() == ResolveInfo::Internal) &&
+ (isGlobal() || isWeak()) &&
+ (isDefine() || isCommon()))
+ return true;
+ return false;
+}
//===----------------------------------------------------------------------===//
// ResolveInfo Factory Methods
//===----------------------------------------------------------------------===//
ResolveInfo* ResolveInfo::Create(const ResolveInfo::key_type& pKey)
{
- ResolveInfo* result = static_cast<ResolveInfo*>(
+ ResolveInfo* info = static_cast<ResolveInfo*>(
malloc(sizeof(ResolveInfo)+pKey.size()+1));
- if (NULL == result)
+ if (NULL == info)
return NULL;
- new (result) ResolveInfo();
- std::memcpy(result->m_Name, pKey.data(), pKey.size());
- result->m_Name[pKey.size()] = '\0';
- result->m_BitField &= ~ResolveInfo::RESOLVE_MASK;
- result->m_BitField |= (pKey.size() << ResolveInfo::NAME_LENGTH_OFFSET);
- return result;
+ new (info) ResolveInfo(); // call constructor at the `result` address.
+ std::memcpy(info->m_Name, pKey.data(), pKey.size());
+ info->m_Name[pKey.size()] = '\0';
+ info->m_BitField &= ~ResolveInfo::RESOLVE_MASK;
+ info->m_BitField |= (pKey.size() << ResolveInfo::NAME_LENGTH_OFFSET);
+ return info;
}
void ResolveInfo::Destroy(ResolveInfo*& pInfo)
diff --git a/lib/LD/StaticResolver.cpp b/lib/LD/StaticResolver.cpp
index 6401262..21826ef 100644
--- a/lib/LD/StaticResolver.cpp
+++ b/lib/LD/StaticResolver.cpp
@@ -20,14 +20,14 @@
bool StaticResolver::resolve(ResolveInfo& __restrict__ pOld,
const ResolveInfo& __restrict__ pNew,
- bool &pOverride) const
+ bool &pOverride, LDSymbol::ValueType pValue) const
{
/* The state table itself.
* The first index is a link_row and the second index is a bfd_link_hash_type.
*
* Cs -> all rest kind of common (d_C, wd_C)
- * Is -> all kind of indeirect
+ * Is -> all kind of indirect
*/
static const enum LinkAction link_action[LAST_ORD][LAST_ORD] =
{
@@ -169,6 +169,20 @@
}
/* Fall through */
case MDEF: { /* multiple definition error. */
+ if (pOld.isDefine() && pNew.isDefine() &&
+ pOld.isAbsolute() && pNew.isAbsolute() &&
+ (pOld.desc() == pNew.desc() || pOld.desc() == ResolveInfo::NoType ||
+ pNew.desc() == ResolveInfo::NoType)) {
+ if (pOld.outSymbol()->value() == pValue) {
+ pOverride = true;
+ old->override(pNew);
+ break;
+ } else {
+ error(diag::multiple_absolute_definitions) << pNew.name()
+ << pOld.outSymbol()->value() << pValue;
+ break;
+ }
+ }
error(diag::multiple_definitions) << pNew.name();
break;
}
diff --git a/lib/LD/StubFactory.cpp b/lib/LD/StubFactory.cpp
index 0124ec0..3d7c56a 100644
--- a/lib/LD/StubFactory.cpp
+++ b/lib/LD/StubFactory.cpp
@@ -50,11 +50,10 @@
// find the island for the input relocation
BranchIsland* island = pBRIslandFactory.find(*(pReloc.targetRef().frag()));
if (NULL == island) {
- island = pBRIslandFactory.produce(*(pReloc.targetRef().frag()));
+ return NULL;
}
// find if there is such a stub in the island already
- assert(NULL != island);
Stub* stub = island->findStub(prototype, pReloc);
if (NULL != stub) {
// reset the branch target to the stub instead!
diff --git a/lib/MC/Android.mk b/lib/MC/Android.mk
index 0f8911b..cbd1962 100644
--- a/lib/MC/Android.mk
+++ b/lib/MC/Android.mk
@@ -9,8 +9,8 @@
InputAction.cpp \
InputBuilder.cpp \
InputFactory.cpp \
+ Input.cpp \
MCLDDirectory.cpp \
- MCLDInput.cpp \
SearchDirs.cpp \
SymbolCategory.cpp \
ZOption.cpp
diff --git a/lib/MC/CommandAction.cpp b/lib/MC/CommandAction.cpp
index 91b5904..bae5fbf 100644
--- a/lib/MC/CommandAction.cpp
+++ b/lib/MC/CommandAction.cpp
@@ -11,6 +11,8 @@
#include <mcld/MC/SearchDirs.h>
#include <mcld/MC/Attribute.h>
#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/FileSystem.h>
+#include <mcld/LinkerConfig.h>
using namespace mcld;
@@ -35,13 +37,13 @@
//===----------------------------------------------------------------------===//
NamespecAction::NamespecAction(unsigned int pPosition,
const std::string &pNamespec,
- SearchDirs& pSearchDirs)
+ const SearchDirs& pSearchDirs)
: InputAction(pPosition), m_Namespec(pNamespec), m_SearchDirs(pSearchDirs) {
}
bool NamespecAction::activate(InputBuilder& pBuilder) const
{
- sys::fs::Path* path = NULL;
+ const sys::fs::Path* path = NULL;
// find out the real path of the namespec.
if (pBuilder.getConstraint().isSharedSystem()) {
// In the system with shared object support, we can find both archive
@@ -218,3 +220,63 @@
return true;
}
+//===----------------------------------------------------------------------===//
+// DefSymAction
+//===----------------------------------------------------------------------===//
+DefSymAction::DefSymAction(unsigned int pPosition, std::string& pAssignment)
+ : InputAction(pPosition), m_Assignment(pAssignment) {
+}
+
+bool DefSymAction::activate(InputBuilder& pBuilder) const
+{
+ pBuilder.createNode<InputTree::Positional>("defsym", "NAN");
+ Input* input = *pBuilder.getCurrentNode();
+ pBuilder.setContext(*input, false);
+
+ m_Assignment.append(";");
+ pBuilder.setMemory(*input, &m_Assignment[0], m_Assignment.size());
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// ScriptAction
+//===----------------------------------------------------------------------===//
+ScriptAction::ScriptAction(unsigned int pPosition,
+ const std::string& pFileName,
+ ScriptFile::Kind pKind,
+ const SearchDirs& pSearchDirs)
+ : InputAction(pPosition),
+ m_FileName(pFileName),
+ m_Kind(pKind),
+ m_SearchDirs(pSearchDirs) {
+}
+
+bool ScriptAction::activate(InputBuilder& pBuilder) const
+{
+ sys::fs::Path path(m_FileName);
+
+ if (!exists(path)) {
+ const sys::fs::Path* res = m_SearchDirs.find(m_FileName, Input::Script);
+ if (res == NULL) {
+ switch (m_Kind) {
+ case ScriptFile::LDScript:
+ fatal(diag::err_cannot_find_scriptfile) << "linker script" << m_FileName;
+ break;
+ case ScriptFile::VersionScript:
+ fatal(diag::err_cannot_find_scriptfile) << "version script" << m_FileName;
+ break;
+ case ScriptFile::DynamicList:
+ fatal(diag::err_cannot_find_scriptfile) << "dynamic list" << m_FileName;
+ break;
+ default:
+ break;
+ }
+ return false;
+ }
+ path.assign(res->native());
+ }
+
+ pBuilder.createNode<InputTree::Positional>(path.stem().native(), path);
+
+ return true;
+}
diff --git a/lib/MC/FileAction.cpp b/lib/MC/FileAction.cpp
index 8660558..1c7e5ae 100644
--- a/lib/MC/FileAction.cpp
+++ b/lib/MC/FileAction.cpp
@@ -7,10 +7,8 @@
//
//===----------------------------------------------------------------------===//
#include <mcld/MC/FileAction.h>
-#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/Input.h>
#include <mcld/MC/InputBuilder.h>
-#include <mcld/MC/ContextFactory.h>
-#include <mcld/Support/MemoryAreaFactory.h>
using namespace mcld;
diff --git a/lib/MC/MCLDInput.cpp b/lib/MC/Input.cpp
similarity index 90%
rename from lib/MC/MCLDInput.cpp
rename to lib/MC/Input.cpp
index a10466b..2d948c2 100644
--- a/lib/MC/MCLDInput.cpp
+++ b/lib/MC/Input.cpp
@@ -1,4 +1,4 @@
-//===- MCLDInput.cpp ------------------------------------------------------===//
+//===- Input.cpp ----------------------------------------------------------===//
//
// The MCLinker Project
//
@@ -6,10 +6,9 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/Input.h>
#include <mcld/MC/Attribute.h>
#include <mcld/LD/LDContext.h>
-#include <mcld/Support/MemoryArea.h>
using namespace mcld;
@@ -71,7 +70,5 @@
{
// Attribute is deleted by AttributeFactory
// MemoryArea is deleted by MemoryAreaFactory
- if (NULL != m_pMemArea)
- m_pMemArea->clear();
}
diff --git a/lib/MC/InputBuilder.cpp b/lib/MC/InputBuilder.cpp
index 9142801..842c476 100644
--- a/lib/MC/InputBuilder.cpp
+++ b/lib/MC/InputBuilder.cpp
@@ -131,10 +131,6 @@
FileHandle::Permission pPerm)
{
MemoryArea *memory = m_pMemFactory->produce(pInput.path(), pMode, pPerm);
-
- if (!memory->handler()->isGood())
- return false;
-
pInput.setMemArea(memory);
return true;
}
diff --git a/lib/MC/SearchDirs.cpp b/lib/MC/SearchDirs.cpp
index 940553e..971f866 100644
--- a/lib/MC/SearchDirs.cpp
+++ b/lib/MC/SearchDirs.cpp
@@ -73,89 +73,136 @@
return insert(pPath.native());
}
-mcld::sys::fs::Path* SearchDirs::find(const std::string& pNamespec, mcld::Input::Type pType)
+mcld::sys::fs::Path*
+SearchDirs::find(const std::string& pNamespec, mcld::Input::Type pType)
{
- assert(Input::DynObj == pType || Input::Archive == pType);
+ assert(Input::DynObj == pType ||
+ Input::Archive == pType ||
+ Input::Script == pType);
std::string file;
- SpecToFilename(pNamespec, file);
+ switch(pType) {
+ case Input::Script:
+ file.assign(pNamespec);
+ break;
+ case Input::DynObj:
+ case Input::Archive :
+ SpecToFilename(pNamespec, file);
+ break;
+ default:
+ break;
+ } // end of switch
+
// for all MCLDDirectorys
DirList::iterator mcld_dir, mcld_dir_end = m_DirList.end();
- for (mcld_dir=m_DirList.begin(); mcld_dir!=mcld_dir_end; ++mcld_dir) {
+ for (mcld_dir = m_DirList.begin(); mcld_dir != mcld_dir_end; ++mcld_dir) {
// for all entries in MCLDDirectory
MCLDDirectory::iterator entry = (*mcld_dir)->begin();
MCLDDirectory::iterator enEnd = (*mcld_dir)->end();
switch(pType) {
- case Input::DynObj: {
- while (entry!=enEnd) {
- if (file == entry.path()->stem().native() ) {
- if(mcld::sys::fs::detail::shared_library_extension == entry.path()->extension().native()) {
- return entry.path();
- }
- }
- ++entry;
- }
+ case Input::Script: {
+ while (entry != enEnd) {
+ if (file == entry.path()->filename())
+ return entry.path();
+ ++entry;
}
- /** Fall through **/
- case Input::Archive : {
- entry = (*mcld_dir)->begin();
- enEnd = (*mcld_dir)->end();
- while ( entry!=enEnd ) {
- if (file == entry.path()->stem().native() &&
- mcld::sys::fs::detail::static_library_extension == entry.path()->extension().native()) {
+ break;
+ }
+ case Input::DynObj: {
+ while (entry != enEnd) {
+ if (file == entry.path()->stem().native() ) {
+ if (mcld::sys::fs::detail::shared_library_extension ==
+ entry.path()->extension().native()) {
return entry.path();
}
- ++entry;
}
+ ++entry;
}
- default:
- break;
+ }
+ /** Fall through **/
+ case Input::Archive : {
+ entry = (*mcld_dir)->begin();
+ enEnd = (*mcld_dir)->end();
+ while (entry != enEnd) {
+ if (file == entry.path()->stem().native() &&
+ mcld::sys::fs::detail::static_library_extension ==
+ entry.path()->extension().native()) {
+ return entry.path();
+ }
+ ++entry;
+ }
+ }
+ default:
+ break;
} // end of switch
- } // end of while
+ } // end of for
return NULL;
}
const mcld::sys::fs::Path*
SearchDirs::find(const std::string& pNamespec, mcld::Input::Type pType) const
{
- assert(Input::DynObj == pType || Input::Archive == pType);
+ assert(Input::DynObj == pType ||
+ Input::Archive == pType ||
+ Input::Script == pType);
std::string file;
- SpecToFilename(pNamespec, file);
+ switch(pType) {
+ case Input::Script:
+ file.assign(pNamespec);
+ break;
+ case Input::DynObj:
+ case Input::Archive :
+ SpecToFilename(pNamespec, file);
+ break;
+ default:
+ break;
+ } // end of switch
+
// for all MCLDDirectorys
DirList::const_iterator mcld_dir, mcld_dir_end = m_DirList.end();
- for (mcld_dir=m_DirList.begin(); mcld_dir!=mcld_dir_end; ++mcld_dir) {
+ for (mcld_dir = m_DirList.begin(); mcld_dir != mcld_dir_end; ++mcld_dir) {
// for all entries in MCLDDirectory
MCLDDirectory::iterator entry = (*mcld_dir)->begin();
MCLDDirectory::iterator enEnd = (*mcld_dir)->end();
switch(pType) {
- case Input::DynObj: {
- while (entry!=enEnd) {
- if (file == entry.path()->stem().native() ) {
- if(mcld::sys::fs::detail::shared_library_extension == entry.path()->extension().native()) {
- return entry.path();
- }
- }
- ++entry;
- }
+ case Input::Script: {
+ while (entry != enEnd) {
+ if (file == entry.path()->filename())
+ return entry.path();
+ ++entry;
}
- /** Fall through **/
- case Input::Archive : {
- entry = (*mcld_dir)->begin();
- enEnd = (*mcld_dir)->end();
- while ( entry!=enEnd ) {
- if (file == entry.path()->stem().native() &&
- mcld::sys::fs::detail::static_library_extension == entry.path()->extension().native()) {
+ break;
+ }
+ case Input::DynObj: {
+ while (entry != enEnd) {
+ if (file == entry.path()->stem().native() ) {
+ if (mcld::sys::fs::detail::shared_library_extension ==
+ entry.path()->extension().native()) {
return entry.path();
}
- ++entry;
}
+ ++entry;
}
- default:
- break;
+ }
+ /** Fall through **/
+ case Input::Archive : {
+ entry = (*mcld_dir)->begin();
+ enEnd = (*mcld_dir)->end();
+ while ( entry!=enEnd ) {
+ if (file == entry.path()->stem().native() &&
+ mcld::sys::fs::detail::static_library_extension ==
+ entry.path()->extension().native()) {
+ return entry.path();
+ }
+ ++entry;
+ }
+ }
+ default:
+ break;
} // end of switch
- } // end of while
+ } // end of for
return NULL;
}
diff --git a/lib/MC/ZOption.cpp b/lib/MC/ZOption.cpp
index a58562d..8b11765 100644
--- a/lib/MC/ZOption.cpp
+++ b/lib/MC/ZOption.cpp
@@ -10,16 +10,10 @@
using namespace mcld;
-//==========================
+//===----------------------------------------------------------------------===//
// ZOption
-
+//===----------------------------------------------------------------------===//
ZOption::ZOption()
- : m_Kind(Unknown),
- m_PageSize(0x0)
-{
-}
-
-ZOption::~ZOption()
-{
+ : m_Kind(Unknown), m_PageSize(0x0) {
}
diff --git a/lib/Object/ObjectBuilder.cpp b/lib/Object/ObjectBuilder.cpp
index f5c9fe5..6738c3c 100644
--- a/lib/Object/ObjectBuilder.cpp
+++ b/lib/Object/ObjectBuilder.cpp
@@ -10,6 +10,7 @@
#include <mcld/Module.h>
#include <mcld/LinkerConfig.h>
+#include <mcld/LinkerScript.h>
#include <mcld/IRBuilder.h>
#include <mcld/Object/SectionMap.h>
#include <mcld/LD/LDSection.h>
@@ -40,20 +41,35 @@
uint32_t pAlign)
{
// try to get one from output LDSection
- const SectionMap::NamePair& pair = m_Module.getScript().sectionMap().find(pName);
- std::string output_name = (pair.isNull())?pName:pair.to;
- LDSection* output_sect = LDSection::Create(output_name, pKind, pType, pFlag);
- output_sect->setAlign(pAlign);
- m_Module.getSectionTable().push_back(output_sect);
+ SectionMap::const_mapping pair =
+ m_Module.getScript().sectionMap().find("*", pName);
+
+ std::string output_name = (pair.first == NULL) ? pName : pair.first->name();
+
+ LDSection* output_sect = m_Module.getSection(output_name);
+ if (NULL == output_sect) {
+ output_sect = LDSection::Create(pName, pKind, pType, pFlag);
+ output_sect->setAlign(pAlign);
+ m_Module.getSectionTable().push_back(output_sect);
+ }
return output_sect;
}
/// MergeSection - merge the pInput section to the pOutput section
-LDSection* ObjectBuilder::MergeSection(LDSection& pInputSection)
+LDSection* ObjectBuilder::MergeSection(const Input& pInputFile,
+ LDSection& pInputSection)
{
- const SectionMap::NamePair& pair =
- m_Module.getScript().sectionMap().find(pInputSection.name());
- std::string output_name = (pair.isNull())?pInputSection.name():pair.to;
+ SectionMap::mapping pair =
+ m_Module.getScript().sectionMap().find(pInputFile.path().native(),
+ pInputSection.name());
+
+ if (pair.first != NULL && pair.first->isDiscard()) {
+ pInputSection.setKind(LDFileFormat::Ignore);
+ return NULL;
+ }
+
+ std::string output_name = (pair.first == NULL) ?
+ pInputSection.name() : pair.first->name();
LDSection* target = m_Module.getSection(output_name);
if (NULL == target) {
@@ -66,11 +82,6 @@
}
switch (target->kind()) {
- // Some *OUTPUT sections should not be merged.
- case LDFileFormat::Relocation:
- case LDFileFormat::NamePool:
- /** do nothing **/
- return target;
case LDFileFormat::EhFrame: {
EhFrame* eh_frame = NULL;
if (target->hasEhFrame())
@@ -78,16 +89,22 @@
else
eh_frame = IRBuilder::CreateEhFrame(*target);
- eh_frame->merge(*pInputSection.getEhFrame());
- UpdateSectionAlign(*target, pInputSection);
+ eh_frame->merge(pInputFile, *pInputSection.getEhFrame());
+ UpdateSectionAlign(*target, pInputSection);
return target;
}
default: {
+ if (!target->hasSectionData())
+ IRBuilder::CreateSectionData(*target);
+
SectionData* data = NULL;
- if (target->hasSectionData())
+ if (pair.first != NULL) {
+ assert(pair.second != NULL);
+ data = pair.second->getSection()->getSectionData();
+ } else {
+ // orphan section
data = target->getSectionData();
- else
- data = IRBuilder::CreateSectionData(*target);
+ }
if (MoveSectionData(*pInputSection.getSectionData(), *data)) {
UpdateSectionAlign(*target, pInputSection);
@@ -104,7 +121,7 @@
{
assert(&pFrom != &pTo && "Cannot move section data to itself!");
- uint32_t offset = pTo.getSection().size();
+ uint64_t offset = pTo.getSection().size();
AlignFragment* align = NULL;
if (pFrom.getSection().align() > 1) {
// if the align constraint is larger than 1, append an alignment
@@ -149,7 +166,7 @@
uint32_t pAlignConstraint)
{
// get initial offset.
- uint32_t offset = 0;
+ uint64_t offset = 0;
if (!pSD.empty())
offset = pSD.back().getOffset() + pSD.back().size();
diff --git a/lib/Object/ObjectLinker.cpp b/lib/Object/ObjectLinker.cpp
index 1b16f95..f5eec4c 100644
--- a/lib/Object/ObjectLinker.cpp
+++ b/lib/Object/ObjectLinker.cpp
@@ -9,6 +9,7 @@
#include <mcld/Object/ObjectLinker.h>
#include <mcld/LinkerConfig.h>
+#include <mcld/LinkerScript.h>
#include <mcld/Module.h>
#include <mcld/InputTree.h>
#include <mcld/IRBuilder.h>
@@ -20,27 +21,37 @@
#include <mcld/LD/DynObjReader.h>
#include <mcld/LD/GroupReader.h>
#include <mcld/LD/BinaryReader.h>
+#include <mcld/LD/GarbageCollection.h>
#include <mcld/LD/ObjectWriter.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/LD/RelocData.h>
#include <mcld/LD/Relocator.h>
+#include <mcld/LD/SectionData.h>
+#include <mcld/LD/BranchIslandFactory.h>
+#include <mcld/Script/ScriptFile.h>
+#include <mcld/Script/ScriptReader.h>
+#include <mcld/Script/Assignment.h>
+#include <mcld/Script/Operand.h>
+#include <mcld/Script/RpnEvaluator.h>
#include <mcld/Support/RealPath.h>
-#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/FileOutputBuffer.h>
#include <mcld/Support/MsgHandling.h>
-#include <mcld/Support/DefSymParser.h>
#include <mcld/Target/TargetLDBackend.h>
-#include <mcld/Fragment/FragmentLinker.h>
+#include <mcld/Fragment/Relocation.h>
#include <mcld/Object/ObjectBuilder.h>
#include <llvm/Support/Casting.h>
-
+#include <llvm/Support/Host.h>
using namespace llvm;
using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// ObjectLinker
+//===----------------------------------------------------------------------===//
ObjectLinker::ObjectLinker(const LinkerConfig& pConfig,
TargetLDBackend& pLDBackend)
: m_Config(pConfig),
- m_pLinker(NULL),
m_pModule(NULL),
m_pBuilder(NULL),
m_LDBackend(pLDBackend),
@@ -49,54 +60,39 @@
m_pArchiveReader(NULL),
m_pGroupReader(NULL),
m_pBinaryReader(NULL),
+ m_pScriptReader(NULL),
m_pWriter(NULL) {
}
ObjectLinker::~ObjectLinker()
{
- delete m_pLinker;
delete m_pObjectReader;
delete m_pDynObjReader;
delete m_pArchiveReader;
delete m_pGroupReader;
delete m_pBinaryReader;
+ delete m_pScriptReader;
delete m_pWriter;
}
-void ObjectLinker::setup(Module& pModule, IRBuilder& pBuilder)
+bool ObjectLinker::initialize(Module& pModule, IRBuilder& pBuilder)
{
m_pModule = &pModule;
m_pBuilder = &pBuilder;
- // set up soname
- if (!m_Config.options().soname().empty()) {
- m_pModule->setName(m_Config.options().soname());
- }
-}
-
-/// initFragmentLinker - initialize FragmentLinker
-/// Connect all components with FragmentLinker
-bool ObjectLinker::initFragmentLinker()
-{
- if (NULL == m_pLinker) {
- m_pLinker = new FragmentLinker(m_Config,
- *m_pModule,
- m_LDBackend);
- }
-
// initialize the readers and writers
- // Because constructor can not be failed, we initalize all readers and
- // writers outside the FragmentLinker constructors.
m_pObjectReader = m_LDBackend.createObjectReader(*m_pBuilder);
m_pArchiveReader = m_LDBackend.createArchiveReader(*m_pModule);
m_pDynObjReader = m_LDBackend.createDynObjReader(*m_pBuilder);
m_pBinaryReader = m_LDBackend.createBinaryReader(*m_pBuilder);
m_pGroupReader = new GroupReader(*m_pModule, *m_pObjectReader,
*m_pDynObjReader, *m_pArchiveReader, *m_pBinaryReader);
+ m_pScriptReader = new ScriptReader(*m_pGroupReader);
m_pWriter = m_LDBackend.createWriter();
// initialize Relocator
m_LDBackend.initRelocator();
+
return true;
}
@@ -122,7 +118,8 @@
for (input = m_pModule->input_begin(); input!=inEnd; ++input) {
// is a group node
if (isGroup(input)) {
- getGroupReader()->readGroup(input, m_pBuilder->getInputBuilder(), m_Config);
+ getGroupReader()->readGroup(input, inEnd, m_pBuilder->getInputBuilder(),
+ m_Config);
continue;
}
@@ -143,14 +140,15 @@
continue;
}
+ bool doContinue = false;
// read input as a binary file
- if (m_Config.options().isBinaryInput()) {
+ if (getBinaryReader()->isMyFormat(**input, doContinue)) {
(*input)->setType(Input::Object);
getBinaryReader()->readBinary(**input);
m_pModule->getObjectList().push_back(*input);
}
// is a relocatable object file
- else if (getObjectReader()->isMyFormat(**input)) {
+ else if (doContinue && getObjectReader()->isMyFormat(**input, doContinue)) {
(*input)->setType(Input::Object);
getObjectReader()->readHeader(**input);
getObjectReader()->readSections(**input);
@@ -158,25 +156,39 @@
m_pModule->getObjectList().push_back(*input);
}
// is a shared object file
- else if (getDynObjReader()->isMyFormat(**input)) {
+ else if (doContinue && getDynObjReader()->isMyFormat(**input, doContinue)) {
(*input)->setType(Input::DynObj);
getDynObjReader()->readHeader(**input);
getDynObjReader()->readSymbols(**input);
m_pModule->getLibraryList().push_back(*input);
}
// is an archive
- else if (getArchiveReader()->isMyFormat(**input)) {
+ else if (doContinue && getArchiveReader()->isMyFormat(**input, doContinue)) {
(*input)->setType(Input::Archive);
Archive archive(**input, m_pBuilder->getInputBuilder());
- getArchiveReader()->readArchive(archive);
+ getArchiveReader()->readArchive(m_Config, archive);
if(archive.numOfObjectMember() > 0) {
m_pModule->getInputTree().merge<InputTree::Inclusive>(input,
- archive.inputs());
+ archive.inputs());
+ }
+ }
+ // try to parse input as a linker script
+ else if (doContinue && getScriptReader()->isMyFormat(**input, doContinue)) {
+ ScriptFile script(ScriptFile::LDScript, **input,
+ m_pBuilder->getInputBuilder());
+ if (getScriptReader()->readScript(m_Config, script)) {
+ (*input)->setType(Input::Script);
+ script.activate(*m_pModule);
+ if (script.inputs().size() > 0) {
+ m_pModule->getInputTree().merge<InputTree::Inclusive>(input,
+ script.inputs());
+ }
}
}
else {
- fatal(diag::err_unrecognized_input_file) << (*input)->path()
- << m_Config.targets().triple().str();
+ if (m_Config.options().warnMismatch())
+ warning(diag::warn_unrecognized_input_file) << (*input)->path()
+ << m_Config.targets().triple().str();
}
} // end of for
}
@@ -217,6 +229,16 @@
return true;
}
+void ObjectLinker::dataStrippingOpt()
+{
+ // Garbege collection
+ if (m_Config.options().GCSections()) {
+ GarbageCollection GC(m_Config, m_LDBackend, *m_pModule);
+ GC.run();
+ }
+ return;
+}
+
/// readRelocations - read all relocation entries
///
/// All symbols should be read and resolved before this function.
@@ -247,14 +269,21 @@
// Some *INPUT sections should not be merged.
case LDFileFormat::Ignore:
case LDFileFormat::Null:
- case LDFileFormat::Relocation:
case LDFileFormat::NamePool:
case LDFileFormat::Group:
case LDFileFormat::StackNote:
// skip
continue;
+ case LDFileFormat::Relocation: {
+ if (!(*sect)->hasRelocData())
+ continue; // skip
+
+ if ((*sect)->getLink()->kind() == LDFileFormat::Ignore)
+ (*sect)->setKind(LDFileFormat::Ignore);
+ break;
+ }
case LDFileFormat::Target:
- if (!m_LDBackend.mergeSection(*m_pModule, **sect)) {
+ if (!m_LDBackend.mergeSection(*m_pModule, **obj, **sect)) {
error(diag::err_cannot_merge_section) << (*sect)->name()
<< (*obj)->name();
return false;
@@ -265,16 +294,12 @@
continue; // skip
LDSection* out_sect = NULL;
- if (NULL == (out_sect = builder.MergeSection(**sect))) {
- error(diag::err_cannot_merge_section) << (*sect)->name()
- << (*obj)->name();
- return false;
- }
-
- if (!m_LDBackend.updateSectionFlags(*out_sect, **sect)) {
- error(diag::err_cannot_merge_section) << (*sect)->name()
- << (*obj)->name();
- return false;
+ if (NULL != (out_sect = builder.MergeSection(**obj, **sect))) {
+ if (!m_LDBackend.updateSectionFlags(*out_sect, **sect)) {
+ error(diag::err_cannot_merge_section) << (*sect)->name()
+ << (*obj)->name();
+ return false;
+ }
}
break;
}
@@ -283,25 +308,105 @@
continue; // skip
LDSection* out_sect = NULL;
- if (NULL == (out_sect = builder.MergeSection(**sect))) {
- error(diag::err_cannot_merge_section) << (*sect)->name()
- << (*obj)->name();
- return false;
- }
-
- if (!m_LDBackend.updateSectionFlags(*out_sect, **sect)) {
- error(diag::err_cannot_merge_section) << (*sect)->name()
- << (*obj)->name();
- return false;
+ if (NULL != (out_sect = builder.MergeSection(**obj, **sect))) {
+ if (!m_LDBackend.updateSectionFlags(*out_sect, **sect)) {
+ error(diag::err_cannot_merge_section) << (*sect)->name()
+ << (*obj)->name();
+ return false;
+ }
}
break;
}
} // end of switch
} // for each section
} // for each obj
+
+ RpnEvaluator evaluator(*m_pModule, m_LDBackend);
+ SectionMap::iterator out, outBegin, outEnd;
+ outBegin = m_pModule->getScript().sectionMap().begin();
+ outEnd = m_pModule->getScript().sectionMap().end();
+ for (out = outBegin; out != outEnd; ++out) {
+ uint64_t out_align = 0x0, in_align = 0x0;
+ LDSection* out_sect = (*out)->getSection();
+ SectionMap::Output::iterator in, inBegin, inEnd;
+ inBegin = (*out)->begin();
+ inEnd = (*out)->end();
+
+ // force input alignment from ldscript if any
+ if ((*out)->prolog().hasSubAlign()) {
+ evaluator.eval((*out)->prolog().subAlign(), in_align);
+ }
+
+ for (in = inBegin; in != inEnd; ++in) {
+ LDSection* in_sect = (*in)->getSection();
+ if ((*out)->prolog().hasSubAlign())
+ in_sect->setAlign(in_align);
+
+ if (builder.MoveSectionData(*in_sect->getSectionData(),
+ *out_sect->getSectionData())) {
+ builder.UpdateSectionAlign(*out_sect, *in_sect);
+ m_LDBackend.updateSectionFlags(*out_sect, *in_sect);
+ }
+ } // for each input section description
+
+ // force output alignment from ldscript if any
+ if ((*out)->prolog().hasAlign()) {
+ evaluator.eval((*out)->prolog().align(), out_align);
+ out_sect->setAlign(out_align);
+ }
+
+ if ((*out)->hasContent()) {
+ LDSection* target = m_pModule->getSection((*out)->name());
+ assert(target != NULL && target->hasSectionData());
+ if (builder.MoveSectionData(*out_sect->getSectionData(),
+ *target->getSectionData())) {
+ builder.UpdateSectionAlign(*target, *out_sect);
+ m_LDBackend.updateSectionFlags(*target, *out_sect);
+ }
+ }
+ } // for each output section description
+
return true;
}
+void ObjectLinker::addSymbolToOutput(ResolveInfo& pInfo, Module& pModule)
+{
+ // section symbols will be defined by linker later, we should not add section
+ // symbols to output here
+ if (ResolveInfo::Section == pInfo.type() || NULL == pInfo.outSymbol())
+ return;
+
+ // if the symbols defined in the Ignore sections (e.g. discared by GC), then
+ // not to put them to output
+ if (pInfo.outSymbol()->hasFragRef() && LDFileFormat::Ignore ==
+ pInfo.outSymbol()->fragRef()->frag()->getParent()->getSection().kind())
+ return;
+
+ if (pInfo.shouldForceLocal(m_Config))
+ pModule.getSymbolTable().forceLocal(*pInfo.outSymbol());
+ else
+ pModule.getSymbolTable().add(*pInfo.outSymbol());
+}
+
+void ObjectLinker::addSymbolsToOutput(Module& pModule)
+{
+ // Traverse all the free ResolveInfo and add the output symobols to output
+ NamePool::freeinfo_iterator free_it,
+ free_end = pModule.getNamePool().freeinfo_end();
+ for (free_it = pModule.getNamePool().freeinfo_begin(); free_it != free_end;
+ ++free_it)
+ addSymbolToOutput(**free_it, pModule);
+
+
+ // Traverse all the resolveInfo and add the output symbol to output
+ NamePool::syminfo_iterator info_it,
+ info_end = pModule.getNamePool().syminfo_end();
+ for (info_it = pModule.getNamePool().syminfo_begin(); info_it != info_end;
+ ++info_it)
+ addSymbolToOutput(*info_it.getEntry(), pModule);
+}
+
+
/// addStandardSymbols - shared object and executable files need some
/// standard symbols
/// @return if there are some input symbols with the same name to the
@@ -331,40 +436,63 @@
/// scripts.
bool ObjectLinker::addScriptSymbols()
{
- const LinkerScript& script = m_pModule->getScript();
- LinkerScript::DefSymMap::const_entry_iterator it;
- LinkerScript::DefSymMap::const_entry_iterator ie = script.defSymMap().end();
- // go through the entire defSymMap
- for (it = script.defSymMap().begin(); it != ie; ++it) {
- const llvm::StringRef sym = it.getEntry()->key();
- ResolveInfo* old_info = m_pModule->getNamePool().findInfo(sym);
+ LinkerScript& script = m_pModule->getScript();
+ LinkerScript::Assignments::iterator it, ie = script.assignments().end();
+ // go through the entire symbol assignments
+ for (it = script.assignments().begin(); it != ie; ++it) {
+ LDSymbol* symbol = NULL;
+ assert((*it).second.symbol().type() == Operand::SYMBOL);
+ const llvm::StringRef symName = (*it).second.symbol().name();
+ ResolveInfo::Type type = ResolveInfo::NoType;
+ ResolveInfo::Visibility vis = ResolveInfo::Default;
+ size_t size = 0;
+ ResolveInfo* old_info = m_pModule->getNamePool().findInfo(symName);
// if the symbol does not exist, we can set type to NOTYPE
// else we retain its type, same goes for size - 0 or retain old value
// and visibility - Default or retain
if (old_info != NULL) {
- if(!m_pBuilder->AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
- sym,
- static_cast<ResolveInfo::Type>(old_info->type()),
- ResolveInfo::Define,
- ResolveInfo::Absolute,
- old_info->size(),
- 0x0,
- FragmentRef::Null(),
- old_info->visibility()))
- return false;
+ type = static_cast<ResolveInfo::Type>(old_info->type());
+ vis = old_info->visibility();
+ size = old_info->size();
}
- else {
- if (!m_pBuilder->AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
- sym,
- ResolveInfo::NoType,
- ResolveInfo::Define,
- ResolveInfo::Absolute,
- 0x0,
- 0x0,
- FragmentRef::Null(),
- ResolveInfo::Default))
- return false;
+
+ // Add symbol and refine the visibility if needed
+ // FIXME: bfd linker would change the binding instead, but currently
+ // ABS is also a kind of Binding in ResolveInfo.
+ switch ((*it).second.type()) {
+ case Assignment::HIDDEN:
+ vis = ResolveInfo::Hidden;
+ // Fall through
+ case Assignment::DEFAULT:
+ symbol =
+ m_pBuilder->AddSymbol<IRBuilder::Force,
+ IRBuilder::Unresolve>(symName,
+ type,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ size,
+ 0x0,
+ FragmentRef::Null(),
+ vis);
+ break;
+ case Assignment::PROVIDE_HIDDEN:
+ vis = ResolveInfo::Hidden;
+ // Fall through
+ case Assignment::PROVIDE:
+ symbol =
+ m_pBuilder->AddSymbol<IRBuilder::AsReferred,
+ IRBuilder::Unresolve>(symName,
+ type,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ size,
+ 0x0,
+ FragmentRef::Null(),
+ vis);
+ break;
}
+ // Set symbol of this assignment.
+ (*it).first = symbol;
}
return true;
}
@@ -387,10 +515,18 @@
RelocData::iterator reloc, rEnd = (*rs)->getRelocData()->end();
for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) {
Relocation* relocation = llvm::cast<Relocation>(reloc);
+
+ // bypass the reloc if the symbol is in the discarded input section
+ ResolveInfo* info = relocation->symInfo();
+ if (!info->outSymbol()->hasFragRef() &&
+ ResolveInfo::Section == info->type() &&
+ ResolveInfo::Undefined == info->desc())
+ continue;
+
// scan relocation
if (LinkerConfig::Object != m_Config.codeGenType())
m_LDBackend.getRelocator()->scanRelocation(
- *relocation, *m_pBuilder, *m_pModule, **rs);
+ *relocation, *m_pBuilder, *m_pModule, **rs, **input);
else
m_LDBackend.getRelocator()->partialScanRelocation(
*relocation, *m_pModule, **rs);
@@ -450,12 +586,18 @@
/// In ELF, will compute the size of.symtab, .strtab, .dynsym, .dynstr,
/// .hash and .shstrtab sections.
///
- /// dump all symbols and strings from FragmentLinker and build the format-dependent
+ /// dump all symbols and strings from ObjectLinker and build the format-dependent
/// hash table.
/// @note sizeNamePools replies on LinkerConfig::CodePosition. Must determine
/// code position model before calling GNULDBackend::sizeNamePools()
m_LDBackend.sizeNamePools(*m_pModule);
+ // Do this after backend prelayout since it may add eh_frame entries.
+ LDSection* eh_frame_sect = m_pModule->getSection(".eh_frame");
+ if (eh_frame_sect && eh_frame_sect->hasEhFrame())
+ eh_frame_sect->getEhFrame()->computeOffsetSize();
+ m_LDBackend.createAndSizeEhFrameHdr(*m_pModule);
+
return true;
}
@@ -478,30 +620,69 @@
}
/// finalizeSymbolValue - finalize the resolved symbol value.
-/// Before relocate(), after layout(), FragmentLinker should correct value of all
+/// Before relocate(), after layout(), ObjectLinker should correct value of all
/// symbol.
bool ObjectLinker::finalizeSymbolValue()
{
- bool finalized = m_pLinker->finalizeSymbols() && m_LDBackend.finalizeSymbols();
- bool scriptSymsAdded = true;
- uint64_t symVal;
- const LinkerScript& script = m_pModule->getScript();
- LinkerScript::DefSymMap::const_entry_iterator it;
- LinkerScript::DefSymMap::const_entry_iterator ie = script.defSymMap().end();
+ Module::sym_iterator symbol, symEnd = m_pModule->sym_end();
+ for (symbol = m_pModule->sym_begin(); symbol != symEnd; ++symbol) {
- DefSymParser parser(*m_pModule);
- for (it = script.defSymMap().begin(); it != ie; ++it) {
- llvm::StringRef symName = it.getEntry()->key();
- llvm::StringRef expr = it.getEntry()->value();
+ if ((*symbol)->resolveInfo()->isAbsolute() ||
+ (*symbol)->resolveInfo()->type() == ResolveInfo::File) {
+ // absolute symbols should just use its value directly (i.e., the result
+ // of symbol resolution)
+ continue;
+ }
- LDSymbol* symbol = m_pModule->getNamePool().findSymbol(symName);
- assert(NULL != symbol && "--defsym symbol should be in the name pool");
- scriptSymsAdded &= parser.parse(expr, symVal);
- if (!scriptSymsAdded)
- break;
- symbol->setValue(symVal);
+ if ((*symbol)->resolveInfo()->type() == ResolveInfo::ThreadLocal) {
+ m_LDBackend.finalizeTLSSymbol(**symbol);
+ continue;
+ }
+
+ if ((*symbol)->hasFragRef()) {
+ // set the virtual address of the symbol. If the output file is
+ // relocatable object file, the section's virtual address becomes zero.
+ // And the symbol's value become section relative offset.
+ uint64_t value = (*symbol)->fragRef()->getOutputOffset();
+ assert(NULL != (*symbol)->fragRef()->frag());
+ uint64_t addr =
+ (*symbol)->fragRef()->frag()->getParent()->getSection().addr();
+ (*symbol)->setValue(value + addr);
+ continue;
+ }
}
- return finalized && scriptSymsAdded ;
+
+ RpnEvaluator evaluator(*m_pModule, m_LDBackend);
+ bool finalized = m_LDBackend.finalizeSymbols();
+ bool scriptSymsFinalized = true;
+ LinkerScript& script = m_pModule->getScript();
+ LinkerScript::Assignments::iterator assign, assignEnd;
+ assignEnd = script.assignments().end();
+ for (assign = script.assignments().begin(); assign != assignEnd; ++assign) {
+ LDSymbol* symbol = (*assign).first;
+ Assignment& assignment = (*assign).second;
+
+ if (symbol == NULL)
+ continue;
+
+ scriptSymsFinalized &= assignment.assign(evaluator);
+ if (!scriptSymsFinalized)
+ break;
+
+ symbol->setValue(assignment.symbol().value());
+ } // for each script symbol assignment
+
+ bool assertionsPassed = true;
+ LinkerScript::Assertions::iterator assert, assertEnd;
+ assertEnd = script.assertions().end();
+ for (assert = script.assertions().begin(); assert != assertEnd; ++assert) {
+ uint64_t res = 0x0;
+ evaluator.eval((*assert).getRpnExpr(), res);
+ if (res == 0x0)
+ fatal(diag::err_assert_failed) << (*assert).message();
+ } // for each assertion in ldscript
+
+ return finalized && scriptSymsFinalized && assertionsPassed;
}
/// relocate - applying relocation entries and create relocation
@@ -511,20 +692,66 @@
/// and push_back into the relocation section
bool ObjectLinker::relocation()
{
- return m_pLinker->applyRelocations();
+ // when producing relocatables, no need to apply relocation
+ if (LinkerConfig::Object == m_Config.codeGenType())
+ return true;
+
+ // apply all relocations of all inputs
+ Module::obj_iterator input, inEnd = m_pModule->obj_end();
+ for (input = m_pModule->obj_begin(); input != inEnd; ++input) {
+ m_LDBackend.getRelocator()->initializeApply(**input);
+ LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
+ for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
+ // bypass the reloc section if
+ // 1. its section kind is changed to Ignore. (The target section is a
+ // discarded group section.)
+ // 2. it has no reloc data. (All symbols in the input relocs are in the
+ // discarded group sections)
+ if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData())
+ continue;
+ RelocData::iterator reloc, rEnd = (*rs)->getRelocData()->end();
+ for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) {
+ Relocation* relocation = llvm::cast<Relocation>(reloc);
+
+ // bypass the reloc if the symbol is in the discarded input section
+ ResolveInfo* info = relocation->symInfo();
+ if (!info->outSymbol()->hasFragRef() &&
+ ResolveInfo::Section == info->type() &&
+ ResolveInfo::Undefined == info->desc())
+ continue;
+
+ relocation->apply(*m_LDBackend.getRelocator());
+ } // for all relocations
+ } // for all relocation section
+ m_LDBackend.getRelocator()->finalizeApply(**input);
+ } // for all inputs
+
+ // apply relocations created by relaxation
+ BranchIslandFactory* br_factory = m_LDBackend.getBRIslandFactory();
+ BranchIslandFactory::iterator facIter, facEnd = br_factory->end();
+ for (facIter = br_factory->begin(); facIter != facEnd; ++facIter) {
+ BranchIsland& island = *facIter;
+ BranchIsland::reloc_iterator iter, iterEnd = island.reloc_end();
+ for (iter = island.reloc_begin(); iter != iterEnd; ++iter)
+ (*iter)->apply(*m_LDBackend.getRelocator());
+ }
+ return true;
}
/// emitOutput - emit the output file.
-bool ObjectLinker::emitOutput(MemoryArea& pOutput)
+bool ObjectLinker::emitOutput(FileOutputBuffer& pOutput)
{
return llvm::errc::success == getWriter()->writeObject(*m_pModule, pOutput);
}
/// postProcessing - do modification after all processes
-bool ObjectLinker::postProcessing(MemoryArea& pOutput)
+bool ObjectLinker::postProcessing(FileOutputBuffer& pOutput)
{
- m_pLinker->syncRelocationResult(pOutput);
+ if (LinkerConfig::Object != m_Config.codeGenType())
+ normalSyncRelocationResult(pOutput);
+ else
+ partialSyncRelocationResult(pOutput);
// emit .eh_frame_hdr
// eh_frame_hdr should be emitted after syncRelocation, because eh_frame_hdr
@@ -533,3 +760,125 @@
return true;
}
+void ObjectLinker::normalSyncRelocationResult(FileOutputBuffer& pOutput)
+{
+ uint8_t* data = pOutput.getBufferStart();
+
+ // sync all relocations of all inputs
+ Module::obj_iterator input, inEnd = m_pModule->obj_end();
+ for (input = m_pModule->obj_begin(); input != inEnd; ++input) {
+ LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
+ for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
+ // bypass the reloc section if
+ // 1. its section kind is changed to Ignore. (The target section is a
+ // discarded group section.)
+ // 2. it has no reloc data. (All symbols in the input relocs are in the
+ // discarded group sections)
+ if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData())
+ continue;
+ RelocData::iterator reloc, rEnd = (*rs)->getRelocData()->end();
+ for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) {
+ Relocation* relocation = llvm::cast<Relocation>(reloc);
+
+ // bypass the reloc if the symbol is in the discarded input section
+ ResolveInfo* info = relocation->symInfo();
+ if (!info->outSymbol()->hasFragRef() &&
+ ResolveInfo::Section == info->type() &&
+ ResolveInfo::Undefined == info->desc())
+ continue;
+
+ // bypass the relocation with NONE type. This is to avoid overwrite the
+ // target result by NONE type relocation if there is a place which has
+ // two relocations to apply to, and one of it is NONE type. The result
+ // we want is the value of the other relocation result. For example,
+ // in .exidx, there are usually an R_ARM_NONE and R_ARM_PREL31 apply to
+ // the same place
+ if (0x0 == relocation->type())
+ continue;
+ writeRelocationResult(*relocation, data);
+ } // for all relocations
+ } // for all relocation section
+ } // for all inputs
+
+ // sync relocations created by relaxation
+ BranchIslandFactory* br_factory = m_LDBackend.getBRIslandFactory();
+ BranchIslandFactory::iterator facIter, facEnd = br_factory->end();
+ for (facIter = br_factory->begin(); facIter != facEnd; ++facIter) {
+ BranchIsland& island = *facIter;
+ BranchIsland::reloc_iterator iter, iterEnd = island.reloc_end();
+ for (iter = island.reloc_begin(); iter != iterEnd; ++iter) {
+ Relocation* reloc = *iter;
+ writeRelocationResult(*reloc, data);
+ }
+ }
+}
+
+void ObjectLinker::partialSyncRelocationResult(FileOutputBuffer& pOutput)
+{
+ uint8_t* data = pOutput.getBufferStart();
+
+ // traverse outputs' LDSection to get RelocData
+ Module::iterator sectIter, sectEnd = m_pModule->end();
+ for (sectIter = m_pModule->begin(); sectIter != sectEnd; ++sectIter) {
+ if (LDFileFormat::Relocation != (*sectIter)->kind())
+ continue;
+
+ RelocData* reloc_data = (*sectIter)->getRelocData();
+ RelocData::iterator relocIter, relocEnd = reloc_data->end();
+ for (relocIter = reloc_data->begin(); relocIter != relocEnd; ++relocIter) {
+ Relocation* reloc = llvm::cast<Relocation>(relocIter);
+
+ // bypass the relocation with NONE type. This is to avoid overwrite the
+ // target result by NONE type relocation if there is a place which has
+ // two relocations to apply to, and one of it is NONE type. The result
+ // we want is the value of the other relocation result. For example,
+ // in .exidx, there are usually an R_ARM_NONE and R_ARM_PREL31 apply to
+ // the same place
+ if (0x0 == reloc->type())
+ continue;
+ writeRelocationResult(*reloc, data);
+ }
+ }
+}
+
+void ObjectLinker::writeRelocationResult(Relocation& pReloc, uint8_t* pOutput)
+{
+ // get output file offset
+ size_t out_offset =
+ pReloc.targetRef().frag()->getParent()->getSection().offset() +
+ pReloc.targetRef().getOutputOffset();
+
+ uint8_t* target_addr = pOutput + out_offset;
+ // byte swapping if target and host has different endian, and then write back
+ if(llvm::sys::IsLittleEndianHost != m_Config.targets().isLittleEndian()) {
+ uint64_t tmp_data = 0;
+
+ switch(pReloc.size(*m_LDBackend.getRelocator())) {
+ case 8u:
+ std::memcpy(target_addr, &pReloc.target(), 1);
+ break;
+
+ case 16u:
+ tmp_data = mcld::bswap16(pReloc.target());
+ std::memcpy(target_addr, &tmp_data, 2);
+ break;
+
+ case 32u:
+ tmp_data = mcld::bswap32(pReloc.target());
+ std::memcpy(target_addr, &tmp_data, 4);
+ break;
+
+ case 64u:
+ tmp_data = mcld::bswap64(pReloc.target());
+ std::memcpy(target_addr, &tmp_data, 8);
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ std::memcpy(target_addr, &pReloc.target(),
+ pReloc.size(*m_LDBackend.getRelocator())/8);
+}
+
diff --git a/lib/Object/SectionMap.cpp b/lib/Object/SectionMap.cpp
index d3da574..64c4a87 100644
--- a/lib/Object/SectionMap.cpp
+++ b/lib/Object/SectionMap.cpp
@@ -7,112 +7,385 @@
//
//===----------------------------------------------------------------------===//
#include <mcld/Object/SectionMap.h>
-#include <mcld/ADT/StringHash.h>
+#include <mcld/Script/Assignment.h>
+#include <mcld/Script/WildcardPattern.h>
+#include <mcld/Script/StringList.h>
+#include <mcld/Script/Operand.h>
+#include <mcld/Script/Operator.h>
+#include <mcld/Script/RpnExpr.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/SectionData.h>
+#include <mcld/Fragment/NullFragment.h>
+#include <llvm/Support/Casting.h>
#include <cassert>
#include <cstring>
+#include <climits>
+#if !defined(MCLD_ON_WIN32)
+#include <fnmatch.h>
+#define fnmatch0(pattern,string) (fnmatch(pattern,string,0) == 0)
+#else
+#include <windows.h>
+#include <shlwapi.h>
+#define fnmatch0(pattern,string) (PathMatchSpec(string, pattern) == true)
+#endif
using namespace mcld;
-
-
-SectionMap::NamePair SectionMap::NullName;
-
//===----------------------------------------------------------------------===//
-// SectionMap::NamePair
+// SectionMap::Input
//===----------------------------------------------------------------------===//
-SectionMap::NamePair::NamePair()
- : hash(-1) {
-}
-
-SectionMap::NamePair::NamePair(const std::string& pFrom, const std::string& pTo)
- : from(pFrom), to(pTo) {
- hash = SectionMap::hash(pFrom);
-}
-
-bool SectionMap::NamePair::isNull() const
+SectionMap::Input::Input(const std::string& pName,
+ InputSectDesc::KeepPolicy pPolicy)
+ : m_Policy(pPolicy)
{
- return (&NullName == this);
+ m_Spec.m_pWildcardFile =
+ WildcardPattern::create("*", WildcardPattern::SORT_NONE);
+ m_Spec.m_pExcludeFiles = NULL;
+
+ StringList* sections = StringList::create();
+ sections->push_back(
+ WildcardPattern::create(pName, WildcardPattern::SORT_NONE));
+ m_Spec.m_pWildcardSections = sections;
+
+ m_pSection = LDSection::Create(pName, LDFileFormat::Regular, 0, 0);
+ SectionData* sd = SectionData::Create(*m_pSection);
+ m_pSection->setSectionData(sd);
+ new NullFragment(sd);
+ new NullFragment(sd);
+}
+
+SectionMap::Input::Input(const InputSectDesc& pInputDesc)
+ : m_Policy(pInputDesc.policy())
+{
+ m_Spec.m_pWildcardFile = pInputDesc.spec().m_pWildcardFile;
+ m_Spec.m_pExcludeFiles = pInputDesc.spec().m_pExcludeFiles;
+ m_Spec.m_pWildcardSections = pInputDesc.spec().m_pWildcardSections;
+ m_pSection = LDSection::Create("", LDFileFormat::Regular, 0, 0);
+ SectionData* sd = SectionData::Create(*m_pSection);
+ m_pSection->setSectionData(sd);
+ new NullFragment(sd);
+ new NullFragment(sd);
+}
+
+//===----------------------------------------------------------------------===//
+// SectionMap::Output
+//===----------------------------------------------------------------------===//
+SectionMap::Output::Output(const std::string& pName)
+ : m_Name(pName),
+ m_Order(UINT_MAX)
+{
+ m_Prolog.m_pVMA = NULL;
+ m_Prolog.m_Type = OutputSectDesc::LOAD;
+ m_Prolog.m_pLMA = NULL;
+ m_Prolog.m_pAlign = NULL;
+ m_Prolog.m_pSubAlign = NULL;
+ m_Prolog.m_Constraint = OutputSectDesc::NO_CONSTRAINT;
+
+ m_Epilog.m_pRegion = NULL;
+ m_Epilog.m_pLMARegion = NULL;
+ m_Epilog.m_pPhdrs = NULL;
+ m_Epilog.m_pFillExp = NULL;
+
+ m_pSection = LDSection::Create(pName, LDFileFormat::Regular, 0, 0);
+ SectionData* sd = SectionData::Create(*m_pSection);
+ m_pSection->setSectionData(sd);
+
+ m_bIsDiscard = pName.compare("/DISCARD/") == 0;
+}
+
+SectionMap::Output::Output(const OutputSectDesc& pOutputDesc)
+ : m_Name(pOutputDesc.name()),
+ m_Prolog(pOutputDesc.prolog()),
+ m_Epilog(pOutputDesc.epilog()),
+ m_Order(UINT_MAX)
+{
+ m_pSection = LDSection::Create(m_Name, LDFileFormat::Regular, 0, 0);
+ SectionData* sd = SectionData::Create(*m_pSection);
+ m_pSection->setSectionData(sd);
+
+ m_bIsDiscard = m_Name.compare("/DISCARD/") == 0;
+}
+
+bool SectionMap::Output::hasContent() const
+{
+ return m_pSection != NULL && m_pSection->size() != 0;
+}
+
+SectionMap::Output::const_dot_iterator
+SectionMap::Output::find_first_explicit_dot() const
+{
+ for (const_dot_iterator it = dot_begin(), ie = dot_end(); it != ie; ++it) {
+ if ((*it).type() == Assignment::DEFAULT)
+ return it;
+ }
+ return dot_end();
+}
+
+SectionMap::Output::dot_iterator SectionMap::Output::find_first_explicit_dot()
+{
+ for (dot_iterator it = dot_begin(), ie = dot_end(); it != ie; ++it) {
+ if ((*it).type() == Assignment::DEFAULT)
+ return it;
+ }
+ return dot_end();
+}
+
+SectionMap::Output::const_dot_iterator
+SectionMap::Output::find_last_explicit_dot() const
+{
+ typedef DotAssignments::const_reverse_iterator CONST_RIT;
+ for (CONST_RIT rit = dotAssignments().rbegin(), rie = dotAssignments().rend();
+ rit != rie; ++rit) {
+ if ((*rit).type() == Assignment::DEFAULT) {
+ return dot_begin() +
+ (dotAssignments().size() - (rit - dotAssignments().rbegin()) - 1);
+ }
+ }
+ return dot_end();
+}
+
+SectionMap::Output::dot_iterator SectionMap::Output::find_last_explicit_dot()
+{
+ typedef DotAssignments::reverse_iterator RIT;
+ for (RIT rit = dotAssignments().rbegin(), rie = dotAssignments().rend();
+ rit != rie; ++rit) {
+ if ((*rit).type() == Assignment::DEFAULT) {
+ return dot_begin() +
+ (dotAssignments().size() - (rit - dotAssignments().rbegin()) - 1);
+ }
+ }
+ return dot_end();
}
//===----------------------------------------------------------------------===//
// SectionMap
//===----------------------------------------------------------------------===//
-const SectionMap::NamePair& SectionMap::find(const std::string& pFrom) const
+SectionMap::~SectionMap()
{
- unsigned int hash = SectionMap::hash(pFrom);
- return find(pFrom, hash);
-}
-
-SectionMap::NamePair& SectionMap::find(const std::string& pFrom)
-{
- unsigned int hash = SectionMap::hash(pFrom);
- return find(pFrom, hash);
-}
-
-const SectionMap::NamePair&
-SectionMap::find(const std::string& pFrom, unsigned int pHash) const
-{
- NamePairList::const_iterator name_hash, nEnd = m_NamePairList.end();
- for (name_hash = m_NamePairList.begin(); name_hash != nEnd; ++name_hash) {
- if (matched(*name_hash, pFrom, pHash)) {
- return *name_hash;
+ iterator out, outBegin = begin(), outEnd = end();
+ for (out = outBegin; out != outEnd; ++out) {
+ if (*out != NULL) {
+ Output::iterator in, inBegin = (*out)->begin(), inEnd = (*out)->end();
+ for (in = inBegin; in != inEnd; ++in) {
+ if (*in != NULL)
+ delete *in;
+ }
+ delete *out;
}
}
- return NullName;
}
-SectionMap::NamePair&
-SectionMap::find(const std::string& pFrom, unsigned int pHash)
+SectionMap::const_mapping
+SectionMap::find(const std::string& pInputFile,
+ const std::string& pInputSection) const
{
- NamePairList::iterator name_hash, nEnd = m_NamePairList.end();
- for (name_hash = m_NamePairList.begin(); name_hash != nEnd; ++name_hash) {
- if (matched(*name_hash, pFrom, pHash)) {
- return *name_hash;
+ const_iterator out, outBegin = begin(), outEnd = end();
+ for (out = outBegin; out != outEnd; ++out) {
+ Output::const_iterator in, inBegin = (*out)->begin(), inEnd = (*out)->end();
+ for (in = inBegin; in != inEnd; ++in) {
+ if (matched(**in, pInputFile, pInputSection))
+ return std::make_pair(*out, *in);
}
}
- return NullName;
+ return std::make_pair((const Output*)NULL, (const Input*)NULL);
}
-SectionMap::NamePair& SectionMap::append(const std::string &pFrom,
- const std::string &pTo,
- bool &pExist)
+SectionMap::mapping SectionMap::find(const std::string& pInputFile,
+ const std::string& pInputSection)
{
- NamePair& result = find(pFrom);
- if (!result.isNull()) {
- pExist = true;
- return result;
+ iterator out, outBegin = begin(), outEnd = end();
+ for (out = outBegin; out != outEnd; ++out) {
+ Output::iterator in, inBegin = (*out)->begin(), inEnd = (*out)->end();
+ for (in = inBegin; in != inEnd; ++in) {
+ if (matched(**in, pInputFile, pInputSection))
+ return std::make_pair(*out, *in);
+ }
+ }
+ return std::make_pair((Output*)NULL, (Input*)NULL);
+}
+
+SectionMap::const_iterator
+SectionMap::find(const std::string& pOutputSection) const
+{
+ const_iterator out, outBegin = begin(), outEnd = end();
+ for (out = outBegin; out != outEnd; ++out) {
+ if ((*out)->name().compare(pOutputSection) == 0)
+ return out;
+ }
+ return outEnd;
+}
+
+SectionMap::iterator
+SectionMap::find(const std::string& pOutputSection)
+{
+ iterator out, outBegin = begin(), outEnd = end();
+ for (out = outBegin; out != outEnd; ++out) {
+ if ((*out)->name().compare(pOutputSection) == 0)
+ return out;
+ }
+ return outEnd;
+}
+
+std::pair<SectionMap::mapping, bool>
+SectionMap::insert(const std::string& pInputSection,
+ const std::string& pOutputSection,
+ InputSectDesc::KeepPolicy pPolicy)
+{
+ iterator out, outBegin = begin(), outEnd = end();
+ for (out = outBegin; out != outEnd; ++out) {
+ if ((*out)->name().compare(pOutputSection) == 0)
+ break;
+ }
+ if (out != end()) {
+ Output::iterator in, inBegin = (*out)->begin(), inEnd = (*out)->end();
+ for (in = inBegin; in != inEnd; ++in) {
+ if ((*in)->getSection()->name().compare(pInputSection) == 0)
+ break;
+ }
+
+ if (in != (*out)->end()) {
+ return std::make_pair(std::make_pair(*out, *in), false);
+ } else {
+ Input* input = new Input(pInputSection, pPolicy);
+ (*out)->append(input);
+ return std::make_pair(std::make_pair(*out, input), true);
+ }
}
- pExist = false;
- NamePair entry(pFrom, pTo);
- m_NamePairList.push_back(entry);
- return m_NamePairList.back();
+ Output* output = new Output(pOutputSection);
+ m_OutputDescList.push_back(output);
+ Input* input = new Input(pInputSection, pPolicy);
+ output->append(input);
+
+ return std::make_pair(std::make_pair(output, input), true);
}
-bool SectionMap::matched(const NamePair& pNamePair,
- const std::string& pInput,
- unsigned int pHashValue) const
+std::pair<SectionMap::mapping, bool>
+SectionMap::insert(const InputSectDesc& pInputDesc,
+ const OutputSectDesc& pOutputDesc)
{
- if ('*' == pNamePair.from[0])
- return true;
+ iterator out, outBegin = begin(), outEnd = end();
+ for (out = outBegin; out != outEnd; ++out) {
+ if ((*out)->name().compare(pOutputDesc.name()) == 0 &&
+ (*out)->prolog() == pOutputDesc.prolog() &&
+ (*out)->epilog() == pOutputDesc.epilog())
+ break;
+ }
- if (pNamePair.from.size() > pInput.size())
- return false;
+ if (out != end()) {
+ Output::iterator in, inBegin = (*out)->begin(), inEnd = (*out)->end();
+ for (in = inBegin; in != inEnd; ++in) {
+ if ((*in)->policy() == pInputDesc.policy() &&
+ (*in)->spec() == pInputDesc.spec())
+ break;
+ }
- if (!hash::StringHash<hash::ES>::may_include(pNamePair.hash, pHashValue))
- return false;
+ if (in != (*out)->end()) {
+ return std::make_pair(std::make_pair(*out, *in), false);
+ } else {
+ Input* input = new Input(pInputDesc);
+ (*out)->append(input);
+ return std::make_pair(std::make_pair(*out, input), true);
+ }
+ }
- if (0 == strncmp(pInput.c_str(),
- pNamePair.from.c_str(),
- pNamePair.from.size())) {
- return true;
+ Output* output = new Output(pOutputDesc);
+ m_OutputDescList.push_back(output);
+ Input* input = new Input(pInputDesc);
+ output->append(input);
+
+ return std::make_pair(std::make_pair(output, input), true);
+}
+
+SectionMap::iterator
+SectionMap::insert(iterator pPosition, LDSection* pSection)
+{
+ Output* output = new Output(pSection->name());
+ output->append(new Input(pSection->name(), InputSectDesc::NoKeep));
+ output->setSection(pSection);
+ return m_OutputDescList.insert(pPosition, output);
+}
+
+bool SectionMap::matched(const SectionMap::Input& pInput,
+ const std::string& pInputFile,
+ const std::string& pInputSection) const
+{
+ if (pInput.spec().hasFile() && !matched(pInput.spec().file(), pInputFile))
+ return false;
+
+ if (pInput.spec().hasExcludeFiles()) {
+ StringList::const_iterator file, fileEnd;
+ fileEnd = pInput.spec().excludeFiles().end();
+ for (file = pInput.spec().excludeFiles().begin(); file != fileEnd; ++file) {
+ if (matched(llvm::cast<WildcardPattern>(**file), pInputFile)) {
+ return false;
+ }
+ }
+ }
+
+ if (pInput.spec().hasSections()) {
+ StringList::const_iterator sect, sectEnd = pInput.spec().sections().end();
+ for (sect = pInput.spec().sections().begin(); sect != sectEnd; ++sect) {
+ if (matched(llvm::cast<WildcardPattern>(**sect), pInputSection)) {
+ return true;
+ }
+ }
}
return false;
}
-unsigned int SectionMap::hash(const std::string& pString)
+bool SectionMap::matched(const WildcardPattern& pPattern,
+ const std::string& pName) const
{
- static hash::StringHash<hash::ES> hash_func;
- return hash_func(pString);
+ if (pPattern.isPrefix()) {
+ llvm::StringRef name(pName);
+ return name.startswith(pPattern.prefix());
+ } else {
+ return fnmatch0(pPattern.name().c_str(), pName.c_str());
+ }
}
+// fixupDotSymbols - ensure the dot symbols are valid
+void SectionMap::fixupDotSymbols()
+{
+ for (iterator it = begin() + 1, ie = end(); it != ie; ++it) {
+ // fixup the 1st explicit dot assignment if needed
+ if (!(*it)->dotAssignments().empty()) {
+ Output::dot_iterator dot = (*it)->find_first_explicit_dot();
+ if (dot != (*it)->dot_end() &&
+ (*dot).symbol().isDot() &&
+ (*dot).getRpnExpr().hasDot()) {
+ Assignment assign(Assignment::OUTPUT_SECTION,
+ Assignment::DEFAULT,
+ *SymOperand::create("."),
+ *RpnExpr::buildHelperExpr(it - 1));
+ Output::dot_iterator ref = (*it)->dotAssignments().insert(dot, assign);
+ for (RpnExpr::iterator tok = (*dot).getRpnExpr().begin(),
+ tokEnd = (*dot).getRpnExpr().end(); tok != tokEnd; ++tok) {
+ if ((*tok)->kind() == ExprToken::OPERAND &&
+ llvm::cast<Operand>(*tok)->isDot())
+ *tok = &((*ref).symbol());
+ } // for each token in the RHS expr of the dot assignment
+ }
+ }
+
+ // fixup dot in output VMA if needed
+ if ((*it)->prolog().hasVMA() && (*it)->prolog().vma().hasDot()) {
+ Output::dot_iterator dot = (*it)->find_last_explicit_dot();
+ if (dot == (*it)->dot_end()) {
+ Assignment assign(Assignment::OUTPUT_SECTION,
+ Assignment::DEFAULT,
+ *SymOperand::create("."),
+ *RpnExpr::buildHelperExpr(it - 1));
+ dot = (*it)->dotAssignments().insert(dot, assign);
+ }
+ for (RpnExpr::iterator tok = (*it)->prolog().vma().begin(),
+ tokEnd = (*it)->prolog().vma().end(); tok != tokEnd; ++tok) {
+ if ((*tok)->kind() == ExprToken::OPERAND &&
+ llvm::cast<Operand>(*tok)->isDot())
+ *tok = &((*dot).symbol());
+ } // for each token in the RHS expr of the dot assignment
+ }
+
+ } // for each output section
+}
diff --git a/lib/Script/AssertCmd.cpp b/lib/Script/AssertCmd.cpp
new file mode 100644
index 0000000..618731d
--- /dev/null
+++ b/lib/Script/AssertCmd.cpp
@@ -0,0 +1,48 @@
+//===- AssertCmd.cpp ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/AssertCmd.h>
+#include <mcld/Script/RpnExpr.h>
+#include <mcld/Support/raw_ostream.h>
+#include <mcld/Module.h>
+#include <mcld/LinkerScript.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// AssertCmd
+//===----------------------------------------------------------------------===//
+AssertCmd::AssertCmd(RpnExpr& pRpnExpr, const std::string& pMessage)
+ : ScriptCommand(ScriptCommand::ASSERT),
+ m_RpnExpr(pRpnExpr),
+ m_Message(pMessage)
+{
+}
+
+AssertCmd::~AssertCmd()
+{
+}
+
+AssertCmd& AssertCmd::operator=(const AssertCmd& pAssertCmd)
+{
+ return *this;
+}
+
+void AssertCmd::dump() const
+{
+ mcld::outs() << "Assert ( ";
+
+ m_RpnExpr.dump();
+
+ mcld::outs() << " , " << m_Message << " )\n";
+}
+
+void AssertCmd::activate(Module& pModule)
+{
+ pModule.getScript().assertions().push_back(*this);
+}
diff --git a/lib/Script/Assignment.cpp b/lib/Script/Assignment.cpp
new file mode 100644
index 0000000..a7e0f46
--- /dev/null
+++ b/lib/Script/Assignment.cpp
@@ -0,0 +1,175 @@
+//===- Assignment.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/Assignment.h>
+#include <mcld/Script/RpnExpr.h>
+#include <mcld/Script/Operand.h>
+#include <mcld/Script/Operator.h>
+#include <mcld/Script/RpnEvaluator.h>
+#include <mcld/Support/raw_ostream.h>
+#include <mcld/LinkerScript.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/SectionData.h>
+#include <mcld/Module.h>
+#include <llvm/Support/Casting.h>
+#include <cassert>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// Assignment
+//===----------------------------------------------------------------------===//
+Assignment::Assignment(Level pLevel,
+ Type pType,
+ SymOperand& pSymbol,
+ RpnExpr& pRpnExpr)
+ : ScriptCommand(ScriptCommand::ASSIGNMENT),
+ m_Level(pLevel),
+ m_Type(pType),
+ m_Symbol(pSymbol),
+ m_RpnExpr(pRpnExpr)
+{
+}
+
+Assignment::~Assignment()
+{
+}
+
+Assignment& Assignment::operator=(const Assignment& pAssignment)
+{
+ return *this;
+}
+
+void Assignment::dump() const
+{
+ switch (type()) {
+ case DEFAULT:
+ break;
+ case HIDDEN:
+ mcld::outs() << "HIDDEN ( ";
+ break;
+ case PROVIDE:
+ mcld::outs() << "PROVIDE ( ";
+ break;
+ case PROVIDE_HIDDEN:
+ mcld::outs() << "PROVIDE_HIDDEN ( ";
+ break;
+ default:
+ break;
+ }
+
+ m_Symbol.dump();
+
+ mcld::outs() << " = ";
+
+ m_RpnExpr.dump();
+
+ if (type() != DEFAULT)
+ mcld::outs() << " )";
+
+ mcld::outs() << ";\n";
+}
+
+void Assignment::activate(Module& pModule)
+{
+ bool isLhsDot = m_Symbol.isDot();
+ LinkerScript& script = pModule.getScript();
+ switch (m_Level) {
+ case OUTSIDE_SECTIONS:
+ assert(!isLhsDot);
+ script.assignments().push_back(std::make_pair((LDSymbol*)NULL, *this));
+ break;
+
+ case OUTPUT_SECTION: {
+ bool hasDotInRhs = m_RpnExpr.hasDot();
+ SectionMap::reference out = script.sectionMap().back();
+ if (hasDotInRhs) {
+ if (!isLhsDot && out->dotAssignments().empty()) {
+ // . = ADDR ( `prev_output_sect' ) + SIZEOF ( `prev_output_sect' )
+ SectionMap::iterator prev = script.sectionMap().begin() +
+ script.sectionMap().size() - 2;
+ Assignment assign(OUTPUT_SECTION,
+ HIDDEN,
+ *SymOperand::create("."),
+ *RpnExpr::buildHelperExpr(prev));
+ out->dotAssignments().push_back(assign);
+ }
+
+ if (!out->dotAssignments().empty()) {
+ Assignment& prevDotAssign = out->dotAssignments().back();
+ // If this is the 1st explicit assignment that includes both lhs dot and
+ // rhs dot, then because of possible orphan sections, we are unable to
+ // substitute the rhs dot now.
+ if (!isLhsDot || prevDotAssign.type() == DEFAULT) {
+ for (RpnExpr::iterator it = m_RpnExpr.begin(), ie = m_RpnExpr.end();
+ it != ie; ++it) {
+ // substitute the rhs dot with the appropriate helper expr
+ if ((*it)->kind() == ExprToken::OPERAND &&
+ llvm::cast<Operand>(*it)->isDot())
+ *it = &(prevDotAssign.symbol());
+ } // for each expression token
+ }
+ }
+ }
+
+ if (isLhsDot) {
+ out->dotAssignments().push_back(*this);
+ } else {
+ script.assignments().push_back(std::make_pair((LDSymbol*)NULL, *this));
+ }
+
+ break;
+ }
+
+ case INPUT_SECTION: {
+ bool hasDotInRhs = m_RpnExpr.hasDot();
+ SectionMap::Output::reference in = script.sectionMap().back()->back();
+ if (hasDotInRhs) {
+ if (in->dotAssignments().empty()) {
+ // . = `frag'
+ RpnExpr* expr =
+ RpnExpr::buildHelperExpr(in->getSection()->getSectionData()->front());
+ Assignment assign(INPUT_SECTION,
+ HIDDEN,
+ *SymOperand::create("."),
+ *expr);
+ in->dotAssignments().push_back(std::make_pair((Fragment*)NULL, assign));
+ }
+
+ Assignment& prevDotAssign = in->dotAssignments().back().second;
+ for (RpnExpr::iterator it = m_RpnExpr.begin(), ie = m_RpnExpr.end();
+ it != ie; ++it) {
+ // substitute the rhs dot with the appropriate helper expr
+ if ((*it)->kind() == ExprToken::OPERAND &&
+ llvm::cast<Operand>(*it)->isDot())
+ *it = &(prevDotAssign.symbol());
+ } // end of for
+ }
+
+ if (isLhsDot) {
+ in->dotAssignments().push_back(
+ std::make_pair(in->getSection()->getSectionData()->front().getNextNode(),
+ *this));
+ } else {
+ script.assignments().push_back(std::make_pair((LDSymbol*)NULL, *this));
+ }
+
+ break;
+ }
+
+ } // end of switch
+}
+
+bool Assignment::assign(RpnEvaluator& pEvaluator)
+{
+ uint64_t result = 0;
+ bool success = pEvaluator.eval(m_RpnExpr, result);
+ if (success)
+ m_Symbol.setValue(result);
+ return success;
+}
diff --git a/lib/Script/BinaryOp.cpp b/lib/Script/BinaryOp.cpp
new file mode 100644
index 0000000..863eb34
--- /dev/null
+++ b/lib/Script/BinaryOp.cpp
@@ -0,0 +1,268 @@
+//===- BinaryOp.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/BinaryOp.h>
+#include <mcld/Script/Operand.h>
+#include <mcld/ADT/SizeTraits.h>
+#include <mcld/Module.h>
+#include <mcld/LinkerScript.h>
+#include <mcld/Target/TargetLDBackend.h>
+#include <llvm/Support/Casting.h>
+#include <cassert>
+
+using namespace mcld;
+//===----------------------------------------------------------------------===//
+// BinaryOp
+//===----------------------------------------------------------------------===//
+template<>
+IntOperand* BinaryOp<Operator::MUL>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() * m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand* BinaryOp<Operator::DIV>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() / m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand* BinaryOp<Operator::MOD>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() % m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand* BinaryOp<Operator::ADD>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() + m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand* BinaryOp<Operator::SUB>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() - m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand* BinaryOp<Operator::LSHIFT>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() << m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand* BinaryOp<Operator::RSHIFT>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() >> m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand* BinaryOp<Operator::LT>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() < m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand* BinaryOp<Operator::LE>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() <= m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand* BinaryOp<Operator::GT>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() > m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand* BinaryOp<Operator::GE>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() >= m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand* BinaryOp<Operator::EQ>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() == m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand* BinaryOp<Operator::NE>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() != m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand*
+BinaryOp<Operator::BITWISE_AND>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() & m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand*
+BinaryOp<Operator::BITWISE_XOR>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() ^ m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand*
+BinaryOp<Operator::BITWISE_OR>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() | m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand*
+BinaryOp<Operator::LOGICAL_AND>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() && m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand*
+BinaryOp<Operator::LOGICAL_OR>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand[0]->value() || m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand* BinaryOp<Operator::ALIGN>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ uint64_t value = m_pOperand[0]->value();
+ uint64_t align = m_pOperand[1]->value();
+ alignAddress(value, align);
+ res->setValue(value);
+ return res;
+}
+
+template<>
+IntOperand*
+BinaryOp<Operator::DATA_SEGMENT_RELRO_END>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ /* FIXME: Currently we handle relro in a different way, and now the result
+ of this expression won't affect DATA_SEGMENT_ALIGN. */
+ IntOperand* res = result();
+ uint64_t value = m_pOperand[0]->value() + m_pOperand[1]->value();
+ alignAddress(value, pBackend.commonPageSize());
+ res->setValue(value);
+ return res;
+}
+
+template<>
+IntOperand* BinaryOp<Operator::MAX>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ if (m_pOperand[0]->value() >= m_pOperand[1]->value())
+ res->setValue(m_pOperand[0]->value());
+ else
+ res->setValue(m_pOperand[1]->value());
+ return res;
+}
+
+template<>
+IntOperand* BinaryOp<Operator::MIN>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ if (m_pOperand[0]->value() <= m_pOperand[1]->value())
+ res->setValue(m_pOperand[0]->value());
+ else
+ res->setValue(m_pOperand[1]->value());
+ return res;
+}
+
+
+/* SEGMENT_START(segment, default) */
+template<>
+IntOperand*
+BinaryOp<Operator::SEGMENT_START>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ /* Currently we look up segment address from -T command line options. */
+ SectOperand* sect = llvm::cast<SectOperand>(m_pOperand[0]);
+ const LinkerScript::AddressMap& addressMap =
+ pModule.getScript().addressMap();
+ LinkerScript::AddressMap::const_iterator addr;
+ if (sect->name().compare("text-segment") == 0)
+ addr = addressMap.find(".text");
+ else if (sect->name().compare("data-segment") == 0)
+ addr = addressMap.find(".data");
+ else if (sect->name().compare("bss-segment") == 0)
+ addr = addressMap.find(".bss");
+ else
+ addr = addressMap.find(sect->name());
+
+ if (addr != addressMap.end())
+ res->setValue(addr.getEntry()->value());
+ else {
+ assert(m_pOperand[1]->type() == Operand::INTEGER);
+ res->setValue(m_pOperand[1]->value());
+ }
+ return res;
+}
diff --git a/lib/Script/CMakeLists.txt b/lib/Script/CMakeLists.txt
new file mode 100644
index 0000000..6fed079
--- /dev/null
+++ b/lib/Script/CMakeLists.txt
@@ -0,0 +1,40 @@
+# flex+bison settings
+find_package(BISON)
+find_package(FLEX)
+BISON_TARGET(PARSER ScriptParser.yy ${CMAKE_CURRENT_BINARY_DIR}/ScriptParser.cpp)
+FLEX_TARGET(LEXER ScriptScanner.ll ${CMAKE_CURRENT_BINARY_DIR}/ScriptScanner.cpp)
+ADD_FLEX_BISON_DEPENDENCY(LEXER PARSER)
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+add_mcld_library(MCLDScript
+ AssertCmd.cpp
+ Assignment.cpp
+ BinaryOp.cpp
+ EntryCmd.cpp
+ FileToken.cpp
+ GroupCmd.cpp
+ InputSectDesc.cpp
+ InputToken.cpp
+ NameSpec.cpp
+ NullaryOp.cpp
+ Operand.cpp
+ Operator.cpp
+ OutputArchCmd.cpp
+ OutputCmd.cpp
+ OutputFormatCmd.cpp
+ OutputSectDesc.cpp
+ RpnEvaluator.cpp
+ RpnExpr.cpp
+ ScriptCommand.cpp
+ ScriptFile.cpp
+ ScriptReader.cpp
+ SearchDirCmd.cpp
+ SectionsCmd.cpp
+ StrToken.cpp
+ StringList.cpp
+ TernaryOp.cpp
+ UnaryOp.cpp
+ WildcardPattern.cpp
+ ${BISON_PARSER_OUTPUTS}
+ ${FLEX_LEXER_OUTPUTS}
+ )
diff --git a/lib/Script/EntryCmd.cpp b/lib/Script/EntryCmd.cpp
new file mode 100644
index 0000000..9e33c53
--- /dev/null
+++ b/lib/Script/EntryCmd.cpp
@@ -0,0 +1,40 @@
+//===- EntryCmd.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/EntryCmd.h>
+#include <mcld/Support/raw_ostream.h>
+#include <mcld/LinkerScript.h>
+#include <mcld/Module.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// EntryCmd
+//===----------------------------------------------------------------------===//
+EntryCmd::EntryCmd(const std::string& pEntry)
+ : ScriptCommand(ScriptCommand::ENTRY),
+ m_Entry(pEntry)
+{
+}
+
+EntryCmd::~EntryCmd()
+{
+}
+
+void EntryCmd::dump() const
+{
+ mcld::outs() << "ENTRY ( " << m_Entry << " )\n";
+}
+
+void EntryCmd::activate(Module& pModule)
+{
+ LinkerScript& script = pModule.getScript();
+ if (!script.hasEntry())
+ script.setEntry(m_Entry);
+}
+
diff --git a/lib/Script/FileToken.cpp b/lib/Script/FileToken.cpp
new file mode 100644
index 0000000..2247d6e
--- /dev/null
+++ b/lib/Script/FileToken.cpp
@@ -0,0 +1,51 @@
+//===- FileToken.cpp ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/FileToken.h>
+#include <mcld/Support/GCFactory.h>
+#include <llvm/Support/ManagedStatic.h>
+
+using namespace mcld;
+
+typedef GCFactory<FileToken, MCLD_SYMBOLS_PER_INPUT> FileTokenFactory;
+static llvm::ManagedStatic<FileTokenFactory> g_FileTokenFactory;
+
+//===----------------------------------------------------------------------===//
+// FileToken
+//===----------------------------------------------------------------------===//
+FileToken::FileToken()
+{
+}
+
+FileToken::FileToken(const std::string& pName, bool pAsNeeded)
+ : InputToken(InputToken::File, pName, pAsNeeded)
+{
+}
+
+FileToken::~FileToken()
+{
+}
+
+FileToken* FileToken::create(const std::string& pName, bool pAsNeeded)
+{
+ FileToken* result = g_FileTokenFactory->allocate();
+ new (result) FileToken(pName, pAsNeeded);
+ return result;
+}
+
+void FileToken::destroy(FileToken*& pFileToken)
+{
+ g_FileTokenFactory->destroy(pFileToken);
+ g_FileTokenFactory->deallocate(pFileToken);
+ pFileToken = NULL;
+}
+
+void FileToken::clear()
+{
+ g_FileTokenFactory->clear();
+}
diff --git a/lib/Script/GroupCmd.cpp b/lib/Script/GroupCmd.cpp
new file mode 100644
index 0000000..4673242
--- /dev/null
+++ b/lib/Script/GroupCmd.cpp
@@ -0,0 +1,165 @@
+//===- GroupCmd.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/GroupCmd.h>
+#include <mcld/Script/StringList.h>
+#include <mcld/Script/InputToken.h>
+#include <mcld/MC/InputBuilder.h>
+#include <mcld/MC/Attribute.h>
+#include <mcld/Support/Path.h>
+#include <mcld/Support/raw_ostream.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/InputTree.h>
+#include <mcld/LinkerScript.h>
+#include <mcld/LD/GroupReader.h>
+#include <llvm/Support/Casting.h>
+#include <cassert>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// GroupCmd
+//===----------------------------------------------------------------------===//
+GroupCmd::GroupCmd(StringList& pStringList,
+ InputTree& pInputTree,
+ InputBuilder& pBuilder,
+ GroupReader& pGroupReader,
+ const LinkerConfig& pConfig)
+ : ScriptCommand(ScriptCommand::GROUP),
+ m_StringList(pStringList),
+ m_InputTree(pInputTree),
+ m_Builder(pBuilder),
+ m_GroupReader(pGroupReader),
+ m_Config(pConfig)
+{
+}
+
+GroupCmd::~GroupCmd()
+{
+}
+
+void GroupCmd::dump() const
+{
+ mcld::outs() << "GROUP ( ";
+ bool prev = false, cur = false;
+ for (StringList::const_iterator it = m_StringList.begin(),
+ ie = m_StringList.end(); it != ie; ++it) {
+ assert((*it)->kind() == StrToken::Input);
+ InputToken* input = llvm::cast<InputToken>(*it);
+ cur = input->asNeeded();
+ if (!prev && cur)
+ mcld::outs() << "AS_NEEDED ( ";
+ else if (prev && !cur)
+ mcld::outs() << " )";
+
+ if (input->type() == InputToken::NameSpec)
+ mcld::outs() << "-l";
+ mcld::outs() << input->name() << " ";
+
+ prev = cur;
+ }
+
+ if (!m_StringList.empty() && prev)
+ mcld::outs() << " )";
+
+ mcld::outs() << " )\n";
+}
+
+void GroupCmd::activate(Module& pModule)
+{
+ LinkerScript& script = pModule.getScript();
+ // construct the Group tree
+ m_Builder.setCurrentTree(m_InputTree);
+ // --start-group
+ m_Builder.enterGroup();
+ InputTree::iterator group = m_Builder.getCurrentNode();
+
+ for (StringList::const_iterator it = m_StringList.begin(),
+ ie = m_StringList.end(); it != ie; ++it) {
+
+ assert((*it)->kind() == StrToken::Input);
+ InputToken* token = llvm::cast<InputToken>(*it);
+ if (token->asNeeded())
+ m_Builder.getAttributes().setAsNeeded();
+ else
+ m_Builder.getAttributes().unsetAsNeeded();
+
+ switch (token->type()) {
+ case InputToken::File: {
+ sys::fs::Path path;
+
+ // 1. Looking for file in the sysroot prefix, if a sysroot prefix is
+ // configured and the filename starts with '/'
+ if (script.hasSysroot() &&
+ (token->name().size() > 0 && token->name()[0] == '/')) {
+ path = script.sysroot();
+ path.append(token->name());
+ } else {
+ // 2. Try to open the file in CWD
+ path.assign(token->name());
+ if (!sys::fs::exists(path)) {
+ // 3. Search through the library search path
+ sys::fs::Path* p =
+ script.directories().find(token->name(), Input::Script);
+ if (p != NULL)
+ path = *p;
+ }
+ }
+
+ if (!sys::fs::exists(path))
+ fatal(diag::err_cannot_open_input) << path.filename() << path;
+
+ m_Builder.createNode<InputTree::Positional>(
+ path.filename().native(), path, Input::Unknown);
+ break;
+ }
+ case InputToken::NameSpec: {
+ const sys::fs::Path* path = NULL;
+ // find out the real path of the namespec.
+ if (m_Builder.getConstraint().isSharedSystem()) {
+ // In the system with shared object support, we can find both archive
+ // and shared object.
+ if (m_Builder.getAttributes().isStatic()) {
+ // with --static, we must search an archive.
+ path = script.directories().find(token->name(), Input::Archive);
+ } else {
+ // otherwise, with --Bdynamic, we can find either an archive or a
+ // shared object.
+ path = script.directories().find(token->name(), Input::DynObj);
+ }
+ } else {
+ // In the system without shared object support, only look for an archive
+ path = script.directories().find(token->name(), Input::Archive);
+ }
+
+ if (NULL == path)
+ fatal(diag::err_cannot_find_namespec) << token->name();
+
+ m_Builder.createNode<InputTree::Positional>(
+ token->name(), *path, Input::Unknown);
+ break;
+ }
+ default:
+ assert(0 && "Invalid script token in GROUP!");
+ break;
+ } // end of switch
+
+ Input* input = *m_Builder.getCurrentNode();
+ assert(input != NULL);
+ if (!m_Builder.setMemory(*input, FileHandle::ReadOnly))
+ error(diag::err_cannot_open_input) << input->name() << input->path();
+ m_Builder.setContext(*input);
+ }
+
+ // --end-group
+ m_Builder.exitGroup();
+
+ // read the group
+ m_GroupReader.readGroup(group, m_InputTree.end(), m_Builder, m_Config);
+}
+
diff --git a/lib/Script/InputSectDesc.cpp b/lib/Script/InputSectDesc.cpp
new file mode 100644
index 0000000..842b720
--- /dev/null
+++ b/lib/Script/InputSectDesc.cpp
@@ -0,0 +1,102 @@
+//===- InputSectDesc.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/InputSectDesc.h>
+#include <mcld/Script/WildcardPattern.h>
+#include <mcld/Support/raw_ostream.h>
+#include <mcld/LinkerScript.h>
+#include <mcld/Module.h>
+#include <llvm/Support/Casting.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// InputSectDesc
+//===----------------------------------------------------------------------===//
+InputSectDesc::InputSectDesc(KeepPolicy pPolicy,
+ const Spec& pSpec,
+ const OutputSectDesc& pOutputDesc)
+ : ScriptCommand(ScriptCommand::INPUT_SECT_DESC),
+ m_KeepPolicy(pPolicy),
+ m_Spec(pSpec),
+ m_OutputSectDesc(pOutputDesc)
+{
+}
+
+InputSectDesc::~InputSectDesc()
+{
+}
+
+void InputSectDesc::dump() const
+{
+ if (m_KeepPolicy == Keep)
+ mcld::outs() << "KEEP (";
+
+ assert (m_Spec.hasFile());
+ if (m_Spec.file().sortPolicy() == WildcardPattern::SORT_BY_NAME)
+ mcld::outs() << "SORT (";
+
+ mcld::outs() << m_Spec.file().name();
+
+ if (m_Spec.hasSections()) {
+ mcld::outs() << "(";
+
+ if (m_Spec.hasExcludeFiles()) {
+ mcld::outs() << "EXCLUDE_FILE (";
+ for (StringList::const_iterator it = m_Spec.excludeFiles().begin(),
+ ie = m_Spec.excludeFiles().end(); it != ie; ++it) {
+ mcld::outs() << (*it)->name() << " ";
+ }
+ mcld::outs() << ")";
+ }
+
+ if (m_Spec.hasSections()) {
+ for (StringList::const_iterator it = m_Spec.sections().begin(),
+ ie = m_Spec.sections().end(); it != ie; ++it) {
+ assert((*it)->kind() == StrToken::Wildcard);
+ WildcardPattern* wildcard = llvm::cast<WildcardPattern>(*it);
+
+ switch (wildcard->sortPolicy()) {
+ case WildcardPattern::SORT_BY_NAME:
+ mcld::outs() << "SORT (";
+ break;
+ case WildcardPattern::SORT_BY_ALIGNMENT:
+ mcld::outs() << "SORT_BY_ALIGNMENT (";
+ break;
+ case WildcardPattern::SORT_BY_NAME_ALIGNMENT:
+ mcld::outs() << "SORT_BY_NAME_ALIGNMENT (";
+ break;
+ case WildcardPattern::SORT_BY_ALIGNMENT_NAME:
+ mcld::outs() << "SORT_BY_ALIGNMENT_NAME (";
+ break;
+ default:
+ break;
+ }
+
+ mcld::outs() << wildcard->name() << " ";
+
+ if (wildcard->sortPolicy() != WildcardPattern::SORT_NONE)
+ mcld::outs() << ")";
+ }
+ }
+ mcld::outs() << ")";
+ }
+
+ if (m_Spec.file().sortPolicy() == WildcardPattern::SORT_BY_NAME)
+ mcld::outs() << ")";
+
+ if (m_KeepPolicy == Keep)
+ mcld::outs() << ")";
+
+ mcld::outs() << "\n";
+}
+
+void InputSectDesc::activate(Module& pModule)
+{
+ pModule.getScript().sectionMap().insert(*this, m_OutputSectDesc);
+}
diff --git a/lib/Script/InputToken.cpp b/lib/Script/InputToken.cpp
new file mode 100644
index 0000000..45b006a
--- /dev/null
+++ b/lib/Script/InputToken.cpp
@@ -0,0 +1,28 @@
+//===- InputToken.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/InputToken.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// InputToken
+//===----------------------------------------------------------------------===//
+InputToken::InputToken()
+ : m_Type(Unknown), m_bAsNeeded(false)
+{
+}
+
+InputToken::InputToken(Type pType, const std::string& pName, bool pAsNeeded)
+ : StrToken(StrToken::Input, pName), m_Type(pType), m_bAsNeeded(pAsNeeded)
+{
+}
+
+InputToken::~InputToken()
+{
+}
diff --git a/lib/Script/NameSpec.cpp b/lib/Script/NameSpec.cpp
new file mode 100644
index 0000000..da7a62c
--- /dev/null
+++ b/lib/Script/NameSpec.cpp
@@ -0,0 +1,51 @@
+//===- NameSpec.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/NameSpec.h>
+#include <mcld/Support/GCFactory.h>
+#include <llvm/Support/ManagedStatic.h>
+
+using namespace mcld;
+
+typedef GCFactory<NameSpec, MCLD_SYMBOLS_PER_INPUT> NameSpecFactory;
+static llvm::ManagedStatic<NameSpecFactory> g_NameSpecFactory;
+
+//===----------------------------------------------------------------------===//
+// NameSpec
+//===----------------------------------------------------------------------===//
+NameSpec::NameSpec()
+{
+}
+
+NameSpec::NameSpec(const std::string& pName, bool pAsNeeded)
+ : InputToken(InputToken::NameSpec, pName, pAsNeeded)
+{
+}
+
+NameSpec::~NameSpec()
+{
+}
+
+NameSpec* NameSpec::create(const std::string& pName, bool pAsNeeded)
+{
+ NameSpec* result = g_NameSpecFactory->allocate();
+ new (result) NameSpec(pName, pAsNeeded);
+ return result;
+}
+
+void NameSpec::destroy(NameSpec*& pNameSpec)
+{
+ g_NameSpecFactory->destroy(pNameSpec);
+ g_NameSpecFactory->deallocate(pNameSpec);
+ pNameSpec = NULL;
+}
+
+void NameSpec::clear()
+{
+ g_NameSpecFactory->clear();
+}
diff --git a/lib/Script/NullaryOp.cpp b/lib/Script/NullaryOp.cpp
new file mode 100644
index 0000000..69382ec
--- /dev/null
+++ b/lib/Script/NullaryOp.cpp
@@ -0,0 +1,45 @@
+//===- NullaryOp.cpp ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/NullaryOp.h>
+#include <mcld/Script/Operand.h>
+#include <mcld/Target/TargetLDBackend.h>
+
+using namespace mcld;
+//===----------------------------------------------------------------------===//
+// NullaryOp
+//===----------------------------------------------------------------------===//
+template<>
+IntOperand*
+NullaryOp<Operator::SIZEOF_HEADERS>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(pBackend.sectionStartOffset());
+ return res;
+}
+
+template<>
+IntOperand*
+NullaryOp<Operator::MAXPAGESIZE>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(pBackend.abiPageSize());
+ return res;
+}
+
+template<>
+IntOperand*
+NullaryOp<Operator::COMMONPAGESIZE>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(pBackend.commonPageSize());
+ return res;
+}
diff --git a/lib/Script/Operand.cpp b/lib/Script/Operand.cpp
new file mode 100644
index 0000000..690ba9b
--- /dev/null
+++ b/lib/Script/Operand.cpp
@@ -0,0 +1,241 @@
+//===- Operand.cpp --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/Operand.h>
+#include <mcld/Support/raw_ostream.h>
+#include <mcld/Support/GCFactory.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/SectionData.h>
+#include <mcld/Fragment/Fragment.h>
+#include <llvm/Support/ManagedStatic.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// Operand
+//===----------------------------------------------------------------------===//
+Operand::Operand(Type pType)
+ : ExprToken(ExprToken::OPERAND), m_Type(pType)
+{
+}
+
+Operand::~Operand()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// SymOperand
+//===----------------------------------------------------------------------===//
+typedef GCFactory<SymOperand, MCLD_SYMBOLS_PER_INPUT> SymOperandFactory;
+static llvm::ManagedStatic<SymOperandFactory> g_SymOperandFactory;
+
+SymOperand::SymOperand()
+ : Operand(Operand::SYMBOL), m_Value(0)
+{
+}
+
+SymOperand::SymOperand(const std::string& pName)
+ : Operand(Operand::SYMBOL), m_Name(pName), m_Value(0)
+{
+}
+
+void SymOperand::dump() const
+{
+ mcld::outs() << m_Name;
+}
+
+bool SymOperand::isDot() const
+{
+ assert(!m_Name.empty());
+ return m_Name.size() == 1 && m_Name[0] == '.';
+}
+
+SymOperand* SymOperand::create(const std::string& pName)
+{
+ SymOperand* result = g_SymOperandFactory->allocate();
+ new (result) SymOperand(pName);
+ return result;
+}
+
+void SymOperand::destroy(SymOperand*& pOperand)
+{
+ g_SymOperandFactory->destroy(pOperand);
+ g_SymOperandFactory->deallocate(pOperand);
+ pOperand = NULL;
+}
+
+void SymOperand::clear()
+{
+ g_SymOperandFactory->clear();
+}
+
+//===----------------------------------------------------------------------===//
+// IntOperand
+//===----------------------------------------------------------------------===//
+typedef GCFactory<IntOperand, MCLD_SYMBOLS_PER_INPUT> IntOperandFactory;
+static llvm::ManagedStatic<IntOperandFactory> g_IntOperandFactory;
+
+IntOperand::IntOperand()
+ : Operand(Operand::INTEGER), m_Value(0)
+{
+}
+
+IntOperand::IntOperand(uint64_t pValue)
+ : Operand(Operand::INTEGER), m_Value(pValue)
+{
+}
+
+void IntOperand::dump() const
+{
+ mcld::outs() << m_Value;
+}
+
+IntOperand* IntOperand::create(uint64_t pValue)
+{
+ IntOperand* result = g_IntOperandFactory->allocate();
+ new (result) IntOperand(pValue);
+ return result;
+}
+
+void IntOperand::destroy(IntOperand*& pOperand)
+{
+ g_IntOperandFactory->destroy(pOperand);
+ g_IntOperandFactory->deallocate(pOperand);
+ pOperand = NULL;
+}
+
+void IntOperand::clear()
+{
+ g_IntOperandFactory->clear();
+}
+
+//===----------------------------------------------------------------------===//
+// SectOperand
+//===----------------------------------------------------------------------===//
+typedef GCFactory<SectOperand, MCLD_SECTIONS_PER_INPUT> SectOperandFactory;
+static llvm::ManagedStatic<SectOperandFactory> g_SectOperandFactory;
+SectOperand::SectOperand()
+ : Operand(Operand::SECTION)
+{
+}
+
+SectOperand::SectOperand(const std::string& pName)
+ : Operand(Operand::SECTION), m_Name(pName)
+{
+}
+
+void SectOperand::dump() const
+{
+ mcld::outs() << m_Name;
+}
+
+SectOperand* SectOperand::create(const std::string& pName)
+{
+ SectOperand* result = g_SectOperandFactory->allocate();
+ new (result) SectOperand(pName);
+ return result;
+}
+
+void SectOperand::destroy(SectOperand*& pOperand)
+{
+ g_SectOperandFactory->destroy(pOperand);
+ g_SectOperandFactory->deallocate(pOperand);
+ pOperand = NULL;
+}
+
+void SectOperand::clear()
+{
+ g_SectOperandFactory->clear();
+}
+
+//===----------------------------------------------------------------------===//
+// SectDescOperand
+//===----------------------------------------------------------------------===//
+typedef GCFactory<SectDescOperand,
+ MCLD_SECTIONS_PER_INPUT> SectDescOperandFactory;
+static llvm::ManagedStatic<SectDescOperandFactory> g_SectDescOperandFactory;
+SectDescOperand::SectDescOperand()
+ : Operand(Operand::SECTION_DESC), m_pOutputDesc(NULL)
+{
+}
+
+SectDescOperand::SectDescOperand(const SectionMap::Output* pOutputDesc)
+ : Operand(Operand::SECTION_DESC), m_pOutputDesc(pOutputDesc)
+{
+}
+
+void SectDescOperand::dump() const
+{
+ assert(m_pOutputDesc != NULL);
+ mcld::outs() << m_pOutputDesc->getSection()->name();
+}
+
+SectDescOperand* SectDescOperand::create(const SectionMap::Output* pOutputDesc)
+{
+ SectDescOperand* result = g_SectDescOperandFactory->allocate();
+ new (result) SectDescOperand(pOutputDesc);
+ return result;
+}
+
+void SectDescOperand::destroy(SectDescOperand*& pOperand)
+{
+ g_SectDescOperandFactory->destroy(pOperand);
+ g_SectDescOperandFactory->deallocate(pOperand);
+ pOperand = NULL;
+}
+
+void SectDescOperand::clear()
+{
+ g_SectDescOperandFactory->clear();
+}
+
+//===----------------------------------------------------------------------===//
+// FragOperand
+//===----------------------------------------------------------------------===//
+typedef GCFactory<FragOperand, MCLD_SYMBOLS_PER_INPUT> FragOperandFactory;
+static llvm::ManagedStatic<FragOperandFactory> g_FragOperandFactory;
+
+FragOperand::FragOperand()
+ : Operand(Operand::FRAGMENT), m_pFragment(NULL)
+{
+}
+
+FragOperand::FragOperand(Fragment& pFragment)
+ : Operand(Operand::FRAGMENT), m_pFragment(&pFragment)
+{
+}
+
+void FragOperand::dump() const
+{
+ mcld::outs() << "fragment";
+}
+
+uint64_t FragOperand::value() const
+{
+ return m_pFragment->getOffset() +
+ m_pFragment->getParent()->getSection().addr();
+}
+
+FragOperand* FragOperand::create(Fragment& pFragment)
+{
+ FragOperand* result = g_FragOperandFactory->allocate();
+ new (result) FragOperand(pFragment);
+ return result;
+}
+
+void FragOperand::destroy(FragOperand*& pOperand)
+{
+ g_FragOperandFactory->destroy(pOperand);
+ g_FragOperandFactory->deallocate(pOperand);
+ pOperand = NULL;
+}
+
+void FragOperand::clear()
+{
+ g_FragOperandFactory->clear();
+}
diff --git a/lib/Script/Operator.cpp b/lib/Script/Operator.cpp
new file mode 100644
index 0000000..e50a255
--- /dev/null
+++ b/lib/Script/Operator.cpp
@@ -0,0 +1,390 @@
+//===- Operator.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/Operator.h>
+#include <mcld/Script/NullaryOp.h>
+#include <mcld/Script/UnaryOp.h>
+#include <mcld/Script/BinaryOp.h>
+#include <mcld/Script/TernaryOp.h>
+#include <mcld/Script/Operand.h>
+#include <mcld/Support/raw_ostream.h>
+
+using namespace mcld;
+//===----------------------------------------------------------------------===//
+// Operator
+//===----------------------------------------------------------------------===//
+const char* Operator::OpNames[] = {
+ "+",
+ "-",
+ "!",
+ "~",
+ "*",
+ "/",
+ "%",
+ "+",
+ "-",
+ "<<",
+ ">>",
+ "<",
+ "<=",
+ ">",
+ ">=",
+ "==",
+ "!=",
+ "&",
+ "^",
+ "|",
+ "&&",
+ "||",
+ "?:",
+ "=",
+ "+=",
+ "-=",
+ "*=",
+ "/=",
+ "&=",
+ "|=",
+ "<<=",
+ ">>=",
+ "ABSOLUTE",
+ "ADDR",
+ "ALIGN",
+ "ALIGNOF",
+ "BLOCK",
+ "DATA_SEGMENT_ALIGN",
+ "DATA_SEGMENT_END",
+ "DATA_SEGMENT_RELRO_END",
+ "DEFINED",
+ "LENGTH",
+ "LOADADDR",
+ "MAX",
+ "MIN",
+ "NEXT",
+ "ORIGIN",
+ "SEGMENT_START",
+ "SIZEOF",
+ "SIZEOF_HEADERS",
+ "MAXPAGESIZE",
+ "COMMONPAGESIZE"
+};
+
+Operator::Operator(Arity pArity,
+ Type pType)
+ : ExprToken(ExprToken::OPERATOR),
+ m_Arity(pArity),
+ m_Type(pType)
+{
+ m_pIntOperand = IntOperand::create(0);
+}
+
+Operator::~Operator()
+{
+}
+
+void Operator::dump() const
+{
+ mcld::outs() << OpNames[type()];
+}
+
+/* Nullary operator */
+template<>
+Operator& Operator::create<Operator::SIZEOF_HEADERS>()
+{
+ static NullaryOp<Operator::SIZEOF_HEADERS> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::MAXPAGESIZE>()
+{
+ static NullaryOp<Operator::MAXPAGESIZE> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::COMMONPAGESIZE>()
+{
+ static NullaryOp<Operator::COMMONPAGESIZE> op;
+ return op;
+}
+
+/* Unary operator */
+template<>
+Operator& Operator::create<Operator::UNARY_PLUS>()
+{
+ static UnaryOp<Operator::UNARY_PLUS> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::UNARY_MINUS>()
+{
+ static UnaryOp<Operator::UNARY_MINUS> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::LOGICAL_NOT>()
+{
+ static UnaryOp<Operator::LOGICAL_NOT> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::BITWISE_NOT>()
+{
+ static UnaryOp<Operator::BITWISE_NOT> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::ABSOLUTE>()
+{
+ static UnaryOp<Operator::ABSOLUTE> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::ADDR>()
+{
+ static UnaryOp<Operator::ADDR> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::ALIGNOF>()
+{
+ static UnaryOp<Operator::ALIGNOF> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::DATA_SEGMENT_END>()
+{
+ static UnaryOp<Operator::DATA_SEGMENT_END> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::DEFINED>()
+{
+ static UnaryOp<Operator::DEFINED> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::LENGTH>()
+{
+ static UnaryOp<Operator::LENGTH> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::LOADADDR>()
+{
+ static UnaryOp<Operator::LOADADDR> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::NEXT>()
+{
+ static UnaryOp<Operator::NEXT> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::ORIGIN>()
+{
+ static UnaryOp<Operator::ORIGIN> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::SIZEOF>()
+{
+ static UnaryOp<Operator::SIZEOF> op;
+ return op;
+}
+
+/* Binary operator */
+template<>
+Operator& Operator::create<Operator::MUL>()
+{
+ static BinaryOp<Operator::MUL> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::DIV>()
+{
+ static BinaryOp<Operator::DIV> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::MOD>()
+{
+ static BinaryOp<Operator::MOD> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::ADD>()
+{
+ static BinaryOp<Operator::ADD> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::SUB>()
+{
+ static BinaryOp<Operator::SUB> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::LSHIFT>()
+{
+ static BinaryOp<Operator::LSHIFT> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::RSHIFT>()
+{
+ static BinaryOp<Operator::RSHIFT> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::LT>()
+{
+ static BinaryOp<Operator::LT> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::LE>()
+{
+ static BinaryOp<Operator::LE> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::GT>()
+{
+ static BinaryOp<Operator::GT> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::GE>()
+{
+ static BinaryOp<Operator::GE> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::EQ>()
+{
+ static BinaryOp<Operator::EQ> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::NE>()
+{
+ static BinaryOp<Operator::NE> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::BITWISE_AND>()
+{
+ static BinaryOp<Operator::BITWISE_AND> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::BITWISE_XOR>()
+{
+ static BinaryOp<Operator::BITWISE_XOR> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::BITWISE_OR>()
+{
+ static BinaryOp<Operator::BITWISE_OR> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::LOGICAL_AND>()
+{
+ static BinaryOp<Operator::LOGICAL_AND> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::LOGICAL_OR>()
+{
+ static BinaryOp<Operator::LOGICAL_OR> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::ALIGN>()
+{
+ static BinaryOp<Operator::ALIGN> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::DATA_SEGMENT_RELRO_END>()
+{
+ static BinaryOp<Operator::DATA_SEGMENT_RELRO_END> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::MAX>()
+{
+ static BinaryOp<Operator::MAX> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::MIN>()
+{
+ static BinaryOp<Operator::MIN> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::SEGMENT_START>()
+{
+ static BinaryOp<Operator::SEGMENT_START> op;
+ return op;
+}
+
+/* Ternary operator */
+template<>
+Operator& Operator::create<Operator::TERNARY_IF>()
+{
+ static TernaryOp<Operator::TERNARY_IF> op;
+ return op;
+}
+
+template<>
+Operator& Operator::create<Operator::DATA_SEGMENT_ALIGN>()
+{
+ static TernaryOp<Operator::DATA_SEGMENT_ALIGN> op;
+ return op;
+}
diff --git a/lib/Script/OutputArchCmd.cpp b/lib/Script/OutputArchCmd.cpp
new file mode 100644
index 0000000..4393b84
--- /dev/null
+++ b/lib/Script/OutputArchCmd.cpp
@@ -0,0 +1,36 @@
+//===- OutputArchCmd.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/OutputArchCmd.h>
+#include <mcld/Support/raw_ostream.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// OutputArchCmd
+//===----------------------------------------------------------------------===//
+OutputArchCmd::OutputArchCmd(const std::string& pArch)
+ : ScriptCommand(ScriptCommand::OUTPUT_ARCH),
+ m_Arch(pArch)
+{
+}
+
+OutputArchCmd::~OutputArchCmd()
+{
+}
+
+void OutputArchCmd::dump() const
+{
+ mcld::outs() << "OUTPUT_ARCH ( " << m_Arch << " )\n";
+}
+
+void OutputArchCmd::activate(Module& pModule)
+{
+ // TODO
+}
+
diff --git a/lib/Script/OutputCmd.cpp b/lib/Script/OutputCmd.cpp
new file mode 100644
index 0000000..c37adcc
--- /dev/null
+++ b/lib/Script/OutputCmd.cpp
@@ -0,0 +1,41 @@
+//===- OutputCmd.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/OutputCmd.h>
+#include <mcld/Support/raw_ostream.h>
+#include <mcld/LinkerScript.h>
+#include <mcld/Module.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// OutputCmd
+//===----------------------------------------------------------------------===//
+OutputCmd::OutputCmd(const std::string& pOutputFile)
+ : ScriptCommand(ScriptCommand::OUTPUT),
+ m_OutputFile(pOutputFile)
+{
+}
+
+OutputCmd::~OutputCmd()
+{
+}
+
+void OutputCmd::dump() const
+{
+ mcld::outs() << "OUTPUT ( " << m_OutputFile << " )\n";
+}
+
+void OutputCmd::activate(Module& pModule)
+{
+ pModule.getScript().setOutputFile(m_OutputFile);
+ // TODO: set the output name if there is no `-o filename' on the cmdline.
+ // This option is to define a default name for the output file other than the
+ // usual default of a.out.
+}
+
diff --git a/lib/Script/OutputFormatCmd.cpp b/lib/Script/OutputFormatCmd.cpp
new file mode 100644
index 0000000..eca9df5
--- /dev/null
+++ b/lib/Script/OutputFormatCmd.cpp
@@ -0,0 +1,53 @@
+//===- OutputFormatCmd.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/OutputFormatCmd.h>
+#include <mcld/Support/raw_ostream.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// OutputFormatCmd
+//===----------------------------------------------------------------------===//
+OutputFormatCmd::OutputFormatCmd(const std::string& pFormat)
+ : ScriptCommand(ScriptCommand::OUTPUT_FORMAT)
+{
+ m_FormatList.push_back(pFormat);
+}
+
+OutputFormatCmd::OutputFormatCmd(const std::string& pDefault,
+ const std::string& pBig,
+ const std::string& pLittle)
+ : ScriptCommand(ScriptCommand::OUTPUT_FORMAT)
+{
+ m_FormatList.push_back(pDefault);
+ m_FormatList.push_back(pBig);
+ m_FormatList.push_back(pLittle);
+}
+
+OutputFormatCmd::~OutputFormatCmd()
+{
+}
+
+void OutputFormatCmd::dump() const
+{
+ mcld::outs() << "OUTPUT_FORMAT ( ";
+ assert(m_FormatList.size() == 1 || m_FormatList.size() == 3);
+ for (size_t i = 0; i < m_FormatList.size(); ++i) {
+ if (i != 0)
+ mcld::outs() << " , ";
+ mcld::outs() << m_FormatList[i];
+ }
+ mcld::outs() << " )\n";
+}
+
+void OutputFormatCmd::activate(Module& pModule)
+{
+ // TODO
+}
+
diff --git a/lib/Script/OutputSectDesc.cpp b/lib/Script/OutputSectDesc.cpp
new file mode 100644
index 0000000..3442c4e
--- /dev/null
+++ b/lib/Script/OutputSectDesc.cpp
@@ -0,0 +1,196 @@
+//===- OutputSectDesc.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/OutputSectDesc.h>
+#include <mcld/Script/RpnExpr.h>
+#include <mcld/Script/StringList.h>
+#include <mcld/Script/StrToken.h>
+#include <mcld/Script/InputSectDesc.h>
+#include <mcld/Support/raw_ostream.h>
+#include <mcld/LinkerScript.h>
+#include <mcld/Module.h>
+#include <llvm/Support/Casting.h>
+#include <cassert>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// OutputSectDesc
+//===----------------------------------------------------------------------===//
+OutputSectDesc::OutputSectDesc(const std::string& pName,
+ const Prolog& pProlog)
+ : ScriptCommand(ScriptCommand::OUTPUT_SECT_DESC),
+ m_Name(pName),
+ m_Prolog(pProlog)
+{
+}
+
+OutputSectDesc::~OutputSectDesc()
+{
+ for (iterator it = begin(), ie = end(); it != ie; ++it) {
+ if (*it != NULL)
+ delete *it;
+ }
+}
+
+void OutputSectDesc::dump() const
+{
+ mcld::outs() << m_Name << "\t";
+
+ if (m_Prolog.hasVMA()) {
+ m_Prolog.vma().dump();
+ mcld::outs() << "\t";
+ }
+
+ switch (m_Prolog.type()) {
+ case NOLOAD:
+ mcld::outs() << "(NOLOAD)";
+ break;
+ case DSECT:
+ mcld::outs() << "(DSECT)";
+ break;
+ case COPY:
+ mcld::outs() << "(COPY)";
+ break;
+ case INFO:
+ mcld::outs() << "(INFO)";
+ break;
+ case OVERLAY:
+ mcld::outs() << "(OVERLAY)";
+ break;
+ default:
+ break;
+ }
+ mcld::outs() << ":\n";
+
+ if (m_Prolog.hasLMA()) {
+ mcld::outs() << "\tAT ( ";
+ m_Prolog.lma().dump();
+ mcld::outs() << " )\n";
+ }
+
+ if (m_Prolog.hasAlign()) {
+ mcld::outs() << "\tALIGN ( ";
+ m_Prolog.align().dump();
+ mcld::outs() << " )\n";
+ }
+
+ if (m_Prolog.hasSubAlign()) {
+ mcld::outs() << "\tSUBALIGN ( ";
+ m_Prolog.subAlign().dump();
+ mcld::outs() << " )\n";
+ }
+
+ switch (m_Prolog.constraint()) {
+ case ONLY_IF_RO:
+ mcld::outs() << "\tONLY_IF_RO\n";
+ break;
+ case ONLY_IF_RW:
+ mcld::outs() << "\tONLY_IF_RW\n";
+ break;
+ default:
+ break;
+ }
+
+ mcld::outs() << "\t{\n";
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ switch ((*it)->getKind()) {
+ case ScriptCommand::ASSIGNMENT:
+ case ScriptCommand::INPUT_SECT_DESC:
+ mcld::outs() << "\t\t";
+ (*it)->dump();
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+ mcld::outs() << "\t}";
+
+ if (m_Epilog.hasRegion())
+ mcld::outs() << "\t>" << m_Epilog.region();
+ if (m_Epilog.hasLMARegion())
+ mcld::outs() << "\tAT>" << m_Epilog.lmaRegion();
+
+ if (m_Epilog.hasPhdrs()) {
+ for (StringList::const_iterator it = m_Epilog.phdrs().begin(),
+ ie = m_Epilog.phdrs().end(); it != ie; ++it) {
+ assert((*it)->kind() == StrToken::String);
+ mcld::outs() << ":" << (*it)->name() << " ";
+ }
+ }
+
+ if (m_Epilog.hasFillExp()) {
+ mcld::outs() << "= ";
+ m_Epilog.fillExp().dump();
+ }
+ mcld::outs() << "\n";
+}
+
+void OutputSectDesc::push_back(ScriptCommand* pCommand)
+{
+ switch (pCommand->getKind()) {
+ case ScriptCommand::ASSIGNMENT:
+ case ScriptCommand::INPUT_SECT_DESC:
+ m_OutputSectCmds.push_back(pCommand);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+}
+
+void OutputSectDesc::setEpilog(const Epilog& pEpilog)
+{
+ m_Epilog.m_pRegion = pEpilog.m_pRegion;
+ m_Epilog.m_pLMARegion = pEpilog.m_pLMARegion;
+ m_Epilog.m_pPhdrs = pEpilog.m_pPhdrs;
+ m_Epilog.m_pFillExp = pEpilog.m_pFillExp;
+}
+
+void OutputSectDesc::activate(Module& pModule)
+{
+ // Assignment in an output section
+ OutputSectCmds assignments;
+
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ switch ((*it)->getKind()) {
+ case ScriptCommand::ASSIGNMENT:
+ assignments.push_back(*it);
+ break;
+ case ScriptCommand::INPUT_SECT_DESC: {
+ (*it)->activate(pModule);
+
+ for (iterator assign = assignments.begin(), assignEnd = assignments.end();
+ assign != assignEnd; ++assign) {
+ (*assign)->activate(pModule);
+ }
+ assignments.clear();
+ break;
+ }
+ default:
+ assert(0);
+ break;
+ }
+ }
+
+ if (!assignments.empty()) {
+ InputSectDesc::Spec spec;;
+ spec.m_pWildcardFile = NULL;
+ spec.m_pExcludeFiles = NULL;
+ spec.m_pWildcardSections = NULL;
+ InputSectDesc inputDesc(InputSectDesc::Keep, spec, *this);
+ pModule.getScript().sectionMap().insert(inputDesc, *this);
+
+ for (iterator assign = assignments.begin(), assignEnd = assignments.end();
+ assign != assignEnd; ++assign) {
+ (*assign)->activate(pModule);
+ }
+ assignments.clear();
+ }
+}
diff --git a/lib/Script/RpnEvaluator.cpp b/lib/Script/RpnEvaluator.cpp
new file mode 100644
index 0000000..52cb79f
--- /dev/null
+++ b/lib/Script/RpnEvaluator.cpp
@@ -0,0 +1,114 @@
+//===- RpnEvaluator.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/LD/LDSymbol.h>
+#include <mcld/Script/RpnExpr.h>
+#include <mcld/Script/RpnEvaluator.h>
+#include <mcld/Script/ExprToken.h>
+#include <mcld/Script/Operator.h>
+#include <mcld/Script/Operand.h>
+#include <mcld/Module.h>
+#include <llvm/Support/Casting.h>
+#include <llvm/Support/DataTypes.h>
+#include <stack>
+#include <cassert>
+
+using namespace mcld;
+
+RpnEvaluator::RpnEvaluator(const Module& pModule,
+ const TargetLDBackend& pBackend)
+ : m_Module(pModule),
+ m_Backend(pBackend)
+{
+}
+
+bool RpnEvaluator::eval(const RpnExpr& pExpr, uint64_t& pResult)
+{
+ std::stack<Operand*> operandStack;
+ for (RpnExpr::const_iterator it = pExpr.begin(), ie = pExpr.end(); it != ie;
+ ++it) {
+ switch((*it)->kind()) {
+ case ExprToken::OPERATOR: {
+ Operator* op = llvm::cast<Operator>(*it);
+ switch (op->arity()) {
+ case Operator::NULLARY: {
+ operandStack.push(op->eval(m_Module, m_Backend));
+ break;
+ }
+ case Operator::UNARY: {
+ Operand* opd = operandStack.top();
+ operandStack.pop();
+ op->appendOperand(opd);
+ operandStack.push(op->eval(m_Module, m_Backend));
+ break;
+ }
+ case Operator::BINARY: {
+ Operand* opd2 = operandStack.top();
+ operandStack.pop();
+ Operand* opd1 = operandStack.top();
+ operandStack.pop();
+ op->appendOperand(opd1);
+ op->appendOperand(opd2);
+ operandStack.push(op->eval(m_Module, m_Backend));
+ break;
+ }
+ case Operator::TERNARY: {
+ Operand* opd3 = operandStack.top();
+ operandStack.pop();
+ Operand* opd2 = operandStack.top();
+ operandStack.pop();
+ Operand* opd1 = operandStack.top();
+ operandStack.pop();
+ op->appendOperand(opd1);
+ op->appendOperand(opd2);
+ op->appendOperand(opd3);
+ operandStack.push(op->eval(m_Module, m_Backend));
+ break;
+ }
+ } // end of switch operator arity
+ break;
+ }
+
+ case ExprToken::OPERAND: {
+ Operand* opd = llvm::cast<Operand>(*it);
+ switch (opd->type()) {
+ case Operand::SYMBOL: {
+ // It's possible that there are no operators in an expression, so
+ // we set up symbol operand here.
+ if (!opd->isDot()) {
+ SymOperand* sym_opd = llvm::cast<SymOperand>(opd);
+ const LDSymbol* symbol =
+ m_Module.getNamePool().findSymbol(sym_opd->name());
+ if (symbol == NULL) {
+ fatal(diag::fail_sym_resolution) << __FILE__ << __LINE__
+ << "mclinker@googlegroups.com";
+ }
+ sym_opd->setValue(symbol->value());
+ }
+ operandStack.push(opd);
+ break;
+ }
+ default:
+ operandStack.push(opd);
+ break;
+ } // end of switch operand type
+ break;
+ }
+
+ } // end of switch
+ } // end of for
+
+ // stack top is result
+ assert(operandStack.top()->type() == Operand::SYMBOL ||
+ operandStack.top()->type() == Operand::INTEGER ||
+ operandStack.top()->type() == Operand::FRAGMENT);
+ pResult = operandStack.top()->value();
+ return true;
+}
+
diff --git a/lib/Script/RpnExpr.cpp b/lib/Script/RpnExpr.cpp
new file mode 100644
index 0000000..a9a4cae
--- /dev/null
+++ b/lib/Script/RpnExpr.cpp
@@ -0,0 +1,105 @@
+//===- RPNExpr.cpp --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/RpnExpr.h>
+#include <mcld/Script/ExprToken.h>
+#include <mcld/Script/Operand.h>
+#include <mcld/Script/Operator.h>
+#include <mcld/Support/GCFactory.h>
+#include <mcld/Support/raw_ostream.h>
+#include <llvm/Support/ManagedStatic.h>
+#include <llvm/Support/Casting.h>
+
+using namespace mcld;
+
+typedef GCFactory<RpnExpr, MCLD_SYMBOLS_PER_INPUT> ExprFactory;
+static llvm::ManagedStatic<ExprFactory> g_ExprFactory;
+
+//===----------------------------------------------------------------------===//
+// RpnExpr
+//===----------------------------------------------------------------------===//
+RpnExpr::RpnExpr()
+{
+}
+
+RpnExpr::~RpnExpr()
+{
+}
+
+bool RpnExpr::hasDot() const
+{
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ if ((*it)->kind() == ExprToken::OPERAND &&
+ llvm::cast<Operand>(*it)->isDot())
+ return true;
+ }
+ return false;
+}
+
+void RpnExpr::dump() const
+{
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ (*it)->dump();
+ mcld::outs() << " ";
+ }
+}
+
+void RpnExpr::push_back(ExprToken* pToken)
+{
+ m_TokenQueue.push_back(pToken);
+}
+
+RpnExpr* RpnExpr::create()
+{
+ RpnExpr* result = g_ExprFactory->allocate();
+ new (result) RpnExpr();
+ return result;
+}
+
+void RpnExpr::destroy(RpnExpr*& pRpnExpr)
+{
+ g_ExprFactory->destroy(pRpnExpr);
+ g_ExprFactory->deallocate(pRpnExpr);
+ pRpnExpr = NULL;
+}
+
+void RpnExpr::clear()
+{
+ g_ExprFactory->clear();
+}
+
+RpnExpr::iterator RpnExpr::insert(iterator pPosition, ExprToken* pToken)
+{
+ return m_TokenQueue.insert(pPosition, pToken);
+}
+
+void RpnExpr::erase(iterator pPosition)
+{
+ m_TokenQueue.erase(pPosition);
+}
+
+// buildHelperExpr - build the helper expr:
+// ADDR ( `output_sect' ) + SIZEOF ( `output_sect' )
+RpnExpr* RpnExpr::buildHelperExpr(SectionMap::iterator pIter)
+{
+ RpnExpr* expr = RpnExpr::create();
+ expr->push_back(SectDescOperand::create(*pIter));
+ expr->push_back(&Operator::create<Operator::ADDR>());
+ expr->push_back(SectDescOperand::create(*pIter));
+ expr->push_back(&Operator::create<Operator::SIZEOF>());
+ expr->push_back(&Operator::create<Operator::ADD>());
+ return expr;
+}
+
+// buildHelperExpr - build the helper expr: `fragment'
+RpnExpr* RpnExpr::buildHelperExpr(Fragment& pFrag)
+{
+ RpnExpr* expr = RpnExpr::create();
+ expr->push_back(FragOperand::create(pFrag));
+ return expr;
+}
diff --git a/lib/Script/ScriptCommand.cpp b/lib/Script/ScriptCommand.cpp
new file mode 100644
index 0000000..e360645
--- /dev/null
+++ b/lib/Script/ScriptCommand.cpp
@@ -0,0 +1,19 @@
+//===- ScriptCommand.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/ScriptCommand.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// ScriptCommand
+//===----------------------------------------------------------------------===//
+ScriptCommand::~ScriptCommand()
+{
+}
+
diff --git a/lib/Script/ScriptFile.cpp b/lib/Script/ScriptFile.cpp
new file mode 100644
index 0000000..00a8056
--- /dev/null
+++ b/lib/Script/ScriptFile.cpp
@@ -0,0 +1,252 @@
+//===- ScriptFile.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/ScriptFile.h>
+#include <mcld/Script/StringList.h>
+#include <mcld/Script/ScriptCommand.h>
+#include <mcld/Script/EntryCmd.h>
+#include <mcld/Script/OutputFormatCmd.h>
+#include <mcld/Script/GroupCmd.h>
+#include <mcld/Script/OutputCmd.h>
+#include <mcld/Script/SearchDirCmd.h>
+#include <mcld/Script/OutputArchCmd.h>
+#include <mcld/Script/AssertCmd.h>
+#include <mcld/Script/SectionsCmd.h>
+#include <mcld/Script/RpnExpr.h>
+#include <mcld/Script/Operand.h>
+#include <mcld/Script/StrToken.h>
+#include <mcld/MC/Input.h>
+#include <mcld/MC/InputBuilder.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/InputTree.h>
+#include <mcld/ADT/HashEntry.h>
+#include <mcld/ADT/HashTable.h>
+#include <mcld/ADT/StringHash.h>
+#include <llvm/Support/Casting.h>
+#include <llvm/Support/ManagedStatic.h>
+#include <cassert>
+
+using namespace mcld;
+
+typedef HashEntry<std::string,
+ void*,
+ hash::StringCompare<std::string> > ParserStrEntry;
+typedef HashTable<ParserStrEntry,
+ hash::StringHash<hash::DJB>,
+ EntryFactory<ParserStrEntry> > ParserStrPool;
+static llvm::ManagedStatic<ParserStrPool> g_ParserStrPool;
+
+//===----------------------------------------------------------------------===//
+// ScriptFile
+//===----------------------------------------------------------------------===//
+ScriptFile::ScriptFile(Kind pKind, Input& pInput, InputBuilder& pBuilder)
+ : m_Kind(pKind),
+ m_Input(pInput),
+ m_Name(pInput.path().native()),
+ m_pInputTree(NULL),
+ m_Builder(pBuilder),
+ m_bHasSectionsCmd(false),
+ m_bInSectionsCmd(false),
+ m_bInOutputSectDesc(false),
+ m_pRpnExpr(NULL),
+ m_pStringList(NULL),
+ m_bAsNeeded(false)
+{
+ // FIXME: move creation of input tree out of ScriptFile.
+ m_pInputTree = new InputTree();
+}
+
+ScriptFile::~ScriptFile()
+{
+ for (iterator it = begin(), ie = end(); it != ie; ++it) {
+ if (*it != NULL)
+ delete *it;
+ }
+ if (NULL != m_pInputTree)
+ delete m_pInputTree;
+}
+
+void ScriptFile::dump() const
+{
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it)
+ (*it)->dump();
+}
+
+void ScriptFile::activate(Module& pModule)
+{
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it)
+ (*it)->activate(pModule);
+}
+
+void ScriptFile::addEntryPoint(const std::string& pSymbol)
+{
+ EntryCmd* entry = new EntryCmd(pSymbol);
+
+ if (m_bInSectionsCmd) {
+ assert(!m_CommandQueue.empty());
+ SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
+ sections->push_back(entry);
+ } else {
+ m_CommandQueue.push_back(entry);
+ }
+}
+
+void ScriptFile::addOutputFormatCmd(const std::string& pName)
+{
+ m_CommandQueue.push_back(new OutputFormatCmd(pName));
+}
+
+void ScriptFile::addOutputFormatCmd(const std::string& pDefault,
+ const std::string& pBig,
+ const std::string& pLittle)
+{
+ m_CommandQueue.push_back(new OutputFormatCmd(pDefault, pBig, pLittle));
+}
+
+void ScriptFile::addGroupCmd(StringList& pStringList,
+ GroupReader& pGroupReader,
+ const LinkerConfig& pConfig)
+{
+ m_CommandQueue.push_back(
+ new GroupCmd(pStringList, *m_pInputTree, m_Builder, pGroupReader, pConfig));
+}
+
+void ScriptFile::addOutputCmd(const std::string& pFileName)
+{
+ m_CommandQueue.push_back(new OutputCmd(pFileName));
+}
+
+void ScriptFile::addSearchDirCmd(const std::string& pPath)
+{
+ m_CommandQueue.push_back(new SearchDirCmd(pPath));
+}
+
+void ScriptFile::addOutputArchCmd(const std::string& pArch)
+{
+ m_CommandQueue.push_back(new OutputArchCmd(pArch));
+}
+
+void ScriptFile::addAssertCmd(RpnExpr& pRpnExpr, const std::string& pMessage)
+{
+ m_CommandQueue.push_back(new AssertCmd(pRpnExpr, pMessage));
+}
+
+void ScriptFile::addAssignment(const std::string& pSymbolName,
+ RpnExpr& pRpnExpr,
+ Assignment::Type pType)
+{
+ if (m_bInSectionsCmd) {
+ assert(!m_CommandQueue.empty());
+ SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
+ if (m_bInOutputSectDesc) {
+ assert(!sections->empty());
+ OutputSectDesc* output_desc =
+ llvm::cast<OutputSectDesc>(sections->back());
+ output_desc->push_back(new Assignment(Assignment::INPUT_SECTION,
+ pType,
+ *(SymOperand::create(pSymbolName)),
+ pRpnExpr));
+ } else {
+ sections->push_back(new Assignment(Assignment::OUTPUT_SECTION,
+ pType,
+ *(SymOperand::create(pSymbolName)),
+ pRpnExpr));
+ }
+ } else {
+ m_CommandQueue.push_back(new Assignment(Assignment::OUTSIDE_SECTIONS,
+ pType,
+ *(SymOperand::create(pSymbolName)),
+ pRpnExpr));
+ }
+}
+
+bool ScriptFile::hasSectionsCmd() const
+{
+ return m_bHasSectionsCmd;
+}
+
+void ScriptFile::enterSectionsCmd()
+{
+ m_bHasSectionsCmd = true;
+ m_bInSectionsCmd = true;
+ m_CommandQueue.push_back(new SectionsCmd());
+}
+
+void ScriptFile::leaveSectionsCmd()
+{
+ m_bInSectionsCmd = false;
+}
+
+void ScriptFile::enterOutputSectDesc(const std::string& pName,
+ const OutputSectDesc::Prolog& pProlog)
+{
+ assert(!m_CommandQueue.empty());
+ assert(m_bInSectionsCmd);
+ SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
+ sections->push_back(new OutputSectDesc(pName, pProlog));
+
+ m_bInOutputSectDesc = true;
+}
+
+void ScriptFile::leaveOutputSectDesc(const OutputSectDesc::Epilog& pEpilog)
+{
+ assert(!m_CommandQueue.empty());
+ assert(m_bInSectionsCmd);
+ SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
+
+ assert(!sections->empty() && m_bInOutputSectDesc);
+ OutputSectDesc* output_desc = llvm::cast<OutputSectDesc>(sections->back());
+ output_desc->setEpilog(pEpilog);
+
+ m_bInOutputSectDesc = false;
+}
+
+void ScriptFile::addInputSectDesc(InputSectDesc::KeepPolicy pPolicy,
+ const InputSectDesc::Spec& pSpec)
+{
+ assert(!m_CommandQueue.empty());
+ assert(m_bInSectionsCmd);
+ SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
+
+ assert(!sections->empty() && m_bInOutputSectDesc);
+ OutputSectDesc* output_sect = llvm::cast<OutputSectDesc>(sections->back());
+
+ output_sect->push_back(new InputSectDesc(pPolicy, pSpec, *output_sect));
+}
+
+RpnExpr* ScriptFile::createRpnExpr()
+{
+ m_pRpnExpr = RpnExpr::create();
+ return m_pRpnExpr;
+}
+
+StringList* ScriptFile::createStringList()
+{
+ m_pStringList = StringList::create();
+ return m_pStringList;
+}
+
+void ScriptFile::setAsNeeded(bool pEnable)
+{
+ m_bAsNeeded = pEnable;
+}
+
+const std::string& ScriptFile::createParserStr(const char* pText,
+ size_t pLength)
+{
+ bool exist = false;
+ ParserStrEntry* entry =
+ g_ParserStrPool->insert(std::string(pText, pLength), exist);
+ return entry->key();
+}
+
+void ScriptFile::clearParserStrPool()
+{
+ g_ParserStrPool->clear();
+}
+
diff --git a/lib/Script/ScriptParser.yy b/lib/Script/ScriptParser.yy
new file mode 100644
index 0000000..7b35e0e
--- /dev/null
+++ b/lib/Script/ScriptParser.yy
@@ -0,0 +1,936 @@
+/*===- ScriptParser.yy ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===*/
+
+%{
+/* C/C++ Declarations */
+#include <mcld/Script/ScriptReader.h>
+#include <mcld/Script/ScriptScanner.h>
+#include <mcld/Script/Operand.h>
+#include <mcld/Script/Operator.h>
+#include <mcld/Script/Assignment.h>
+#include <mcld/Script/RpnExpr.h>
+#include <mcld/Script/FileToken.h>
+#include <mcld/Script/NameSpec.h>
+#include <mcld/Script/WildcardPattern.h>
+#include <mcld/Support/MsgHandling.h>
+using namespace mcld;
+
+#undef yylex
+#define yylex m_ScriptScanner.lex
+%}
+
+%code requires {
+#include <mcld/Script/StrToken.h>
+#include <mcld/Script/StringList.h>
+#include <mcld/Script/OutputSectDesc.h>
+#include <mcld/Script/InputSectDesc.h>
+#include <llvm/Support/DataTypes.h>
+
+using namespace mcld;
+
+}
+
+%pure-parser
+%require "2.4"
+%skeleton "glr.cc"
+%defines "ScriptParser.h"
+%debug
+%error-verbose
+%define namespace "mcld"
+%define "parser_class_name" "ScriptParser"
+%parse-param { const class LinkerConfig& m_LDConfig }
+%parse-param { class ScriptFile& m_ScriptFile }
+%parse-param { class ScriptScanner& m_ScriptScanner }
+%parse-param { class GroupReader& m_GroupReader}
+%lex-param { const class ScriptFile& m_ScriptFile }
+
+%locations
+%initial-action
+{
+ /* Initialize the initial location. */
+ @$.begin.filename = @$.end.filename = &(m_ScriptFile.name());
+}
+
+%start script_file
+
+%union {
+ const std::string* string;
+ uint64_t integer;
+ RpnExpr* rpn_expr;
+ StrToken* str_token;
+ StringList* str_tokens;
+ OutputSectDesc::Prolog output_prolog;
+ OutputSectDesc::Type output_type;
+ OutputSectDesc::Constraint output_constraint;
+ OutputSectDesc::Epilog output_epilog;
+ WildcardPattern* wildcard;
+ InputSectDesc::Spec input_spec;
+}
+
+%token END 0 /* EOF */
+%token <string> STRING LNAMESPEC
+%token <integer> INTEGER
+
+/* Initial states */
+%token LINKER_SCRIPT DEFSYM VERSION_SCRIPT DYNAMIC_LIST
+
+/* Entry point */
+%token ENTRY
+/* File Commands */
+%token INCLUDE
+%token INPUT
+%token GROUP
+%token AS_NEEDED
+%token OUTPUT
+%token SEARCH_DIR
+%token STARTUP
+/* Format Commands */
+%token OUTPUT_FORMAT
+%token TARGET
+/* Misc Commands */
+%token ASSERT
+%token EXTERN
+%token FORCE_COMMON_ALLOCATION
+%token INHIBIT_COMMON_ALLOCATION
+%token INSERT
+%token NOCROSSREFS
+%token OUTPUT_ARCH
+%token LD_FEATURE
+/* Assignments */
+%token HIDDEN
+%token PROVIDE
+%token PROVIDE_HIDDEN
+/* SECTIONS Command */
+%token SECTIONS
+/* MEMORY Command */
+%token MEMORY
+/* PHDRS Command */
+%token PHDRS
+/* Builtin Functions */
+%token ABSOLUTE
+%token ADDR
+%token ALIGN
+%token ALIGNOF
+%token BLOCK
+%token DATA_SEGMENT_ALIGN
+%token DATA_SEGMENT_END
+%token DATA_SEGMENT_RELRO_END
+%token DEFINED
+%token LENGTH
+%token LOADADDR
+%token MAX
+%token MIN
+%token NEXT
+%token ORIGIN
+%token SEGMENT_START
+%token SIZEOF
+%token SIZEOF_HEADERS
+%token CONSTANT
+/* Symbolic Constants */
+%token MAXPAGESIZE
+%token COMMONPAGESIZE
+/* Input Section Description */
+%token EXCLUDE_FILE
+%token COMMON
+%token KEEP
+%token SORT_BY_NAME
+%token SORT_BY_ALIGNMENT
+%token SORT_NONE
+%token SORT_BY_INIT_PRIORITY
+/* Output Section Data */
+%token BYTE
+%token SHORT
+%token LONG
+%token QUAD
+%token SQUAD
+%token FILL
+/* Output Section Discarding */
+%token DISCARD
+/* Output Section Keywords */
+%token CREATE_OBJECT_SYMBOLS
+%token CONSTRUCTORS
+/* Output Section Attributes */
+/* Output Section Type */
+%token NOLOAD
+%token DSECT
+%token COPY
+%token INFO
+%token OVERLAY
+/* Output Section LMA */
+%token AT
+/* Forced Input Alignment */
+%token SUBALIGN
+/* Output Section Constraint */
+%token ONLY_IF_RO
+%token ONLY_IF_RW
+/* Operators are listed top to bottem, in ascending order */
+%left ','
+%right '=' ADD_ASSIGN SUB_ASSIGN MUL_ASSIGN DIV_ASSIGN AND_ASSIGN OR_ASSIGN LS_ASSIGN RS_ASSIGN
+%right '?' ':'
+%left LOGICAL_OR
+%left LOGICAL_AND
+%left '|'
+%left '^'
+%left '&'
+%left EQ NE
+%left '<' LE '>' GE
+%left LSHIFT RSHIFT
+%left '+' '-'
+%left '*' '/' '%'
+%right UNARY_PLUS UNARY_MINUS '!' '~'
+
+%type <integer> exp
+%type <string> string symbol opt_region opt_lma_region wildcard_pattern
+%type <rpn_expr> script_exp opt_lma opt_align opt_subalign opt_fill
+%type <str_token> input phdr
+%type <str_tokens> input_list opt_phdr opt_exclude_files input_sect_wildcard_patterns
+%type <output_prolog> output_desc_prolog opt_vma_and_type
+%type <output_type> opt_type type
+%type <output_constraint> opt_constraint
+%type <output_epilog> output_desc_epilog
+%type <wildcard> wildcard_file wildcard_section
+%type <input_spec> input_sect_spec
+
+%%
+
+script_file : LINKER_SCRIPT
+ { m_ScriptScanner.setLexState(ScriptFile::LDScript); }
+ linker_script
+ { m_ScriptScanner.popLexState(); }
+ ;
+
+linker_script : linker_script script_command
+ | /* Empty */
+ ;
+
+script_command : entry_command
+ | output_format_command
+ | group_command
+ | output_command
+ | search_dir_command
+ | output_arch_command
+ | assert_command
+ | symbol_assignment
+ | sections_command
+ | ';'
+ ;
+
+entry_command : ENTRY '(' STRING ')'
+ { m_ScriptFile.addEntryPoint(*$3); }
+ ;
+
+output_format_command : OUTPUT_FORMAT '(' STRING ')'
+ { m_ScriptFile.addOutputFormatCmd(*$3); }
+ | OUTPUT_FORMAT '(' STRING ',' STRING ',' STRING ')'
+ { m_ScriptFile.addOutputFormatCmd(*$3, *$5, *$7); }
+ ;
+
+group_command : GROUP '(' input_list ')'
+ { m_ScriptFile.addGroupCmd(*$3, m_GroupReader, m_LDConfig); }
+ ;
+
+search_dir_command : SEARCH_DIR '(' STRING ')'
+ { m_ScriptFile.addSearchDirCmd(*$3); }
+ ;
+
+output_command : OUTPUT '(' STRING ')'
+ { m_ScriptFile.addOutputCmd(*$3); }
+ ;
+
+output_arch_command : OUTPUT_ARCH '(' STRING ')'
+ { m_ScriptFile.addOutputArchCmd(*$3); }
+ ;
+
+assert_command : ASSERT '(' script_exp ',' string ')'
+ { m_ScriptFile.addAssertCmd(*$3, *$5); }
+ ;
+
+input_list : { m_ScriptFile.createStringList(); }
+ inputs
+ { $$ = m_ScriptFile.getCurrentStringList(); }
+ ;
+
+inputs : input
+ { m_ScriptFile.getCurrentStringList()->push_back($1); }
+ | inputs input
+ { m_ScriptFile.getCurrentStringList()->push_back($2); }
+ | inputs ',' input
+ { m_ScriptFile.getCurrentStringList()->push_back($3); }
+ | AS_NEEDED '('
+ { m_ScriptFile.setAsNeeded(true); }
+ inputs ')'
+ { m_ScriptFile.setAsNeeded(false); }
+ | inputs AS_NEEDED '('
+ { m_ScriptFile.setAsNeeded(true); }
+ inputs ')'
+ { m_ScriptFile.setAsNeeded(false); }
+ | inputs ',' AS_NEEDED '('
+ { m_ScriptFile.setAsNeeded(true); }
+ inputs ')'
+ { m_ScriptFile.setAsNeeded(false); }
+ ;
+
+input : string
+ { $$ = FileToken::create(*$1, m_ScriptFile.asNeeded()); }
+ | LNAMESPEC
+ { $$ = NameSpec::create(*$1, m_ScriptFile.asNeeded()); }
+ ;
+
+/*
+ SECTIONS
+ {
+ sections-command
+ sections-command
+ ...
+ }
+*/
+sections_command : SECTIONS
+ { m_ScriptFile.enterSectionsCmd(); }
+ '{' sect_commands '}'
+ { m_ScriptFile.leaveSectionsCmd(); }
+ ;
+
+sect_commands : sect_commands sect_cmd
+ | /* Empty */
+ ;
+
+/*
+Each sections-command may of be one of the following:
+
+an ENTRY command (see Entry command)
+a symbol assignment (see Assignments)
+an output section description
+an overlay description
+*/
+sect_cmd : entry_command
+ | symbol_assignment
+ | output_sect_desc
+ ;
+
+/*
+The full description of an output section looks like this:
+
+ section [address] [(type)] :
+ [AT(lma)]
+ [ALIGN(section_align)]
+ [SUBALIGN(subsection_align)]
+ [constraint]
+ {
+ output-section-command
+ output-section-command
+ ...
+ } [>region] [AT>lma_region] [:phdr :phdr ...] [=fillexp]
+*/
+output_sect_desc : string output_desc_prolog
+ { m_ScriptFile.enterOutputSectDesc(*$1, $2); }
+ '{'
+ output_sect_commands
+ '}' output_desc_epilog
+ { m_ScriptFile.leaveOutputSectDesc($7); }
+ ;
+
+output_desc_prolog : {
+ m_ScriptScanner.setLexState(ScriptFile::Expression);
+ /* create exp for vma */
+ m_ScriptFile.createRpnExpr();
+ }
+ opt_vma_and_type
+ { m_ScriptScanner.popLexState(); }
+ ':'
+ opt_lma opt_align opt_subalign opt_constraint
+ {
+ $$.m_pVMA = $2.m_pVMA;
+ $$.m_Type = $2.m_Type;
+ $$.m_pLMA = $5;
+ $$.m_pAlign = $6;
+ $$.m_pSubAlign = $7;
+ $$.m_Constraint = $8;
+ }
+ ;
+
+output_sect_commands : output_sect_commands output_sect_cmd
+ | /* Empty */
+ ;
+
+output_desc_epilog : opt_region opt_lma_region opt_phdr opt_fill
+ {
+ $$.m_pRegion = $1;
+ $$.m_pLMARegion = $2;
+ $$.m_pPhdrs = $3;
+ $$.m_pFillExp = $4;
+ }
+ ;
+
+/* Output Section Attributes */
+opt_vma_and_type : exp opt_type
+ {
+ $$.m_pVMA = m_ScriptFile.getCurrentRpnExpr();
+ $$.m_Type = $2;
+ }
+ | opt_type
+ {
+ $$.m_pVMA = NULL;
+ $$.m_Type = $1;
+ }
+ ;
+
+opt_type : '(' type ')'
+ { $$ = $2; }
+ | '(' ')'
+ { $$ = OutputSectDesc::LOAD; }
+ | /* Empty */
+ { $$ = OutputSectDesc::LOAD; }
+ ;
+
+type : NOLOAD
+ { $$ = OutputSectDesc::NOLOAD; }
+ | DSECT
+ { $$ = OutputSectDesc::DSECT; }
+ | COPY
+ { $$ = OutputSectDesc::COPY; }
+ | INFO
+ { $$ = OutputSectDesc::INFO; }
+ | OVERLAY
+ { $$ = OutputSectDesc::OVERLAY; }
+ ;
+
+opt_lma : AT '(' script_exp ')'
+ { $$ = $3; }
+ | /* Empty */
+ { $$ = NULL; }
+ ;
+
+/* Forced Output Alignment */
+opt_align : ALIGN '(' script_exp ')'
+ { $$ = $3; }
+ | /* Empty */
+ { $$ = NULL; }
+ ;
+
+/* Forced Input Alignment */
+opt_subalign : SUBALIGN '(' script_exp ')'
+ { $$ = $3; }
+ | /* Empty */
+ { $$ = NULL; }
+ ;
+
+opt_constraint : ONLY_IF_RO
+ { $$ = OutputSectDesc::ONLY_IF_RO; }
+ | ONLY_IF_RW
+ { $$ = OutputSectDesc::ONLY_IF_RW; }
+ | /* Empty */
+ { $$ = OutputSectDesc::NO_CONSTRAINT; }
+ ;
+
+opt_region : '>' string
+ { $$ = $2; }
+ | /* Empty */
+ { $$ = NULL; }
+ ;
+
+opt_lma_region : AT '>' string
+ { $$ = $3; }
+ | /* Empty */
+ { $$ = NULL; }
+ ;
+
+opt_phdr : { m_ScriptFile.createStringList(); }
+ phdrs
+ { $$ = m_ScriptFile.getCurrentStringList(); }
+ ;
+
+phdrs : phdrs ':' phdr
+ { m_ScriptFile.getCurrentStringList()->push_back($3); }
+ | /* Empty */
+ ;
+
+phdr : string
+ { $$ = StrToken::create(*$1); }
+ ;
+
+opt_fill : '=' script_exp
+ { $$ = $2; }
+ | /* Empty */
+ { $$ = NULL; }
+ ;
+
+/*
+Each output-section-command may be one of the following:
+
+a symbol assignment (see Assignments)
+an input section description (see Input Section)
+data values to include directly (see Output Section Data)
+a special output section keyword (see Output Section Keywords)
+*/
+output_sect_cmd : symbol_assignment
+ | input_sect_desc
+ | output_sect_data
+ | output_sect_keyword
+ | ';'
+ ;
+
+input_sect_desc : input_sect_spec
+ { m_ScriptFile.addInputSectDesc(InputSectDesc::NoKeep, $1); }
+ | KEEP '(' input_sect_spec ')'
+ { m_ScriptFile.addInputSectDesc(InputSectDesc::Keep, $3); }
+ ;
+
+input_sect_spec : string
+ {
+ $$.m_pWildcardFile =
+ WildcardPattern::create(*$1, WildcardPattern::SORT_NONE);
+ $$.m_pExcludeFiles = NULL;
+ $$.m_pWildcardSections = NULL;
+ }
+ | wildcard_file '(' opt_exclude_files input_sect_wildcard_patterns ')'
+ {
+ $$.m_pWildcardFile = $1;
+ $$.m_pExcludeFiles = $3;
+ $$.m_pWildcardSections = $4;
+ }
+ ;
+
+wildcard_file : wildcard_pattern
+ { $$ = WildcardPattern::create(*$1, WildcardPattern::SORT_NONE); }
+ | SORT_BY_NAME '(' wildcard_pattern ')'
+ { $$ = WildcardPattern::create(*$3, WildcardPattern::SORT_BY_NAME); }
+ ;
+
+wildcard_pattern : string
+ { $$ = $1; }
+ | '*'
+ { $$ = &m_ScriptFile.createParserStr("*", 1); }
+ | '?'
+ { $$ = &m_ScriptFile.createParserStr("?", 1); }
+ ;
+
+opt_exclude_files : EXCLUDE_FILE '('
+ { m_ScriptFile.createStringList(); }
+ exclude_files ')'
+ { $$ = m_ScriptFile.getCurrentStringList(); }
+ | /* Empty */
+ { $$ = NULL; }
+ ;
+
+exclude_files : exclude_files wildcard_pattern
+ {
+ m_ScriptFile.getCurrentStringList()->push_back(
+ WildcardPattern::create(*$2, WildcardPattern::SORT_NONE));
+ }
+ | wildcard_pattern
+ {
+ m_ScriptFile.getCurrentStringList()->push_back(
+ WildcardPattern::create(*$1, WildcardPattern::SORT_NONE));
+ }
+ ;
+
+input_sect_wildcard_patterns : { m_ScriptFile.createStringList(); }
+ wildcard_sections
+ { $$ = m_ScriptFile.getCurrentStringList(); }
+ ;
+
+wildcard_sections : wildcard_sections wildcard_section
+ {
+ m_ScriptFile.getCurrentStringList()->push_back($2);
+ }
+ | wildcard_section
+ {
+ m_ScriptFile.getCurrentStringList()->push_back($1);
+ }
+ ;
+
+wildcard_section : wildcard_pattern
+ { $$ = WildcardPattern::create(*$1, WildcardPattern::SORT_NONE); }
+ | SORT_NONE '(' wildcard_pattern ')'
+ { $$ = WildcardPattern::create(*$3, WildcardPattern::SORT_NONE); }
+ | SORT_BY_NAME '(' wildcard_pattern ')'
+ { $$ = WildcardPattern::create(*$3, WildcardPattern::SORT_BY_NAME); }
+ | SORT_BY_ALIGNMENT '(' wildcard_pattern ')'
+ { $$ = WildcardPattern::create(*$3, WildcardPattern::SORT_BY_ALIGNMENT); }
+ | SORT_BY_NAME '(' SORT_BY_ALIGNMENT '(' wildcard_pattern ')' ')'
+ { $$ = WildcardPattern::create(*$5, WildcardPattern::SORT_BY_NAME_ALIGNMENT); }
+ | SORT_BY_ALIGNMENT '('SORT_BY_NAME '(' wildcard_pattern ')' ')'
+ { $$ = WildcardPattern::create(*$5, WildcardPattern::SORT_BY_ALIGNMENT_NAME); }
+ | SORT_BY_NAME '(' SORT_BY_NAME '(' wildcard_pattern ')' ')'
+ { $$ = WildcardPattern::create(*$5, WildcardPattern::SORT_BY_NAME); }
+ | SORT_BY_ALIGNMENT '(' SORT_BY_ALIGNMENT '(' wildcard_pattern ')' ')'
+ { $$ = WildcardPattern::create(*$5, WildcardPattern::SORT_BY_ALIGNMENT); }
+ | SORT_BY_INIT_PRIORITY '(' wildcard_pattern ')'
+ { $$ = WildcardPattern::create(*$3, WildcardPattern::SORT_BY_INIT_PRIORITY); }
+ ;
+
+output_sect_data : BYTE '(' script_exp ')'
+ | SHORT '(' script_exp ')'
+ | LONG '(' script_exp ')'
+ | QUAD '(' script_exp ')'
+ | SQUAD '(' script_exp ')'
+ ;
+
+output_sect_keyword : CREATE_OBJECT_SYMBOLS
+ | CONSTRUCTORS
+ | SORT_BY_NAME '(' CONSTRUCTORS ')'
+ ;
+
+symbol_assignment : symbol '=' script_exp ';'
+ { m_ScriptFile.addAssignment(*$1, *$3); }
+ | symbol ADD_ASSIGN exp ';'
+ | symbol SUB_ASSIGN exp ';'
+ | symbol MUL_ASSIGN exp ';'
+ | symbol DIV_ASSIGN exp ';'
+ | symbol AND_ASSIGN exp ';'
+ | symbol OR_ASSIGN exp ';'
+ | symbol LS_ASSIGN exp ';'
+ | symbol RS_ASSIGN exp ';'
+ | HIDDEN '(' symbol '=' script_exp ')' ';'
+ {
+ m_ScriptFile.addAssignment(*$3, *$5,
+ Assignment::HIDDEN);
+ }
+ | PROVIDE '(' symbol '=' script_exp ')' ';'
+ {
+ m_ScriptFile.addAssignment(*$3, *$5,
+ Assignment::PROVIDE);
+ }
+ | PROVIDE_HIDDEN '(' symbol '=' script_exp ')' ';'
+ {
+ m_ScriptFile.addAssignment(*$3, *$5,
+ Assignment::PROVIDE_HIDDEN);
+ }
+ ;
+
+script_exp : {
+ m_ScriptScanner.setLexState(ScriptFile::Expression);
+ m_ScriptFile.createRpnExpr();
+ }
+ exp
+ {
+ m_ScriptScanner.popLexState();
+ $$ = m_ScriptFile.getCurrentRpnExpr();
+ }
+ ;
+
+exp : '(' exp ')'
+ {
+ $$ = $2;
+ }
+ | '+' exp %prec UNARY_PLUS
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::UNARY_PLUS>());
+ $$ = $2 + 1;
+ }
+ | '-' exp %prec UNARY_MINUS
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::UNARY_MINUS>());
+ $$ = $2 + 1;
+ }
+ | '!' exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::LOGICAL_NOT>());
+ $$ = $2 + 1;
+ }
+ | '~' exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::BITWISE_NOT>());
+ $$ = $2 + 1;
+ }
+ | exp '*' exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::MUL>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp '/' exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::DIV>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp '%' exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::MOD>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp '+' exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::ADD>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp '-' exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::SUB>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp LSHIFT exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::LSHIFT>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp RSHIFT exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::RSHIFT>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp '<' exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::LT>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp LE exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::LE>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp '>' exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::GT>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp GE exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::GE>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp EQ exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::EQ>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp NE exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::NE>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp '&' exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::BITWISE_AND>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp '^' exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::BITWISE_XOR>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp '|' exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::BITWISE_OR>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp LOGICAL_AND exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::LOGICAL_AND>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp LOGICAL_OR exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::LOGICAL_OR>());
+ $$ = $1 + $3 + 1;
+ }
+ | exp '?' exp ':' exp
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::TERNARY_IF>());
+ $$ = $1 + $3 + $5 + 1;
+ }
+ | ABSOLUTE '(' exp ')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::ABSOLUTE>());
+ $$ = $3 + 1;
+ }
+ | ADDR '(' string ')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(SectOperand::create(*$3));
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::ADDR>());
+ $$ = 2;
+ }
+ | ALIGN '(' exp ')'
+ {
+ RpnExpr::iterator pos = m_ScriptFile.getCurrentRpnExpr()->begin() +
+ m_ScriptFile.getCurrentRpnExpr()->size() - $3;
+ m_ScriptFile.getCurrentRpnExpr()->insert(pos, SymOperand::create("."));
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::ALIGN>());
+ $$ = $3 + 2;
+ }
+ | ALIGN '(' exp ',' exp ')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::ALIGN>());
+ $$ = $3 + $5 + 1;
+ }
+ | ALIGNOF '(' string ')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(SectOperand::create(*$3));
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::ALIGNOF>());
+ $$ = 2;
+ }
+ | BLOCK '(' exp ')'
+ {
+ RpnExpr::iterator pos = m_ScriptFile.getCurrentRpnExpr()->begin() +
+ m_ScriptFile.getCurrentRpnExpr()->size() - $3;
+ m_ScriptFile.getCurrentRpnExpr()->insert(pos, SymOperand::create("."));
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::ALIGN>());
+ $$ = $3 + 2;
+ }
+ | DATA_SEGMENT_ALIGN
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(SymOperand::create("."));
+ }
+ '(' exp ',' exp ')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::DATA_SEGMENT_ALIGN>());
+ $$ = $4 + $6 + 2;
+ }
+ | DATA_SEGMENT_END '(' exp ')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::DATA_SEGMENT_END>());
+ $$ = $3 + 1;
+ }
+ | DATA_SEGMENT_RELRO_END '(' exp ',' exp ')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::DATA_SEGMENT_RELRO_END>());
+ $$ = $3 + $5 + 1;
+ }
+ | DEFINED '(' symbol ')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(SymOperand::create(*$3));
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::DEFINED>());
+ $$ = 2;
+ }
+ | LENGTH '(' string ')'
+ {
+ /* TODO */
+ }
+ | LOADADDR '(' string ')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(SectOperand::create(*$3));
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::LOADADDR>());
+ $$ = 2;
+ }
+ | MAX '(' exp ',' exp ')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::MAX>());
+ $$ = $3 + $5 + 1;
+ }
+ | MIN '(' exp ',' exp ')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::MIN>());
+ $$ = $3 + $5 + 1;
+ }
+ | NEXT '(' exp ')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::NEXT>());
+ $$ = $3 + 1;
+ }
+ | ORIGIN '(' string ')'
+ {
+ /* TODO */
+ }
+ | SEGMENT_START '(' string
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(SectOperand::create(*$3));
+ }
+ ',' exp ')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::SEGMENT_START>());
+ $$ = $6 + 2;
+ }
+ | SIZEOF '(' string ')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(SectOperand::create(*$3));
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::SIZEOF>());
+ $$ = 2;
+ }
+ | SIZEOF_HEADERS
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::SIZEOF_HEADERS>());
+ $$ = 1;
+ }
+ | CONSTANT '(' MAXPAGESIZE ')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::MAXPAGESIZE>());
+ $$ = 1;
+ }
+ | CONSTANT '(' COMMONPAGESIZE')'
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(
+ &Operator::create<Operator::COMMONPAGESIZE>());
+ $$ = 1;
+ }
+ | INTEGER
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(IntOperand::create($1));
+ $$ = 1;
+ }
+ | symbol
+ {
+ m_ScriptFile.getCurrentRpnExpr()->push_back(SymOperand::create(*$1));
+ $$ = 1;
+ }
+ ;
+
+symbol : STRING
+ { $$ = $1; }
+ ;
+
+string : STRING
+ { $$ = $1; }
+ | '"' STRING '"'
+ { $$ = $2; }
+ ;
+
+%%
+
+void mcld::ScriptParser::error(const mcld::ScriptParser::location_type& pLoc,
+ const std::string &pMsg)
+{
+ position last = pLoc.end - 1;
+ std::string filename = "NaN";
+ if (last.filename != NULL)
+ filename = *last.filename;
+
+ mcld::error(diag::err_syntax_error)
+ << filename << last.line << last.column << pMsg;
+}
+
diff --git a/lib/Script/ScriptReader.cpp b/lib/Script/ScriptReader.cpp
new file mode 100644
index 0000000..37c3ce9
--- /dev/null
+++ b/lib/Script/ScriptReader.cpp
@@ -0,0 +1,58 @@
+//===- ScriptReader.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/ScriptReader.h>
+#include <mcld/Script/ScriptScanner.h>
+#include <mcld/Script/ScriptFile.h>
+#include <mcld/MC/Input.h>
+#include <mcld/Support/MemoryArea.h>
+
+#include <llvm/ADT/StringRef.h>
+
+#include <istream>
+#include <sstream>
+
+using namespace mcld;
+
+ScriptReader::ScriptReader(GroupReader& pGroupReader)
+ : m_GroupReader(pGroupReader)
+{
+}
+
+ScriptReader::~ScriptReader()
+{
+}
+
+/// isMyFormat
+bool ScriptReader::isMyFormat(Input& input, bool &doContinue) const
+{
+ doContinue = true;
+ // always return true now
+ return true;
+}
+
+bool ScriptReader::readScript(const LinkerConfig& pConfig,
+ ScriptFile& pScriptFile)
+{
+ bool result = false;
+ Input& input = pScriptFile.input();
+ size_t size = input.memArea()->size();
+ llvm::StringRef region = input.memArea()->request(input.fileOffset(), size);
+ std::stringbuf buf(region.data());
+
+ std::istream in(&buf);
+ ScriptScanner scanner(&in);
+ ScriptParser parser(pConfig,
+ pScriptFile,
+ scanner,
+ m_GroupReader);
+ result = (0 == parser.parse());;
+
+ return result;
+}
+
diff --git a/lib/Script/ScriptScanner.ll b/lib/Script/ScriptScanner.ll
new file mode 100644
index 0000000..f3fd921
--- /dev/null
+++ b/lib/Script/ScriptScanner.ll
@@ -0,0 +1,388 @@
+/*===- ScriptScanner.ll ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===*/
+
+%{
+/* C/C++ Declarations */
+
+#include <mcld/Script/ScriptScanner.h>
+#include <mcld/Script/ScriptFile.h>
+#include <mcld/Support/MsgHandling.h>
+#include <llvm/ADT/StringRef.h>
+#include <string>
+
+typedef mcld::ScriptParser::token token;
+typedef mcld::ScriptParser::token_type token_type;
+
+#define yyterminate() return token::END
+#define YY_NO_UNISTD_H
+%}
+
+/* Flex Declarations and Options */
+%option c++
+%option batch
+%option noyywrap
+%option nounput
+%option stack
+
+%{
+#define YY_USER_ACTION yylloc->columns(yyleng);
+%}
+
+/* abbrev. of RE @ref binutils ld/ldlex.l */
+FILENAMECHAR1 [_a-zA-Z\/\.\\\$\_\~]
+SYMBOLCHARN [_a-zA-Z\/\.\\\$\_\~0-9]
+NOCFILENAMECHAR [_a-zA-Z0-9\/\.\-\_\+\$\[\]\\\~]
+WILDCHAR [_a-zA-Z0-9\/\.\-\_\+\$\[\]\\\,\~\?\*\^\!]
+WS [ \t\r]
+
+/* Start conditions */
+%s LDSCRIPT
+%s EXPRESSION
+
+%% /* Regular Expressions */
+
+ /* code to place at the beginning of yylex() */
+%{
+ /* reset location */
+ yylloc->step();
+
+ /* determine the initial parser state */
+ if (m_Kind == ScriptFile::Unknown) {
+ m_Kind = pScriptFile.getKind();
+ switch (pScriptFile.getKind()) {
+ case ScriptFile::LDScript:
+ case ScriptFile::Expression:
+ return token::LINKER_SCRIPT;
+ case ScriptFile::VersionScript:
+ case ScriptFile::DynamicList:
+ default:
+ assert(0 && "Unsupported script type!");
+ break;
+ }
+ }
+%}
+
+ /* Entry Point */
+<LDSCRIPT>"ENTRY" { return token::ENTRY; }
+ /* File Commands */
+<LDSCRIPT>"INCLUDE" { return token::INCLUDE; }
+<LDSCRIPT>"INPUT" { return token::INPUT; }
+<LDSCRIPT>"GROUP" { return token::GROUP; }
+<LDSCRIPT>"AS_NEEDED" { return token::AS_NEEDED; }
+<LDSCRIPT>"OUTPUT" { return token::OUTPUT; }
+<LDSCRIPT>"SEARCH_DIR" { return token::SEARCH_DIR; }
+<LDSCRIPT>"STARTUP" { return token::STARTUP; }
+ /* Format Commands */
+<LDSCRIPT>"OUTPUT_FORMAT" { return token::OUTPUT_FORMAT; }
+<LDSCRIPT>"TARGET" { return token::TARGET; }
+ /* Misc Commands */
+<LDSCRIPT>"ASSERT" { return token::ASSERT; }
+<LDSCRIPT>"EXTERN" { return token::EXTERN; }
+<LDSCRIPT>"FORCE_COMMON_ALLOCATION" { return token::FORCE_COMMON_ALLOCATION; }
+<LDSCRIPT>"INHIBIT_COMMON_ALLOCATION" { return token::INHIBIT_COMMON_ALLOCATION; }
+<LDSCRIPT>"INSERT" { return token::INSERT; }
+<LDSCRIPT>"NOCROSSREFS" { return token::NOCROSSREFS; }
+<LDSCRIPT>"OUTPUT_ARCH" { return token::OUTPUT_ARCH; }
+<LDSCRIPT>"LD_FEATURE" { return token::LD_FEATURE; }
+ /* Assignemnts */
+<LDSCRIPT,EXPRESSION>"HIDDEN" { return token::HIDDEN; }
+<LDSCRIPT,EXPRESSION>"PROVIDE" { return token::PROVIDE; }
+<LDSCRIPT,EXPRESSION>"PROVIDE_HIDDEN" { return token::PROVIDE_HIDDEN; }
+ /* SECTIONS Command */
+<LDSCRIPT>"SECTIONS" { return token::SECTIONS; }
+ /* MEMORY Command */
+<LDSCRIPT>"MEMORY" { return token::MEMORY; }
+ /* PHDRS Command */
+<LDSCRIPT>"PHDRS" { return token::PHDRS; }
+ /* Builtin Functions */
+<EXPRESSION>"ABSOLUTE" { return token::ABSOLUTE; }
+<EXPRESSION>"ADDR" { return token::ADDR; }
+<LDSCRIPT,EXPRESSION>"ALIGN" { return token::ALIGN; }
+<EXPRESSION>"ALIGNOF" { return token::ALIGNOF; }
+<EXPRESSION>"BLOCK" { return token::BLOCK; }
+<EXPRESSION>"DATA_SEGMENT_ALIGN" { return token::DATA_SEGMENT_ALIGN; }
+<EXPRESSION>"DATA_SEGMENT_END" { return token::DATA_SEGMENT_END; }
+<EXPRESSION>"DATA_SEGMENT_RELRO_END" { return token::DATA_SEGMENT_RELRO_END; }
+<EXPRESSION>"DEFINED" { return token::DEFINED; }
+<EXPRESSION>"LENGTH" { return token::LENGTH; }
+<EXPRESSION>"LOADADDR" { return token::LOADADDR; }
+<EXPRESSION>"MAX" { return token::MAX; }
+<EXPRESSION>"MIN" { return token::MIN; }
+<EXPRESSION>"NEXT" { return token::NEXT; }
+<EXPRESSION>"ORIGIN" { return token::ORIGIN; }
+<EXPRESSION>"SEGMENT_START" { return token::SEGMENT_START; }
+<EXPRESSION>"SIZEOF" { return token::SIZEOF; }
+<EXPRESSION>"SIZEOF_HEADERS" { return token::SIZEOF_HEADERS; }
+<EXPRESSION>"CONSTANT" { return token::CONSTANT; }
+ /* Symbolic Constants */
+<EXPRESSION>"MAXPAGESIZE" { return token::MAXPAGESIZE; }
+<EXPRESSION>"COMMONPAGESIZE" { return token::COMMONPAGESIZE; }
+ /* Input Section Description */
+<LDSCRIPT>"EXCLUDE_FILE" { return token::EXCLUDE_FILE; }
+<LDSCRIPT>"KEEP" { return token::KEEP; }
+<LDSCRIPT>"SORT" { return token::SORT_BY_NAME; }
+<LDSCRIPT>"SORT_BY_NAME" { return token::SORT_BY_NAME; }
+<LDSCRIPT>"SORT_BY_ALIGNMENT" { return token::SORT_BY_ALIGNMENT; }
+<LDSCRIPT>"SORT_NONE" { return token::SORT_NONE; }
+<LDSCRIPT>"SORT_BY_INIT_PRIORITY" { return token::SORT_BY_INIT_PRIORITY; }
+ /* Output Section Data */
+<LDSCRIPT>"BYTE" { return token::BYTE; }
+<LDSCRIPT>"SHORT" { return token::SHORT; }
+<LDSCRIPT>"LONG" { return token::LONG; }
+<LDSCRIPT>"QUAD" { return token::QUAD; }
+<LDSCRIPT>"SQUAD" { return token::SQUAD; }
+<LDSCRIPT>"FILL" { return token::FILL; }
+ /* Output Section Discarding */
+<LDSCRIPT>"DISCARD" { return token::DISCARD; }
+ /* Output Section Keywords */
+<LDSCRIPT>"CREATE_OBJECT_SYMBOLS" { return token::CREATE_OBJECT_SYMBOLS; }
+<LDSCRIPT>"CONSTRUCTORS" { return token::CONSTRUCTORS; }
+ /* Output Section Attributes */
+ /* Output Section Type */
+<LDSCRIPT,EXPRESSION>"NOLOAD" { return token::NOLOAD; }
+<LDSCRIPT,EXPRESSION>"DSECT" { return token::DSECT; }
+<LDSCRIPT,EXPRESSION>"COPY" { return token::COPY; }
+<LDSCRIPT,EXPRESSION>"INFO" { return token::INFO; }
+<LDSCRIPT,EXPRESSION>"OVERLAY" { return token::OVERLAY; }
+ /* Output Section LMA */
+<LDSCRIPT>"AT" { return token::AT; }
+ /* Forced Input Alignment */
+<LDSCRIPT>"SUBALIGN" { return token::SUBALIGN; }
+ /* Output Section Constraint */
+<LDSCRIPT>"ONLY_IF_RO" { return token::ONLY_IF_RO; }
+<LDSCRIPT>"ONLY_IF_RW" { return token::ONLY_IF_RW; }
+ /* Operators */
+<LDSCRIPT,EXPRESSION>"<<" { return token::LSHIFT; }
+<LDSCRIPT,EXPRESSION>">>" { return token::RSHIFT; }
+<LDSCRIPT,EXPRESSION>"==" { return token::EQ; }
+<LDSCRIPT,EXPRESSION>"!=" { return token::NE; }
+<LDSCRIPT,EXPRESSION>"<=" { return token::LE; }
+<LDSCRIPT,EXPRESSION>">=" { return token::GE; }
+<LDSCRIPT,EXPRESSION>"&&" { return token::LOGICAL_AND; }
+<LDSCRIPT,EXPRESSION>"||" { return token::LOGICAL_OR; }
+<LDSCRIPT,EXPRESSION>"+=" { return token::ADD_ASSIGN; }
+<LDSCRIPT,EXPRESSION>"-=" { return token::SUB_ASSIGN; }
+<LDSCRIPT,EXPRESSION>"*=" { return token::MUL_ASSIGN; }
+<LDSCRIPT,EXPRESSION>"/=" { return token::DIV_ASSIGN; }
+<LDSCRIPT,EXPRESSION>"&=" { return token::AND_ASSIGN; }
+<LDSCRIPT,EXPRESSION>"|=" { return token::OR_ASSIGN; }
+<LDSCRIPT,EXPRESSION>"<<=" { return token::LS_ASSIGN; }
+<LDSCRIPT,EXPRESSION>">>=" { return token::RS_ASSIGN; }
+<LDSCRIPT,EXPRESSION>"," { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"=" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"?" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>":" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"|" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"^" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"&" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"<" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>">" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"+" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"-" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"*" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"/" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"%" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"!" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"~" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>";" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"(" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>")" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"{" { return static_cast<token_type>(*yytext); }
+<LDSCRIPT,EXPRESSION>"}" { return static_cast<token_type>(*yytext); }
+
+ /* Numbers */
+<LDSCRIPT,EXPRESSION>((("$"|0[xX])([0-9A-Fa-f])+)|(([0-9])+))(M|K|m|k)? {
+ llvm::StringRef str(yytext, yyleng);
+ switch (str.back()) {
+ case 'k':
+ case 'K':
+ str.substr(0, yyleng - 1).getAsInteger(0, yylval->integer);
+ yylval->integer *= 1024;
+ break;
+ case 'm':
+ case 'M':
+ str.substr(0, yyleng - 1).getAsInteger(0, yylval->integer);
+ yylval->integer *= 1024 * 1024;
+ break;
+ default:
+ str.getAsInteger(0, yylval->integer);
+ break;
+ }
+ return token::INTEGER;
+}
+
+ /* Expression string */
+<EXPRESSION>{FILENAMECHAR1}{SYMBOLCHARN}* {
+ const std::string& str = pScriptFile.createParserStr(yytext, yyleng);
+ yylval->string = &str;
+ return token::STRING;
+}
+
+ /* String */
+<LDSCRIPT>{FILENAMECHAR1}{NOCFILENAMECHAR}* {
+ const std::string& str = pScriptFile.createParserStr(yytext, yyleng);
+ yylval->string = &str;
+ return token::STRING;
+}
+
+<LDSCRIPT,EXPRESSION>\"(\\.|[^\\"])*\" {
+ /*" c string literal */
+ const std::string& str = pScriptFile.createParserStr(yytext, yyleng);
+ yylval->string = &str;
+ return token::STRING;
+}
+
+ /* -l namespec */
+<LDSCRIPT>"-l"{FILENAMECHAR1}{NOCFILENAMECHAR}* {
+ const std::string& str = pScriptFile.createParserStr(yytext + 2, yyleng - 2);
+ yylval->string = &str;
+ return token::LNAMESPEC;
+}
+
+ /* WILDCHAR String */
+<LDSCRIPT>{WILDCHAR}* {
+ if (yytext[0] == '/' && yytext[1] == '*') {
+ yyless (2);
+ enterComments(*yylloc);
+ } else {
+ const std::string& str = pScriptFile.createParserStr(yytext, yyleng);
+ yylval->string = &str;
+ return token::STRING;
+ }
+}
+
+ /* gobble up C comments */
+<LDSCRIPT,EXPRESSION>"/*" {
+ enterComments(*yylloc);
+ yylloc->step();
+}
+
+ /* gobble up white-spaces */
+<LDSCRIPT,EXPRESSION>{WS}+ {
+ yylloc->step();
+}
+
+ /* gobble up end-of-lines */
+<LDSCRIPT,EXPRESSION>\n {
+ yylloc->lines(1);
+ yylloc->step();
+}
+
+%% /* Additional Code */
+
+namespace mcld {
+
+ScriptScanner::ScriptScanner(std::istream* yyin, std::ostream* yyout)
+ : yyFlexLexer(yyin, yyout), m_Kind(ScriptFile::Unknown)
+{
+}
+
+ScriptScanner::~ScriptScanner()
+{
+}
+
+void ScriptScanner::enterComments(ScriptParser::location_type& pLocation)
+{
+ const int start_line = pLocation.begin.line;
+ const int start_col = pLocation.begin.column;
+
+ int ch = 0;
+
+ while (true) {
+ ch = yyinput();
+ pLocation.columns(1);
+
+ while (ch != '*' && ch != EOF) {
+ if (ch == '\n') {
+ pLocation.lines(1);
+ }
+
+ ch = yyinput();
+ pLocation.columns(1);
+ }
+
+ if (ch == '*') {
+ ch = yyinput();
+ pLocation.columns(1);
+
+ while (ch == '*') {
+ ch = yyinput();
+ pLocation.columns(1);
+ }
+
+ if (ch == '/')
+ break;
+ }
+
+ if (ch == '\n')
+ pLocation.lines(1);
+
+ if (ch == EOF) {
+ error(diag::err_unterminated_comment) << pLocation.begin.filename
+ << start_line
+ << start_col;
+ break;
+ }
+ }
+}
+
+void ScriptScanner::setLexState(ScriptFile::Kind pKind)
+{
+ /* push the state into the top of stach */
+ m_StateStack.push(pKind);
+
+ switch (pKind) {
+ case ScriptFile::LDScript:
+ BEGIN(LDSCRIPT);
+ break;
+ case ScriptFile::Expression:
+ BEGIN(EXPRESSION);
+ break;
+ case ScriptFile::VersionScript:
+ case ScriptFile::DynamicList:
+ default:
+ assert(0 && "Unsupported script type!");
+ break;
+ }
+}
+
+void ScriptScanner::popLexState()
+{
+ /* pop the last state */
+ m_StateStack.pop();
+
+ /* resume the appropriate state */
+ if (!m_StateStack.empty()) {
+ switch (m_StateStack.top()) {
+ case ScriptFile::LDScript:
+ BEGIN(LDSCRIPT);
+ break;
+ case ScriptFile::Expression:
+ BEGIN(EXPRESSION);
+ break;
+ case ScriptFile::VersionScript:
+ case ScriptFile::DynamicList:
+ default:
+ assert(0 && "Unsupported script type!");
+ break;
+ }
+ }
+}
+
+} /* namespace of mcld */
+
+#ifdef yylex
+#undef yylex
+#endif
+
+int yyFlexLexer::yylex()
+{
+ return 0;
+}
+
diff --git a/lib/Script/SearchDirCmd.cpp b/lib/Script/SearchDirCmd.cpp
new file mode 100644
index 0000000..dd9a56f
--- /dev/null
+++ b/lib/Script/SearchDirCmd.cpp
@@ -0,0 +1,38 @@
+//===- SearchDirCmd.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/SearchDirCmd.h>
+#include <mcld/Support/raw_ostream.h>
+#include <mcld/LinkerScript.h>
+#include <mcld/Module.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// SearchDirCmd
+//===----------------------------------------------------------------------===//
+SearchDirCmd::SearchDirCmd(const std::string& pPath)
+ : ScriptCommand(ScriptCommand::SEARCH_DIR),
+ m_Path(pPath)
+{
+}
+
+SearchDirCmd::~SearchDirCmd()
+{
+}
+
+void SearchDirCmd::dump() const
+{
+ mcld::outs() << "SEARCH_DIR ( " << m_Path << " )\n";
+}
+
+void SearchDirCmd::activate(Module& pModule)
+{
+ pModule.getScript().directories().insert(m_Path);
+}
+
diff --git a/lib/Script/SectionsCmd.cpp b/lib/Script/SectionsCmd.cpp
new file mode 100644
index 0000000..4ecc838
--- /dev/null
+++ b/lib/Script/SectionsCmd.cpp
@@ -0,0 +1,94 @@
+//===- SectionsCmd.cpp ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/SectionsCmd.h>
+#include <mcld/Support/raw_ostream.h>
+#include <cassert>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// SectionsCmd
+//===----------------------------------------------------------------------===//
+SectionsCmd::SectionsCmd()
+ : ScriptCommand(ScriptCommand::SECTIONS)
+{
+}
+
+SectionsCmd::~SectionsCmd()
+{
+ for (iterator it = begin(), ie = end(); it != ie; ++it) {
+ if (*it != NULL)
+ delete *it;
+ }
+}
+
+void SectionsCmd::dump() const
+{
+ mcld::outs() << "SECTIONS\n{\n";
+
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ switch ((*it)->getKind()) {
+ case ScriptCommand::ENTRY:
+ case ScriptCommand::ASSIGNMENT:
+ case ScriptCommand::OUTPUT_SECT_DESC:
+ mcld::outs() << "\t";
+ (*it)->dump();
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+
+ mcld::outs() << "}\n";
+}
+
+void SectionsCmd::push_back(ScriptCommand* pCommand)
+{
+ switch (pCommand->getKind()) {
+ case ScriptCommand::ENTRY:
+ case ScriptCommand::ASSIGNMENT:
+ case ScriptCommand::OUTPUT_SECT_DESC:
+ m_SectionCommands.push_back(pCommand);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+}
+
+void SectionsCmd::activate(Module& pModule)
+{
+ // Assignment between output sections
+ SectionCommands assignments;
+
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ switch ((*it)->getKind()) {
+ case ScriptCommand::ENTRY:
+ (*it)->activate(pModule);
+ break;
+ case ScriptCommand::ASSIGNMENT:
+ assignments.push_back(*it);
+ break;
+ case ScriptCommand::OUTPUT_SECT_DESC: {
+ (*it)->activate(pModule);
+
+ iterator assign, assignEnd = assignments.end();
+ for (assign = assignments.begin(); assign != assignEnd; ++assign)
+ (*assign)->activate(pModule);
+ assignments.clear();
+
+ break;
+ }
+ default:
+ assert(0);
+ break;
+ }
+ }
+}
diff --git a/lib/Script/StrToken.cpp b/lib/Script/StrToken.cpp
new file mode 100644
index 0000000..f886623
--- /dev/null
+++ b/lib/Script/StrToken.cpp
@@ -0,0 +1,52 @@
+//===- StrToken.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/StrToken.h>
+#include <mcld/Support/GCFactory.h>
+#include <llvm/Support/ManagedStatic.h>
+
+using namespace mcld;
+
+typedef GCFactory<StrToken, MCLD_SYMBOLS_PER_INPUT> StrTokenFactory;
+static llvm::ManagedStatic<StrTokenFactory> g_StrTokenFactory;
+
+//===----------------------------------------------------------------------===//
+// StrToken
+//===----------------------------------------------------------------------===//
+StrToken::StrToken()
+ : m_Kind(Unknown)
+{
+}
+
+StrToken::StrToken(Kind pKind, const std::string& pString)
+ : m_Kind(pKind), m_Name(pString)
+{
+}
+
+StrToken::~StrToken()
+{
+}
+
+StrToken* StrToken::create(const std::string& pString)
+{
+ StrToken* result = g_StrTokenFactory->allocate();
+ new (result) StrToken(String, pString);
+ return result;
+}
+
+void StrToken::destroy(StrToken*& pStrToken)
+{
+ g_StrTokenFactory->destroy(pStrToken);
+ g_StrTokenFactory->deallocate(pStrToken);
+ pStrToken = NULL;
+}
+
+void StrToken::clear()
+{
+ g_StrTokenFactory->clear();
+}
diff --git a/lib/Script/StringList.cpp b/lib/Script/StringList.cpp
new file mode 100644
index 0000000..e5637fb
--- /dev/null
+++ b/lib/Script/StringList.cpp
@@ -0,0 +1,60 @@
+//===- StringList.cpp ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/StringList.h>
+#include <mcld/Script/StrToken.h>
+#include <mcld/Support/raw_ostream.h>
+#include <mcld/Support/GCFactory.h>
+#include <llvm/Support/ManagedStatic.h>
+
+using namespace mcld;
+
+typedef GCFactory<StringList, MCLD_SYMBOLS_PER_INPUT> StringListFactory;
+static llvm::ManagedStatic<StringListFactory> g_StringListFactory;
+
+//===----------------------------------------------------------------------===//
+// StringList
+//===----------------------------------------------------------------------===//
+StringList::StringList()
+{
+}
+
+StringList::~StringList()
+{
+}
+
+void StringList::push_back(StrToken* pToken)
+{
+ m_Tokens.push_back(pToken);
+}
+
+void StringList::dump() const
+{
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it)
+ mcld::outs() << (*it)->name() << "\t";
+ mcld::outs() << "\n";
+}
+
+StringList* StringList::create()
+{
+ StringList* result = g_StringListFactory->allocate();
+ new (result) StringList();
+ return result;
+}
+
+void StringList::destroy(StringList*& pStringList)
+{
+ g_StringListFactory->destroy(pStringList);
+ g_StringListFactory->deallocate(pStringList);
+ pStringList = NULL;
+}
+
+void StringList::clear()
+{
+ g_StringListFactory->clear();
+}
diff --git a/lib/Script/TernaryOp.cpp b/lib/Script/TernaryOp.cpp
new file mode 100644
index 0000000..131f460
--- /dev/null
+++ b/lib/Script/TernaryOp.cpp
@@ -0,0 +1,58 @@
+//===- TernaryOp.cpp ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/TernaryOp.h>
+#include <mcld/Script/Operand.h>
+#include <mcld/ADT/SizeTraits.h>
+
+using namespace mcld;
+//===----------------------------------------------------------------------===//
+// TernaryOp
+//===----------------------------------------------------------------------===//
+template<>
+IntOperand*
+TernaryOp<Operator::TERNARY_IF>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ if (m_pOperand[0]->value())
+ res->setValue(m_pOperand[1]->value());
+ else
+ res->setValue(m_pOperand[2]->value());
+ return res;
+}
+
+/* DATA_SEGMENT_ALIGN(maxpagesize, commonpagesize) */
+template<>
+IntOperand*
+TernaryOp<Operator::DATA_SEGMENT_ALIGN>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ /* This is equivalent to either
+ (ALIGN(maxpagesize) + (. & (maxpagesize - 1)))
+ or
+ (ALIGN(maxpagesize) + (. & (maxpagesize - commonpagesize)))
+ */
+ IntOperand* res = result();
+ uint64_t dot = m_pOperand[0]->value();
+ uint64_t maxPageSize = m_pOperand[1]->value();
+ uint64_t commonPageSize = m_pOperand[2]->value();
+ uint64_t form1 = 0, form2 = 0;
+
+ alignAddress(dot, maxPageSize);
+
+ form1 = dot + (dot & (maxPageSize - 1));
+ form2 = dot + (dot & (maxPageSize - commonPageSize));
+
+ if (form1 <= form2)
+ res->setValue(form1);
+ else
+ res->setValue(form2);
+ return res;
+}
+
diff --git a/lib/Script/UnaryOp.cpp b/lib/Script/UnaryOp.cpp
new file mode 100644
index 0000000..866bbb2
--- /dev/null
+++ b/lib/Script/UnaryOp.cpp
@@ -0,0 +1,188 @@
+//===- UnaryOp.cpp --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/UnaryOp.h>
+#include <mcld/Script/Operand.h>
+#include <mcld/Object/SectionMap.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/Module.h>
+#include <llvm/Support/Casting.h>
+#include <cassert>
+
+using namespace mcld;
+//===----------------------------------------------------------------------===//
+// UnaryOp
+//===----------------------------------------------------------------------===//
+template<>
+IntOperand* UnaryOp<Operator::UNARY_PLUS>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(+ m_pOperand->value());
+ return res;
+}
+
+template<>
+IntOperand*
+UnaryOp<Operator::UNARY_MINUS>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(- m_pOperand->value());
+ return res;
+}
+
+template<>
+IntOperand*
+UnaryOp<Operator::LOGICAL_NOT>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(! m_pOperand->value());
+ return res;
+}
+
+template<>
+IntOperand*
+UnaryOp<Operator::BITWISE_NOT>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(~ m_pOperand->value());
+ return res;
+}
+
+template<>
+IntOperand* UnaryOp<Operator::ABSOLUTE>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ // TODO
+ assert(0);
+ return result();
+}
+
+template<>
+IntOperand* UnaryOp<Operator::ADDR>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ const LDSection* sect = NULL;
+ switch (m_pOperand->type()) {
+ case Operand::SECTION:
+ sect = pModule.getSection(llvm::cast<SectOperand>(m_pOperand)->name());
+ break;
+ case Operand::SECTION_DESC:
+ sect = llvm::cast<SectDescOperand>(m_pOperand)->outputDesc()->getSection();
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ assert(sect != NULL);
+ res->setValue(sect->addr());
+ return res;
+}
+
+template<>
+IntOperand* UnaryOp<Operator::ALIGNOF>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ const LDSection* sect = NULL;
+ switch (m_pOperand->type()) {
+ case Operand::SECTION:
+ sect = pModule.getSection(llvm::cast<SectOperand>(m_pOperand)->name());
+ break;
+ case Operand::SECTION_DESC:
+ sect = llvm::cast<SectDescOperand>(m_pOperand)->outputDesc()->getSection();
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ assert(sect != NULL);
+ res->setValue(sect->align());
+ return res;
+}
+
+template<>
+IntOperand*
+UnaryOp<Operator::DATA_SEGMENT_END>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ res->setValue(m_pOperand->value());
+ return res;
+}
+
+template<>
+IntOperand* UnaryOp<Operator::DEFINED>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ // TODO
+ assert(0);
+ return result();
+}
+
+template<>
+IntOperand* UnaryOp<Operator::LENGTH>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ // TODO
+ assert(0);
+ return result();
+}
+
+template<>
+IntOperand* UnaryOp<Operator::LOADADDR>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ // TODO
+ assert(0);
+ return result();
+}
+
+template<>
+IntOperand* UnaryOp<Operator::NEXT>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ // TODO
+ assert(0);
+ return result();
+}
+
+template<>
+IntOperand* UnaryOp<Operator::ORIGIN>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ // TODO
+ assert(0);
+ return result();
+}
+
+template<>
+IntOperand* UnaryOp<Operator::SIZEOF>::eval(const Module& pModule,
+ const TargetLDBackend& pBackend)
+{
+ IntOperand* res = result();
+ const LDSection* sect = NULL;
+ switch (m_pOperand->type()) {
+ case Operand::SECTION:
+ sect = pModule.getSection(llvm::cast<SectOperand>(m_pOperand)->name());
+ break;
+ case Operand::SECTION_DESC:
+ sect = llvm::cast<SectDescOperand>(m_pOperand)->outputDesc()->getSection();
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ assert(sect != NULL);
+ res->setValue(sect->size());
+ return res;
+}
diff --git a/lib/Script/WildcardPattern.cpp b/lib/Script/WildcardPattern.cpp
new file mode 100644
index 0000000..035250e
--- /dev/null
+++ b/lib/Script/WildcardPattern.cpp
@@ -0,0 +1,69 @@
+//===- WildcardPattern.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Script/WildcardPattern.h>
+#include <mcld/Support/raw_ostream.h>
+#include <mcld/Support/GCFactory.h>
+#include <llvm/Support/ManagedStatic.h>
+#include <cassert>
+
+using namespace mcld;
+
+typedef GCFactory<WildcardPattern,
+ MCLD_SYMBOLS_PER_INPUT> WildcardPatternFactory;
+static llvm::ManagedStatic<WildcardPatternFactory> g_WildcardPatternFactory;
+
+//===----------------------------------------------------------------------===//
+// WildcardPattern
+//===----------------------------------------------------------------------===//
+WildcardPattern::WildcardPattern()
+ : m_bIsPrefix(false)
+{
+}
+
+WildcardPattern::WildcardPattern(const std::string& pPattern,
+ SortPolicy pPolicy)
+ : StrToken(StrToken::Wildcard, pPattern), m_SortPolicy(pPolicy)
+{
+ if (pPattern.find_first_of('*') == (pPattern.size() - 1))
+ m_bIsPrefix = true;
+ else
+ m_bIsPrefix = false;
+}
+
+WildcardPattern::~WildcardPattern()
+{
+}
+
+llvm::StringRef WildcardPattern::prefix() const
+{
+ if (isPrefix())
+ return llvm::StringRef(name().c_str(), name().size() - 1);
+
+ return llvm::StringRef(name());
+}
+
+WildcardPattern* WildcardPattern::create(const std::string& pPattern,
+ SortPolicy pPolicy)
+{
+ WildcardPattern* result = g_WildcardPatternFactory->allocate();
+ new (result) WildcardPattern(pPattern, pPolicy);
+ return result;
+}
+
+void WildcardPattern::destroy(WildcardPattern*& pWildcardPattern)
+{
+ g_WildcardPatternFactory->destroy(pWildcardPattern);
+ g_WildcardPatternFactory->deallocate(pWildcardPattern);
+ pWildcardPattern = NULL;
+}
+
+void WildcardPattern::clear()
+{
+ g_WildcardPatternFactory->clear();
+}
diff --git a/lib/Support/Android.mk b/lib/Support/Android.mk
index ce9c6f1..36983ed 100644
--- a/lib/Support/Android.mk
+++ b/lib/Support/Android.mk
@@ -2,25 +2,21 @@
mcld_support_SRC_FILES := \
CommandLine.cpp \
- DefSymParser.cpp \
Directory.cpp \
- FileHandle.cpp \
- FileSystem.cpp \
- HandleToArea.cpp \
- LEB128.cpp \
- MemoryArea.cpp \
+ FileHandle.cpp \
+ FileOutputBuffer.cpp \
+ FileSystem.cpp \
+ LEB128.cpp \
+ MemoryArea.cpp \
MemoryAreaFactory.cpp \
- MemoryRegion.cpp \
MsgHandling.cpp \
- Path.cpp \
- RealPath.cpp \
- RegionFactory.cpp \
- Space.cpp \
+ Path.cpp \
+ raw_ostream.cpp \
+ RealPath.cpp \
SystemUtils.cpp \
- TargetRegistry.cpp \
- ToolOutputFile.cpp \
- raw_mem_ostream.cpp \
- raw_ostream.cpp
+ Target.cpp \
+ TargetRegistry.cpp \
+ ToolOutputFile.cpp
# For the host
# =====================================================
diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp
index 96eb60b..033f88b 100644
--- a/lib/Support/CommandLine.cpp
+++ b/lib/Support/CommandLine.cpp
@@ -142,7 +142,8 @@
long long unsigned size = 0;
Arg.drop_front(17).getAsInteger(0, size);
Val.setPageSize(static_cast<uint64_t>(size));
- } else if (Arg.startswith("max-page-size=")) {
+ }
+ else if (Arg.startswith("max-page-size=")) {
Val.setKind(ZOption::MaxPageSize);
long long unsigned size = 0;
Arg.drop_front(14).getAsInteger(0, size);
diff --git a/lib/Support/DefSymParser.cpp b/lib/Support/DefSymParser.cpp
deleted file mode 100644
index 424364d..0000000
--- a/lib/Support/DefSymParser.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-//===- DefSymParser.cpp ---------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/Support/DefSymParser.h>
-#include <mcld/Support/MsgHandling.h>
-#include <mcld/LD/LDSymbol.h>
-
-using namespace llvm;
-using namespace mcld;
-
-DefSymParser::DefSymParser(const Module& pModule)
- : m_Module(pModule) {
-}
-
-// passing a valid operator will return a number whose quantity relative
-// to other such obtained quantities will give the priority of the operator
-static inline int precedence(const char* x)
-{
- switch (*x) {
- case '-' :
- case '+' : return 0;
- case '/' :
- case '*' : return 1;
- default : assert("Unsupported operator specified");
- }
- return 0;
-}
-
-bool DefSymParser::parse(StringRef pExpr, uint64_t& pSymVal)
-{
- std::stack<const char*> operatorStack;
- std::stack<unsigned long> operandStack;
- unsigned long operand1 = 0,
- operand2 = 0,
- result = 0;
- std::string token;
- std::vector<std::string> postfixString;
- std::vector<std::string>::iterator it;
- llvm::StringRef::iterator si = pExpr.begin();
-
- // Implement a modified Shunting Yard algorithm to form a RPN of the
- // given expression
- while (si != pExpr.end()) {
- if (*si == '+' || *si == '-' || *si == '*' || *si == '/') {
- if (token.empty() && (*si == '+' || *si == '-'))
- // we have a case such as a++b or a+-b or a-+b
- // pushing 0 when a token begins with a + or - operator
- // solves unary operator problem
- token = "0";
- // An operator encountered means a token ended, push it to
- // postfix string queue.
- postfixString.push_back(token);
- token.clear();
-
- if (operatorStack.empty()) {
- operatorStack.push(si);
- }
- else {
- if (precedence(si) <= precedence(operatorStack.top())) {
- // if the precedence of incoming operator is less or equal to
- // top of stack, we clear stack till top is lower precedence
- // or its empty
- while (!operatorStack.empty()) {
- if (precedence(si) <= precedence(operatorStack.top())) {
- postfixString.push_back(std::string(operatorStack.top(),1));
- operatorStack.pop();
- }
- else {
- break;
- }
- }
- }
- operatorStack.push(si);
- }
- si++;
- continue;
- }
- // keep reading the token when there is no operator encountered
- token += *si;
- si++;
- }
- postfixString.push_back(token);
- // pop off any remaining operators from operator stack
- while (!operatorStack.empty()) {
- postfixString.push_back(std::string(operatorStack.top(),1));
- operatorStack.pop();
- }
- //evaluate the postfix expression written above
-
- for (it=postfixString.begin(); it != postfixString.end(); it++) {
- switch (*((*it).c_str())) {
- case '*':
- case '-':
- case '+':
- case '/':
- // when postfix string has an operator, pop first two operands from
- // operand stack, use them in evaluate expression and push result
- // back to stack
- assert(!operandStack.empty() && "Invalid expression: extra operand");
- operand2 = operandStack.top();
- operandStack.pop();
- operand1 = operandStack.top();
- operandStack.pop();
- if (*((*it).c_str()) == '*')
- result = operand1 * operand2;
- else if (*((*it).c_str()) == '/')
- result = operand1 / operand2;
- else if (*((*it).c_str()) == '-')
- result = operand1 - operand2;
- else
- result = operand1 + operand2;
- operandStack.push(result);
- break;
- default:
- // if the string encountered in postfix queue is a string
- // try converting it to integer.
- llvm::StringRef stringOperand(*it);
- if(stringOperand.getAsInteger(0,result)) {
- // the integer conversion failed means the token is a symbol
- // or its invalid if the NamePool has no such symbol;
- const LDSymbol* symbol =
- m_Module.getNamePool().findSymbol(stringOperand);
-
- if (!symbol)
- fatal(diag::fail_sym_resolution)
- << __FILE__ << __LINE__
- << "mclinker@googlegroups.com" ;
- result = symbol->value();
- }
- operandStack.push(result);
- }
- }
- // once complete queue is processed, stack top is result
- pSymVal = operandStack.top();
- return true;
-}
diff --git a/lib/Support/FileOutputBuffer.cpp b/lib/Support/FileOutputBuffer.cpp
new file mode 100644
index 0000000..ed8c898
--- /dev/null
+++ b/lib/Support/FileOutputBuffer.cpp
@@ -0,0 +1,59 @@
+//===- FileOutputBuffer.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/FileOutputBuffer.h>
+#include <mcld/Support/FileHandle.h>
+#include <mcld/Support/Path.h>
+
+using namespace mcld;
+using llvm::sys::fs::mapped_file_region;
+
+FileOutputBuffer::FileOutputBuffer(llvm::sys::fs::mapped_file_region* pRegion,
+ FileHandle& pFileHandle)
+ : m_pRegion(pRegion), m_FileHandle(pFileHandle)
+{
+}
+
+FileOutputBuffer::~FileOutputBuffer()
+{
+ // Unmap buffer, letting OS flush dirty pages to file on disk.
+ m_pRegion.reset(0);
+}
+
+llvm::error_code FileOutputBuffer::create(FileHandle& pFileHandle,
+ size_t pSize, llvm::OwningPtr<FileOutputBuffer>& pResult)
+{
+ llvm::error_code EC;
+ llvm::OwningPtr<mapped_file_region> mapped_file(new mapped_file_region(
+ pFileHandle.handler(),
+ false,
+ mapped_file_region::readwrite,
+ pSize,
+ 0,
+ EC));
+
+ if (EC)
+ return EC;
+
+ pResult.reset(new FileOutputBuffer(mapped_file.get(), pFileHandle));
+ if (pResult)
+ mapped_file.take();
+ return llvm::error_code::success();
+}
+
+MemoryRegion FileOutputBuffer::request(size_t pOffset, size_t pLength)
+{
+ if (pOffset > getBufferSize() || (pOffset + pLength) > getBufferSize())
+ return MemoryRegion();
+ return MemoryRegion(getBufferStart() + pOffset, pLength);
+}
+
+llvm::StringRef FileOutputBuffer::getPath() const
+{
+ return m_FileHandle.path().native();
+}
diff --git a/lib/Support/HandleToArea.cpp b/lib/Support/HandleToArea.cpp
deleted file mode 100644
index 31a26c5..0000000
--- a/lib/Support/HandleToArea.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-//===- HandleToArea.cpp ----------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/Support/HandleToArea.h>
-#include <mcld/Support/MemoryArea.h>
-#include <llvm/ADT/StringRef.h>
-
-using namespace mcld;
-
-//===----------------------------------------------------------------------===//
-// HandleToArea
-//===----------------------------------------------------------------------===//
-bool HandleToArea::push_back(FileHandle* pHandle, MemoryArea* pArea)
-{
- if (NULL == pHandle || NULL == pArea)
- return false;
-
- Bucket bucket;
- bucket.hash_value = HashFunction()(
- llvm::StringRef(pHandle->path().native().c_str(),
- pHandle->path().native().size()));
-
- bucket.handle = pHandle;
- bucket.area = pArea;
- m_AreaMap.push_back(bucket);
- return true;
-}
-
-bool HandleToArea::erase(MemoryArea* pArea)
-{
- if (NULL == pArea || NULL == pArea->handler())
- return false;
-
- return erase(pArea->handler()->path());
-}
-
-bool HandleToArea::erase(const sys::fs::Path& pPath)
-{
- unsigned int hash_value = HashFunction()(
- llvm::StringRef(pPath.native().c_str(),
- pPath.native().size()));
-
- HandleToAreaMap::iterator bucket, bEnd = m_AreaMap.end();
- for (bucket = m_AreaMap.begin(); bucket != bEnd; ++bucket) {
- if (bucket->hash_value == hash_value && bucket->handle->path() == pPath) {
- // found
- m_AreaMap.erase(bucket);
- return true;
- }
- }
-
- return false;
-}
-
-HandleToArea::Result HandleToArea::findFirst(const sys::fs::Path& pPath)
-{
- unsigned int hash_value = HashFunction()(llvm::StringRef(pPath.native().c_str(),
- pPath.native().size()));
-
- HandleToAreaMap::iterator bucket, bEnd = m_AreaMap.end();
-
- for (bucket = m_AreaMap.begin(); bucket != bEnd; ++bucket) {
- if (bucket->hash_value == hash_value) {
- if (bucket->handle->path() == pPath) {
- return Result(bucket->handle, bucket->area);
- }
- }
- }
-
- return Result(NULL, NULL);
-}
-
-HandleToArea::ConstResult HandleToArea::findFirst(const sys::fs::Path& pPath) const
-{
- unsigned int hash_value = HashFunction()(llvm::StringRef(pPath.native().c_str(),
- pPath.native().size()));
-
- HandleToAreaMap::const_iterator bucket, bEnd = m_AreaMap.end();
-
- for (bucket = m_AreaMap.begin(); bucket != bEnd; ++bucket) {
- if (bucket->hash_value == hash_value) {
- if (bucket->handle->path() == pPath) {
- return ConstResult(bucket->handle, bucket->area);
- }
- }
- }
-
- return ConstResult(NULL, NULL);
-}
-
diff --git a/lib/Support/MemoryArea.cpp b/lib/Support/MemoryArea.cpp
index c4015ea..862e6f1 100644
--- a/lib/Support/MemoryArea.cpp
+++ b/lib/Support/MemoryArea.cpp
@@ -7,161 +7,39 @@
//
//===----------------------------------------------------------------------===//
#include <mcld/Support/MemoryArea.h>
-#include <mcld/Support/Space.h>
-#include <mcld/Support/MemoryRegion.h>
-#include <mcld/Support/FileHandle.h>
-#include <mcld/Support/MsgHandling.h>
+#include <llvm/Support/system_error.h>
+
+#include <cassert>
using namespace mcld;
//===--------------------------------------------------------------------===//
// MemoryArea
//===--------------------------------------------------------------------===//
-// MemoryArea - special constructor
-// This constructor is used for *SPECIAL* situation. I'm sorry I can not
-// reveal what is the special situation.
-MemoryArea::MemoryArea(Space& pUniverse)
- : m_pFileHandle(NULL) {
- m_SpaceMap.insert(std::make_pair(Key(pUniverse.start(), pUniverse.size()),
- &pUniverse));
-}
-
-MemoryArea::MemoryArea(FileHandle& pFileHandle)
- : m_pFileHandle(&pFileHandle) {
-}
-
-MemoryArea::~MemoryArea()
+MemoryArea::MemoryArea(llvm::StringRef pFilename)
{
+ llvm::MemoryBuffer::getFile(pFilename,
+ m_pMemoryBuffer,
+ /*FileSize*/ -1,
+ /*RequiresNullTerminator*/ false);
}
-// The layout of MemorySpace in the virtual memory space
-//
-// | : page boundary
-// [,]: MemoryRegion
-// - : fillment
-// = : data
-//
-// |---[=|====|====|==]--|
-// ^ ^ ^ ^
-// | | | |
-// | r_start +r_len |
-// space.data +space.size
-//
-// space.file_offset is the offset of the mapped file segment from the start of
-// the file. if the MemorySpace's type is ALLOCATED_ARRAY, the distances of
-// (space.data, r_start) and (r_len, space.size) are zero.
-//
-MemoryRegion* MemoryArea::request(size_t pOffset, size_t pLength)
+MemoryArea::MemoryArea(const char* pMemBuffer, size_t pSize)
{
- Space* space = find(pOffset, pLength);
- if (NULL == space) {
- // not found
- if (NULL == m_pFileHandle) {
- // if m_pFileHandle is NULL, clients delegate us an universal Space and
- // we never remove it. In that way, space can not be NULL.
- unreachable(diag::err_out_of_range_region) << pOffset << pLength;
- }
-
- space = Space::Create(*m_pFileHandle, pOffset, pLength);
- m_SpaceMap.insert(std::make_pair(Key(space->start(), space->size()), space));
- }
-
- // adjust r_start
- off_t distance = pOffset - space->start();
- void* r_start = space->memory() + distance;
-
- // now, we have a legal space to hold the new MemoryRegion
- return MemoryRegion::Create(r_start, pLength, *space);
+ llvm::StringRef mem(pMemBuffer, pSize);
+ llvm::MemoryBuffer* buffer =
+ llvm::MemoryBuffer::getMemBuffer(mem, /*BufferName*/ "NaN",
+ /*RequiresNullTerminator*/ false);
+ assert(buffer != NULL);
+ m_pMemoryBuffer.reset(buffer);
}
-// release - release a MemoryRegion
-void MemoryArea::release(MemoryRegion* pRegion)
+llvm::StringRef MemoryArea::request(size_t pOffset, size_t pLength)
{
- if (NULL == pRegion)
- return;
-
- Space *space = pRegion->parent();
- MemoryRegion::Destroy(pRegion);
-
- if (0 == space->numOfRegions()) {
-
- if (NULL != m_pFileHandle) {
- // if m_pFileHandle is NULL, clients delegate us an universal Space and
- // we never remove it. Otherwise, we have to synchronize and release
- // Space.
- if (m_pFileHandle->isWritable()) {
- // synchronize writable space before we release it.
- Space::Sync(space, *m_pFileHandle);
- }
-
- std::pair<SpaceMapType::iterator, SpaceMapType::iterator> range =
- m_SpaceMap.equal_range(Key(space->start(), space->size()));
- SpaceMapType::iterator it;
- for (it = range.first; it != range.second; ++it) {
- if (space == it->second)
- break;
- }
- m_SpaceMap.erase(it);
-
- Space::Release(space, *m_pFileHandle);
- assert(NULL != space);
- Space::Destroy(space);
- }
- }
+ return llvm::StringRef(m_pMemoryBuffer->getBufferStart() + pOffset, pLength);
}
-// clear - release all MemoryRegions
-void MemoryArea::clear()
+size_t MemoryArea::size() const
{
- if (NULL == m_pFileHandle)
- return;
-
- SpaceMapType::iterator space, sEnd = m_SpaceMap.end();
- if (m_pFileHandle->isWritable()) {
- for (space = m_SpaceMap.begin(); space != sEnd; ++space) {
- Space::Sync(space->second, *m_pFileHandle);
- Space::Release(space->second, *m_pFileHandle);
- assert(NULL != space->second);
- Space::Destroy(space->second);
- }
- }
- else {
- for (space = m_SpaceMap.begin(); space != sEnd; ++space) {
- Space::Release(space->second, *m_pFileHandle);
- assert(NULL != space->second);
- Space::Destroy(space->second);
- }
- }
-
- m_SpaceMap.clear();
+ return m_pMemoryBuffer->getBufferSize();
}
-
-//===--------------------------------------------------------------------===//
-// SpaceList methods
-//===--------------------------------------------------------------------===//
-Space* MemoryArea::find(size_t pOffset, size_t pLength)
-{
- std::pair<SpaceMapType::iterator, SpaceMapType::iterator> range =
- m_SpaceMap.equal_range(Key(pOffset, pLength));
- SpaceMapType::iterator it;
- for (it = range.first; it != range.second; ++it) {
- if ((it->second->start() <= pOffset) &&
- ((pOffset + pLength) <= (it->second->start() + it->second->size())))
- return it->second;
- }
- return NULL;
-}
-
-const Space* MemoryArea::find(size_t pOffset, size_t pLength) const
-{
- std::pair<SpaceMapType::const_iterator, SpaceMapType::const_iterator> range =
- m_SpaceMap.equal_range(Key(pOffset, pLength));
- SpaceMapType::const_iterator it;
- for (it = range.first; it != range.second; ++it) {
- if ((it->second->start() <= pOffset) &&
- ((pOffset + pLength) <= (it->second->start() + it->second->size())))
- return it->second;
- }
- return NULL;
-}
-
diff --git a/lib/Support/MemoryAreaFactory.cpp b/lib/Support/MemoryAreaFactory.cpp
index 224e0a6..655c525 100644
--- a/lib/Support/MemoryAreaFactory.cpp
+++ b/lib/Support/MemoryAreaFactory.cpp
@@ -9,7 +9,6 @@
#include <mcld/Support/MemoryAreaFactory.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/SystemUtils.h>
-#include <mcld/Support/Space.h>
using namespace mcld;
@@ -22,88 +21,59 @@
MemoryAreaFactory::~MemoryAreaFactory()
{
- HandleToArea::iterator rec, rEnd = m_HandleToArea.end();
- for (rec = m_HandleToArea.begin(); rec != rEnd; ++rec) {
- if (rec->handle->isOpened()) {
- rec->handle->close();
- }
- delete rec->handle;
- }
}
-MemoryArea*
-MemoryAreaFactory::produce(const sys::fs::Path& pPath,
- FileHandle::OpenMode pMode)
+MemoryArea* MemoryAreaFactory::produce(const sys::fs::Path& pPath,
+ FileHandle::OpenMode pMode)
{
- HandleToArea::Result map_result = m_HandleToArea.findFirst(pPath);
- if (NULL == map_result.area) {
- // can not found
- FileHandle* handler = new FileHandle();
- if (!handler->open(pPath, pMode)) {
- error(diag::err_cannot_open_file) << pPath
- << sys::strerror(handler->error());
- }
-
+ llvm::StringRef name(pPath.native());
+ if (m_AreaMap.find(name) == m_AreaMap.end()) {
MemoryArea* result = allocate();
- new (result) MemoryArea(*handler);
-
- m_HandleToArea.push_back(handler, result);
+ new (result) MemoryArea(name);
+ m_AreaMap[name] = result;
return result;
}
- return map_result.area;
+ return m_AreaMap[name];
}
-MemoryArea*
-MemoryAreaFactory::produce(const sys::fs::Path& pPath,
- FileHandle::OpenMode pMode,
- FileHandle::Permission pPerm)
+MemoryArea* MemoryAreaFactory::produce(const sys::fs::Path& pPath,
+ FileHandle::OpenMode pMode,
+ FileHandle::Permission pPerm)
{
- HandleToArea::Result map_result = m_HandleToArea.findFirst(pPath);
- if (NULL == map_result.area) {
- // can not found
- FileHandle* handler = new FileHandle();
- if (!handler->open(pPath, pMode, pPerm)) {
- error(diag::err_cannot_open_file) << pPath
- << sys::strerror(handler->error());
- }
-
+ llvm::StringRef name(pPath.native());
+ if (m_AreaMap.find(name) == m_AreaMap.end()) {
MemoryArea* result = allocate();
- new (result) MemoryArea(*handler);
-
- m_HandleToArea.push_back(handler, result);
+ new (result) MemoryArea(name);
+ m_AreaMap[name] = result;
return result;
}
- return map_result.area;
+ return m_AreaMap[name];
}
MemoryArea* MemoryAreaFactory::produce(void* pMemBuffer, size_t pSize)
{
- Space* space = Space::Create(pMemBuffer, pSize);
- MemoryArea* result = allocate();
- new (result) MemoryArea(*space);
- return result;
+ const char* base = reinterpret_cast<const char*>(pMemBuffer);
+ llvm::StringRef name(base, pSize);
+ if (m_AreaMap.find(name) == m_AreaMap.end()) {
+ MemoryArea* result = allocate();
+ new (result) MemoryArea(base, pSize);
+ m_AreaMap[name] = result;
+ return result;
+ }
+
+ return m_AreaMap[name];
}
-MemoryArea*
-MemoryAreaFactory::produce(int pFD, FileHandle::OpenMode pMode)
+MemoryArea* MemoryAreaFactory::produce(int pFD, FileHandle::OpenMode pMode)
{
- FileHandle* handler = new FileHandle();
- handler->delegate(pFD, pMode);
-
- MemoryArea* result = allocate();
- new (result) MemoryArea(*handler);
-
- return result;
+ // TODO
+ return NULL;
}
void MemoryAreaFactory::destruct(MemoryArea* pArea)
{
- m_HandleToArea.erase(pArea);
- pArea->clear();
- pArea->handler()->close();
destroy(pArea);
deallocate(pArea);
}
-
diff --git a/lib/Support/MemoryRegion.cpp b/lib/Support/MemoryRegion.cpp
deleted file mode 100644
index 410500a..0000000
--- a/lib/Support/MemoryRegion.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//===- MemoryRegion.cpp ---------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/Support/MemoryRegion.h>
-#include <mcld/Support/RegionFactory.h>
-
-#include <llvm/Support/ManagedStatic.h>
-
-using namespace mcld;
-
-static llvm::ManagedStatic<RegionFactory> g_RegionFactory;
-
-//===----------------------------------------------------------------------===//
-// MemoryRegion
-//===----------------------------------------------------------------------===//
-MemoryRegion::MemoryRegion()
- : m_pParent(NULL), m_VMAStart(0), m_Length(0) {
-}
-
-MemoryRegion::MemoryRegion(MemoryRegion::Address pVMAStart, size_t pSize)
- : m_pParent(NULL), m_VMAStart(pVMAStart), m_Length(pSize) {
-}
-
-MemoryRegion::~MemoryRegion()
-{
-}
-
-MemoryRegion* MemoryRegion::Create(void* pStart, size_t pSize)
-{
- return g_RegionFactory->produce(static_cast<Address>(pStart), pSize);
-}
-
-MemoryRegion* MemoryRegion::Create(void* pStart, size_t pSize, Space& pSpace)
-{
- MemoryRegion* result = g_RegionFactory->produce(static_cast<Address>(pStart),
- pSize);
- result->setParent(pSpace);
- pSpace.addRegion(*result);
- return result;
-}
-
-void MemoryRegion::Destroy(MemoryRegion*& pRegion)
-{
- if (NULL == pRegion)
- return;
-
- if (pRegion->hasParent())
- pRegion->parent()->removeRegion(*pRegion);
- g_RegionFactory->destruct(pRegion);
- pRegion = NULL;
-}
-
diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp
index 563fe1f..57d4bd8 100644
--- a/lib/Support/Path.cpp
+++ b/lib/Support/Path.cpp
@@ -197,9 +197,10 @@
Path Path::extension() const
{
- size_t begin_pos = m_PathName.find_last_of('.');
- Path result_path(m_PathName.substr(begin_pos));
- return result_path;
+ size_t pos = m_PathName.find_last_of('.');
+ if (pos == StringType::npos)
+ return Path();
+ return Path(m_PathName.substr(pos));
}
//===--------------------------------------------------------------------===//
diff --git a/lib/Support/RegionFactory.cpp b/lib/Support/RegionFactory.cpp
deleted file mode 100644
index a52921b..0000000
--- a/lib/Support/RegionFactory.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-//===- RegionFactory.cpp --------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/Support/RegionFactory.h>
-#include <mcld/Support/Space.h>
-
-#include <new>
-
-using namespace mcld;
-
-//===----------------------------------------------------------------------===//
-// RegionFactory
-//===----------------------------------------------------------------------===//
-MemoryRegion*
-RegionFactory::produce(Address pVMAStart, size_t pSize)
-{
- MemoryRegion* result = Alloc::allocate();
- new (result) MemoryRegion(pVMAStart, pSize);
- return result;
-}
-
-void RegionFactory::destruct(MemoryRegion* pRegion)
-{
- destroy(pRegion);
- deallocate(pRegion);
-}
-
diff --git a/lib/Support/Space.cpp b/lib/Support/Space.cpp
deleted file mode 100644
index b9a306e..0000000
--- a/lib/Support/Space.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-//===- Space.cpp ----------------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/Support/Space.h>
-#include <mcld/Support/FileHandle.h>
-#include <mcld/Support/MsgHandling.h>
-#include <mcld/Support/SystemUtils.h>
-#include <cstdlib>
-#include <unistd.h>
-
-using namespace mcld;
-
-//===----------------------------------------------------------------------===//
-// constant data
-//===----------------------------------------------------------------------===//
-static const int PageSize = mcld::sys::GetPageSize();
-
-//===----------------------------------------------------------------------===//
-// Non-member functions
-//===----------------------------------------------------------------------===//
-//
-// low address A page high address
-// |--------------------|------------------|
-// ^ page_offset ^ pFileOffset ^ page_boundary
-//
-// Given a file offset, return the page offset.
-// return the first page boundary \b before pFileOffset
-inline static off_t page_offset(off_t pFileOffset)
-{ return pFileOffset & ~ (PageSize - 1); }
-
-// page_boundary - Given a file size, return the size to read integral pages.
-// return the first page boundary \b after pFileOffset
-inline static off_t page_boundary(off_t pFileOffset)
-{ return (pFileOffset + (PageSize - 1)) & ~ (PageSize - 1); }
-
-inline static Space::Type policy(off_t pOffset, size_t pLength)
-{
-#if defined(MCLD_ON_WIN32)
- return Space::ALLOCATED_ARRAY;
-#endif
- const size_t threshold = (PageSize*3)/4; // 3/4 page size in Linux
- if (pLength < threshold)
- return Space::ALLOCATED_ARRAY;
- else
- return Space::MMAPED;
-}
-
-//===----------------------------------------------------------------------===//
-// Space
-//===----------------------------------------------------------------------===//
-Space::Space()
- : m_Data(NULL), m_StartOffset(0), m_Size(0),
- m_RegionCount(0), m_Type(UNALLOCATED) {
-}
-
-Space::Space(Space::Type pType, void* pMemBuffer, size_t pSize)
- : m_Data(static_cast<Address>(pMemBuffer)), m_StartOffset(0), m_Size(pSize),
- m_RegionCount(0), m_Type(pType)
-{
-}
-
-Space::~Space()
-{
- // do nothing. m_Data is deleted by @ref releaseSpace
-}
-
-Space* Space::Create(void* pMemBuffer, size_t pSize)
-{
- Space* result = new Space(EXTERNAL, pMemBuffer, pSize);
- return result;
-}
-
-Space* Space::Create(FileHandle& pHandler, size_t pStart, size_t pSize)
-{
- Type type;
- void* memory = NULL;
- Space* result = NULL;
- size_t start = 0, size = 0, total_offset = 0;
- switch(type = policy(pStart, pSize)) {
- case ALLOCATED_ARRAY: {
- // adjust total_offset, start and size
- total_offset = pStart + pSize;
- start = pStart;
- if (total_offset > pHandler.size()) {
- if (pHandler.isWritable()) {
- size = pSize;
- pHandler.truncate(total_offset);
- }
- else if (pHandler.size() > start) {
- // not writable -> shrink the size
- size = pHandler.size() - start;
- }
- else {
- // create a space out of a read-only file.
- fatal(diag::err_cannot_read_small_file) << pHandler.path()
- << pHandler.size()
- << start << size;
- }
- }
- else {
- // within the space.
- size = pSize;
- }
-
- // malloc
- memory = (void*)malloc(size);
- if (!pHandler.read(memory, start, size))
- error(diag::err_cannot_read_file) << pHandler.path() << start << size;
-
- break;
- }
- case MMAPED: {
- // adjust total_offset, start and size
- total_offset = page_boundary(pStart + pSize);
- start = page_offset(pStart);
- if (total_offset > pHandler.size()) {
- if (pHandler.isWritable()) {
- size = page_boundary((pStart - start) + pSize);
- pHandler.truncate(total_offset);
- }
- else if (pHandler.size() > start)
- size = pHandler.size() - start;
- else {
- // create a space out of a read-only file.
- fatal(diag::err_cannot_read_small_file) << pHandler.path()
- << pHandler.size()
- << start << size;
- }
- }
- else
- size = page_boundary((pStart - start) + pSize);
-
- // mmap
- if (!pHandler.mmap(memory, start, size))
- error(diag::err_cannot_mmap_file) << pHandler.path() << start << size;
-
- break;
- }
- default:
- break;
- } // end of switch
-
- result = new Space(type, memory, size);
- result->setStart(start);
- return result;
-}
-
-void Space::Destroy(Space*& pSpace)
-{
- delete pSpace;
- pSpace = NULL;
-}
-
-void Space::Release(Space* pSpace, FileHandle& pHandler)
-{
- if (NULL == pSpace)
- return;
-
- switch(pSpace->type()) {
- case ALLOCATED_ARRAY:
- free(pSpace->memory());
- break;
- case MMAPED:
- if (!pHandler.munmap(pSpace->memory(), pSpace->size()))
- error(diag::err_cannot_munmap_file) << pHandler.path();
- break;
- default: // external and unallocated memory buffers
- break;
- } // end of switch
-}
-
-void Space::Sync(Space* pSpace, FileHandle& pHandler)
-{
- if (NULL == pSpace || !pHandler.isWritable())
- return;
-
- switch(pSpace->type()) {
- case Space::ALLOCATED_ARRAY: {
- if (!pHandler.write(pSpace->memory(),
- pSpace->start(),
- pSpace->size())) {
- error(diag::err_cannot_write_file) << pHandler.path()
- << pSpace->start()
- << pSpace->size();
- }
- return;
- }
- case Space::MMAPED:
- default: {
- // system will eventually write bakc the memory after
- // calling ::munmap
- return;
- }
- } // end of switch
-}
-
diff --git a/lib/Support/Target.cpp b/lib/Support/Target.cpp
new file mode 100644
index 0000000..d0e5f29
--- /dev/null
+++ b/lib/Support/Target.cpp
@@ -0,0 +1,81 @@
+//===- Target.cpp ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/Target.h>
+#include <llvm/ADT/Triple.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// Target
+//===----------------------------------------------------------------------===//
+Target::Target()
+ : Name(NULL),
+ TripleMatchQualityFn(NULL),
+ TargetMachineCtorFn(NULL),
+ MCLinkerCtorFn(NULL),
+ TargetLDBackendCtorFn(NULL),
+ DiagnosticLineInfoCtorFn(NULL) {
+}
+
+unsigned int Target::getTripleQuality(const llvm::Triple& pTriple) const
+{
+ if (NULL == TripleMatchQualityFn)
+ return 0;
+ return TripleMatchQualityFn(pTriple);
+}
+
+MCLDTargetMachine*
+Target::createTargetMachine(const std::string& pTriple,
+ const llvm::Target& pTarget,
+ llvm::TargetMachine& pTM) const
+{
+ if (NULL == TargetMachineCtorFn)
+ return NULL;
+ return TargetMachineCtorFn(pTarget, *this, pTM, pTriple);
+}
+
+/// createMCLinker - create target-specific MCLinker
+MCLinker*
+Target::createMCLinker(const std::string &pTriple,
+ LinkerConfig& pConfig,
+ Module& pModule,
+ FileHandle& pFileHandle) const
+{
+ if (NULL == MCLinkerCtorFn)
+ return NULL;
+ return MCLinkerCtorFn(pTriple, pConfig, pModule, pFileHandle);
+}
+
+/// emulate - given MCLinker default values for the other aspects of the
+/// target system.
+bool Target::emulate(LinkerScript& pScript, LinkerConfig& pConfig) const
+{
+ if (NULL == EmulationFn)
+ return false;
+ return EmulationFn(pScript, pConfig);
+}
+
+/// createLDBackend - create target-specific LDBackend
+TargetLDBackend* Target::createLDBackend(const LinkerConfig& pConfig) const
+{
+ if (NULL == TargetLDBackendCtorFn)
+ return NULL;
+ return TargetLDBackendCtorFn(pConfig);
+}
+
+/// createDiagnosticLineInfo - create target-specific DiagnosticLineInfo
+DiagnosticLineInfo*
+Target::createDiagnosticLineInfo(const mcld::Target& pTarget,
+ const std::string& pTriple) const
+{
+ if (NULL == DiagnosticLineInfoCtorFn)
+ return NULL;
+ return DiagnosticLineInfoCtorFn(pTarget, pTriple);
+}
+
diff --git a/lib/Support/TargetRegistry.cpp b/lib/Support/TargetRegistry.cpp
index 38074d5..afffc5c 100644
--- a/lib/Support/TargetRegistry.cpp
+++ b/lib/Support/TargetRegistry.cpp
@@ -8,36 +8,98 @@
//===----------------------------------------------------------------------===//
#include <mcld/Support/TargetRegistry.h>
+using namespace mcld;
-mcld::TargetRegistry::TargetListTy mcld::TargetRegistry::s_TargetList;
+TargetRegistry::TargetListTy mcld::TargetRegistry::s_TargetList;
-void mcld::TargetRegistry::RegisterTarget(mcld::Target &T)
+//===----------------------------------------------------------------------===//
+// TargetRegistry
+//===----------------------------------------------------------------------===//
+void TargetRegistry::RegisterTarget(Target& pTarget,
+ const char* pName,
+ Target::TripleMatchQualityFnTy pQualityFn)
{
- s_TargetList.push_back(&T);
+ pTarget.Name = pName;
+ pTarget.TripleMatchQualityFn = pQualityFn;
+
+ s_TargetList.push_back(&pTarget);
}
-const mcld::Target*
-mcld::TargetRegistry::lookupTarget(const llvm::Target &pTarget)
+const Target* TargetRegistry::lookupTarget(const std::string &pTriple,
+ std::string &pError)
{
- mcld::Target *result = 0;
- TargetListTy::const_iterator TIter, TEnd = s_TargetList.end();
- for (TIter=s_TargetList.begin(); TIter!=TEnd; ++TIter) {
- if ((*TIter)->get()==&pTarget) {
- result = (*TIter);
- break;
+ if (empty()) {
+ pError = "Unable to find target for this triple (no target are registered)";
+ return NULL;
+ }
+
+ llvm::Triple triple(pTriple);
+ Target* best = NULL, *ambiguity = NULL;
+ unsigned int highest = 0;
+
+ for (iterator target = begin(), ie = end(); target != ie; ++target) {
+ unsigned int quality = (*target)->getTripleQuality(triple);
+ if (quality > 0) {
+ if (NULL == best || highest < quality) {
+ highest = quality;
+ best = *target;
+ ambiguity = NULL;
+ }
+ else if (highest == quality) {
+ ambiguity = *target;
+ }
+ }
+ }
+
+ if (NULL == best) {
+ pError = "No availaible targets are compatible with this triple.";
+ return NULL;
+ }
+
+ if (NULL != ambiguity) {
+ pError = std::string("Ambiguous targets: \"") +
+ best->name() + "\" and \"" + ambiguity->name() + "\"";
+ return NULL;
+ }
+
+ return best;
+}
+
+const Target* TargetRegistry::lookupTarget(const std::string& pArchName,
+ llvm::Triple& pTriple,
+ std::string& pError)
+{
+ const Target* result = NULL;
+ if (!pArchName.empty()) {
+ for (mcld::TargetRegistry::iterator it = mcld::TargetRegistry::begin(),
+ ie = mcld::TargetRegistry::end(); it != ie; ++it) {
+ if (pArchName == (*it)->name()) {
+ result = *it;
+ break;
+ }
+ }
+
+ if (NULL == result) {
+ pError = std::string("invalid target '") + pArchName + "'.\n";
+ return NULL;
+ }
+
+ // Adjust the triple to match (if known), otherwise stick with the
+ // module/host triple.
+ llvm::Triple::ArchType type =
+ llvm::Triple::getArchTypeForLLVMName(pArchName);
+ if (llvm::Triple::UnknownArch != type)
+ pTriple.setArch(type);
+ }
+ else {
+ std::string error;
+ result = lookupTarget(pTriple.getTriple(), error);
+ if (NULL == result) {
+ pError = std::string("unable to get target for `") +
+ pTriple.getTriple() + "'\n" +
+ "(Detail: " + error + ")\n";
+ return NULL;
}
}
return result;
}
-
-const mcld::Target*
-mcld::TargetRegistry::lookupTarget(const std::string &pTriple,
- std::string &pError)
-{
- const llvm::Target* target = llvm::TargetRegistry::lookupTarget(pTriple, pError);
- if (!target)
- return NULL;
-
- return lookupTarget( *target );
-}
-
diff --git a/lib/Support/ToolOutputFile.cpp b/lib/Support/ToolOutputFile.cpp
index 0554398..1223d93 100644
--- a/lib/Support/ToolOutputFile.cpp
+++ b/lib/Support/ToolOutputFile.cpp
@@ -11,12 +11,12 @@
#include <mcld/Support/Path.h>
#include <mcld/Support/FileHandle.h>
#include <mcld/Support/MemoryArea.h>
-#include <mcld/Support/raw_mem_ostream.h>
#include <mcld/Support/SystemUtils.h>
#include <mcld/Support/MsgHandling.h>
#include <llvm/Support/Signals.h>
+#include <llvm/Support/Path.h>
#include <llvm/Support/FormattedStream.h>
using namespace mcld;
@@ -24,56 +24,53 @@
//===----------------------------------------------------------------------===//
// CleanupInstaller
//===----------------------------------------------------------------------===//
-ToolOutputFile::CleanupInstaller::CleanupInstaller(const std::string& pPath)
+ToolOutputFile::CleanupInstaller::CleanupInstaller(const sys::fs::Path& pPath)
: Keep(false), m_Path(pPath) {
// Arrange for the file to be deleted if the process is killed.
- if ("-" != m_Path)
- llvm::sys::RemoveFileOnSignal(m_Path);
+ if ("-" != m_Path.native())
+ llvm::sys::RemoveFileOnSignal(m_Path.native());
}
ToolOutputFile::CleanupInstaller::~CleanupInstaller()
{
// Delete the file if the client hasn't told us not to.
// FIXME: In Windows, some path in CJK characters can not be removed by LLVM
- // sys::fs::remove
- if (!Keep && "_" != m_Path)
- llvm::sys::fs::remove(m_Path);
+ // llvm::sys::Path
+ if (!Keep && "_" != m_Path.native()) {
+ bool Existed;
+ llvm::sys::fs::remove(m_Path.native(), Existed);
+ }
// Ok, the file is successfully written and closed, or deleted. There's no
// further need to clean it up on signals.
- if ("_" != m_Path)
- llvm::sys::DontRemoveFileOnSignal(m_Path);
+ if ("_" != m_Path.native())
+ llvm::sys::DontRemoveFileOnSignal(m_Path.native());
}
//===----------------------------------------------------------------------===//
// ToolOutputFile
//===----------------------------------------------------------------------===//
-ToolOutputFile::ToolOutputFile(const std::string& pPath,
+ToolOutputFile::ToolOutputFile(const sys::fs::Path& pPath,
FileHandle::OpenMode pMode,
FileHandle::Permission pPermission)
: m_Installer(pPath),
- m_pMemoryArea(NULL),
- m_pOStream(NULL),
- m_pFOStream(NULL) {
+ m_pFdOstream(NULL),
+ m_pFormattedOstream(NULL) {
if (!m_FileHandle.open(pPath, pMode, pPermission)) {
// If open fails, no clean-up is needed.
m_Installer.Keep = true;
fatal(diag::err_cannot_open_output_file)
- << pPath
- << sys::strerror(m_FileHandle.error());
+ << pPath
+ << sys::strerror(m_FileHandle.error());
return;
}
-
- m_pMemoryArea = new MemoryArea(m_FileHandle);
- m_pOStream = new raw_mem_ostream(*m_pMemoryArea);
}
ToolOutputFile::~ToolOutputFile()
{
- delete m_pFOStream;
- delete m_pOStream;
- delete m_pMemoryArea;
+ if (m_pFdOstream != NULL)
+ delete m_pFdOstream;
}
void ToolOutputFile::keep()
@@ -81,29 +78,24 @@
m_Installer.Keep = true;
}
-/// mem_os - Return the contained raw_mem_ostream.
-raw_mem_ostream& ToolOutputFile::mem_os()
+/// os - Return the containeed raw_fd_ostream.
+/// Since os is rarely used, we lazily initialize it.
+llvm::raw_fd_ostream& ToolOutputFile::os()
{
- assert(NULL != m_pOStream);
- return *m_pOStream;
+ if (m_pFdOstream == NULL) {
+ assert(m_FileHandle.isOpened() &&
+ m_FileHandle.isGood() &&
+ m_FileHandle.isWritable());
+ m_pFdOstream = new llvm::raw_fd_ostream(m_FileHandle.handler(), false);
+ }
+ return *m_pFdOstream;
}
-/// formatted_os - Return the containeed formatted_raw_ostream.
-/// Since formatted_os is rarely used, we lazily initialize it.
+/// formatted_os - Return the contained formatted_raw_ostream
llvm::formatted_raw_ostream& ToolOutputFile::formatted_os()
{
- if (NULL == m_pFOStream) {
- assert(NULL != m_pOStream);
- m_pFOStream = new llvm::formatted_raw_ostream(*m_pOStream);
+ if (m_pFormattedOstream == NULL) {
+ m_pFormattedOstream = new llvm::formatted_raw_ostream(os());
}
-
- return *m_pFOStream;
+ return *m_pFormattedOstream;
}
-
-/// memory - Return the contained MemoryArea.
-MemoryArea& ToolOutputFile::memory()
-{
- assert(NULL != m_pOStream);
- return m_pOStream->getMemoryArea();
-}
-
diff --git a/lib/Support/Unix/FileSystem.inc b/lib/Support/Unix/FileSystem.inc
index 7a727e9..811085e 100644
--- a/lib/Support/Unix/FileSystem.inc
+++ b/lib/Support/Unix/FileSystem.inc
@@ -15,6 +15,7 @@
#include <fcntl.h>
#include <mcld/Support/FileHandle.h>
#include <mcld/Support/Directory.h>
+#include <llvm/Support/ErrorHandling.h>
namespace mcld{
namespace sys{
diff --git a/lib/Support/raw_mem_ostream.cpp b/lib/Support/raw_mem_ostream.cpp
deleted file mode 100644
index c3066dd..0000000
--- a/lib/Support/raw_mem_ostream.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-//===- raw_mem_ostream.cpp ------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/Support/raw_mem_ostream.h>
-#include <mcld/Support/MsgHandling.h>
-#include <mcld/Support/MemoryRegion.h>
-#include <mcld/Support/MemoryArea.h>
-#include <mcld/Support/FileHandle.h>
-
-using namespace mcld;
-
-//===----------------------------------------------------------------------===//
-// raw_mem_ostream
-//===----------------------------------------------------------------------===//
-raw_mem_ostream::raw_mem_ostream(MemoryArea &pMemoryArea)
- : m_MemoryArea(pMemoryArea), m_Position(0) {
- if (NULL == m_MemoryArea.handler() ||
- !(m_MemoryArea.handler()->isGood() &&
- m_MemoryArea.handler()->isWritable())) {
- fatal(diag::fatal_unwritable_output) << m_MemoryArea.handler()->path();
- }
-}
-
-raw_mem_ostream::~raw_mem_ostream()
-{
- flush();
- m_MemoryArea.clear();
-}
-
-void raw_mem_ostream::write_impl(const char *pPtr, size_t pSize)
-{
- MemoryRegion* region = m_MemoryArea.request(m_Position, pSize);
- memcpy(region->start(), pPtr, pSize);
- m_Position += pSize;
-}
-
-uint64_t raw_mem_ostream::current_pos() const
-{
- return m_Position;
-}
-
diff --git a/lib/Target/ARM/ARM.h b/lib/Target/ARM/ARM.h
index 53e4795..6fec04e 100644
--- a/lib/Target/ARM/ARM.h
+++ b/lib/Target/ARM/ARM.h
@@ -6,12 +6,17 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ARM_H
-#define MCLD_ARM_H
+#ifndef MCLD_TARGET_ARM_H
+#define MCLD_TARGET_ARM_H
#include <string>
-#include <mcld/Target/TargetMachine.h>
+
+namespace llvm {
+class Target;
+} // namespace of llvm
namespace mcld {
+
+class Target;
class TargetLDBackend;
extern mcld::Target TheARMTarget;
diff --git a/lib/Target/ARM/ARMDiagnostic.cpp b/lib/Target/ARM/ARMDiagnostic.cpp
index b63a192..77cb87e 100644
--- a/lib/Target/ARM/ARMDiagnostic.cpp
+++ b/lib/Target/ARM/ARMDiagnostic.cpp
@@ -6,21 +6,16 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include <llvm/ADT/Triple.h>
#include <mcld/Support/TargetRegistry.h>
#include <mcld/LD/DWARFLineInfo.h>
#include "ARM.h"
using namespace mcld;
-//===----------------------------------------------------------------------===//
-// ARMDiagnostic
-
-
namespace mcld {
//===----------------------------------------------------------------------===//
// createARMDiagnostic - the help function to create corresponding ARMDiagnostic
-//
+//===----------------------------------------------------------------------===//
DiagnosticLineInfo* createARMDiagLineInfo(const mcld::Target& pTarget,
const std::string &pTriple)
{
@@ -29,8 +24,9 @@
} // namespace of mcld
-//==========================
+//===----------------------------------------------------------------------===//
// InitializeARMDiagnostic
+//===----------------------------------------------------------------------===//
extern "C" void MCLDInitializeARMDiagnosticLineInfo() {
// Register the linker frontend
mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheARMTarget, createARMDiagLineInfo);
diff --git a/lib/Target/ARM/ARMELFAttributeData.cpp b/lib/Target/ARM/ARMELFAttributeData.cpp
new file mode 100644
index 0000000..87ed1d3
--- /dev/null
+++ b/lib/Target/ARM/ARMELFAttributeData.cpp
@@ -0,0 +1,1074 @@
+//===- ARMELFAttributeData.h ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "ARMELFAttributeData.h"
+
+#include <mcld/LinkerConfig.h>
+#include <mcld/MC/Input.h>
+#include <mcld/Support/LEB128.h>
+#include <mcld/Support/MsgHandling.h>
+
+using namespace mcld;
+
+const ELFAttributeValue *ARMELFAttributeData::getAttributeValue(TagType pTag) const
+{
+ if (pTag <= Tag_Max) {
+ const ELFAttributeValue &attr_value = m_Attrs[pTag];
+
+ if (attr_value.isInitialized()) {
+ return &attr_value;
+ } else {
+ // Don't return uninitialized attribute value.
+ return NULL;
+ }
+ } else {
+ UnknownAttrsMap::const_iterator attr_it = m_UnknownAttrs.find(pTag);
+
+ if (attr_it == m_UnknownAttrs.end()) {
+ return NULL;
+ } else {
+ return &attr_it->second;
+ }
+ }
+}
+
+std::pair<ELFAttributeValue*, bool>
+ARMELFAttributeData::getOrCreateAttributeValue(TagType pTag)
+{
+ ELFAttributeValue *attr_value = NULL;
+
+ if (pTag <= Tag_Max) {
+ attr_value = &m_Attrs[pTag];
+ } else {
+ // An unknown tag encounterred.
+ attr_value = &m_UnknownAttrs[pTag];
+ }
+
+ assert(attr_value != NULL);
+
+ // Setup the value type.
+ if (!attr_value->isUninitialized()) {
+ return std::make_pair(attr_value, false);
+ } else {
+ attr_value->setType(GetAttributeValueType(pTag));
+ return std::make_pair(attr_value, true);
+ }
+}
+
+unsigned int ARMELFAttributeData::GetAttributeValueType(TagType pTag)
+{
+ // See ARM [ABI-addenda], 2.2.6.
+ switch (pTag) {
+ case Tag_compatibility: {
+ return (ELFAttributeValue::Int | ELFAttributeValue::String);
+ }
+ case Tag_nodefaults: {
+ return (ELFAttributeValue::Int | ELFAttributeValue::NoDefault);
+ }
+ case Tag_CPU_raw_name:
+ case Tag_CPU_name: {
+ return ELFAttributeValue::String;
+ }
+ default: {
+ if (pTag < 32)
+ return ELFAttributeValue::Int;
+ else
+ return ((pTag & 1) ? ELFAttributeValue::String :
+ ELFAttributeValue::Int);
+ }
+ }
+ // unreachable
+}
+
+//===--------------------------------------------------------------------===//
+// Helper Functions for merge()
+//===--------------------------------------------------------------------===//
+
+namespace {
+
+/*
+ * Helper function to decode value in Tag_also_compatible_with.
+ *
+ * @ref ARM [ABI-addenda], 2.3.7.3
+ */
+static int
+decode_secondary_compatibility_attribute(const ELFAttributeValue &pValue)
+{
+ // The encoding of Tag_also_compatible_with is:
+ //
+ // Tag_also_compatible_with (=65), NTSB: data
+ //
+ // The data can be either an ULEB128-encoded number followed by a NULL byte or
+ // a NULL-terminated string. Currently, only the following byte sequence in
+ // data are currently defined:
+ //
+ // Tag_CPU_arch (=6) [The arch] 0
+ assert((pValue.type() == ELFAttributeValue::String) &&
+ "Value of Tag_also_compatible_with must be a string!");
+
+ const std::string &data = pValue.getStringValue();
+
+ // Though the integer is in LEB128 format, but they occupy only 1 byte in
+ // currently defined value.
+ if (data.length() < 2)
+ // Must have a byte for Tag_CPU_arch (=6)
+ // a byte for specifying the CPU architecture (CPU_Arch_ARM_*)
+ //
+ // Currently, the 2nd byte can only be v4T (=2) or v6-M (=11).
+ return -1;
+
+ if ((static_cast<uint8_t>(data[0]) == ARMELFAttributeData::Tag_CPU_arch) &&
+ ((data[1] == ARMELFAttributeData::CPU_Arch_ARM_V4T) ||
+ (data[1] == ARMELFAttributeData::CPU_Arch_ARM_V6_M)))
+ return static_cast<uint32_t>(data[1]);
+
+ // Tag_also_compatible_with can be safely ignored.
+ return -1;
+}
+
+/*
+ * This helper array keeps the ordering of the values in attributes such as
+ * Tag_ABI_align_needed which are sored as 1 > 2 > 0.
+ */
+static const int value_ordering_120[] = { 0, 2, 1 };
+
+} // anonymous namespace
+
+//===--------------------------------------------------------------------===//
+// End Helper Functions for merge()
+//===--------------------------------------------------------------------===//
+
+bool ARMELFAttributeData::merge(const LinkerConfig& pConfig,
+ const Input &pInput, TagType pTag,
+ const ELFAttributeValue& pInAttr)
+{
+ // Pre-condition
+ // 1. The out_attr must be initailized and has value of the same type as
+ // pInAttr.
+ // 2. The value helf by out_attr and pInAttr must be different.
+ ELFAttributeValue &out_attr = m_Attrs[pTag];
+
+ // Attribute in the output must have value assigned.
+ assert(out_attr.isInitialized() && "No output attribute to be merged!");
+
+ switch (pTag) {
+ case Tag_CPU_arch: {
+ // Need value of Tag_also_compatible_with in the input for merge.
+ if (pInAttr.getIntValue() <= CPU_Arch_Max) {
+ m_CPUArch = pInAttr.getIntValue();
+ } else {
+ error(diag::error_unknown_cpu_arch) << pInput.name();
+ return false;
+ }
+ break;
+ }
+ case Tag_CPU_name: {
+ // need value of Tag_CPU_arch in the input for merge
+ m_CPUName = pInAttr.getStringValue();
+ break;
+ }
+ case Tag_CPU_raw_name: {
+ // need value of Tag_CPU_arch in the input for merge
+ m_CPURawName = pInAttr.getStringValue();
+ break;
+ }
+ case Tag_FP_arch: {
+ // need value of Tag_HardFP_use in the input for merge
+ m_FPArch = pInAttr.getIntValue();
+ break;
+ }
+ case Tag_ABI_HardFP_use: {
+ // need value of Tag_FP_arch in the input for merge
+ m_HardFPUse = pInAttr.getIntValue();
+ break;
+ }
+ case Tag_also_compatible_with: {
+ // need value of Tag_CPU_arch in the input for merge
+ m_SecondaryCPUArch = decode_secondary_compatibility_attribute(pInAttr);
+ break;
+ }
+ case Tag_ABI_VFP_args: {
+ // need value of Tag_ABI_FP_number_model in the input for merge
+ m_VFPArgs = pInAttr.getIntValue();
+ break;
+ }
+ // The value of these tags are integers and after merge, only the greatest
+ // value held by pInAttr and out_attr goes into output.
+ case Tag_ARM_ISA_use:
+ case Tag_THUMB_ISA_use:
+ case Tag_WMMX_arch:
+ case Tag_Advanced_SIMD_arch:
+ case Tag_ABI_FP_rounding:
+ case Tag_ABI_FP_exceptions:
+ case Tag_ABI_FP_user_exceptions:
+ case Tag_ABI_FP_number_model:
+ case Tag_FP_HP_extension:
+ case Tag_CPU_unaligned_access:
+ case Tag_T2EE_use: {
+ assert((out_attr.type() == ELFAttributeValue::Int) &&
+ (pInAttr.type() == ELFAttributeValue::Int) &&
+ "should have integer parameeter!");
+ if (pInAttr.getIntValue() > out_attr.getIntValue())
+ out_attr.setIntValue(pInAttr.getIntValue());
+ break;
+ }
+ // The value of these tags are integers and after merge, only the smallest
+ // value held by pInAttr and out_attr goes into output.
+ case Tag_ABI_align_preserved:
+ case Tag_ABI_PCS_RO_data: {
+ assert((out_attr.type() == ELFAttributeValue::Int) &&
+ (pInAttr.type() == ELFAttributeValue::Int) &&
+ "should have integer parameeter!");
+ if (pInAttr.getIntValue() < out_attr.getIntValue())
+ out_attr.setIntValue(pInAttr.getIntValue());
+ break;
+ }
+ // The values of these attributes are sorted as 1 > 2 > 0. And the greater
+ // value becomes output.
+ case Tag_ABI_align_needed:
+ case Tag_ABI_FP_denormal:
+ case Tag_ABI_PCS_GOT_use: {
+ const int in_val = pInAttr.getIntValue();
+ const int out_val = out_attr.getIntValue();
+
+ if (in_val <= 2) {
+ if (out_val <= 2) {
+ // Use value_ordering_120 to determine the ordering.
+ if (value_ordering_120[in_val] > value_ordering_120[out_val]) {
+ out_attr.setIntValue(in_val);
+ }
+ }
+ } else {
+ // input value > 2, for future-proofing
+ if (in_val > out_val) {
+ out_attr.setIntValue(in_val);
+ }
+ }
+ break;
+ }
+ // These tags use the first value ever seen.
+ case Tag_ABI_optimization_goals:
+ case Tag_ABI_FP_optimization_goals: {
+ break;
+ }
+ // Tag_CPU_arch_profile
+ case Tag_CPU_arch_profile: {
+ if (pInAttr.getIntValue() == Arch_Profile_None)
+ return true;
+
+ switch (out_attr.getIntValue()) {
+ case Arch_Profile_None: {
+ out_attr.setIntValue(pInAttr.getIntValue());
+ break;
+ }
+ case Arch_Profile_RealOrApp: {
+ if (pInAttr.getIntValue() != Arch_Profile_Microcontroller)
+ out_attr.setIntValue(pInAttr.getIntValue());
+ else
+ warning(diag::warn_mismatch_cpu_arch_profile)
+ << pInAttr.getIntValue() << pInput.name();
+ break;
+ }
+ default: {
+ // out_attr is Arch_Profile_Application or Arch_Profile_Realtime or
+ // Arch_Profile_Microcontroller.
+ if ((pInAttr.getIntValue() == Arch_Profile_RealOrApp) &&
+ (out_attr.getIntValue() != Arch_Profile_Microcontroller)) {
+ // do nothing
+ } else {
+ if (pConfig.options().warnMismatch())
+ warning(diag::warn_mismatch_cpu_arch_profile)
+ << pInAttr.getIntValue() << pInput.name();
+ }
+ break;
+ }
+ }
+ break;
+ }
+ // Tag_MPextension_use and Tag_MPextension_use_legacy
+ case Tag_MPextension_use:
+ case Tag_MPextension_use_legacy: {
+ if (m_MPextensionUse < 0) {
+ m_MPextensionUse = pInAttr.getIntValue();
+ } else {
+ if (static_cast<unsigned>(m_MPextensionUse) != pInAttr.getIntValue()) {
+ warning(diag::error_mismatch_mpextension_use) << pInput.name();
+ }
+ }
+ break;
+ }
+ // Tag_DIV_use
+ case Tag_DIV_use: {
+ if (pInAttr.getIntValue() == 2) {
+ // 2 means the code was permitted to use SDIV/UDIV in anyway.
+ out_attr.setIntValue(2);
+ } else {
+ // Merge until settling down Tag_CPU_arch.
+ m_DIVUse = pInAttr.getIntValue();
+ }
+ break;
+ }
+ // Tag_ABI_enum_size
+ case Tag_ABI_enum_size: {
+ if ((out_attr.getIntValue() == Enum_Unused) ||
+ (out_attr.getIntValue() == Enum_Containerized_As_Possible))
+ out_attr.setIntValue(pInAttr.getIntValue());
+ else if (pInAttr.getIntValue() != Enum_Containerized_As_Possible &&
+ pConfig.options().warnMismatch())
+ warning(diag::warn_mismatch_enum_size)
+ << pInput.name() << pInAttr.getIntValue()
+ << out_attr.getIntValue();
+ break;
+ }
+ // Tag_ABI_FP_16bit_format
+ case Tag_ABI_FP_16bit_format: {
+ // 0: doesn't use any 16-bit FP number
+ // 1: use IEEE 754 format 16-bit FP number
+ // 2: use VFPv3/Advanced SIMD "alternative format" 16-bit FP number
+ if (pInAttr.getIntValue() != 0) {
+ if (out_attr.getIntValue() == 0) {
+ out_attr.setIntValue(pInAttr.getIntValue());
+ } else {
+ if (pConfig.options().warnMismatch())
+ warning(diag::warn_mismatch_fp16_format) << pInput.name();
+ }
+ }
+ break;
+ }
+ // Tag_nodefaults
+ case Tag_nodefaults: {
+ // There's nothing to do for this tag. It doesn't have an actual value.
+ break;
+ }
+ // Tag_conformance
+ case Tag_conformance: {
+ // Throw away the value if the attribute value doesn't match.
+ if (out_attr.getStringValue() != pInAttr.getStringValue())
+ out_attr.setStringValue("");
+ break;
+ }
+ // Tag_Virtualization_use
+ case Tag_Virtualization_use: {
+ // 0: No use of any virtualization extension
+ // 1: TrustZone
+ // 2: Virtualization extension such as HVC and ERET
+ // 3: TrustZone and virtualization extension are permitted
+ if (pInAttr.getIntValue() != 0) {
+ if (out_attr.getIntValue() == 0) {
+ out_attr.setIntValue(pInAttr.getIntValue());
+ } else {
+ if ((out_attr.getIntValue() <= 3) && (pInAttr.getIntValue() <= 3)) {
+ // Promote to 3
+ out_attr.setIntValue(3);
+ } else {
+ warning(diag::warn_unrecognized_virtualization_use)
+ << pInput.name() << pInAttr.getIntValue();
+ }
+ }
+ }
+ break;
+ }
+ // Tag_ABI_WMMX_args
+ case Tag_ABI_WMMX_args: {
+ // There's no way to merge this value (i.e., objects contain different
+ // value in this tag are definitely incompatible.)
+ if (pConfig.options().warnMismatch())
+ warning(diag::warn_mismatch_abi_wmmx_args) << pInput.name();
+ break;
+ }
+ // Tag_PCS_config
+ case Tag_PCS_config: {
+ // 0 means no standard configuration used or no information recorded.
+ if (pInAttr.getIntValue() != 0) {
+ if (out_attr.getIntValue() == 0)
+ out_attr.setIntValue(pInAttr.getIntValue());
+ else {
+ // Different values in these attribute are conflict
+ if (pConfig.options().warnMismatch())
+ warning(diag::warn_mismatch_pcs_config) << pInput.name();
+ }
+ }
+ break;
+ }
+ // Tag_ABI_PCS_R9_use
+ case Tag_ABI_PCS_R9_use: {
+ if (pInAttr.getIntValue() != R9_Unused) {
+ if (out_attr.getIntValue() == R9_Unused)
+ out_attr.setIntValue(pInAttr.getIntValue());
+ else {
+ if (pConfig.options().warnMismatch())
+ warning(diag::warn_mismatch_r9_use) << pInput.name();
+ }
+ }
+ break;
+ }
+ // Tag_ABI_PCS_RW_data
+ case Tag_ABI_PCS_RW_data: {
+ if (pInAttr.getIntValue() == RW_data_SB_Relative) {
+ // Require using R9 as SB (global Static Base register).
+ if ((out_attr.getIntValue() != R9_Unused) &&
+ (out_attr.getIntValue() != R9_SB) &&
+ pConfig.options().warnMismatch())
+ warning(diag::warn_mismatch_r9_use) << pInput.name();
+ }
+ // Choose the smaller value
+ if (pInAttr.getIntValue() < out_attr.getIntValue())
+ out_attr.setIntValue(pInAttr.getIntValue());
+ break;
+ }
+ // Tag_ABI_PCS_wchar_t
+ case Tag_ABI_PCS_wchar_t: {
+ // 0: no use of wchar_t
+ // 2: sizeof(wchar_t) = 2
+ // 4: sizeof(wchar_t) = 4
+ if (pInAttr.getIntValue() != 0) {
+ if (out_attr.getIntValue() == 0)
+ out_attr.setIntValue(pInAttr.getIntValue());
+ else {
+ if (pConfig.options().warnMismatch())
+ warning(diag::warn_mismatch_wchar_size)
+ << pInput.name() << pInAttr.getIntValue()
+ << out_attr.getIntValue();
+ }
+ }
+ break;
+ }
+ default: {
+ // Handle unknown attributes:
+ //
+ // Since we don't know how to merge the value of unknown attribute, we
+ // have to ignore it. There're two rules related to the processing (See
+ // ARM [ABI-addenda] 2.2.6, Coding extensibility and compatibility.):
+ //
+ // 1. For tag N where N >= 128, tag N has the same properties as
+ // tag N % 128.
+ // 2. Tag 64-127 can be safely ignored.
+ // 3. Tag 0-63 must be comprehended, therefore we cannot ignore.
+ if (pConfig.options().warnMismatch()) {
+ if ((pTag & 127) < 64) {
+ warning(diag::warn_unknown_mandatory_attribute) << pTag
+ << pInput.name();
+ } else {
+ warning(diag::warn_unknown_attribute) << pTag << pInput.name();
+ }
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+//===--------------------------------------------------------------------===//
+// Helper Functions for postMerge()
+//===--------------------------------------------------------------------===//
+
+namespace {
+
+/*
+ * Helper function to encode value in Tag_also_compatible_with.
+ *
+ * @ref ARM [ABI-addenda], 2.3.7.3
+ */
+static void
+encode_secondary_compatibility_attribute(ELFAttributeValue &pValue, int pArch)
+{
+ if ((pArch < 0) || (pArch > ARMELFAttributeData::CPU_Arch_Max)) {
+ pValue.setStringValue("");
+ } else {
+ char new_value[] = {
+ ARMELFAttributeData::Tag_CPU_arch,
+ static_cast<char>(pArch),
+ 0
+ };
+ pValue.setStringValue(std::string(new_value, sizeof(new_value)));
+ }
+ return;
+}
+
+/*
+ * Combine the main and secondary CPU arch value
+ */
+static int
+calculate_cpu_arch(int cpu_arch, int secondary_arch)
+{
+ // short-circuit
+ if ((secondary_arch < 0) ||
+ ((cpu_arch + secondary_arch) != (ARMELFAttributeData::CPU_Arch_ARM_V4T +
+ ARMELFAttributeData::CPU_Arch_ARM_V6_M)))
+ return cpu_arch;
+
+ if ((cpu_arch == ARMELFAttributeData::CPU_Arch_ARM_V4T) &&
+ (secondary_arch == ARMELFAttributeData::CPU_Arch_ARM_V6_M))
+ return ARMELFAttributeData::CPU_Arch_ARM_V4T_Plus_V6_M;
+ else if ((cpu_arch == ARMELFAttributeData::CPU_Arch_ARM_V6_M) &&
+ (secondary_arch == ARMELFAttributeData::CPU_Arch_ARM_V4T))
+ return ARMELFAttributeData::CPU_Arch_ARM_V4T_Plus_V6_M;
+ else
+ return cpu_arch;
+}
+
+/*
+ * Given a CPU arch X and a CPU arch Y in which Y is newer than X, the value in
+ * cpu_compatibility_table[X][Y] is the CPU arch required to run ISA both from X
+ * and Y. 0 in the table means unreachable and -1 means conflict architecture
+ * profile.
+ */
+#define CPU(C) ARMELFAttributeData::CPU_Arch_ARM_ ## C
+static const int cpu_compatibility_table[][CPU(V4T_Plus_V6_M) + 1] =
+{
+ /* old\new ARM v6T2 ARM v6K ARM v7 ARM v6-M ARM v6S-M ARM v7E-M ARMv8, ARM v4t + v6-M */
+ /* Pre v4 */ { CPU(V6T2), CPU(V6K), CPU(V7), -1, -1, -1, -1, -1 },
+ /* ARM v4 */ { CPU(V6T2), CPU(V6K), CPU(V7), -1, -1, -1, -1, -1 },
+ /* ARM v4T */ { CPU(V6T2), CPU(V6K), CPU(V7), CPU(V6K), CPU(V6K), CPU(V7E_M), CPU(V8), CPU(V4T) },
+ /* ARM v5T */ { CPU(V6T2), CPU(V6K), CPU(V7), CPU(V6K), CPU(V6K), CPU(V7E_M), CPU(V8), CPU(V5T) },
+ /* ARM v5TE */ { CPU(V6T2), CPU(V6K), CPU(V7), CPU(V6K), CPU(V6K), CPU(V7E_M), CPU(V8), CPU(V5TE) },
+ /* ARM v5TEJ */ { CPU(V6T2), CPU(V6K), CPU(V7), CPU(V6K), CPU(V6K), CPU(V7E_M), CPU(V8), CPU(V5TEJ) },
+ /* ARM v6 */ { CPU(V6T2), CPU(V6K), CPU(V7), CPU(V6K), CPU(V6K), CPU(V7E_M), CPU(V8), CPU(V6) },
+ /* ARM v6KZ */ { CPU(V7), CPU(V6KZ), CPU(V7), CPU(V6KZ), CPU(V6KZ), CPU(V7E_M), CPU(V8), CPU(V6KZ) },
+ /* ARM v6T2 */ { CPU(V6T2), CPU(V7), CPU(V7), CPU(V7), CPU(V7), CPU(V7E_M), CPU(V8), CPU(V6T2) },
+ /* ARM v6K */ { 0, CPU(V6K), CPU(V7), CPU(V6K), CPU(V6K), CPU(V7E_M), CPU(V8), CPU(V6K) },
+ /* ARM v7 */ { 0, 0, CPU(V7), CPU(V7), CPU(V7), CPU(V7E_M), CPU(V8), CPU(V7) },
+ /* ARM v6-M */ { 0, 0, 0, CPU(V6_M), CPU(V6S_M), CPU(V7E_M), CPU(V8), CPU(V6_M) },
+ /* ARM v6S-M */ { 0, 0, 0, 0, CPU(V6S_M), CPU(V7E_M), CPU(V8), CPU(V6S_M) },
+ /* ARM v7E-M */ { 0, 0, 0, 0, 0, CPU(V7E_M), CPU(V8), CPU(V7E_M) },
+ /* ARM v8 */ { 0, 0, 0, 0, 0, 0, CPU(V8), CPU(V8) },
+ /* v4T + v6-M */ { 0, 0, 0, 0, 0, 0, 0, CPU(V4T_Plus_V6_M) }
+};
+
+/*
+ * Helper function to determine the merge of two different CPU arch.
+ */
+static int merge_cpu_arch(int out_cpu_arch, int in_cpu_arch)
+{
+ if (out_cpu_arch > CPU(V4T_Plus_V6_M))
+ return in_cpu_arch;
+
+ int new_cpu_arch, old_cpu_arch;
+ if (out_cpu_arch > in_cpu_arch) {
+ new_cpu_arch = out_cpu_arch;
+ old_cpu_arch = in_cpu_arch;
+ } else {
+ new_cpu_arch = in_cpu_arch;
+ old_cpu_arch = out_cpu_arch;
+ }
+
+ // No need to check the compatibility since the CPU architectures before
+ // V6KZ add features monotonically.
+ if (new_cpu_arch <= CPU(V6KZ))
+ return new_cpu_arch;
+
+ return cpu_compatibility_table[old_cpu_arch][new_cpu_arch - CPU(V6T2)];
+}
+#undef CPU
+
+/*
+ * Generic CPU name is used when Tag_CPU_name is unable to guess during the
+ * merge of Tag_CPU_arch.
+ */
+static const char* generic_cpu_name_table[] = {
+ /* Pre v4 */"Pre v4",
+ /* Pre v4 */"ARM v4",
+ /* ARM v4T */"ARM v4T",
+ /* ARM v5T */"ARM v5T",
+ /* ARM v5TE */"ARM v5TE",
+ /* ARM v5TEJ */"ARM v5TEJ",
+ /* ARM v6 */"ARM v6",
+ /* ARM v6KZ */"ARM v6KZ",
+ /* ARM v6T2 */"ARM v6T2",
+ /* ARM v6K */"ARM v6K",
+ /* ARM v7 */"ARM v7",
+ /* ARM v6-M */"ARM v6-M",
+ /* ARM v6S-M */"ARM v6S-M",
+ /* ARM v7E-M */"ARM v7E-M",
+ /* ARM v8 */"ARM v8",
+};
+
+static const char* get_generic_cpu_name(int cpu_arch) {
+ assert(cpu_arch < sizeof(generic_cpu_name_table) / sizeof(generic_cpu_name_table[0]));
+ return generic_cpu_name_table[cpu_arch];
+}
+
+/*
+ * Helper functions & data used in the merge of two different FP arch.
+ */
+static const struct fp_config_data {
+ int version;
+ int regs;
+} fp_configs[] = {
+ { 0, 0 },
+ { 1, 16 },
+ { 2, 16 },
+ { 3, 32 },
+ { 3, 16 },
+ { 4, 32 },
+ { 4, 16 },
+ { 8, 32 },
+ { 8, 16 },
+};
+
+static const size_t num_fp_configs =
+ sizeof(fp_configs) / sizeof(fp_config_data);
+
+// Given h(x, y) = (x * (y >> 4) + (y >> 5))
+//
+// fp_config_hash_table[ h(0, 0) = 0 ] = 0
+// fp_config_hash_table[ h(1, 16) = 1 ] = 1
+// fp_config_hash_table[ h(2, 16) = 2 ] = 2
+// fp_config_hash_table[ h(3, 32) = 7 ] = 3
+// fp_config_hash_table[ h(3, 16) = 3 ] = 4
+// fp_config_hash_table[ h(4, 32) = 9 ] = 5
+// fp_config_hash_table[ h(4, 16) = 4 ] = 6
+// fp_config_hash_table[ h(8, 32) = 17 ] = 7
+// fp_config_hash_table[ h(8, 16) = 8 ] = 8
+//
+// h(0, 0) = 0
+static const uint8_t fp_config_hash_table[] =
+{
+#define UND static_cast<uint8_t>(-1)
+ /* 0 */0,
+ /* 1 */1,
+ /* 2 */2,
+ /* 3 */4,
+ /* 4 */6,
+ /* 5 */UND,
+ /* 6 */UND,
+ /* 7 */3,
+ /* 8 */8,
+ /* 9 */5,
+ /* 10 */UND,
+ /* 11 */UND,
+ /* 12 */UND,
+ /* 13 */UND,
+ /* 14 */UND,
+ /* 15 */UND,
+ /* 16 */UND,
+ /* 17 */7,
+#undef UND
+};
+
+static const size_t num_hash_table_entries =
+ sizeof(fp_config_hash_table) / sizeof(fp_config_hash_table[0]);
+
+static int calculate_fp_config_hash(const struct fp_config_data &pConfig)
+{
+ int x = pConfig.version;
+ int y = pConfig.regs;
+ return (x * (y >> 4) + (y >> 5));
+}
+
+static int get_fp_arch_of_config(const struct fp_config_data &pConfig)
+{
+ int hash = calculate_fp_config_hash(pConfig);
+ assert(hash < num_hash_table_entries);
+ return fp_config_hash_table[hash];
+}
+
+static bool is_allowed_use_of_div(int cpu_arch, int cpu_arch_profile,
+ int div_use) {
+ // 0: The code was permitted to use SDIV and UDIV in the Thumb ISA on v7-R or
+ // v7-M.
+ // 1: The code was not permitted to use SDIV and UDIV.
+ // 2: The code was explicitly permitted to use SDIV and UDIV.
+ switch (div_use) {
+ case 0: {
+ if ((cpu_arch == ARMELFAttributeData::CPU_Arch_ARM_V7) &&
+ ((cpu_arch_profile == 'R') || (cpu_arch_profile == 'M'))) {
+ return true;
+ } else {
+ return (cpu_arch >= ARMELFAttributeData::CPU_Arch_ARM_V7E_M);
+ }
+ }
+ case 1: {
+ return false;
+ }
+ case 2:
+ // For future proofing
+ default: {
+ return true;
+ }
+ }
+}
+
+} // anonymous namespace
+
+//===--------------------------------------------------------------------===//
+// End Helper Functions for postMerge()
+//===--------------------------------------------------------------------===//
+
+bool ARMELFAttributeData::postMerge(const LinkerConfig& pConfig,
+ const Input &pInput)
+{
+ // Process Tag_CPU_arch, Tag_CPU_name, Tag_CPU_raw_name, and
+ // Tag_also_compatible_with.
+ ELFAttributeValue &out_cpu_arch_attr = m_Attrs[Tag_CPU_arch];
+ ELFAttributeValue &out_secondary_compatibility_attr =
+ m_Attrs[Tag_also_compatible_with];
+
+ if ((m_CurrentCPUArch < 0) && out_cpu_arch_attr.isInitialized()) {
+ // Current input initializes the value of Tag_CPU_arch. Validate it.
+ int out_cpu_arch = out_cpu_arch_attr.getIntValue();
+
+ if (out_cpu_arch > CPU_Arch_Max) {
+ error(diag::error_unknown_cpu_arch) << pInput.name();
+ return false;
+ }
+
+ // Initialize m_CurrentCPUArch.
+ int out_secondary_arch = -1;
+ if (out_secondary_compatibility_attr.isInitialized())
+ out_secondary_arch = decode_secondary_compatibility_attribute(
+ out_secondary_compatibility_attr);
+
+ m_CurrentCPUArch = calculate_cpu_arch(out_cpu_arch, out_secondary_arch);
+ }
+
+ if (m_CPUArch >= 0) {
+ assert(out_cpu_arch_attr.isInitialized() && "CPU arch has never set!");
+ assert(m_CurrentCPUArch >= 0);
+
+ int in_cpu_arch = calculate_cpu_arch(m_CPUArch, m_SecondaryCPUArch);
+ int result_cpu_arch = merge_cpu_arch(m_CurrentCPUArch, in_cpu_arch);
+
+ if (result_cpu_arch < 0) {
+ warning(diag::warn_mismatch_cpu_arch_profile)
+ << in_cpu_arch << pInput.name();
+ } else {
+ if (result_cpu_arch != m_CurrentCPUArch) {
+ // Value of Tag_CPU_arch are going to changea.
+ m_CurrentCPUArch = result_cpu_arch;
+
+ // Write the result value to the output.
+ if (result_cpu_arch == CPU_Arch_ARM_V4T_Plus_V6_M) {
+ out_cpu_arch_attr.setIntValue(CPU_Arch_ARM_V4T);
+ encode_secondary_compatibility_attribute(
+ out_secondary_compatibility_attr, CPU_Arch_ARM_V6_M);
+ } else {
+ out_cpu_arch_attr.setIntValue(result_cpu_arch);
+ encode_secondary_compatibility_attribute(
+ out_secondary_compatibility_attr, -1);
+ }
+
+ ELFAttributeValue &out_cpu_name = m_Attrs[Tag_CPU_name];
+ ELFAttributeValue &out_cpu_raw_name = m_Attrs[Tag_CPU_raw_name];
+
+ if (m_CurrentCPUArch != in_cpu_arch) {
+ // Unable to guess the Tag_CPU_name. Use the generic name.
+ if (out_cpu_name.isInitialized()) {
+ out_cpu_name.setStringValue(get_generic_cpu_name(m_CurrentCPUArch));
+ }
+
+ // Tag_CPU_raw_name becomes unknown. Set to default value to disable
+ // it.
+ out_cpu_raw_name.setStringValue("");
+ } else {
+ // Use the value of Tag_CPU_name and Tag_CPU_raw_name from the input.
+ if (!m_CPUName.empty()) {
+ ELFAttributeValue &out_cpu_name = m_Attrs[Tag_CPU_name];
+ assert(out_cpu_name.isInitialized() && "CPU name has never set!");
+ out_cpu_name.setStringValue(m_CPUName);
+ }
+
+ if (!m_CPURawName.empty()) {
+ ELFAttributeValue &out_cpu_raw_name = m_Attrs[Tag_CPU_raw_name];
+ assert(out_cpu_raw_name.isInitialized() &&
+ "CPU raw name has never set!");
+ out_cpu_raw_name.setStringValue(m_CPURawName);
+ }
+ }
+ }
+ }
+ } // (m_CPUArch >= 0)
+
+ // Process Tag_ABI_VFP_args.
+ if (m_VFPArgs >= 0) {
+ ELFAttributeValue &out_attr = m_Attrs[Tag_ABI_VFP_args];
+ ELFAttributeValue &out_float_number_model_attr =
+ m_Attrs[Tag_ABI_FP_number_model];
+
+ assert(out_attr.isInitialized() && "VFP args has never set!");
+
+ // If the output is not permitted to use floating number, this attribute
+ // is ignored (migrate the value from input directly.)
+ if (out_float_number_model_attr.isUninitialized() ||
+ (out_float_number_model_attr.getIntValue() == 0)) {
+ // Inherit requirement from input.
+ out_attr.setIntValue(m_VFPArgs);
+ } else {
+ if (pConfig.options().warnMismatch())
+ warning(diag::warn_mismatch_vfp_args) << pInput.name();
+ }
+ }
+
+ // Process Tag_FP_arch.
+ ELFAttributeValue &out_fp_arch_attr = m_Attrs[Tag_FP_arch];
+ if (m_FPArch >= 0) {
+ assert(out_fp_arch_attr.isInitialized() && "FP arch has never set!");
+
+ // Tag_FP_arch
+ // 0: instructions requiring FP hardware are not permitted
+ // 1: VFP1
+ // 2: VFP2
+ // 3: VFP3 D32
+ // 4: VFP3 D16
+ // 5: VFP4 D32
+ // 6: VFP4 D16
+ // 7: ARM v8-A D32
+ // 8: ARM v8-A D16
+ if (out_fp_arch_attr.getIntValue() == 0) {
+ // Output has no constraints on FP hardware. Copy the requirement from
+ // input.
+ out_fp_arch_attr.setIntValue(m_FPArch);
+ } else if (m_FPArch == 0) {
+ // Input has no constraints on FP hardware. Do nothing.
+ } else {
+ // If here, both output and input contain non-zero value of Tag_FP_arch.
+
+ // Version greater than num_fp_configs is not defined. Choose the greater
+ // one for future-proofing.
+ if (static_cast<unsigned>(m_FPArch) > num_fp_configs) {
+ if (static_cast<unsigned>(m_FPArch) > out_fp_arch_attr.getIntValue()) {
+ out_fp_arch_attr.setIntValue(m_FPArch);
+ }
+ } else {
+ if (out_fp_arch_attr.getIntValue() < num_fp_configs) {
+ const struct fp_config_data &input_fp_config = fp_configs[ m_FPArch ];
+
+ const struct fp_config_data &output_fp_config =
+ fp_configs[ out_fp_arch_attr.getIntValue() ];
+
+ const struct fp_config_data result_fp_config = {
+ /*version*/((output_fp_config.version > input_fp_config.version) ?
+ output_fp_config.version : input_fp_config.version),
+ /* regs */((output_fp_config.regs > input_fp_config.regs) ?
+ output_fp_config.regs : input_fp_config.regs),
+ };
+ // Find the attribute value corresponding the result_fp_config
+ out_fp_arch_attr.setIntValue(get_fp_arch_of_config(result_fp_config));
+ }
+ }
+ }
+ } // (m_FPArch >= 0)
+
+ // Process Tag_ABI_HardFP_use.
+ ELFAttributeValue &out_hardfp_use_attr = m_Attrs[Tag_ABI_HardFP_use];
+
+ if (!m_HardFPUseInitialized && out_hardfp_use_attr.isInitialized()) {
+ m_HardFPUse = out_hardfp_use_attr.getIntValue();
+ m_HardFPUseInitialized = true;
+ }
+
+ if (m_HardFPUse >= 0) {
+ // Tag_ABI_HardFP_use depends on the meaning of Tag_FP_arch when it's 0.
+ assert(out_hardfp_use_attr.isInitialized() && "HardFP use has never set!");
+
+ if (out_fp_arch_attr.isUninitialized() ||
+ (out_fp_arch_attr.getIntValue() == 0)) {
+ // Has no constraints on FP hardware.
+ out_hardfp_use_attr.setIntValue(m_HardFPUse);
+ } else {
+ // Both output and input contain non-zero value of Tag_FP_arch and we have
+ // different Tag_ABI_HaedFP_Use settings other than 0.
+ if ((out_fp_arch_attr.getIntValue() > 0) && (m_HardFPUse > 0))
+ // Promote to 3 (The user permitted this entity to use both SP and DP
+ // VFP instruction.)
+ out_hardfp_use_attr.setIntValue(3);
+ }
+ }
+
+ // Move the value of Tag_MPextension_use_legacy to Tag_MPextension_use.
+ ELFAttributeValue &out_mpextension_use_legacy =
+ m_Attrs[Tag_MPextension_use_legacy];
+
+ ELFAttributeValue &out_mpextension_use = m_Attrs[Tag_MPextension_use];
+
+ // If Tag_MPextension_use_legacy has value, it must be introduced by current
+ // input since it is reset every time after the merge completed.
+ if (out_mpextension_use_legacy.isInitialized()) {
+ if (out_mpextension_use.isInitialized()) {
+ if (m_MPextensionUse < 0) {
+ // The value of Tag_MPextension_use is introduced by the current input.
+ // Check whether it is consistent with the one set in legacy.
+ m_MPextensionUse = out_mpextension_use.getIntValue();
+ } else {
+ // Current input introduces value of Tag_MPextension_use in
+ // m_MPextensionUse.
+ }
+
+ // Check the consistency between m_MPextensionUse and the value of
+ // Tag_MPextension_use_legacy.
+ if (static_cast<unsigned>(m_MPextensionUse) !=
+ out_mpextension_use_legacy.getIntValue()) {
+ error(diag::error_mismatch_mpextension_use) << pInput.name();
+ return false;
+ }
+ } else {
+ if (m_MPextensionUse < 0) {
+ // Tag_MPextension_use is not set. Initialize it and move the value.
+ out_mpextension_use.setType(ELFAttributeValue::Int);
+ out_mpextension_use.setIntValue(out_mpextension_use.getIntValue());
+ } else {
+ // Unreachable case since the value to unitialized attribute is directly
+ // assigned in ELFAttribute::Subsection::merge().
+ assert(false && "Tag_MPextension_use is uninitialized but have value?");
+ }
+ }
+
+ // Reset the attribute to uninitialized so it won't be included in the
+ // output.
+ out_mpextension_use_legacy.setType(ELFAttributeValue::Uninitialized);
+ }
+
+ // Process Tag_MPextension_use.
+ if (m_MPextensionUse > 0) {
+ assert(out_mpextension_use.isInitialized());
+
+ if (static_cast<unsigned>(m_MPextensionUse) >
+ out_mpextension_use.getIntValue()) {
+ out_mpextension_use.setIntValue(m_MPextensionUse);
+ }
+ }
+
+ // Process Tag_DIV_use.
+ ELFAttributeValue &out_div_use_attr = m_Attrs[Tag_DIV_use];
+
+ if (!m_DIVUseInitialized && out_div_use_attr.isInitialized()) {
+ // Perform the merge by reverting value of Tag_DIV_use and setup m_DIVUse.
+ m_DIVUse = out_div_use_attr.getIntValue();
+ out_div_use_attr.setIntValue(0);
+ m_DIVUseInitialized = true;
+ }
+
+ if (m_DIVUse >= 0) {
+ assert(out_div_use_attr.isInitialized());
+
+ const ELFAttributeValue &out_cpu_arch_profile_attr =
+ m_Attrs[Tag_CPU_arch_profile];
+
+ int out_cpu_arch_profile = Arch_Profile_None;
+ if (out_cpu_arch_profile_attr.isInitialized()) {
+ out_cpu_arch_profile = out_cpu_arch_profile_attr.getIntValue();
+ }
+
+ if (m_DIVUse == 1) {
+ // Input (=1) was not permitted to use SDIV and UDIV. See whether current
+ // output was explicitly permitted the use.
+ if (!is_allowed_use_of_div(m_CurrentCPUArch, out_cpu_arch_profile,
+ out_div_use_attr.getIntValue())) {
+ out_div_use_attr.setIntValue(1);
+ }
+ } else {
+ if (out_div_use_attr.getIntValue() != 1) {
+ // Output does not explicitly forbid the use of SDIV/UDIV. See whether
+ // the input attribute can allow it under current CPU architecture
+ // profile.
+ if (is_allowed_use_of_div(m_CurrentCPUArch, out_cpu_arch_profile,
+ m_DIVUse)) {
+ out_div_use_attr.setIntValue(m_DIVUse);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+size_t ARMELFAttributeData::sizeOutput() const {
+ size_t result = 0;
+
+ // Size contributed by known attributes
+ for (unsigned i = 0; i <= Tag_Max; ++i) {
+ TagType tag = static_cast<TagType>(i);
+ const ELFAttributeValue &value = m_Attrs[tag];
+
+ if (value.shouldEmit()) {
+ result += leb128::size(static_cast<uint32_t>(tag));
+ result += value.getSize();
+ }
+ }
+
+ // Size contributed by unknown attributes
+ for (UnknownAttrsMap::const_iterator unknown_attr_it = m_UnknownAttrs.begin(),
+ unknown_attr_end = m_UnknownAttrs.end();
+ unknown_attr_it != unknown_attr_end; ++unknown_attr_it) {
+ TagType tag = unknown_attr_it->first;
+ const ELFAttributeValue &value = unknown_attr_it->second;
+
+ if (value.shouldEmit()) {
+ result += leb128::size(static_cast<uint32_t>(tag));
+ result += value.getSize();
+ }
+ }
+
+ return result;
+}
+
+size_t ARMELFAttributeData::emit(char *pBuf) const {
+ char *buffer = pBuf;
+
+ // Tag_conformance "should be emitted first in a file-scope sub-subsection of
+ // the first public subsection of the attribute section."
+ //
+ // See ARM [ABI-addenda], 2.3.7.4 Conformance tag
+ const ELFAttributeValue &attr_conformance = m_Attrs[Tag_conformance];
+
+ if (attr_conformance.shouldEmit()) {
+ if (!ELFAttributeData::WriteAttribute(Tag_conformance, attr_conformance,
+ buffer)) {
+ return 0;
+ }
+ }
+
+ // Tag_nodefaults "should be emitted before any other tag in an attribute
+ // subsection other that the conformance tag"
+ //
+ // See ARM [ABI-addenda], 2.3.7.5 No defaults tag
+ const ELFAttributeValue &attr_nodefaults = m_Attrs[Tag_nodefaults];
+
+ if (attr_nodefaults.shouldEmit()) {
+ if (!ELFAttributeData::WriteAttribute(Tag_nodefaults, attr_nodefaults,
+ buffer)) {
+ return 0;
+ }
+ }
+
+ // Tag_conformance (=67)
+ // Tag_nodefaults (=64)
+ for (unsigned i = 0; i < Tag_nodefaults; ++i) {
+ TagType tag = static_cast<TagType>(i);
+ const ELFAttributeValue &value = m_Attrs[tag];
+
+ if (value.shouldEmit() &&
+ !ELFAttributeData::WriteAttribute(tag, value, buffer)) {
+ return 0;
+ }
+ }
+
+ for (unsigned i = (Tag_nodefaults + 1); i <= Tag_Max; ++i) {
+ TagType tag = static_cast<TagType>(i);
+ const ELFAttributeValue &value = m_Attrs[tag];
+
+ if (value.shouldEmit() && (i != Tag_conformance) &&
+ !ELFAttributeData::WriteAttribute(tag, value, buffer)) {
+ return 0;
+ }
+ }
+
+ for (UnknownAttrsMap::const_iterator unknown_attr_it = m_UnknownAttrs.begin(),
+ unknown_attr_end = m_UnknownAttrs.end();
+ unknown_attr_it != unknown_attr_end; ++unknown_attr_it) {
+ TagType tag = unknown_attr_it->first;
+ const ELFAttributeValue &value = unknown_attr_it->second;
+
+ if (value.shouldEmit() &&
+ !ELFAttributeData::WriteAttribute(tag, value, buffer)) {
+ return 0;
+ }
+ }
+
+ return (buffer - pBuf);
+}
diff --git a/lib/Target/ARM/ARMELFAttributeData.h b/lib/Target/ARM/ARMELFAttributeData.h
new file mode 100644
index 0000000..01e7816
--- /dev/null
+++ b/lib/Target/ARM/ARMELFAttributeData.h
@@ -0,0 +1,242 @@
+//===- ARMELFAttributeData.h ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ARM_ELF_ATTRIBUTE_DATA_H
+#define MCLD_ARM_ELF_ATTRIBUTE_DATA_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Target/ELFAttributeData.h>
+#include <mcld/Target/ELFAttributeValue.h>
+
+#include <map>
+#include <string>
+
+namespace mcld {
+
+/** \class ARMELFAttributeData
+ * \brief ARMELFAttributeData handles public ("aeabi") attributes subsection in
+ * ARM ELF.
+ *
+ */
+class ARMELFAttributeData : public ELFAttributeData {
+public:
+ enum Tag {
+ // 0-3 are generic and are defined in ELFAttributeData.
+ Tag_CPU_raw_name = 4,
+ Tag_CPU_name = 5,
+ Tag_CPU_arch = 6,
+ Tag_CPU_arch_profile = 7,
+ Tag_ARM_ISA_use = 8,
+ Tag_THUMB_ISA_use = 9,
+ Tag_FP_arch = 10,
+ Tag_WMMX_arch = 11,
+ Tag_Advanced_SIMD_arch = 12,
+ Tag_PCS_config = 13,
+ Tag_ABI_PCS_R9_use = 14,
+ Tag_ABI_PCS_RW_data = 15,
+ Tag_ABI_PCS_RO_data = 16,
+ Tag_ABI_PCS_GOT_use = 17,
+ Tag_ABI_PCS_wchar_t = 18,
+ Tag_ABI_FP_rounding = 19,
+ Tag_ABI_FP_denormal = 20,
+ Tag_ABI_FP_exceptions = 21,
+ Tag_ABI_FP_user_exceptions = 22,
+ Tag_ABI_FP_number_model = 23,
+ Tag_ABI_align_needed = 24,
+ Tag_ABI_align_preserved = 25,
+ Tag_ABI_enum_size = 26,
+ Tag_ABI_HardFP_use = 27,
+ Tag_ABI_VFP_args = 28,
+ Tag_ABI_WMMX_args = 29,
+ Tag_ABI_optimization_goals = 30,
+ Tag_ABI_FP_optimization_goals = 31,
+ Tag_compatibility = 32,
+
+ Tag_CPU_unaligned_access = 34,
+
+ Tag_FP_HP_extension = 36,
+
+ Tag_ABI_FP_16bit_format = 38,
+
+ Tag_MPextension_use = 42,
+
+ Tag_DIV_use = 44,
+
+ Tag_nodefaults = 64,
+ Tag_also_compatible_with = 65,
+ Tag_T2EE_use = 66,
+ Tag_conformance = 67,
+ Tag_Virtualization_use = 68,
+
+ Tag_MPextension_use_legacy = 70,
+
+ Tag_Max = Tag_MPextension_use_legacy,
+
+ // Alias
+ Tag_VFP_arch = Tag_FP_arch,
+ Tag_ABI_align8_needed = Tag_ABI_align_needed,
+ Tag_ABI_align8_preserved = Tag_ABI_align_preserved,
+ Tag_VFP_HP_extension = Tag_FP_HP_extension
+ };
+
+ // For Tag_CPU_arch
+ enum {
+ CPU_Arch_ARM_Pre_V4,
+ CPU_Arch_ARM_V4, // e.g., SA110
+ CPU_Arch_ARM_V4T, // e.g., ARM7TDMI
+ CPU_Arch_ARM_V5T, // e.g., ARM9TDMI
+ CPU_Arch_ARM_V5TE, // e.g., ARM946E-S
+ CPU_Arch_ARM_V5TEJ, // e.g., ARM926EJ-S
+ CPU_Arch_ARM_V6, // e.g., ARM1136J-S
+ CPU_Arch_ARM_V6KZ, // e.g., ARM1176JZ-S
+ CPU_Arch_ARM_V6T2, // e.g., ARM1156T2F-S
+ CPU_Arch_ARM_V6K, // e.g., ARM1136J-S
+ CPU_Arch_ARM_V7, // e.g., Cortex A8, Cortex M3
+ CPU_Arch_ARM_V6_M, // e.g., Cortex M1
+ CPU_Arch_ARM_V6S_M, // e.g., v6-M with the value of System extensions
+ CPU_Arch_ARM_V7E_M, // e.g., v7-M with DSP extensions
+ CPU_Arch_ARM_V8,
+
+ CPU_Arch_Max = CPU_Arch_ARM_V8,
+
+ // This is a pseudo-architecture to describe an architecture mixed with
+ // the subset of armv4t and armv6-m. This never appears in the value of
+ // Tag_CPU_arch.
+ CPU_Arch_ARM_V4T_Plus_V6_M = (CPU_Arch_Max + 1),
+
+ CPU_Arch_Plus_Pseudo_Max = CPU_Arch_ARM_V4T_Plus_V6_M,
+ };
+
+ // For Tag_CPU_arch_profile
+ enum {
+ Arch_Profile_None = 0,
+ Arch_Profile_Application = 'A',
+ Arch_Profile_Realtime = 'R',
+ Arch_Profile_Microcontroller = 'M',
+ Arch_Profile_RealOrApp = 'S'
+ };
+
+ // For Tag_ABI_enum_size
+ enum {
+ Enum_Unused,
+ Enum_Smallest_Container,
+ Enum_32bit_Container,
+ Enum_Containerized_As_Possible
+ };
+
+ // For Tag_ABI_PCS_R9_use
+ enum {
+ R9_V6,
+ R9_SB,
+ R9_TLS,
+ R9_Unused
+ };
+
+ // For Tag_ABI_PCS_RW_data
+ enum {
+ RW_data_Absolute,
+ RW_data_PC_Relative,
+ RW_data_SB_Relative,
+ RW_data_unused
+ };
+
+public:
+ // ARM [ABI-addenda], 2.2.2: A public attributes subsection is named aeabi.
+ ARMELFAttributeData()
+ : ELFAttributeData("aeabi"), m_CurrentCPUArch(-1),
+ m_DIVUseInitialized(false), m_HardFPUseInitialized(false) { }
+
+public:
+ virtual const ELFAttributeValue *getAttributeValue(TagType pTag) const;
+
+ virtual std::pair<ELFAttributeValue*, bool>
+ getOrCreateAttributeValue(TagType pTag);
+
+ virtual bool preMerge(const Input &pInput)
+ {
+ // Reset states.
+ m_CPUArch = -1;
+ m_CPUName.clear();
+ m_CPURawName.clear();
+ m_SecondaryCPUArch = -1;
+ m_VFPArgs = -1;
+ m_FPArch = -1;
+ m_HardFPUse = -1;
+ m_MPextensionUse = -1;
+ m_DIVUse = -1;
+ return true;
+ }
+
+ virtual bool merge(const LinkerConfig& pConfig, const Input &pInput,
+ TagType pTag, const ELFAttributeValue& pInAttr);
+
+ virtual bool postMerge(const LinkerConfig& pConfig, const Input &pInput);
+
+ virtual size_t sizeOutput() const;
+
+ virtual size_t emit(char *pBuf) const;
+
+private:
+ /// GetAttributeValueType - obtain the value type of the indicated tag.
+ static unsigned int GetAttributeValueType(TagType pTag);
+
+private:
+ // The storage for known tags which is indexed by the tag
+ ELFAttributeValue m_Attrs[Tag_Max + 1];
+
+ // The storage for unknown tags
+ typedef std::map<TagType, ELFAttributeValue> UnknownAttrsMap;
+ UnknownAttrsMap m_UnknownAttrs;
+
+ // This is a cache for the current output architecture calculate from of
+ // Tag_CPU_arch and Tag_also_compatible_with.
+ int m_CurrentCPUArch;
+
+ // Value of Tag_DIV_use and Tag_ABI_HardFP_use requires further examination
+ // for the every time adding to the output. These booleans are initialized to
+ // false and set to true until the corresponding attribute is initialized.
+ bool m_DIVUseInitialized;
+ bool m_HardFPUseInitialized;
+
+ // These attributes have dependency with each other. During the merge, we
+ // record their attribute values in the associated variables as follows and
+ // process them in postmerge() (when all other attributes are settled down.)
+
+ // Record the value of input Tag_CPU_arch.
+ int m_CPUArch;
+
+ // Record the value of input Tag_CPU_name.
+ std::string m_CPUName;
+
+ // Record the value of input Tag_CPU_raw_name.
+ std::string m_CPURawName;
+
+ // Record the value of input Tag_FP_arch.
+ int m_FPArch;
+
+ // Record the value of input Tag_ABI_HardFP_use.
+ int m_HardFPUse;
+
+ // Record the value of input Tag_also_compatible_with.
+ int m_SecondaryCPUArch;
+
+ // Record the value of input Tag_ABI_VFP_args.
+ int m_VFPArgs;
+
+ // Record the value of input Tag_MPextension_use and Tag_MPextension_use_legacy.
+ int m_MPextensionUse;
+
+ // Record the value of input Tag_DIV_use.
+ int m_DIVUse;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/ARM/ARMELFMCLinker.cpp b/lib/Target/ARM/ARMELFMCLinker.cpp
index daccc84..8e9a440 100644
--- a/lib/Target/ARM/ARMELFMCLinker.cpp
+++ b/lib/Target/ARM/ARMELFMCLinker.cpp
@@ -8,15 +8,12 @@
//===----------------------------------------------------------------------===//
#include "ARMELFMCLinker.h"
-#include <mcld/LinkerConfig.h>
-#include <mcld/Object/SectionMap.h>
-
using namespace mcld;
ARMELFMCLinker::ARMELFMCLinker(LinkerConfig& pConfig,
mcld::Module &pModule,
- MemoryArea& pOutput)
- : ELFMCLinker(pConfig, pModule, pOutput) {
+ FileHandle& pFileHandle)
+ : ELFMCLinker(pConfig, pModule, pFileHandle) {
}
ARMELFMCLinker::~ARMELFMCLinker()
diff --git a/lib/Target/ARM/ARMELFMCLinker.h b/lib/Target/ARM/ARMELFMCLinker.h
index 91f297f..1306bc9 100644
--- a/lib/Target/ARM/ARMELFMCLinker.h
+++ b/lib/Target/ARM/ARMELFMCLinker.h
@@ -16,7 +16,7 @@
namespace mcld {
class Module;
-class MemoryArea;
+class FileHandle;
/** \class ARMELFMCLinker
* \brief ARMELFMCLinker sets up the environment for linking.
@@ -26,7 +26,7 @@
public:
ARMELFMCLinker(LinkerConfig& pConfig,
mcld::Module& pModule,
- MemoryArea& pOutput);
+ FileHandle& pFileHandle);
~ARMELFMCLinker();
};
diff --git a/lib/Target/ARM/ARMEmulation.cpp b/lib/Target/ARM/ARMEmulation.cpp
index 8b64f40..a890a87 100644
--- a/lib/Target/ARM/ARMEmulation.cpp
+++ b/lib/Target/ARM/ARMEmulation.cpp
@@ -34,11 +34,11 @@
pConfig.attribute().predefined().setDynamic();
// set up section map
- if (pConfig.codeGenType() != LinkerConfig::Object) {
- bool exist = false;
- pScript.sectionMap().append(".ARM.exidx", ".ARM.exidx", exist);
- pScript.sectionMap().append(".ARM.extab", ".ARM.extab", exist);
- pScript.sectionMap().append(".ARM.attributes", ".ARM.attributes", exist);
+ if (pConfig.options().getScriptList().empty() &&
+ pConfig.codeGenType() != LinkerConfig::Object) {
+ pScript.sectionMap().insert(".ARM.exidx*", ".ARM.exidx");
+ pScript.sectionMap().insert(".ARM.extab*", ".ARM.extab");
+ pScript.sectionMap().insert(".ARM.attributes*", ".ARM.attributes");
}
return true;
}
diff --git a/lib/Target/ARM/ARMFixupKinds.h b/lib/Target/ARM/ARMFixupKinds.h
deleted file mode 100644
index f42b940..0000000
--- a/lib/Target/ARM/ARMFixupKinds.h
+++ /dev/null
@@ -1,98 +0,0 @@
-//===- ARMFixupKinds.h ----------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_LIB_TARGET_ARM_ARM_FIXUP_KINDS_H_
-#define MCLD_LIB_TARGET_ARM_ARM_FIXUP_KINDS_H_
-
-#include <llvm/MC/MCFixup.h>
-
-namespace mcld {
-namespace ARM {
-
-enum Fixups {
- // fixup_arm_ldst_pcrel_12 - 12-bit PC relative relocation for symbol
- // addresses
- fixup_arm_ldst_pcrel_12 = FirstTargetFixupKind,
-
- // fixup_t2_ldst_pcrel_12 - Equivalent to fixup_arm_ldst_pcrel_12, with
- // the 16-bit halfwords reordered.
- fixup_t2_ldst_pcrel_12,
-
- // fixup_arm_pcrel_10 - 10-bit PC relative relocation for symbol addresses
- // used in VFP instructions where the lower 2 bits are not encoded
- // (so it's encoded as an 8-bit immediate).
- fixup_arm_pcrel_10,
- // fixup_t2_pcrel_10 - Equivalent to fixup_arm_pcrel_10, accounting for
- // the short-swapped encoding of Thumb2 instructions.
- fixup_t2_pcrel_10,
- // fixup_thumb_adr_pcrel_10 - 10-bit PC relative relocation for symbol
- // addresses where the lower 2 bits are not encoded (so it's encoded as an
- // 8-bit immediate).
- fixup_thumb_adr_pcrel_10,
- // fixup_arm_adr_pcrel_12 - 12-bit PC relative relocation for the ADR
- // instruction.
- fixup_arm_adr_pcrel_12,
- // fixup_t2_adr_pcrel_12 - 12-bit PC relative relocation for the ADR
- // instruction.
- fixup_t2_adr_pcrel_12,
- // fixup_arm_condbranch - 24-bit PC relative relocation for conditional branch
- // instructions.
- fixup_arm_condbranch,
- // fixup_arm_uncondbranch - 24-bit PC relative relocation for
- // branch instructions. (unconditional)
- fixup_arm_uncondbranch,
- // fixup_t2_condbranch - 20-bit PC relative relocation for Thumb2 direct
- // unconditional branch instructions.
- fixup_t2_condbranch,
- // fixup_t2_uncondbranch - 20-bit PC relative relocation for Thumb2 direct
- // branch unconditional branch instructions.
- fixup_t2_uncondbranch,
-
- // fixup_arm_thumb_br - 12-bit fixup for Thumb B instructions.
- fixup_arm_thumb_br,
-
- // fixup_arm_thumb_bl - Fixup for Thumb BL instructions.
- fixup_arm_thumb_bl,
-
- // fixup_arm_thumb_blx - Fixup for Thumb BLX instructions.
- fixup_arm_thumb_blx,
-
- // fixup_arm_thumb_cb - Fixup for Thumb branch instructions.
- fixup_arm_thumb_cb,
-
- // fixup_arm_thumb_cp - Fixup for Thumb load/store from constant pool instrs.
- fixup_arm_thumb_cp,
-
- // fixup_arm_thumb_bcc - Fixup for Thumb conditional branching instructions.
- fixup_arm_thumb_bcc,
-
- // The next two are for the movt/movw pair
- // the 16bit imm field are split into imm{15-12} and imm{11-0}
- fixup_arm_movt_hi16, // :upper16:
- fixup_arm_movw_lo16, // :lower16:
- fixup_t2_movt_hi16, // :upper16:
- fixup_t2_movw_lo16, // :lower16:
-
- // It is possible to create an "immediate" that happens to be pcrel.
- // movw r0, :lower16:Foo-(Bar+8) and movt r0, :upper16:Foo-(Bar+8)
- // result in different reloc tags than the above two.
- // Needed to support ELF::R_ARM_MOVT_PREL and ELF::R_ARM_MOVW_PREL_NC
- fixup_arm_movt_hi16_pcrel, // :upper16:
- fixup_arm_movw_lo16_pcrel, // :lower16:
- fixup_t2_movt_hi16_pcrel, // :upper16:
- fixup_t2_movw_lo16_pcrel, // :lower16:
-
- // Marker
- LastTargetFixupKind,
- NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
-};
-
-} // namespace ARM
-} // namespace mcld
-
-#endif
diff --git a/lib/Target/ARM/ARMGNUInfo.h b/lib/Target/ARM/ARMGNUInfo.h
index ba51126..531a817 100644
--- a/lib/Target/ARM/ARMGNUInfo.h
+++ b/lib/Target/ARM/ARMGNUInfo.h
@@ -23,9 +23,7 @@
uint64_t defaultTextSegmentAddr() const { return 0x8000; }
- uint64_t flags() const
- { return llvm::ELF::EF_ARM_EABI_VER5; }
-
+ uint64_t flags() const { return llvm::ELF::EF_ARM_EABI_VER5; }
};
} // namespace of mcld
diff --git a/lib/Target/ARM/ARMGOT.cpp b/lib/Target/ARM/ARMGOT.cpp
index 1796635..3e9dc31 100644
--- a/lib/Target/ARM/ARMGOT.cpp
+++ b/lib/Target/ARM/ARMGOT.cpp
@@ -12,7 +12,6 @@
#include <mcld/LD/LDSection.h>
#include <mcld/LD/LDFileFormat.h>
-#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MsgHandling.h>
namespace {
@@ -24,15 +23,11 @@
//===----------------------------------------------------------------------===//
// ARMGOT
ARMGOT::ARMGOT(LDSection& pSection)
- : GOT(pSection), m_pLast(NULL)
+ : GOT(pSection), m_pGOTPLTFront(NULL), m_pGOTFront(NULL)
{
- // Create GOT0 entries.
- reserve(ARMGOT0Num);
-
- // Skip GOT0 entries.
- for (unsigned int i = 0; i < ARMGOT0Num; ++i) {
- consume();
- }
+ // create GOT0, and put them into m_SectionData immediately
+ for (unsigned int i = 0; i < ARMGOT0Num; ++i)
+ new ARMGOTEntry(0, m_SectionData);
}
ARMGOT::~ARMGOT()
@@ -41,86 +36,64 @@
bool ARMGOT::hasGOT1() const
{
- return (m_SectionData->size() > ARMGOT0Num);
+ return ((!m_GOT.empty()) || (!m_GOTPLT.empty()));
}
-void ARMGOT::reserve(size_t pNum)
+ARMGOTEntry* ARMGOT::createGOT()
{
- for (size_t i = 0; i < pNum; i++) {
- new ARMGOTEntry(0, m_SectionData);
- }
+ ARMGOTEntry* entry = new ARMGOTEntry(0, NULL);
+ m_GOT.push_back(entry);
+ return entry;
}
-ARMGOTEntry* ARMGOT::consume()
+ARMGOTEntry* ARMGOT::createGOTPLT()
{
- if (NULL == m_pLast) {
- assert(!empty() && "Consume empty GOT entry!");
- m_pLast = llvm::cast<ARMGOTEntry>(&m_SectionData->front());
- return m_pLast;
+ ARMGOTEntry* entry = new ARMGOTEntry(0, NULL);
+ m_GOTPLT.push_back(entry);
+ return entry;
+}
+
+void ARMGOT::finalizeSectionSize()
+{
+ uint32_t offset = 0;
+ SectionData::FragmentListType& frag_list = m_SectionData->getFragmentList();
+ // setup GOT0 offset
+ SectionData::iterator frag, fragEnd = m_SectionData->end();
+ for (frag = m_SectionData->begin(); frag != fragEnd; ++frag) {
+ frag->setOffset(offset);
+ offset += frag->size();
}
- m_pLast = llvm::cast<ARMGOTEntry>(m_pLast->getNextNode());
- return m_pLast;
-}
-
-void ARMGOT::reserveGOTPLT()
-{
- ARMGOTEntry* entry = new ARMGOTEntry(0, m_SectionData);
- if (NULL == m_GOTPLT.front) {
- // GOTPLT is empty
- if (NULL == m_GOT.front) {
- // GOT part is also empty. Since entry is the last entry, we can assign
- // it to GOTPLT directly.
- m_GOTPLT.front = entry;
- }
- else {
- // GOTn is not empty. Shift GOTn backward by one entry.
- m_GOTPLT.front = m_GOT.front;
- m_GOT.front = llvm::cast<ARMGOTEntry>(m_GOT.front->getNextNode());
+ // push GOTPLT into the SectionData and setup the offset
+ if (!m_GOTPLT.empty()) {
+ m_pGOTPLTFront = m_GOTPLT.front();
+ entry_iterator it, end = m_GOTPLT.end();
+ for (it = m_GOTPLT.begin(); it != end; ++it) {
+ ARMGOTEntry* entry = *it;
+ frag_list.push_back(entry);
+ entry->setParent(m_SectionData);
+ entry->setOffset(offset);
+ offset += entry->size();
}
}
- else {
- // GOTPLT is not empty
- if (NULL != m_GOT.front)
- m_GOT.front = llvm::cast<ARMGOTEntry>(m_GOT.front->getNextNode());
- }
-}
+ m_GOTPLT.clear();
-void ARMGOT::reserveGOT()
-{
- ARMGOTEntry* entry = new ARMGOTEntry(0, m_SectionData);
- if (NULL == m_GOT.front) {
- // Entry must be the last entry. We can directly assign it to GOT part.
- m_GOT.front = entry;
+ // push GOT into the SectionData and setup the offset
+ if (!m_GOT.empty()) {
+ m_pGOTFront = m_GOT.front();
+ entry_iterator it, end = m_GOT.end();
+ for (it = m_GOT.begin(); it != end; ++it) {
+ ARMGOTEntry* entry = *it;
+ frag_list.push_back(entry);
+ entry->setParent(m_SectionData);
+ entry->setOffset(offset);
+ offset += entry->size();
+ }
}
-}
+ m_GOT.clear();
-ARMGOTEntry* ARMGOT::consumeGOTPLT()
-{
- assert(NULL != m_GOTPLT.front && "Consuming empty GOTPLT section!");
-
- if (NULL == m_GOTPLT.last_used) {
- m_GOTPLT.last_used = m_GOTPLT.front;
- }
- else {
- m_GOTPLT.last_used = llvm::cast<ARMGOTEntry>(m_GOTPLT.last_used->getNextNode());
- assert(m_GOTPLT.last_used != m_GOT.front && "No GOT/PLT entry to consume!");
- }
- return m_GOTPLT.last_used;
-}
-
-ARMGOTEntry* ARMGOT::consumeGOT()
-{
- assert(NULL != m_GOT.front && "Consuming empty GOT section!");
-
- if (NULL == m_GOT.last_used) {
- m_GOT.last_used = m_GOT.front;
- }
- else {
- m_GOT.last_used = llvm::cast<ARMGOTEntry>(m_GOT.last_used->getNextNode());
- assert(m_GOT.last_used != NULL && "No GOTn entry to consume!");
- }
- return m_GOT.last_used;
+ // set section size
+ m_Section.setSize(offset);
}
void ARMGOT::applyGOT0(uint64_t pAddress)
@@ -131,15 +104,15 @@
void ARMGOT::applyGOTPLT(uint64_t pPLTBase)
{
- if (NULL == m_GOTPLT.front)
+ if (NULL == m_pGOTPLTFront)
return;
- SectionData::iterator entry(m_GOTPLT.front);
+ SectionData::iterator entry(m_pGOTPLTFront);
SectionData::iterator e_end;
- if (NULL == m_GOT.front)
+ if (NULL == m_pGOTFront)
e_end = m_SectionData->end();
else
- e_end = SectionData::iterator(m_GOT.front);
+ e_end = SectionData::iterator(m_pGOTFront);
while (entry != e_end) {
llvm::cast<ARMGOTEntry>(entry)->setValue(pPLTBase);
@@ -149,7 +122,7 @@
uint64_t ARMGOT::emit(MemoryRegion& pRegion)
{
- uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.begin());
ARMGOTEntry* got = NULL;
uint64_t result = 0x0;
diff --git a/lib/Target/ARM/ARMGOT.h b/lib/Target/ARM/ARMGOT.h
index be22c67..dc85fb0 100644
--- a/lib/Target/ARM/ARMGOT.h
+++ b/lib/Target/ARM/ARMGOT.h
@@ -12,14 +12,14 @@
#include <gtest.h>
#endif
-#include <llvm/ADT/DenseMap.h>
-
#include <mcld/Target/GOT.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <llvm/ADT/DenseMap.h>
+#include <vector>
namespace mcld {
class LDSection;
-class MemoryRegion;
/** \class ARMGOTEntry
* \brief GOT Entry with size of 4 bytes
@@ -56,17 +56,10 @@
~ARMGOT();
- void reserve(size_t pNum = 1);
+ ARMGOTEntry* createGOT();
+ ARMGOTEntry* createGOTPLT();
- void reserveGOTPLT();
-
- void reserveGOT();
-
- ARMGOTEntry* consume();
-
- ARMGOTEntry* consumeGOT();
-
- ARMGOTEntry* consumeGOTPLT();
+ void finalizeSectionSize();
uint64_t emit(MemoryRegion& pRegion);
@@ -77,20 +70,19 @@
bool hasGOT1() const;
private:
- struct Part {
- public:
- Part() : front(NULL), last_used(NULL) { }
-
- public:
- ARMGOTEntry* front;
- ARMGOTEntry* last_used;
- };
+ typedef std::vector<ARMGOTEntry*> EntryListType;
+ typedef EntryListType::iterator entry_iterator;
+ typedef EntryListType::const_iterator const_entry_iterator;
private:
- Part m_GOTPLT;
- Part m_GOT;
+ ARMGOTEntry* m_pGOTPLTFront;
+ ARMGOTEntry* m_pGOTFront;
- ARMGOTEntry* m_pLast; ///< the last consumed entry
+ /// m_GOTPLTEntries - a list of gotplt entries
+ EntryListType m_GOTPLT;
+
+ /// m_GOTEntris - a list of got entries
+ EntryListType m_GOT;
};
} // namespace of mcld
diff --git a/lib/Target/ARM/ARMLDBackend.cpp b/lib/Target/ARM/ARMLDBackend.cpp
index 8e45543..dfcfb0d 100644
--- a/lib/Target/ARM/ARMLDBackend.cpp
+++ b/lib/Target/ARM/ARMLDBackend.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "ARM.h"
#include "ARMGNUInfo.h"
+#include "ARMELFAttributeData.h"
#include "ARMELFDynamic.h"
#include "ARMLDBackend.h"
#include "ARMRelocator.h"
@@ -28,17 +29,21 @@
#include <mcld/Fragment/FillFragment.h>
#include <mcld/Fragment/AlignFragment.h>
#include <mcld/Fragment/RegionFragment.h>
+#include <mcld/Fragment/Stub.h>
+#include <mcld/Fragment/NullFragment.h>
#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/TargetRegistry.h>
-#include <mcld/Fragment/Stub.h>
#include <mcld/LD/BranchIslandFactory.h>
#include <mcld/LD/StubFactory.h>
-#include <mcld/Object/ObjectBuilder.h>
-#include <mcld/Fragment/NullFragment.h>
#include <mcld/LD/LDContext.h>
+#include <mcld/LD/ELFFileFormat.h>
+#include <mcld/LD/ELFSegmentFactory.h>
+#include <mcld/LD/ELFSegment.h>
+#include <mcld/Target/ELFAttribute.h>
#include <mcld/Target/GNUInfo.h>
+#include <mcld/Object/ObjectBuilder.h>
using namespace mcld;
@@ -52,6 +57,7 @@
m_pPLT(NULL),
m_pRelDyn(NULL),
m_pRelPLT(NULL),
+ m_pAttrData(NULL),
m_pDynamic(NULL),
m_pGOTSymbol(NULL),
m_pEXIDXStart(NULL),
@@ -69,6 +75,7 @@
delete m_pRelDyn;
delete m_pRelPLT;
delete m_pDynamic;
+ delete m_pAttrData;
}
void ARMGNULDBackend::initTargetSections(Module& pModule, ObjectBuilder& pBuilder)
@@ -91,6 +98,10 @@
0x0,
0x1);
+ // initialize "aeabi" attributes subsection
+ m_pAttrData = new ARMELFAttributeData();
+ attribute().registerAttributeData(*m_pAttrData);
+
if (LinkerConfig::Object != config().codeGenType()) {
ELFFileFormat* file_format = getOutputFormat();
@@ -206,6 +217,9 @@
if (!config().isCodeStatic() && NULL == m_pDynamic)
m_pDynamic = new ARMELFDynamic(*this, config());
+ // set attribute section size
+ m_pAttributes->setSize(attribute().sizeOutput());
+
// set .got size
// when building shared object, the .got section is must
if (LinkerConfig::Object != config().codeGenType()) {
@@ -316,77 +330,71 @@
const ELFFileFormat* file_format = getOutputFormat();
- if (&pSection == m_pAttributes ||
- &pSection == m_pEXIDX ||
- &pSection == m_pEXTAB) {
- // FIXME: Currently Emitting .ARM.attributes, .ARM.exidx, and .ARM.extab
- // directly from the input file.
- const SectionData* sect_data = pSection.getSectionData();
- SectionData::const_iterator frag_iter, frag_end = sect_data->end();
- uint8_t* out_offset = pRegion.start();
- for (frag_iter = sect_data->begin(); frag_iter != frag_end; ++frag_iter) {
- size_t size = frag_iter->size();
- switch(frag_iter->getKind()) {
- case Fragment::Fillment: {
- const FillFragment& fill_frag =
- llvm::cast<FillFragment>(*frag_iter);
- if (0 == fill_frag.getValueSize()) {
- // virtual fillment, ignore it.
- break;
- }
-
- memset(out_offset, fill_frag.getValue(), fill_frag.size());
- break;
- }
- case Fragment::Region: {
- const RegionFragment& region_frag =
- llvm::cast<RegionFragment>(*frag_iter);
- const uint8_t* start = region_frag.getRegion().start();
- memcpy(out_offset, start, size);
- break;
- }
- case Fragment::Alignment: {
- const AlignFragment& align_frag = llvm::cast<AlignFragment>(*frag_iter);
- uint64_t count = size / align_frag.getValueSize();
- switch (align_frag.getValueSize()) {
- case 1u:
- std::memset(out_offset, align_frag.getValue(), count);
- break;
- default:
- llvm::report_fatal_error(
- "unsupported value size for align fragment emission yet.\n");
- break;
- } // end switch
- break;
- }
- case Fragment::Null: {
- assert(0x0 == size);
- break;
- }
- default:
- llvm::report_fatal_error("unsupported fragment type.\n");
- break;
- } // end switch
- out_offset += size;
- } // end for
- return pRegion.size();
- } // end if
-
- if (&pSection == &(file_format->getPLT())) {
- assert(NULL != m_pPLT && "emitSectionData failed, m_pPLT is NULL!");
+ if (file_format->hasPLT() && (&pSection == &(file_format->getPLT()))) {
uint64_t result = m_pPLT->emit(pRegion);
return result;
}
- if (&pSection == &(file_format->getGOT())) {
- assert(NULL != m_pGOT && "emitSectionData failed, m_pGOT is NULL!");
+ if (file_format->hasGOT() && (&pSection == &(file_format->getGOT()))) {
uint64_t result = m_pGOT->emit(pRegion);
return result;
}
- fatal(diag::unrecognized_output_sectoin)
- << pSection.name()
- << "mclinker@googlegroups.com";
- return 0x0;
+
+ if (&pSection == m_pAttributes) {
+ return attribute().emit(pRegion);
+ }
+
+ // FIXME: Currently Emitting .ARM.attributes, .ARM.exidx, and .ARM.extab
+ // directly from the input file.
+ const SectionData* sect_data = pSection.getSectionData();
+ SectionData::const_iterator frag_iter, frag_end = sect_data->end();
+ uint8_t* out_offset = pRegion.begin();
+ for (frag_iter = sect_data->begin(); frag_iter != frag_end; ++frag_iter) {
+ size_t size = frag_iter->size();
+ switch(frag_iter->getKind()) {
+ case Fragment::Fillment: {
+ const FillFragment& fill_frag =
+ llvm::cast<FillFragment>(*frag_iter);
+ if (0 == fill_frag.getValueSize()) {
+ // virtual fillment, ignore it.
+ break;
+ }
+
+ memset(out_offset, fill_frag.getValue(), fill_frag.size());
+ break;
+ }
+ case Fragment::Region: {
+ const RegionFragment& region_frag =
+ llvm::cast<RegionFragment>(*frag_iter);
+ const char* start = region_frag.getRegion().begin();
+ memcpy(out_offset, start, size);
+ break;
+ }
+ case Fragment::Alignment: {
+ const AlignFragment& align_frag = llvm::cast<AlignFragment>(*frag_iter);
+ uint64_t count = size / align_frag.getValueSize();
+ switch (align_frag.getValueSize()) {
+ case 1u:
+ std::memset(out_offset, align_frag.getValue(), count);
+ break;
+ default:
+ llvm::report_fatal_error(
+ "unsupported value size for align fragment emission yet.\n");
+ break;
+ } // end switch
+ break;
+ }
+ case Fragment::Null: {
+ assert(0x0 == size);
+ break;
+ }
+ default:
+ llvm::report_fatal_error("unsupported fragment type.\n");
+ break;
+ } // end switch
+ out_offset += size;
+ } // end for
+ return pRegion.size();
}
/// finalizeSymbol - finalize the symbol value
@@ -395,46 +403,110 @@
return true;
}
-bool ARMGNULDBackend::mergeSection(Module& pModule, LDSection& pSection)
+bool ARMGNULDBackend::mergeSection(Module& pModule,
+ const Input& pInput,
+ LDSection& pSection)
{
switch (pSection.type()) {
case llvm::ELF::SHT_ARM_ATTRIBUTES: {
- // FIXME: (Luba)
- // Handle ARM attributes in the right way.
- // In current milestone, we goes through the shortcut.
- // It reads input's ARM attributes and copies the first ARM attributes
- // into the output file. The correct way is merge these sections, not
- // just copy.
- if (0 != m_pAttributes->size())
- return true;
-
- // First time we meet a ARM attributes section.
- SectionData* sd = IRBuilder::CreateSectionData(*m_pAttributes);
- ObjectBuilder::MoveSectionData(*pSection.getSectionData(), *sd);
- return true;
+ return attribute().merge(pInput, pSection);
}
+ case llvm::ELF::SHT_ARM_EXIDX: {
+ assert(NULL != pSection.getLink());
+ if (LDFileFormat::Ignore == pSection.getLink()->kind()) {
+ // if the target section of the .ARM.exidx is Ignore, then it should be
+ // ignored as well
+ pSection.setKind(LDFileFormat::Ignore);
+ return true;
+ }
+ }
+ /** fall through **/
default: {
ObjectBuilder builder(config(), pModule);
- return builder.MergeSection(pSection);
+ builder.MergeSection(pInput, pSection);
+ return true;
}
} // end of switch
return true;
}
+void ARMGNULDBackend::setUpReachedSectionsForGC(const Module& pModule,
+ GarbageCollection::SectionReachedListMap& pSectReachedListMap) const
+{
+ // traverse all the input relocations to find the relocation sections applying
+ // .ARM.exidx sections
+ Module::const_obj_iterator input, inEnd = pModule.obj_end();
+ for (input = pModule.obj_begin(); input != inEnd; ++input) {
+ LDContext::const_sect_iterator rs,
+ rsEnd = (*input)->context()->relocSectEnd();
+ for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
+ // bypass the discarded relocation section
+ // 1. its section kind is changed to Ignore. (The target section is a
+ // discarded group section.)
+ // 2. it has no reloc data. (All symbols in the input relocs are in the
+ // discarded group sections)
+ LDSection* reloc_sect = *rs;
+ LDSection* apply_sect = reloc_sect->getLink();
+ if ((LDFileFormat::Ignore == reloc_sect->kind()) ||
+ (!reloc_sect->hasRelocData()))
+ continue;
+
+ if (llvm::ELF::SHT_ARM_EXIDX == apply_sect->type()) {
+ // 1. set up the reference according to relocations
+ bool add_first = false;
+ GarbageCollection::SectionListTy* reached_sects = NULL;
+ RelocData::iterator reloc_it, rEnd = reloc_sect->getRelocData()->end();
+ for (reloc_it = reloc_sect->getRelocData()->begin(); reloc_it != rEnd;
+ ++reloc_it) {
+ Relocation* reloc = llvm::cast<Relocation>(reloc_it);
+ ResolveInfo* sym = reloc->symInfo();
+ // only the target symbols defined in the input fragments can make the
+ // reference
+ if (NULL == sym)
+ continue;
+ if (!sym->isDefine() || !sym->outSymbol()->hasFragRef())
+ continue;
+
+ // only the target symbols defined in the concerned sections can make
+ // the reference
+ const LDSection* target_sect =
+ &sym->outSymbol()->fragRef()->frag()->getParent()->getSection();
+ if (target_sect->kind() != LDFileFormat::Regular &&
+ target_sect->kind() != LDFileFormat::BSS)
+ continue;
+
+ // setup the reached list, if we first add the element to reached list
+ // of this section, create an entry in ReachedSections map
+ if (!add_first) {
+ reached_sects = &pSectReachedListMap.getReachedList(*apply_sect);
+ add_first = true;
+ }
+ reached_sects->insert(target_sect);
+ }
+ reached_sects = NULL;
+ add_first = false;
+ // 2. set up the reference from XXX to .ARM.exidx.XXX
+ assert(apply_sect->getLink() != NULL);
+ pSectReachedListMap.addReference(*apply_sect->getLink(), *apply_sect);
+ }
+ }
+ }
+}
+
bool ARMGNULDBackend::readSection(Input& pInput, SectionData& pSD)
{
Fragment* frag = NULL;
uint32_t offset = pInput.fileOffset() + pSD.getSection().offset();
uint32_t size = pSD.getSection().size();
- MemoryRegion* region = pInput.memArea()->request(offset, size);
- if (NULL == region) {
+ llvm::StringRef region = pInput.memArea()->request(offset, size);
+ if (region.size() == 0) {
// If the input section's size is zero, we got a NULL region.
// use a virtual fill fragment
frag = new FillFragment(0x0, 0, 0);
}
else {
- frag = new RegionFragment(*region);
+ frag = new RegionFragment(region);
}
ObjectBuilder::AppendFragment(*frag, pSD);
@@ -489,18 +561,30 @@
return *m_pRelPLT;
}
+ARMELFAttributeData& ARMGNULDBackend::getAttributeData()
+{
+ assert(NULL != m_pAttrData && ".ARM.attributes section not exist");
+ return *m_pAttrData;
+}
+
+const ARMELFAttributeData& ARMGNULDBackend::getAttributeData() const
+{
+ assert(NULL != m_pAttrData && ".ARM.attributes section not exist");
+ return *m_pAttrData;
+}
+
unsigned int
ARMGNULDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const
{
const ELFFileFormat* file_format = getOutputFormat();
- if (&pSectHdr == &file_format->getGOT()) {
+ if (file_format->hasGOT() && (&pSectHdr == &file_format->getGOT())) {
if (config().options().hasNow())
return SHO_RELRO_LAST;
return SHO_DATA;
}
- if (&pSectHdr == &file_format->getPLT())
+ if (file_format->hasPLT() && (&pSectHdr == &file_format->getPLT()))
return SHO_PLT;
if (&pSectHdr == m_pEXIDX || &pSectHdr == m_pEXTAB) {
@@ -538,8 +622,7 @@
case llvm::ELF::R_ARM_THM_CALL:
case llvm::ELF::R_ARM_THM_XPC22:
case llvm::ELF::R_ARM_THM_JUMP24:
- case llvm::ELF::R_ARM_THM_JUMP19:
- case llvm::ELF::R_ARM_V4BX: {
+ case llvm::ELF::R_ARM_THM_JUMP19: {
// calculate the possible symbol value
uint64_t sym_value = 0x0;
LDSymbol* symbol = relocation->symInfo()->outSymbol();
@@ -561,23 +644,32 @@
pBuilder,
*getBRIslandFactory());
if (NULL != stub) {
- // a stub symbol should be local
- assert(NULL != stub->symInfo() && stub->symInfo()->isLocal());
- LDSection& symtab = file_format->getSymTab();
- LDSection& strtab = file_format->getStrTab();
+ switch (config().options().getStripSymbolMode()) {
+ case GeneralOptions::StripAllSymbols:
+ case GeneralOptions::StripLocals:
+ break;
+ default: {
+ // a stub symbol should be local
+ assert(NULL != stub->symInfo() && stub->symInfo()->isLocal());
+ LDSection& symtab = file_format->getSymTab();
+ LDSection& strtab = file_format->getStrTab();
- // increase the size of .symtab and .strtab if needed
- if (config().targets().is32Bits())
- symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf32_Sym));
- else
- symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf64_Sym));
- symtab.setInfo(symtab.getInfo() + 1);
- strtab.setSize(strtab.size() + stub->symInfo()->nameSize() + 1);
-
+ // increase the size of .symtab and .strtab if needed
+ if (config().targets().is32Bits())
+ symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf32_Sym));
+ else
+ symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf64_Sym));
+ symtab.setInfo(symtab.getInfo() + 1);
+ strtab.setSize(strtab.size() + stub->symInfo()->nameSize() + 1);
+ }
+ } // end of switch
isRelaxed = true;
}
break;
}
+ case llvm::ELF::R_ARM_V4BX:
+ /* FIXME: bypass R_ARM_V4BX relocation now */
+ break;
default:
break;
} // end of switch
@@ -639,7 +731,7 @@
// make PT_ARM_EXIDX
ELFSegment* exidx_seg = elfSegmentTable().produce(llvm::ELF::PT_ARM_EXIDX,
llvm::ELF::PF_R);
- exidx_seg->addSection(m_pEXIDX);
+ exidx_seg->append(m_pEXIDX);
}
}
@@ -648,8 +740,7 @@
//===----------------------------------------------------------------------===//
/// createARMLDBackend - the help funtion to create corresponding ARMLDBackend
///
-TargetLDBackend* createARMLDBackend(const llvm::Target& pTarget,
- const LinkerConfig& pConfig)
+TargetLDBackend* createARMLDBackend(const LinkerConfig& pConfig)
{
if (pConfig.targets().triple().isOSDarwin()) {
assert(0 && "MachO linker is not supported yet");
diff --git a/lib/Target/ARM/ARMLDBackend.h b/lib/Target/ARM/ARMLDBackend.h
index 699fb78..5567293 100644
--- a/lib/Target/ARM/ARMLDBackend.h
+++ b/lib/Target/ARM/ARMLDBackend.h
@@ -18,9 +18,9 @@
namespace mcld {
+class ARMELFAttributeData;
class LinkerConfig;
class GNUInfo;
-class SectionMap;
//===----------------------------------------------------------------------===//
/// ARMGNULDBackend - linker backend of ARM target of GNU ELF format
@@ -103,6 +103,9 @@
OutputRelocSection& getRelPLT();
const OutputRelocSection& getRelPLT() const;
+ ARMELFAttributeData& getAttributeData();
+ const ARMELFAttributeData& getAttributeData() const;
+
LDSymbol* getGOTSymbol() { return m_pGOTSymbol; }
const LDSymbol* getGOTSymbol() const { return m_pGOTSymbol; }
@@ -113,7 +116,12 @@
bool finalizeTargetSymbols();
/// mergeSection - merge target dependent sections
- bool mergeSection(Module& pModule, LDSection& pSection);
+ bool mergeSection(Module& pModule, const Input& pInput, LDSection& pSection);
+
+ /// setUpReachedSectionsForGC - set the reference from section XXX to
+ /// .ARM.exidx.XXX to make sure GC correctly handle section exidx
+ void setUpReachedSectionsForGC(const Module& pModule,
+ GarbageCollection::SectionReachedListMap& pSectReachedListMap) const;
/// readSection - read target dependent sections
bool readSection(Input& pInput, SectionData& pSD);
@@ -159,6 +167,9 @@
/// m_RelPLT - dynamic relocation table of .rel.plt
OutputRelocSection* m_pRelPLT;
+ /// m_pAttrData - attribute data in public ("aeabi") attribute subsection
+ ARMELFAttributeData* m_pAttrData;
+
ARMELFDynamic* m_pDynamic;
LDSymbol* m_pGOTSymbol;
LDSymbol* m_pEXIDXStart;
diff --git a/lib/Target/ARM/ARMMCLinker.cpp b/lib/Target/ARM/ARMMCLinker.cpp
index cc9486e..dcee683 100644
--- a/lib/Target/ARM/ARMMCLinker.cpp
+++ b/lib/Target/ARM/ARMMCLinker.cpp
@@ -22,9 +22,9 @@
MCLinker* createARMMCLinker(const std::string& pTriple,
LinkerConfig& pConfig,
mcld::Module& pModule,
- MemoryArea& pOutput)
+ FileHandle& pFileHandle)
{
- Triple theTriple(pTriple);
+ llvm::Triple theTriple(pTriple);
if (theTriple.isOSDarwin()) {
assert(0 && "MachO linker has not supported yet");
return NULL;
@@ -34,7 +34,7 @@
return NULL;
}
- return new ARMELFMCLinker(pConfig, pModule, pOutput);
+ return new ARMELFMCLinker(pConfig, pModule, pFileHandle);
}
} // namespace of mcld
diff --git a/lib/Target/ARM/ARMPLT.cpp b/lib/Target/ARM/ARMPLT.cpp
index d7342ab..467bbeb 100644
--- a/lib/Target/ARM/ARMPLT.cpp
+++ b/lib/Target/ARM/ARMPLT.cpp
@@ -14,7 +14,6 @@
#include <llvm/Support/Casting.h>
#include <mcld/LD/LDSection.h>
-#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MsgHandling.h>
using namespace mcld;
@@ -28,11 +27,9 @@
//===----------------------------------------------------------------------===//
// ARMPLT
-ARMPLT::ARMPLT(LDSection& pSection,
- ARMGOT &pGOTPLT)
- : PLT(pSection), m_GOT(pGOTPLT), m_PLTEntryIterator() {
+ARMPLT::ARMPLT(LDSection& pSection, ARMGOT &pGOTPLT)
+ : PLT(pSection), m_GOT(pGOTPLT) {
new ARMPLT0(*m_SectionData);
- m_PLTEntryIterator = m_SectionData->begin();
}
ARMPLT::~ARMPLT()
@@ -58,39 +55,12 @@
}
}
-void ARMPLT::reserveEntry(size_t pNum)
+ARMPLT1* ARMPLT::create()
{
- ARMPLT1* plt1_entry = 0;
-
- for (size_t i = 0; i < pNum; ++i) {
- plt1_entry = new (std::nothrow) ARMPLT1(*m_SectionData);
-
- if (!plt1_entry)
- fatal(diag::fail_allocate_memory_plt);
-
- m_GOT.reserveGOTPLT();
- }
-}
-
-ARMPLT1* ARMPLT::consume()
-{
- ++m_PLTEntryIterator;
- assert(m_PLTEntryIterator != m_SectionData->end() &&
- "The number of PLT Entries and ResolveInfo doesn't match");
-
- return llvm::cast<ARMPLT1>(&(*m_PLTEntryIterator));
-}
-
-ARMPLT0* ARMPLT::getPLT0() const {
-
- iterator first = m_SectionData->getFragmentList().begin();
-
- assert(first != m_SectionData->getFragmentList().end() &&
- "FragmentList is empty, getPLT0 failed!");
-
- ARMPLT0* plt0 = &(llvm::cast<ARMPLT0>(*first));
-
- return plt0;
+ ARMPLT1* plt1_entry = new (std::nothrow) ARMPLT1(*m_SectionData);
+ if (!plt1_entry)
+ fatal(diag::fail_allocate_memory_plt);
+ return plt1_entry;
}
void ARMPLT::applyPLT0() {
@@ -181,7 +151,7 @@
uint64_t result = 0x0;
iterator it = begin();
- unsigned char* buffer = pRegion.getBuffer();
+ unsigned char* buffer = pRegion.begin();
memcpy(buffer, llvm::cast<ARMPLT0>((*it)).getValue(), ARMPLT0::EntrySize);
result += ARMPLT0::EntrySize;
++it;
diff --git a/lib/Target/ARM/ARMPLT.h b/lib/Target/ARM/ARMPLT.h
index 9554f0c..e1c8a74 100644
--- a/lib/Target/ARM/ARMPLT.h
+++ b/lib/Target/ARM/ARMPLT.h
@@ -11,6 +11,7 @@
#include <mcld/Target/GOT.h>
#include <mcld/Target/PLT.h>
+#include <mcld/Support/MemoryRegion.h>
namespace {
@@ -33,7 +34,6 @@
namespace mcld {
class ARMGOT;
-class MemoryRegion;
class ARMPLT0 : public PLT::Entry<sizeof(arm_plt0)>
{
@@ -62,9 +62,7 @@
// hasPLT1 - return if this plt section has any plt1 entry
bool hasPLT1() const;
- void reserveEntry(size_t pNum = 1) ;
-
- ARMPLT1* consume();
+ ARMPLT1* create();
ARMPLT0* getPLT0() const;
@@ -76,9 +74,6 @@
private:
ARMGOT& m_GOT;
-
- // Used by getEntry() for mapping a ResolveInfo instance to a PLT1 Entry.
- iterator m_PLTEntryIterator;
};
} // namespace of mcld
diff --git a/lib/Target/ARM/ARMRelocationFunctions.h b/lib/Target/ARM/ARMRelocationFunctions.h
index 94df077..790ed1f 100644
--- a/lib/Target/ARM/ARMRelocationFunctions.h
+++ b/lib/Target/ARM/ARMRelocationFunctions.h
@@ -33,6 +33,7 @@
DECL_ARM_APPLY_RELOC_FUNC(got_prel) \
DECL_ARM_APPLY_RELOC_FUNC(tls) \
DECL_ARM_APPLY_RELOC_FUNC(thm_jump11) \
+DECL_ARM_APPLY_RELOC_FUNC(thm_jump19) \
DECL_ARM_APPLY_RELOC_FUNC(unsupport)
@@ -77,7 +78,7 @@
{ &unsupport, 37, "R_ARM_ALU_SBREL_27_20_CK"}, \
{ &abs32, 38, "R_ARM_TARGET1" }, \
{ &unsupport, 39, "R_ARM_SBREL31" }, \
- { &unsupport, 40, "R_ARM_V4BX" }, \
+ { &none, 40, "R_ARM_V4BX" }, \
{ &got_prel, 41, "R_ARM_TARGET2" }, \
{ &prel31, 42, "R_ARM_PREL31" }, \
{ &movw_abs_nc, 43, "R_ARM_MOVW_ABS_NC" }, \
@@ -88,7 +89,7 @@
{ &thm_movt_abs, 48, "R_ARM_THM_MOVT_ABS" }, \
{ &thm_movw_prel_nc, 49, "R_ARM_THM_MOVW_PREL_NC" }, \
{ &thm_movt_prel, 50, "R_ARM_THM_MOVT_PREL" }, \
- { &unsupport, 51, "R_ARM_THM_JUMP19" }, \
+ { &thm_jump19, 51, "R_ARM_THM_JUMP19" }, \
{ &unsupport, 52, "R_ARM_THM_JUMP6" }, \
{ &unsupport, 53, "R_ARM_THM_ALU_PREL_11_0" }, \
{ &unsupport, 54, "R_ARM_THM_PC12" }, \
diff --git a/lib/Target/ARM/ARMRelocator.cpp b/lib/Target/ARM/ARMRelocator.cpp
index 02e4f14..415c36e 100644
--- a/lib/Target/ARM/ARMRelocator.cpp
+++ b/lib/Target/ARM/ARMRelocator.cpp
@@ -15,12 +15,304 @@
#include <llvm/Support/Host.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/LD/LDSymbol.h>
+#include <mcld/LD/ELFFileFormat.h>
#include <mcld/Object/ObjectBuilder.h>
#include "ARMRelocator.h"
#include "ARMRelocationFunctions.h"
using namespace mcld;
+//=========================================//
+// Relocation helper function //
+//=========================================//
+static Relocator::DWord getThumbBit(const Relocation& pReloc)
+{
+ // Set thumb bit if
+ // - symbol has type of STT_FUNC, is defined and with bit 0 of its value set
+ Relocator::DWord thumbBit =
+ ((!pReloc.symInfo()->isUndef() || pReloc.symInfo()->isDyn()) &&
+ (pReloc.symInfo()->type() == ResolveInfo::Function) &&
+ ((pReloc.symValue() & 0x1) != 0))?
+ 1:0;
+ return thumbBit;
+}
+
+// Using uint64_t to make sure those complicate operations won't cause
+// undefined behavior.
+static
+uint64_t helper_sign_extend(uint64_t pVal, uint64_t pOri_width)
+{
+ assert(pOri_width <= 64);
+ if (pOri_width == 64)
+ return pVal;
+
+ uint64_t mask = (~((uint64_t)0)) >> (64 - pOri_width);
+ pVal &= mask;
+ // Reverse sign bit, then subtract sign bit.
+ uint64_t sign_bit = 1 << (pOri_width - 1);
+ return (pVal ^ sign_bit) - sign_bit;
+}
+
+static
+uint64_t helper_bit_select(uint64_t pA, uint64_t pB, uint64_t pMask)
+{
+ return (pA & ~pMask) | (pB & pMask) ;
+}
+
+// Check if symbol can use relocation R_ARM_RELATIVE
+static bool
+helper_use_relative_reloc(const ResolveInfo& pSym,
+ const ARMRelocator& pFactory)
+{
+ // if symbol is dynamic or undefine or preemptible
+ if (pSym.isDyn() ||
+ pSym.isUndef() ||
+ pFactory.getTarget().isSymbolPreemptible(pSym))
+ return false;
+ return true;
+}
+
+// Strip LSB (THUMB bit) if "S" is a THUMB target.
+static inline void helper_clear_thumb_bit(ARMRelocator::DWord& pValue)
+{
+ pValue &= (~0x1);
+}
+
+static
+ARMRelocator::Address helper_get_GOT_address(ResolveInfo& pSym,
+ ARMRelocator& pParent)
+{
+ ARMGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(pSym);
+ assert(NULL != got_entry);
+ return pParent.getTarget().getGOT().addr() + got_entry->getOffset();
+}
+
+static
+ARMGOTEntry& helper_GOT_init(Relocation& pReloc,
+ bool pHasRel,
+ ARMRelocator& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMGNULDBackend& ld_backend = pParent.getTarget();
+ assert(NULL == pParent.getSymGOTMap().lookUp(*rsym));
+
+ ARMGOTEntry* got_entry = ld_backend.getGOT().createGOT();
+ pParent.getSymGOTMap().record(*rsym, *got_entry);
+ // If we first get this GOT entry, we should initialize it.
+ if (!pHasRel) {
+ // No corresponding dynamic relocation, initialize to the symbol value.
+ got_entry->setValue(ARMRelocator::SymVal);
+ }
+ else {
+ // Initialize corresponding dynamic relocation.
+ Relocation& rel_entry = *ld_backend.getRelDyn().create();
+ if (rsym->isLocal() || helper_use_relative_reloc(*rsym, pParent)) {
+ // Initialize got entry to target symbol address
+ got_entry->setValue(ARMRelocator::SymVal);
+ rel_entry.setType(llvm::ELF::R_ARM_RELATIVE);
+ rel_entry.setSymInfo(NULL);
+ }
+ else {
+ // Initialize got entry to 0 for corresponding dynamic relocation.
+ got_entry->setValue(0);
+ rel_entry.setType(llvm::ELF::R_ARM_GLOB_DAT);
+ rel_entry.setSymInfo(rsym);
+ }
+ rel_entry.targetRef().assign(*got_entry);
+ }
+ return *got_entry;
+}
+
+static
+ARMRelocator::Address helper_GOT_ORG(ARMRelocator& pParent)
+{
+ return pParent.getTarget().getGOT().addr();
+}
+
+static
+ARMRelocator::Address helper_get_PLT_address(ResolveInfo& pSym,
+ ARMRelocator& pParent)
+{
+ ARMPLT1* plt_entry = pParent.getSymPLTMap().lookUp(pSym);
+ assert(NULL != plt_entry);
+ return pParent.getTarget().getPLT().addr() + plt_entry->getOffset();
+}
+
+static
+ARMPLT1& helper_PLT_init(Relocation& pReloc, ARMRelocator& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMGNULDBackend& ld_backend = pParent.getTarget();
+ assert(NULL == pParent.getSymPLTMap().lookUp(*rsym));
+
+ // initialize the plt and the corresponding gotplt and dyn relocation
+ ARMPLT1* plt_entry = ld_backend.getPLT().create();
+ pParent.getSymPLTMap().record(*rsym, *plt_entry);
+
+ assert(NULL == pParent.getSymGOTPLTMap().lookUp(*rsym) &&
+ "PLT entry not exist, but DynRel entry exist!");
+ ARMGOTEntry* gotplt_entry = ld_backend.getGOT().createGOTPLT();
+ pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
+
+ Relocation& rel_entry = *ld_backend.getRelPLT().create();
+ rel_entry.setType(llvm::ELF::R_ARM_JUMP_SLOT);
+ rel_entry.targetRef().assign(*gotplt_entry);
+ rel_entry.setSymInfo(rsym);
+
+ return *plt_entry;
+}
+
+// Get an relocation entry in .rel.dyn and set its type to pType,
+// its FragmentRef to pReloc->targetFrag() and its ResolveInfo to
+// pReloc->symInfo()
+static
+void helper_DynRel_init(Relocation& pReloc,
+ ARMRelocator::Type pType,
+ ARMRelocator& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMGNULDBackend& ld_backend = pParent.getTarget();
+
+ Relocation& rel_entry = *ld_backend.getRelDyn().create();
+ rel_entry.setType(pType);
+ rel_entry.targetRef() = pReloc.targetRef();
+
+ if (pType == llvm::ELF::R_ARM_RELATIVE)
+ rel_entry.setSymInfo(NULL);
+ else
+ rel_entry.setSymInfo(rsym);
+}
+
+static ARMRelocator::DWord
+helper_extract_movw_movt_addend(ARMRelocator::DWord pTarget)
+{
+ // imm16: [19-16][11-0]
+ return helper_sign_extend((((pTarget >> 4)) & 0xf000U) | (pTarget & 0xfffU),
+ 16);
+}
+
+static ARMRelocator::DWord
+helper_insert_val_movw_movt_inst(ARMRelocator::DWord pTarget,
+ ARMRelocator::DWord pImm)
+{
+ // imm16: [19-16][11-0]
+ pTarget &= 0xfff0f000U;
+ pTarget |= pImm & 0x0fffU;
+ pTarget |= (pImm & 0xf000U) << 4;
+ return pTarget;
+}
+
+static ARMRelocator::DWord
+helper_extract_thumb_movw_movt_addend(ARMRelocator::DWord pValue)
+{
+ // imm16: [19-16][26][14-12][7-0]
+ return helper_sign_extend((((pValue >> 4) & 0xf000U) |
+ ((pValue >> 15) & 0x0800U) |
+ ((pValue >> 4) & 0x0700U) |
+ (pValue& 0x00ffU)),
+ 16);
+}
+
+static ARMRelocator::DWord
+helper_insert_val_thumb_movw_movt_inst(ARMRelocator::DWord pValue,
+ ARMRelocator::DWord pImm)
+{
+ // imm16: [19-16][26][14-12][7-0]
+ pValue &= 0xfbf08f00U;
+ pValue |= (pImm & 0xf000U) << 4;
+ pValue |= (pImm & 0x0800U) << 15;
+ pValue |= (pImm & 0x0700U) << 4;
+ pValue |= (pImm & 0x00ffU);
+ return pValue;
+}
+
+static ARMRelocator::DWord
+helper_thumb32_branch_offset(ARMRelocator::DWord pUpper16,
+ ARMRelocator::DWord pLower16)
+{
+ ARMRelocator::DWord s = (pUpper16 & (1U << 10)) >> 10, // 26 bit
+ u = pUpper16 & 0x3ffU, // 25-16
+ l = pLower16 & 0x7ffU, // 10-0
+ j1 = (pLower16 & (1U << 13)) >> 13, // 13
+ j2 = (pLower16 & (1U << 11)) >> 11; // 11
+ ARMRelocator::DWord i1 = j1 ^ s? 0: 1,
+ i2 = j2 ^ s? 0: 1;
+
+ // [31-25][24][23][22][21-12][11-1][0]
+ // 0 s i1 i2 u l 0
+ return helper_sign_extend((s << 24) | (i1 << 23) | (i2 << 22) |
+ (u << 12) | (l << 1),
+ 25);
+}
+
+static ARMRelocator::DWord
+helper_thumb32_branch_upper(ARMRelocator::DWord pUpper16,
+ ARMRelocator::DWord pOffset)
+{
+ uint32_t sign = ((pOffset & 0x80000000U) >> 31);
+ return (pUpper16 & ~0x7ffU) | ((pOffset >> 12) & 0x3ffU) | (sign << 10);
+}
+
+static ARMRelocator::DWord
+helper_thumb32_branch_lower(ARMRelocator::DWord pLower16,
+ ARMRelocator::DWord pOffset)
+{
+ uint32_t sign = ((pOffset & 0x80000000U) >> 31);
+ return ((pLower16 & ~0x2fffU) |
+ ((((pOffset >> 23) & 1) ^ !sign) << 13) |
+ ((((pOffset >> 22) & 1) ^ !sign) << 11) |
+ ((pOffset >> 1) & 0x7ffU));
+}
+
+static ARMRelocator::DWord
+helper_thumb32_cond_branch_offset(ARMRelocator::DWord pUpper16,
+ ARMRelocator::DWord pLower16)
+{
+ uint32_t s = (pUpper16 & 0x0400U) >> 10;
+ uint32_t j1 = (pLower16 & 0x2000U) >> 13;
+ uint32_t j2 = (pLower16 & 0x0800U) >> 11;
+ uint32_t lower = (pLower16 & 0x07ffU);
+ uint32_t upper = (s << 8) | (j2 << 7) | (j1 << 6) | (pUpper16 & 0x003fU);
+ return helper_sign_extend((upper << 12) | (lower << 1), 21);
+}
+
+static ARMRelocator::DWord
+helper_thumb32_cond_branch_upper(ARMRelocator::DWord pUpper16,
+ ARMRelocator::DWord pOffset)
+{
+ uint32_t sign = ((pOffset & 0x80000000U) >> 31);
+ return (pUpper16 & 0xfbc0U) | (sign << 10) | ((pOffset & 0x0003f000U) >> 12);
+}
+
+static ARMRelocator::DWord
+helper_thumb32_cond_branch_lower(ARMRelocator::DWord pLower16,
+ ARMRelocator::DWord pOffset)
+{
+ uint32_t j2 = (pOffset & 0x00080000U) >> 19;
+ uint32_t j1 = (pOffset & 0x00040000U) >> 18;
+ uint32_t lo = (pOffset & 0x00000ffeU) >> 1;
+ return (pLower16 & 0xd000U) | (j1 << 13) | (j2 << 11) | lo;
+}
+
+// Return true if overflow
+static bool
+helper_check_signed_overflow(ARMRelocator::DWord pValue,
+ unsigned bits)
+{
+ int32_t signed_val = static_cast<int32_t>(pValue);
+ int32_t max = (1 << (bits - 1)) - 1;
+ int32_t min = -(1 << (bits - 1));
+ if (signed_val > max || signed_val < min) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
//===--------------------------------------------------------------------===//
// Relocation Functions and Tables
//===--------------------------------------------------------------------===//
@@ -79,7 +371,7 @@
void ARMRelocator::addCopyReloc(ResolveInfo& pSym)
{
- Relocation& rel_entry = *getTarget().getRelDyn().consumeEntry();
+ Relocation& rel_entry = *getTarget().getRelDyn().create();
rel_entry.setType(llvm::ELF::R_ARM_COPY);
assert(pSym.outSymbol()->hasFragRef());
rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef());
@@ -188,7 +480,7 @@
// a dynamic relocations with RELATIVE type to this location is needed.
// Reserve an entry in .rel.dyn
if (config().isCodeIndep()) {
- getTarget().getRelDyn().reserveEntry();
+ helper_DynRel_init(pReloc, llvm::ELF::R_ARM_RELATIVE, *this);
// set Rel bit
rsym->setReserved(rsym->reserved() | ReserveRel);
getTarget().checkAndSetHasTextRel(*pSection.getLink());
@@ -227,21 +519,17 @@
case llvm::ELF::R_ARM_GOT_PREL: {
// A GOT entry is needed for these relocation type.
// return if we already create GOT for this symbol
- if (rsym->reserved() & (ReserveGOT | GOTRel))
+ if (rsym->reserved() & ReserveGOT)
return;
- getTarget().getGOT().reserveGOT();
+
// If building PIC object, a dynamic relocation with
// type RELATIVE is needed to relocate this GOT entry.
- // Reserve an entry in .rel.dyn
- if (config().isCodeIndep()) {
- // create .rel.dyn section if not exist
- getTarget().getRelDyn().reserveEntry();
- // set GOTRel bit
- rsym->setReserved(rsym->reserved() | 0x4u);
- return;
- }
+ if (config().isCodeIndep())
+ helper_GOT_init(pReloc, true, *this);
+ else
+ helper_GOT_init(pReloc, false, *this);
// set GOT bit
- rsym->setReserved(rsym->reserved() | 0x2u);
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
}
@@ -301,18 +589,15 @@
if (!(rsym->reserved() & ReservePLT)){
// Symbol needs PLT entry, we need to reserve a PLT entry
// and the corresponding GOT and dynamic relocation entry
- // in .got and .rel.plt. (GOT entry will be reserved simultaneously
- // when calling ARMPLT->reserveEntry())
- getTarget().getPLT().reserveEntry();
- getTarget().getRelPLT().reserveEntry();
+ // in .got and .rel.plt.
+ helper_PLT_init(pReloc, *this);
// set PLT bit
rsym->setReserved(rsym->reserved() | ReservePLT);
}
}
- if (getTarget().symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), true)) {
- // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
- getTarget().getRelDyn().reserveEntry();
+ if (getTarget().symbolNeedsDynRel(*rsym,
+ (rsym->reserved() & ReservePLT), true)) {
if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
addCopyReloc(*cpy_sym.resolveInfo());
@@ -320,6 +605,10 @@
else {
checkValidReloc(pReloc);
// set Rel bit
+ if (helper_use_relative_reloc(*rsym, *this))
+ helper_DynRel_init(pReloc, llvm::ELF::R_ARM_RELATIVE, *this);
+ else
+ helper_DynRel_init(pReloc, pReloc.type(), *this);
rsym->setReserved(rsym->reserved() | ReserveRel);
getTarget().checkAndSetHasTextRel(*pSection.getLink());
}
@@ -385,9 +674,9 @@
case llvm::ELF::R_ARM_MOVT_BREL:
case llvm::ELF::R_ARM_MOVW_BREL: {
// Relative addressing relocation, may needs dynamic relocation
- if (getTarget().symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), false)) {
+ if (getTarget().symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT),
+ false)) {
// symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
- getTarget().getRelDyn().reserveEntry();
if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
addCopyReloc(*cpy_sym.resolveInfo());
@@ -395,6 +684,7 @@
else {
checkValidReloc(pReloc);
// set Rel bit
+ //helper_DynRel_init(pReloc, pReloc.type(), *this);
rsym->setReserved(rsym->reserved() | ReserveRel);
getTarget().checkAndSetHasTextRel(*pSection.getLink());
}
@@ -434,10 +724,8 @@
// Symbol needs PLT entry, we need to reserve a PLT entry
// and the corresponding GOT and dynamic relocation entry
- // in .got and .rel.plt. (GOT entry will be reserved simultaneously
- // when calling ARMPLT->reserveEntry())
- getTarget().getPLT().reserveEntry();
- getTarget().getRelPLT().reserveEntry();
+ // in .got and .rel.plt.
+ helper_PLT_init(pReloc, *this);
// set PLT bit
rsym->setReserved(rsym->reserved() | ReservePLT);
return;
@@ -453,17 +741,14 @@
case llvm::ELF::R_ARM_GOT_PREL: {
// Symbol needs GOT entry, reserve entry in .got
// return if we already create GOT for this symbol
- if (rsym->reserved() & (ReserveGOT | GOTRel))
+ if (rsym->reserved() & ReserveGOT)
return;
- getTarget().getGOT().reserveGOT();
// if the symbol cannot be fully resolved at link time, then we need a
// dynamic relocation
- if (!getTarget().symbolFinalValueIsKnown(*rsym)) {
- getTarget().getRelDyn().reserveEntry();
- // set GOTRel bit
- rsym->setReserved(rsym->reserved() | GOTRel);
- return;
- }
+ if (!getTarget().symbolFinalValueIsKnown(*rsym))
+ helper_GOT_init(pReloc, true, *this);
+ else
+ helper_GOT_init(pReloc, false, *this);
// set GOT bit
rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
@@ -487,14 +772,14 @@
void ARMRelocator::scanRelocation(Relocation& pReloc,
IRBuilder& pBuilder,
Module& pModule,
- LDSection& pSection)
+ LDSection& pSection,
+ Input& pInput)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
assert(NULL != rsym &&
"ResolveInfo of relocation not set while scanRelocation");
- pReloc.updateAddend();
assert(NULL != pSection.getLink());
if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC))
return;
@@ -514,293 +799,9 @@
// check if we shoule issue undefined reference for the relocation target
// symbol
if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
- fatal(diag::undefined_reference) << rsym->name();
+ issueUndefRef(pReloc, pSection, pInput);
}
-//===--------------------------------------------------------------------===//
-// non-member functions
-//===--------------------------------------------------------------------===//
-static Relocator::DWord getThumbBit(const Relocation& pReloc)
-{
- // Set thumb bit if
- // - symbol has type of STT_FUNC, is defined and with bit 0 of its value set
- Relocator::DWord thumbBit =
- ((!pReloc.symInfo()->isUndef() || pReloc.symInfo()->isDyn()) &&
- (pReloc.symInfo()->type() == ResolveInfo::Function) &&
- ((pReloc.symValue() & 0x1) != 0))?
- 1:0;
- return thumbBit;
-}
-
-//=========================================//
-// Relocation helper function //
-//=========================================//
-
-// Using uint64_t to make sure those complicate operations won't cause
-// undefined behavior.
-static
-uint64_t helper_sign_extend(uint64_t pVal, uint64_t pOri_width)
-{
- assert(pOri_width <= 64);
- if (pOri_width == 64)
- return pVal;
- uint64_t mask = (~((uint64_t)0)) >> (64 - pOri_width);
- pVal &= mask;
- // Reverse sign bit, then subtract sign bit.
- uint64_t sign_bit = 1 << (pOri_width - 1);
- return (pVal ^ sign_bit) - sign_bit;
-}
-
-static
-uint64_t helper_bit_select(uint64_t pA, uint64_t pB, uint64_t pMask)
-{
- return (pA & ~pMask) | (pB & pMask) ;
-}
-
-// Check if symbol can use relocation R_ARM_RELATIVE
-static bool
-helper_use_relative_reloc(const ResolveInfo& pSym,
- const ARMRelocator& pFactory)
-{
- // if symbol is dynamic or undefine or preemptible
- if (pSym.isDyn() ||
- pSym.isUndef() ||
- pFactory.getTarget().isSymbolPreemptible(pSym))
- return false;
- return true;
-}
-
-// Strip LSB (THUMB bit) if "S" is a THUMB target.
-static inline void helper_clear_thumb_bit(ARMRelocator::DWord& pValue)
-{
- pValue &= (~0x1);
-}
-
-static
-ARMGOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
- ARMRelocator& pParent)
-{
- // rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
- ARMGNULDBackend& ld_backend = pParent.getTarget();
-
- ARMGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
- if (NULL == got_entry) {
- got_entry = ld_backend.getGOT().consumeGOT();
- pParent.getSymGOTMap().record(*rsym, *got_entry);
- // If we first get this GOT entry, we should initialize it.
- if (rsym->reserved() & ARMRelocator::ReserveGOT) {
- // No corresponding dynamic relocation, initialize to the symbol value.
- got_entry->setValue(pReloc.symValue());
- }
- else if (rsym->reserved() & ARMRelocator::GOTRel) {
-
- // Initialize corresponding dynamic relocation.
- Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
- if ( rsym->isLocal() ||
- helper_use_relative_reloc(*rsym, pParent)) {
- // Initialize got entry to target symbol address
- got_entry->setValue(pReloc.symValue());
- rel_entry.setType(llvm::ELF::R_ARM_RELATIVE);
- rel_entry.setSymInfo(0);
- }
- else {
- // Initialize got entry to 0 for corresponding dynamic relocation.
- got_entry->setValue(0);
- rel_entry.setType(llvm::ELF::R_ARM_GLOB_DAT);
- rel_entry.setSymInfo(rsym);
- }
- rel_entry.targetRef().assign(*got_entry);
- }
- else {
- fatal(diag::reserve_entry_number_mismatch_got);
- }
- }
- return *got_entry;
-}
-
-static
-ARMRelocator::Address helper_GOT_ORG(ARMRelocator& pParent)
-{
- return pParent.getTarget().getGOT().addr();
-}
-
-
-static
-ARMRelocator::Address helper_GOT(Relocation& pReloc, ARMRelocator& pParent)
-{
- ARMGOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent);
- return helper_GOT_ORG(pParent) + got_entry.getOffset();
-}
-
-
-static
-ARMPLT1& helper_get_PLT_and_init(Relocation& pReloc, ARMRelocator& pParent)
-{
- // rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
- ARMGNULDBackend& ld_backend = pParent.getTarget();
-
- ARMPLT1* plt_entry = pParent.getSymPLTMap().lookUp(*rsym);
- if (NULL != plt_entry)
- return *plt_entry;
-
- plt_entry = ld_backend.getPLT().consume();
- pParent.getSymPLTMap().record(*rsym, *plt_entry);
-
- // If we first get this PLT entry, we should initialize it.
- if (rsym->reserved() & ARMRelocator::ReservePLT) {
- ARMGOTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym);
- assert(NULL == gotplt_entry && "PLT entry not exist, but DynRel entry exist!");
- gotplt_entry = ld_backend.getGOT().consumeGOTPLT();
- pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
-
- // Initialize corresponding dynamic relocation.
- Relocation& rel_entry = *ld_backend.getRelPLT().consumeEntry();
- rel_entry.setType(llvm::ELF::R_ARM_JUMP_SLOT);
- rel_entry.targetRef().assign(*gotplt_entry);
- rel_entry.setSymInfo(rsym);
- }
- else {
- fatal(diag::reserve_entry_number_mismatch_plt);
- }
-
- return *plt_entry;
-}
-
-static
-ARMRelocator::Address helper_PLT_ORG(ARMRelocator& pParent)
-{
- return pParent.getTarget().getPLT().addr();
-}
-
-
-static
-ARMRelocator::Address helper_PLT(Relocation& pReloc, ARMRelocator& pParent)
-{
- ARMPLT1& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
- return helper_PLT_ORG(pParent) + plt_entry.getOffset();
-}
-
-// Get an relocation entry in .rel.dyn and set its type to pType,
-// its FragmentRef to pReloc->targetFrag() and its ResolveInfo to
-// pReloc->symInfo()
-static
-void helper_DynRel(Relocation& pReloc,
- ARMRelocator::Type pType,
- ARMRelocator& pParent)
-{
- // rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
- ARMGNULDBackend& ld_backend = pParent.getTarget();
-
- Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
- rel_entry.setType(pType);
- rel_entry.targetRef() = pReloc.targetRef();
-
- if (pType == llvm::ELF::R_ARM_RELATIVE)
- rel_entry.setSymInfo(0);
- else
- rel_entry.setSymInfo(rsym);
-}
-
-static ARMRelocator::DWord
-helper_extract_movw_movt_addend(ARMRelocator::DWord pTarget)
-{
- // imm16: [19-16][11-0]
- return helper_sign_extend((((pTarget >> 4)) & 0xf000U) | (pTarget & 0xfffU),
- 16);
-}
-
-static ARMRelocator::DWord
-helper_insert_val_movw_movt_inst(ARMRelocator::DWord pTarget,
- ARMRelocator::DWord pImm)
-{
- // imm16: [19-16][11-0]
- pTarget &= 0xfff0f000U;
- pTarget |= pImm & 0x0fffU;
- pTarget |= (pImm & 0xf000U) << 4;
- return pTarget;
-}
-
-static ARMRelocator::DWord
-helper_extract_thumb_movw_movt_addend(ARMRelocator::DWord pValue)
-{
- // imm16: [19-16][26][14-12][7-0]
- return helper_sign_extend((((pValue >> 4) & 0xf000U) |
- ((pValue >> 15) & 0x0800U) |
- ((pValue >> 4) & 0x0700U) |
- (pValue& 0x00ffU)),
- 16);
-}
-
-static ARMRelocator::DWord
-helper_insert_val_thumb_movw_movt_inst(ARMRelocator::DWord pValue,
- ARMRelocator::DWord pImm)
-{
- // imm16: [19-16][26][14-12][7-0]
- pValue &= 0xfbf08f00U;
- pValue |= (pImm & 0xf000U) << 4;
- pValue |= (pImm & 0x0800U) << 15;
- pValue |= (pImm & 0x0700U) << 4;
- pValue |= (pImm & 0x00ffU);
- return pValue;
-}
-
-static ARMRelocator::DWord
-helper_thumb32_branch_offset(ARMRelocator::DWord pUpper16,
- ARMRelocator::DWord pLower16)
-{
- ARMRelocator::DWord s = (pUpper16 & (1U << 10)) >> 10, // 26 bit
- u = pUpper16 & 0x3ffU, // 25-16
- l = pLower16 & 0x7ffU, // 10-0
- j1 = (pLower16 & (1U << 13)) >> 13, // 13
- j2 = (pLower16 & (1U << 11)) >> 11; // 11
- ARMRelocator::DWord i1 = j1 ^ s? 0: 1,
- i2 = j2 ^ s? 0: 1;
-
- // [31-25][24][23][22][21-12][11-1][0]
- // 0 s i1 i2 u l 0
- return helper_sign_extend((s << 24) | (i1 << 23) | (i2 << 22) |
- (u << 12) | (l << 1),
- 25);
-}
-
-static ARMRelocator::DWord
-helper_thumb32_branch_upper(ARMRelocator::DWord pUpper16,
- ARMRelocator::DWord pOffset)
-{
- uint32_t sign = ((pOffset & 0x80000000U) >> 31);
- return (pUpper16 & ~0x7ffU) | ((pOffset >> 12) & 0x3ffU) | (sign << 10);
-}
-
-static ARMRelocator::DWord
-helper_thumb32_branch_lower(ARMRelocator::DWord pLower16,
- ARMRelocator::DWord pOffset)
-{
- uint32_t sign = ((pOffset & 0x80000000U) >> 31);
- return ((pLower16 & ~0x2fffU) |
- ((((pOffset >> 23) & 1) ^ !sign) << 13) |
- ((((pOffset >> 22) & 1) ^ !sign) << 11) |
- ((pOffset >> 1) & 0x7ffU));
-}
-
-// Return true if overflow
-static bool
-helper_check_signed_overflow(ARMRelocator::DWord pValue,
- unsigned bits)
-{
- int32_t signed_val = static_cast<int32_t>(pValue);
- int32_t max = (1 << (bits - 1)) - 1;
- int32_t min = -(1 << (bits - 1));
- if (signed_val > max || signed_val < min) {
- return true;
- } else {
- return false;
- }
-}
-
-
//=========================================//
// Each relocation function implementation //
//=========================================//
@@ -821,43 +822,28 @@
if (T != 0x0)
helper_clear_thumb_bit(S);
- LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
-
// If the flag of target section is not ALLOC, we will not scan this relocation
// but perform static relocation. (e.g., applying .debug section)
- if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
+ if (0x0 == (llvm::ELF::SHF_ALLOC &
+ pReloc.targetRef().frag()->getParent()->getSection().flag())) {
pReloc.target() = (S + A) | T;
return ARMRelocator::OK;
}
- // A local symbol may need REL Type dynamic relocation
- if (rsym->isLocal() && (rsym->reserved() & ARMRelocator::ReserveRel)) {
- helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent);
- pReloc.target() = (S + A) | T ;
- return ARMRelocator::OK;
- }
-
// An external symbol may need PLT and dynamic relocation
if (!rsym->isLocal()) {
if (rsym->reserved() & ARMRelocator::ReservePLT) {
- S = helper_PLT(pReloc, pParent);
+ S = helper_get_PLT_address(*rsym, pParent);
T = 0 ; // PLT is not thumb
}
// If we generate a dynamic relocation (except R_ARM_RELATIVE)
// for a place, we should not perform static relocation on it
// in order to keep the addend store in the place correct.
- if (rsym->reserved() & ARMRelocator::ReserveRel) {
- if (helper_use_relative_reloc(*rsym, pParent)) {
- helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent);
- }
- else {
- helper_DynRel(pReloc, pReloc.type(), pParent);
- return ARMRelocator::OK;
- }
- }
+ if ((rsym->reserved() & ARMRelocator::ReserveRel) &&
+ (!helper_use_relative_reloc(*rsym, pParent)))
+ return ARMRelocator::OK;
}
-
// perform static relocation
pReloc.target() = (S + A) | T;
return ARMRelocator::OK;
@@ -870,17 +856,18 @@
ARMRelocator::Address S = pReloc.symValue();
ARMRelocator::DWord T = getThumbBit(pReloc);
ARMRelocator::DWord A = pReloc.target() + pReloc.addend();
- if (T != 0x0)
- helper_clear_thumb_bit(S);
- // An external symbol may need PLT (this reloc is from stub)
+ // An external symbol may need PLT (this reloc is from a stub/veneer)
if (!pReloc.symInfo()->isLocal()) {
if (pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT) {
- S = helper_PLT(pReloc, pParent);
+ S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
T = 0; // PLT is not thumb.
}
}
+ if (T != 0x0)
+ helper_clear_thumb_bit(S);
+
// perform relocation
pReloc.target() = ((S + A) | T) - pReloc.place();
@@ -913,31 +900,41 @@
// R_ARM_GOT_BREL: GOT(S) + A - GOT_ORG
ARMRelocator::Result got_brel(Relocation& pReloc, ARMRelocator& pParent)
{
- if (!(pReloc.symInfo()->reserved() &
- (ARMRelocator::ReserveGOT | ARMRelocator::GOTRel))) {
+ if (!(pReloc.symInfo()->reserved() & ARMRelocator::ReserveGOT))
return ARMRelocator::BadReloc;
- }
- ARMRelocator::Address GOT_S = helper_GOT(pReloc, pParent);
+
+ ARMRelocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(),
+ pParent);
ARMRelocator::DWord A = pReloc.target() + pReloc.addend();
ARMRelocator::Address GOT_ORG = helper_GOT_ORG(pParent);
// Apply relocation.
pReloc.target() = GOT_S + A - GOT_ORG;
+
+ // setup got entry value if needed
+ ARMGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
+ if (NULL != got_entry && ARMRelocator::SymVal == got_entry->getValue())
+ got_entry->setValue(pReloc.symValue());
return ARMRelocator::OK;
}
// R_ARM_GOT_PREL: GOT(S) + A - P
ARMRelocator::Result got_prel(Relocation& pReloc, ARMRelocator& pParent)
{
- if (!(pReloc.symInfo()->reserved() &
- (ARMRelocator::ReserveGOT | ARMRelocator::GOTRel))) {
+ if (!(pReloc.symInfo()->reserved() & ARMRelocator::ReserveGOT)) {
return ARMRelocator::BadReloc;
}
- ARMRelocator::Address GOT_S = helper_GOT(pReloc, pParent);
+ ARMRelocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(),
+ pParent);
ARMRelocator::DWord A = pReloc.target() + pReloc.addend();
ARMRelocator::Address P = pReloc.place();
// Apply relocation.
pReloc.target() = GOT_S + A - P;
+
+ // setup got entry value if needed
+ ARMGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
+ if (NULL != got_entry && ARMRelocator::SymVal == got_entry->getValue())
+ got_entry->setValue(pReloc.symValue());
return ARMRelocator::OK;
}
@@ -951,7 +948,7 @@
// S depends on PLT exists or not
ARMRelocator::Address S = pReloc.symValue();
if (pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT)
- S = helper_PLT(pReloc, pParent);
+ S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
ARMRelocator::DWord X = S + A - P;
if (helper_check_signed_overflow(X, 11))
@@ -961,6 +958,48 @@
return ARMRelocator::OK;
}
+// R_ARM_THM_JUMP19: ((S + A) | T) - P
+ARMRelocator::Result thm_jump19(Relocation& pReloc, ARMRelocator& pParent)
+{
+ // get lower and upper 16 bit instructions from relocation targetData
+ uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
+ uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
+
+ ARMRelocator::DWord T = getThumbBit(pReloc);
+ ARMRelocator::DWord A = helper_thumb32_cond_branch_offset(upper_inst,
+ lower_inst);
+ ARMRelocator::Address P = pReloc.place();
+ ARMRelocator::Address S;
+ // if symbol has plt
+ if (pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT) {
+ S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
+ T = 0; // PLT is not thumb.
+ }
+ else {
+ S = pReloc.symValue();
+ if (T != 0x0)
+ helper_clear_thumb_bit(S);
+ }
+
+ if (0x0 == T) {
+ // FIXME: conditional branch to PLT in THUMB-2 not supported yet
+ error(diag::unsupport_cond_branch_reloc) << (int)pReloc.type();
+ return ARMRelocator::BadReloc;
+ }
+
+ ARMRelocator::DWord X = ((S + A) | T) - P;
+ if (helper_check_signed_overflow(X, 21))
+ return ARMRelocator::Overflow;
+
+ upper_inst = helper_thumb32_cond_branch_upper(upper_inst, X);
+ lower_inst = helper_thumb32_cond_branch_lower(lower_inst, X);
+
+ *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst;
+ *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst;
+
+ return ARMRelocator::OK;
+}
+
// R_ARM_PC24: ((S + A) | T) - P
// R_ARM_PLT32: ((S + A) | T) - P
// R_ARM_JUMP24: ((S + A) | T) - P
@@ -990,7 +1029,7 @@
// S depends on PLT exists or not
if (pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT) {
- S = helper_PLT(pReloc, pParent);
+ S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
T = 0; // PLT is not thumb.
}
@@ -1039,14 +1078,13 @@
uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
ARMRelocator::DWord T = getThumbBit(pReloc);
- ARMRelocator::DWord A = helper_thumb32_branch_offset(upper_inst,
- lower_inst);
+ ARMRelocator::DWord A = helper_thumb32_branch_offset(upper_inst, lower_inst);
ARMRelocator::Address P = pReloc.place();
ARMRelocator::Address S;
// if symbol has plt
if (pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT) {
- S = helper_PLT(pReloc, pParent);
+ S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
T = 0; // PLT is not thumb.
}
else {
@@ -1111,7 +1149,7 @@
if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
// use plt
if (rsym->reserved() & ARMRelocator::ReservePLT) {
- S = helper_PLT(pReloc, pParent);
+ S = helper_get_PLT_address(*rsym, pParent);
T = 0 ; // PLT is not thumb
}
}
@@ -1158,7 +1196,7 @@
if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
// use plt
if (rsym->reserved() & ARMRelocator::ReservePLT) {
- S = helper_PLT(pReloc, pParent);
+ S = helper_get_PLT_address(*rsym, pParent);
}
}
@@ -1205,7 +1243,7 @@
if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
// use plt
if (rsym->reserved() & ARMRelocator::ReservePLT) {
- S = helper_PLT(pReloc, pParent);
+ S = helper_get_PLT_address(*rsym, pParent);
T = 0; // PLT is not thumb
}
}
@@ -1287,7 +1325,7 @@
if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
// use plt
if (rsym->reserved() & ARMRelocator::ReservePLT) {
- S = helper_PLT(pReloc, pParent);
+ S = helper_get_PLT_address(*rsym, pParent);
}
}
@@ -1340,7 +1378,7 @@
// if symbol has plt
if ( pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT) {
- S = helper_PLT(pReloc, pParent);
+ S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
T = 0; // PLT is not thumb.
}
diff --git a/lib/Target/ARM/ARMRelocator.h b/lib/Target/ARM/ARMRelocator.h
index bf93380..f1c4643 100644
--- a/lib/Target/ARM/ARMRelocator.h
+++ b/lib/Target/ARM/ARMRelocator.h
@@ -14,7 +14,7 @@
#include <mcld/LD/Relocator.h>
#include <mcld/Target/GOT.h>
-#include <mcld/Target/SymbolEntryMap.h>
+#include <mcld/Target/KeyEntryMap.h>
#include "ARMLDBackend.h"
namespace mcld {
@@ -26,50 +26,42 @@
class ARMRelocator : public Relocator
{
public:
- typedef SymbolEntryMap<ARMGOTEntry> SymGOTMap;
- typedef SymbolEntryMap<ARMPLT1> SymPLTMap;
+ typedef KeyEntryMap<ResolveInfo, ARMGOTEntry> SymGOTMap;
+ typedef KeyEntryMap<ResolveInfo, ARMPLT1> SymPLTMap;
/** \enum ReservedEntryType
* \brief The reserved entry type of reserved space in ResolveInfo.
*
* This is used for sacnRelocation to record what kinds of entries are
- * reserved for this resolved symbol
+ * reserved for this resolved symbol In ARM, there are three kinds of
+ * entries, GOT, PLT, and dynamic reloction.
*
- * In ARM, there are three kinds of entries, GOT, PLT, and dynamic reloction.
- * GOT may needs a corresponding relocation to relocate itself, so we
- * separate GOT to two situations: GOT and GOTRel. Besides, for the same
- * symbol, there might be two kinds of entries reserved for different location.
- * For example, reference to the same symbol, one may use GOT and the other may
- * use dynamic relocation.
- *
- * bit: 3 2 1 0
- * | PLT | GOTRel | GOT | Rel |
+ * bit: 3 2 1 0
+ * | | PLT | GOT | Rel |
*
* value Name - Description
*
* 0000 None - no reserved entry
* 0001 ReserveRel - reserve an dynamic relocation entry
* 0010 ReserveGOT - reserve an GOT entry
- * 0011 GOTandRel - For different relocation, we've reserved GOT and
- * Rel for different location.
- * 0100 GOTRel - reserve an GOT entry and the corresponding Dyncamic
- * relocation entry which relocate this GOT entry
- * 0101 GOTRelandRel - For different relocation, we've reserved GOTRel
- * and relocation entry for different location.
- * 1000 ReservePLT - reserve an PLT entry and the corresponding GOT,
- * Dynamic relocation entries
- * 1001 PLTandRel - For different relocation, we've reserved PLT and
- * Rel for different location.
+ * 0100 ReservePLT - reserve an PLT entry and the corresponding GOT,
+ *
*/
enum ReservedEntryType {
None = 0,
ReserveRel = 1,
ReserveGOT = 2,
- GOTandRel = 3,
- GOTRel = 4,
- GOTRelandRel = 5,
- ReservePLT = 8,
- PLTandRel = 9
+ ReservePLT = 4,
+ };
+
+ /** \enum EntryValue
+ * \brief The value of the entries. The symbol value will be decided at after
+ * layout, so we mark the entry during scanRelocation and fill up the actual
+ * value when applying relocations.
+ */
+ enum EntryValue {
+ Default = 0,
+ SymVal = 1
};
public:
@@ -106,7 +98,8 @@
void scanRelocation(Relocation& pReloc,
IRBuilder& pBuilder,
Module& pModule,
- LDSection& pSection);
+ LDSection& pSection,
+ Input& pInput);
private:
void scanLocalReloc(Relocation& pReloc, const LDSection& pSection);
diff --git a/lib/Target/ARM/ARMTargetMachine.cpp b/lib/Target/ARM/ARMTargetMachine.cpp
index 7062f31..25caa56 100644
--- a/lib/Target/ARM/ARMTargetMachine.cpp
+++ b/lib/Target/ARM/ARMTargetMachine.cpp
@@ -11,14 +11,13 @@
#include <mcld/Support/TargetRegistry.h>
-mcld::ARMBaseTargetMachine::ARMBaseTargetMachine(llvm::TargetMachine& pPM,
- const mcld::Target &pTarget,
- const std::string& pTriple)
- : mcld::MCLDTargetMachine(pPM, pTarget, pTriple) {
-}
+using namespace mcld;
-mcld::ARMBaseTargetMachine::~ARMBaseTargetMachine()
-{
+ARMBaseTargetMachine::ARMBaseTargetMachine(llvm::TargetMachine& pPM,
+ const llvm::Target &pLLVMTarget,
+ const mcld::Target &pMCLDTarget,
+ const std::string& pTriple)
+ : MCLDTargetMachine(pPM, pLLVMTarget, pMCLDTarget, pTriple) {
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Target/ARM/ARMTargetMachine.h b/lib/Target/ARM/ARMTargetMachine.h
index 94a7866..375f7b2 100644
--- a/lib/Target/ARM/ARMTargetMachine.h
+++ b/lib/Target/ARM/ARMTargetMachine.h
@@ -10,18 +10,17 @@
#define MCLD_ARM_TARGET_MACHINE_H
#include "ARM.h"
-#include <mcld/Target/TargetMachine.h>
+#include <mcld/CodeGen/TargetMachine.h>
namespace mcld {
class ARMBaseTargetMachine : public MCLDTargetMachine
{
public:
- ARMBaseTargetMachine(llvm::TargetMachine &pTM,
- const mcld::Target &pTarget,
- const std::string &pTriple);
-
- virtual ~ARMBaseTargetMachine();
+ ARMBaseTargetMachine(llvm::TargetMachine& pTM,
+ const llvm::Target& pLLVMTarget,
+ const mcld::Target& pMCLDTarget,
+ const std::string& pTriple);
};
} // namespace of mcld
diff --git a/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp b/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
index fd00641..de43662 100644
--- a/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
+++ b/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/Target/TargetMachine.h"
-#include "mcld/Support/TargetRegistry.h"
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/Support/Target.h>
namespace mcld {
@@ -16,8 +16,8 @@
extern "C" void MCLDInitializeARMLDTargetInfo() {
// register into mcld::TargetRegistry
- mcld::RegisterTarget X(TheARMTarget, "arm" );
- mcld::RegisterTarget Y(TheThumbTarget, "thumb" );
+ mcld::RegisterTarget<llvm::Triple::arm> X(TheARMTarget, "arm");
+ mcld::RegisterTarget<llvm::Triple::thumb> Y(TheThumbTarget, "thumb");
}
} // namespace of mcld
diff --git a/lib/Target/Android.mk b/lib/Target/Android.mk
index 77ab932..e46a09f 100644
--- a/lib/Target/Android.mk
+++ b/lib/Target/Android.mk
@@ -1,15 +1,17 @@
LOCAL_PATH:= $(call my-dir)
mcld_target_SRC_FILES := \
- ELFDynamic.cpp \
- ELFEmulation.cpp \
- ELFMCLinker.cpp \
+ ELFAttribute.cpp \
+ ELFAttributeData.cpp \
+ ELFAttributeValue.cpp \
+ ELFDynamic.cpp \
+ ELFEmulation.cpp \
+ ELFMCLinker.cpp \
GNUInfo.cpp \
- GNULDBackend.cpp \
+ GNULDBackend.cpp \
GOT.cpp \
- OutputRelocSection.cpp \
+ OutputRelocSection.cpp \
PLT.cpp \
- Target.cpp \
TargetLDBackend.cpp
# For the host
diff --git a/lib/Target/ELFAttribute.cpp b/lib/Target/ELFAttribute.cpp
new file mode 100644
index 0000000..76882d3
--- /dev/null
+++ b/lib/Target/ELFAttribute.cpp
@@ -0,0 +1,364 @@
+//===- ELFAttribute.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Target/ELFAttribute.h>
+
+#include <mcld/ADT/SizeTraits.h>
+#include <mcld/Fragment/RegionFragment.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/SectionData.h>
+#include <mcld/LinkerConfig.h>
+#include <mcld/MC/Input.h>
+#include <mcld/Support/LEB128.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Target/ELFAttributeValue.h>
+#include <mcld/Target/GNULDBackend.h>
+
+#include <llvm/ADT/STLExtras.h>
+#include <llvm/Support/Host.h>
+
+#include <cstring>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// ELFAttribute
+//===----------------------------------------------------------------------===//
+ELFAttribute::~ELFAttribute()
+{
+ llvm::DeleteContainerPointers(m_Subsections);
+ return;
+}
+
+bool ELFAttribute::merge(const Input &pInput, LDSection &pInputAttrSectHdr)
+{
+ // Skip corrupt subsection
+ if (pInputAttrSectHdr.size() < MinimalELFAttributeSectionSize)
+ return true;
+
+ // Obtain the region containing the attribute data. Expect exactly one
+ // RegionFragment in the section data.
+ const SectionData* sect_data = pInputAttrSectHdr.getSectionData();
+
+ // FIXME: Why is 2?
+ if ((sect_data->size() != 2) ||
+ (!llvm::isa<RegionFragment>(sect_data->front()))) {
+ return true;
+ }
+
+ const RegionFragment& region_frag =
+ llvm::cast<RegionFragment>(sect_data->front());
+
+ llvm::StringRef region = region_frag.getRegion();
+
+ // Parse the ELF attribute section header. ARM [ABI-addenda], 2.2.3.
+ //
+ // <format-version: ‘A’>
+ // [ <uint32: subsection-length> NTBS: vendor-name
+ // <bytes: vendor-data>
+ // ]*
+ const char *attribute_data = region.begin();
+
+ // format-version
+ if (attribute_data[0] != FormatVersion) {
+ warning(diag::warn_unsupported_attribute_section_format)
+ << pInput.name() << attribute_data[0];
+ return true;
+ }
+
+ size_t subsection_offset = FormatVersionFieldSize;
+
+ // Iterate all subsections containing in this attribute section.
+ do {
+ const char *subsection_data = region.begin() + subsection_offset;
+
+ // subsection-length
+ uint32_t subsection_length =
+ *reinterpret_cast<const uint32_t*>(subsection_data);
+
+ if(llvm::sys::IsLittleEndianHost != m_Config.targets().isLittleEndian())
+ bswap32(subsection_length);
+
+ // vendor-name
+ const char* vendor_name = subsection_data + SubsectionLengthFieldSize;
+ const size_t vendor_name_length = ::strlen(vendor_name) + 1 /* '\0' */;
+
+ // Check the length.
+ if ((vendor_name_length <= 1) ||
+ (subsection_length <= (SubsectionLengthFieldSize + vendor_name_length)))
+ return true;
+
+ // Select the attribute subsection.
+ Subsection *subsection = getSubsection(vendor_name);
+
+ // Only process the subsections whose vendor can be recognized.
+ if (subsection == NULL) {
+ warning(diag::warn_unrecognized_vendor_subsection)
+ << vendor_name << pInput.name();
+ } else {
+ // vendor-data
+ size_t vendor_data_offset = subsection_offset +
+ SubsectionLengthFieldSize +
+ vendor_name_length;
+ size_t vendor_data_size = subsection_length - SubsectionLengthFieldSize -
+ vendor_name_length;
+
+ ConstAddress vendor_data =
+ reinterpret_cast<ConstAddress>(region.begin()) + vendor_data_offset;
+
+ // Merge the vendor data in the subsection.
+ if (!subsection->merge(pInput, vendor_data, vendor_data_size))
+ return false;
+ }
+
+ subsection_offset += subsection_length;
+ } while ((subsection_offset + SubsectionLengthFieldSize) < pInputAttrSectHdr.size());
+
+ return true;
+}
+
+size_t ELFAttribute::sizeOutput() const
+{
+ size_t total_size = FormatVersionFieldSize;
+
+ for (llvm::SmallVectorImpl<Subsection*>::const_iterator
+ subsec_it = m_Subsections.begin(), subsec_end = m_Subsections.end();
+ subsec_it != subsec_end; ++subsec_it) {
+ total_size += (*subsec_it)->sizeOutput();
+ }
+ return total_size;
+}
+
+size_t ELFAttribute::emit(MemoryRegion &pRegion) const
+{
+ // ARM [ABI-addenda], 2.2.3
+ uint64_t total_size = 0;
+
+ // Write format-version.
+ char* buffer = reinterpret_cast<char*>(pRegion.begin());
+ buffer[0] = FormatVersion;
+ total_size += FormatVersionFieldSize;
+
+ for (llvm::SmallVectorImpl<Subsection*>::const_iterator
+ subsec_it = m_Subsections.begin(), subsec_end = m_Subsections.end();
+ subsec_it != subsec_end; ++subsec_it) {
+ // Write out subsection.
+ total_size += (*subsec_it)->emit(buffer + total_size);
+ }
+
+ return total_size;
+}
+
+void ELFAttribute::registerAttributeData(ELFAttributeData& pAttrData)
+{
+ assert((getSubsection(pAttrData.getVendorName()) == NULL) &&
+ "Multiple attribute data for a vendor!");
+ m_Subsections.push_back(new Subsection(*this, pAttrData));
+ return;
+}
+
+ELFAttribute::Subsection *
+ELFAttribute::getSubsection(llvm::StringRef pVendorName) const
+{
+ // Search m_Subsections linearly.
+ for (llvm::SmallVectorImpl<Subsection*>::const_iterator
+ subsec_it = m_Subsections.begin(), subsec_end = m_Subsections.end();
+ subsec_it != subsec_end; ++subsec_it) {
+ Subsection* const subsection = *subsec_it;
+ if (subsection->isMyAttribute(pVendorName)) {
+ return subsection;
+ }
+ }
+
+ // Not found
+ return NULL;
+}
+
+//===----------------------------------------------------------------------===//
+// ELFAttribute::Subsection
+//===----------------------------------------------------------------------===//
+bool ELFAttribute::Subsection::merge(const Input &pInput,
+ ConstAddress pData,
+ size_t pSize)
+{
+ const bool need_swap = (llvm::sys::IsLittleEndianHost !=
+ m_Parent.config().targets().isLittleEndian());
+ // Read attribute sub-subsection from vendor data.
+ //
+ // ARM [ABI-addenda], 2.2.4:
+ //
+ // [ Tag_File (=1) <uint32: byte-size> <attribute>*
+ // | Tag_Section (=2) <uint32: byte-size> <section number>* 0 <attribute>*
+ // | Tag_symbol (=3) <unit32: byte-size> <symbol number>* 0 <attribute>*
+ // ] +
+ const char *subsubsection_data = reinterpret_cast<const char*>(pData);
+ size_t remaining_size = pSize;
+
+ if (!m_AttrData.preMerge(pInput)) {
+ return false;
+ }
+
+ while (remaining_size > ELFAttribute::MinimalELFAttributeSubsectionSize) {
+ // The tag of sub-subsection is encoded in ULEB128.
+ size_t tag_size;
+ uint64_t tag = leb128::decode<uint64_t>(subsubsection_data, tag_size);
+
+ if ((tag_size + 4 /* byte-size */) >= remaining_size)
+ break;
+
+ size_t subsubsection_length =
+ *reinterpret_cast<const uint32_t*>(subsubsection_data + tag_size);
+
+ if (need_swap)
+ bswap32(subsubsection_length);
+
+ if (subsubsection_length > remaining_size) {
+ // The subsubsection is corrupted. Try our best to process it.
+ subsubsection_length = remaining_size;
+ }
+
+ switch (tag) {
+ case ELFAttributeData::Tag_File: {
+ ELFAttributeData::TagType tag;
+ ELFAttributeValue in_attr;
+ // The offset from the start of sub-subsection that <attribute> located
+ size_t attribute_offset = tag_size + 4 /* byte-size */;
+
+ const char* attr_buf = subsubsection_data + attribute_offset;
+ size_t attr_size = subsubsection_length - attribute_offset;
+
+ // Read attributes from the stream.
+ do {
+ if (!ELFAttributeData::ReadTag(tag, attr_buf, attr_size))
+ break;
+
+ ELFAttributeValue *out_attr;
+ bool is_newly_created;
+
+ llvm::tie(out_attr, is_newly_created) =
+ m_AttrData.getOrCreateAttributeValue(tag);
+
+ assert(out_attr != NULL);
+
+ if (is_newly_created) {
+ // Directly read the attribute value to the out_attr.
+ if (!ELFAttributeData::ReadValue(*out_attr, attr_buf, attr_size))
+ break;
+ } else {
+ // The attribute has been defined previously. Read the attribute
+ // to a temporary storage in_attr and perform the merge.
+ in_attr.reset();
+ in_attr.setType(out_attr->type());
+
+ // Read the attribute value.
+ if (!ELFAttributeData::ReadValue(in_attr, attr_buf, attr_size))
+ break;
+
+ // Merge if the read attribute value is different than current one
+ // in output.
+ if ((in_attr != *out_attr) &&
+ !m_AttrData.merge(m_Parent.config(), pInput, tag, in_attr)) {
+ // Fail to merge the attribute.
+ return false;
+ }
+ }
+ } while (attr_size > 0);
+
+ break;
+ }
+ // Skip sub-subsection tagged with Tag_Section and Tag_Symbol. They are
+ // deprecated since ARM [ABI-addenda] r2.09.
+ case ELFAttributeData::Tag_Section:
+ case ELFAttributeData::Tag_Symbol:
+ // Skip any unknown tags.
+ default: {
+ break;
+ }
+ }
+
+ // Update subsubsection_data and remaining_size for next.
+ subsubsection_data += subsubsection_length;
+ remaining_size -= subsubsection_length;
+ } // while (remaining_size > ELFAttribute::MinimalELFAttributeSubsectionSize)
+
+ return m_AttrData.postMerge(m_Parent.config(), pInput);
+}
+
+size_t ELFAttribute::Subsection::sizeOutput() const
+{
+ // ARM [ABI-addenda], 2.2.3 and 2.2.4
+ return ELFAttribute::SubsectionLengthFieldSize +
+ m_AttrData.getVendorName().length() /* vendor-name */ +
+ 1 /* NULL-terminator for vendor-name */ +
+ 1 /* Tag_File */ +
+ sizeof(uint32_t) /* length of sub-subsection */ +
+ m_AttrData.sizeOutput();
+}
+
+size_t ELFAttribute::Subsection::emit(char *pBuf) const
+{
+ // ARM [ABI-addenda], 2.2.3 and 2.2.4
+ const bool need_swap = (llvm::sys::IsLittleEndianHost !=
+ m_Parent.config().targets().isLittleEndian());
+
+ char *buffer = pBuf;
+
+ // The subsection-length and byte-size field in sub-subsection will be patched
+ // later after writing out all attribute data.
+ char *subsection_length_hole = NULL;
+ char *subsubsection_length_hole = NULL;
+
+ // Reserve space for subsection-length.
+ subsection_length_hole = buffer;
+ buffer += 4;
+
+ // Write vendor-name.
+ const std::string &vendor_name = m_AttrData.getVendorName();
+ ::memcpy(buffer, vendor_name.c_str(), vendor_name.length());
+ buffer += vendor_name.length();
+
+ // Write NULL-terminator for vendor-name.
+ *buffer++ = '\0';
+
+ // Write Tag_File (0x01).
+ *buffer++ = '\x01';
+
+ // Reserve space for byte-size for sub-subsection.
+ subsubsection_length_hole = buffer;
+ buffer += sizeof(uint32_t);
+
+ // Write attribute data.
+ uint32_t subsubsection_length = m_AttrData.emit(buffer);
+
+ // Calculate value of subsection-length.
+ uint32_t subsection_length = (buffer - pBuf) + subsubsection_length;
+
+ // ARM [ABI-addenda] 2.2.4
+ //
+ // The byte-size in sub-subsection includes Tag_File (1-byte) and the size
+ // field of itself (4-byte).
+ subsubsection_length += 1 /* Tag_File */ + 4 /* size of byte-size */;
+
+ // Patch subsubsection_length_hole.
+ assert(subsubsection_length_hole != NULL);
+
+ if(need_swap)
+ bswap32(subsubsection_length);
+
+ ::memcpy(subsubsection_length_hole, &subsubsection_length, sizeof(uint32_t));
+
+ // Write subsection-length in subsection_length_hole.
+ if(need_swap)
+ bswap32(subsection_length);
+
+ assert(subsection_length_hole != NULL);
+ ::memcpy(subsection_length_hole, &subsection_length, sizeof(uint32_t));
+
+ return subsection_length;
+}
diff --git a/lib/Target/ELFAttributeData.cpp b/lib/Target/ELFAttributeData.cpp
new file mode 100644
index 0000000..c41918b
--- /dev/null
+++ b/lib/Target/ELFAttributeData.cpp
@@ -0,0 +1,88 @@
+//===- ELFAttributeData.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Target/ELFAttributeData.h>
+
+#include <mcld/Support/LEB128.h>
+#include <mcld/Target/ELFAttributeValue.h>
+#include <cstring>
+#include <cassert>
+
+using namespace mcld;
+
+bool ELFAttributeData::ReadTag(TagType& pTag, const char* &pBuf,
+ size_t &pBufSize)
+{
+ size_t size = 0;
+
+ pTag = static_cast<ELFAttributeData::TagType>(
+ leb128::decode<uint64_t>(pBuf, size));
+
+ if (size > pBufSize)
+ return false;
+
+ pBuf += size;
+ pBufSize -= size;
+
+ return true;
+}
+
+bool ELFAttributeData::ReadValue(ELFAttributeValue& pValue, const char* &pBuf,
+ size_t &pBufSize)
+{
+ // An ULEB128-encoded value
+ if (pValue.isIntValue()) {
+ size_t size = 0;
+ uint64_t int_value = leb128::decode<uint64_t>(pBuf, size);
+ pValue.setIntValue(static_cast<unsigned int>(int_value));
+
+ if (size > pBufSize)
+ return false;
+
+ pBuf += size;
+ pBufSize -= size;
+ }
+
+ // A null-terminated byte string
+ if (pValue.isStringValue()) {
+ pValue.setStringValue(pBuf);
+
+ size_t size = pValue.getStringValue().length() + 1 /* '\0' */;
+ assert(size <= pBufSize);
+ pBuf += size;
+ pBufSize -= size;
+ }
+
+ return true;
+}
+
+bool ELFAttributeData::WriteAttribute(TagType pTag,
+ const ELFAttributeValue& pValue,
+ char* &pBuf)
+{
+ // Write the attribute tag.
+ leb128::encode<uint32_t>(pBuf, pTag);
+
+ // Write the attribute value.
+ if (pValue.isIntValue())
+ leb128::encode<uint32_t>(pBuf, pValue.getIntValue());
+
+ if (pValue.isStringValue()) {
+ // Write string data.
+ size_t str_val_len = pValue.getStringValue().length();
+
+ if (str_val_len > 0)
+ ::memcpy(pBuf, pValue.getStringValue().c_str(), str_val_len);
+ pBuf += str_val_len;
+
+ // Write NULL-terminator.
+ *pBuf++ = '\0';
+ }
+
+ return true;
+}
diff --git a/lib/Target/ELFAttributeValue.cpp b/lib/Target/ELFAttributeValue.cpp
new file mode 100644
index 0000000..0f99325
--- /dev/null
+++ b/lib/Target/ELFAttributeValue.cpp
@@ -0,0 +1,66 @@
+//===- ELFAttributeValue.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <mcld/Target/ELFAttributeValue.h>
+
+#include <llvm/Support/ErrorHandling.h>
+
+#include <mcld/Support/LEB128.h>
+
+using namespace mcld;
+
+size_t ELFAttributeValue::getSize() const
+{
+ size_t size = 0;
+
+ if (isIntValue())
+ size += leb128::size<uint32_t>(m_IntValue);
+
+ if (isStringValue())
+ size += m_StringValue.length() + 1 /* for NULL-terminator */;
+
+ if (size <= 0)
+ // unknown type of the value
+ llvm::report_fatal_error("Unknown type of attribtue value!");
+
+ return size;
+}
+
+bool ELFAttributeValue::isDefaultValue() const
+{
+ if (isUninitialized()) {
+ // Uninitialized attribute means default value
+ return true;
+ } else {
+ if (isIntValue() && (m_IntValue != 0))
+ return false;
+ if (isStringValue() && !m_StringValue.empty())
+ return false;
+
+ // The value hold in the storage is the "default value by default" (i.e., 0
+ // for int type, empty string for string type), but we need to check whether
+ // the "default value" is defined (that is, hasNoDefault() = false.)
+ return !hasNoDefault();
+ }
+ // unreachable
+}
+
+bool ELFAttributeValue::equals(const ELFAttributeValue& pValue) const
+{
+ if ((pValue.type() != m_Type) || isUninitialized())
+ return false;
+
+ if (isIntValue() && (m_IntValue != pValue.getIntValue()))
+ return false;
+
+ if (isStringValue() && (m_StringValue != pValue.getStringValue()))
+ return false;
+
+ return true;
+}
diff --git a/lib/Target/ELFDynamic.cpp b/lib/Target/ELFDynamic.cpp
index aeccd92..25c56c1 100644
--- a/lib/Target/ELFDynamic.cpp
+++ b/lib/Target/ELFDynamic.cpp
@@ -12,7 +12,6 @@
#include <mcld/Target/GNULDBackend.h>
#include <mcld/LD/ELFFileFormat.h>
#include <mcld/LinkerConfig.h>
-#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MsgHandling.h>
using namespace mcld;
@@ -140,10 +139,8 @@
reserveTargetEntries(pFormat); // DT_PLTGOT
- if (pFormat.hasRelPlt() || pFormat.hasRelaPlt())
+ if (pFormat.hasRelPlt() || pFormat.hasRelaPlt()) {
reserveOne(llvm::ELF::DT_PLTREL); // DT_PLTREL
-
- if (pFormat.hasPLT()) {
reserveOne(llvm::ELF::DT_JMPREL); // DT_JMPREL
reserveOne(llvm::ELF::DT_PLTRELSZ); // DT_PLTRELSZ
}
@@ -343,7 +340,7 @@
llvm::Twine(" than the section's demaind.\n"));
}
- uint8_t* address = (uint8_t*)pRegion.start();
+ uint8_t* address = (uint8_t*)pRegion.begin();
EntryListType::const_iterator entry, entryEnd = m_NeedList.end();
for (entry = m_NeedList.begin(); entry != entryEnd; ++entry)
address += (*entry)->emit(address);
diff --git a/lib/Target/ELFEmulation.cpp b/lib/Target/ELFEmulation.cpp
index ff4a757..a68e485 100644
--- a/lib/Target/ELFEmulation.cpp
+++ b/lib/Target/ELFEmulation.cpp
@@ -9,6 +9,7 @@
#include <mcld/Target/ELFEmulation.h>
#include <mcld/LinkerScript.h>
#include <mcld/LinkerConfig.h>
+#include <mcld/Script/InputSectDesc.h>
#include <llvm/Support/Host.h>
@@ -17,63 +18,73 @@
struct NameMap {
const char* from; ///< the prefix of the input string. (match FROM*)
const char* to; ///< the output string.
+ InputSectDesc::KeepPolicy policy; /// mark whether the input is kept in GC
};
static const NameMap map[] =
{
- {".text", ".text"},
- {".rodata", ".rodata"},
- {".data.rel.ro.local", ".data.rel.ro.local"},
- {".data.rel.ro", ".data.rel.ro"},
- {".data", ".data"},
- {".bss", ".bss"},
- {".tdata", ".tdata"},
- {".tbss", ".tbss"},
- {".init_array", ".init_array"},
- {".fini_array", ".fini_array"},
+ {".text*", ".text", InputSectDesc::NoKeep},
+ {".rodata*", ".rodata", InputSectDesc::NoKeep},
+ {".data.rel.ro.local*", ".data.rel.ro.local", InputSectDesc::NoKeep},
+ {".data.rel.ro*", ".data.rel.ro", InputSectDesc::NoKeep},
+ {".data*", ".data", InputSectDesc::NoKeep},
+ {".bss*", ".bss", InputSectDesc::NoKeep},
+ {".tdata*", ".tdata", InputSectDesc::NoKeep},
+ {".tbss*", ".tbss", InputSectDesc::NoKeep},
+ {".init", ".init", InputSectDesc::Keep},
+ {".fini", ".fini", InputSectDesc::Keep},
+ {".preinit_array*", ".preinit_array", InputSectDesc::Keep},
+ {".init_array*", ".init_array", InputSectDesc::Keep},
+ {".fini_array*", ".fini_array", InputSectDesc::Keep},
// TODO: Support DT_INIT_ARRAY for all constructors?
- {".ctors", ".ctors"},
- {".dtors", ".dtors"},
+ {".ctors*", ".ctors", InputSectDesc::Keep},
+ {".dtors*", ".dtors", InputSectDesc::Keep},
+ {".jcr", ".jcr", InputSectDesc::Keep},
// FIXME: in GNU ld, if we are creating a shared object .sdata2 and .sbss2
// sections would be handled differently.
- {".sdata2", ".sdata"},
- {".sbss2", ".sbss"},
- {".sdata", ".sdata"},
- {".sbss", ".sbss"},
- {".lrodata", ".lrodata"},
- {".ldata", ".ldata"},
- {".lbss", ".lbss"},
- {".gcc_except_table", ".gcc_except_table"},
- {".gnu.linkonce.d.rel.ro.local", ".data.rel.ro.local"},
- {".gnu.linkonce.d.rel.ro", ".data.rel.ro"},
- {".gnu.linkonce.r", ".rodata"},
- {".gnu.linkonce.d", ".data"},
- {".gnu.linkonce.b", ".bss"},
- {".gnu.linkonce.sb2", ".sbss"},
- {".gnu.linkonce.sb", ".sbss"},
- {".gnu.linkonce.s2", ".sdata"},
- {".gnu.linkonce.s", ".sdata"},
- {".gnu.linkonce.wi", ".debug_info"},
- {".gnu.linkonce.td", ".tdata"},
- {".gnu.linkonce.tb", ".tbss"},
- {".gnu.linkonce.t", ".text"},
- {".gnu.linkonce.lr", ".lrodata"},
- {".gnu.linkonce.lb", ".lbss"},
- {".gnu.linkonce.l", ".ldata"},
+ {".sdata2*", ".sdata", InputSectDesc::NoKeep},
+ {".sbss2*", ".sbss", InputSectDesc::NoKeep},
+ {".sdata*", ".sdata", InputSectDesc::NoKeep},
+ {".sbss*", ".sbss", InputSectDesc::NoKeep},
+ {".lrodata*", ".lrodata", InputSectDesc::NoKeep},
+ {".ldata*", ".ldata", InputSectDesc::NoKeep},
+ {".lbss*", ".lbss", InputSectDesc::NoKeep},
+ {".gcc_except_table*", ".gcc_except_table", InputSectDesc::Keep},
+ {".gnu.linkonce.d.rel.ro.local*", ".data.rel.ro.local", InputSectDesc::NoKeep},
+ {".gnu.linkonce.d.rel.ro*", ".data.rel.ro", InputSectDesc::NoKeep},
+ {".gnu.linkonce.r*", ".rodata", InputSectDesc::NoKeep},
+ {".gnu.linkonce.d*", ".data", InputSectDesc::NoKeep},
+ {".gnu.linkonce.b*", ".bss", InputSectDesc::NoKeep},
+ {".gnu.linkonce.sb2*", ".sbss", InputSectDesc::NoKeep},
+ {".gnu.linkonce.sb*", ".sbss", InputSectDesc::NoKeep},
+ {".gnu.linkonce.s2*", ".sdata", InputSectDesc::NoKeep},
+ {".gnu.linkonce.s*", ".sdata", InputSectDesc::NoKeep},
+ {".gnu.linkonce.wi*", ".debug_info", InputSectDesc::NoKeep},
+ {".gnu.linkonce.td*", ".tdata", InputSectDesc::NoKeep},
+ {".gnu.linkonce.tb*", ".tbss", InputSectDesc::NoKeep},
+ {".gnu.linkonce.t*", ".text", InputSectDesc::NoKeep},
+ {".gnu.linkonce.lr*", ".lrodata", InputSectDesc::NoKeep},
+ {".gnu.linkonce.lb*", ".lbss", InputSectDesc::NoKeep},
+ {".gnu.linkonce.l*", ".ldata", InputSectDesc::NoKeep},
};
bool mcld::MCLDEmulateELF(LinkerScript& pScript, LinkerConfig& pConfig)
// FIXME: LinkerConfig& pConfig should be constant
{
// set up section map
- if (pConfig.codeGenType() != LinkerConfig::Object) {
+ if (pConfig.options().getScriptList().empty() &&
+ pConfig.codeGenType() != LinkerConfig::Object) {
const unsigned int map_size = (sizeof(map) / sizeof(map[0]) );
for (unsigned int i = 0; i < map_size; ++i) {
- bool exist = false;
- pScript.sectionMap().append(map[i].from, map[i].to, exist);
- if (exist)
+ std::pair<SectionMap::mapping, bool> res =
+ pScript.sectionMap().insert(map[i].from, map[i].to, map[i].policy);
+ if (!res.second)
return false;
}
+ } else {
+ // FIXME: this is the hack to help assignment processing in current
+ // implementation.
+ pScript.sectionMap().insert("", "");
}
if (!pConfig.options().nostdlib()) {
diff --git a/lib/Target/ELFMCLinker.cpp b/lib/Target/ELFMCLinker.cpp
index 3fa9b90..fae5c8c 100644
--- a/lib/Target/ELFMCLinker.cpp
+++ b/lib/Target/ELFMCLinker.cpp
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
#include <mcld/Target/ELFMCLinker.h>
-#include <mcld/LinkerConfig.h>
-#include <mcld/Object/SectionMap.h>
-#include <mcld/Support/MsgHandling.h>
using namespace mcld;
@@ -18,8 +15,8 @@
//===----------------------------------------------------------------------===//
ELFMCLinker::ELFMCLinker(LinkerConfig& pConfig,
mcld::Module& pModule,
- MemoryArea& pOutput)
- : MCLinker(pConfig, pModule, pOutput) {
+ FileHandle& pFileHandle)
+ : MCLinker(pConfig, pModule, pFileHandle) {
}
diff --git a/lib/Target/GNULDBackend.cpp b/lib/Target/GNULDBackend.cpp
index c624f14..796c93e 100644
--- a/lib/Target/GNULDBackend.cpp
+++ b/lib/Target/GNULDBackend.cpp
@@ -17,25 +17,39 @@
#include <mcld/Module.h>
#include <mcld/LinkerConfig.h>
+#include <mcld/LinkerScript.h>
#include <mcld/IRBuilder.h>
#include <mcld/InputTree.h>
#include <mcld/Config/Config.h>
#include <mcld/ADT/SizeTraits.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/LDContext.h>
-#include <mcld/Fragment/FillFragment.h>
#include <mcld/LD/EhFrame.h>
#include <mcld/LD/EhFrameHdr.h>
#include <mcld/LD/RelocData.h>
#include <mcld/LD/RelocationFactory.h>
-#include <mcld/MC/Attribute.h>
-#include <mcld/Support/MemoryArea.h>
-#include <mcld/Support/MemoryRegion.h>
-#include <mcld/Support/MsgHandling.h>
-#include <mcld/Support/MemoryAreaFactory.h>
#include <mcld/LD/BranchIslandFactory.h>
+#include <mcld/LD/ELFSegmentFactory.h>
+#include <mcld/LD/ELFSegment.h>
#include <mcld/LD/StubFactory.h>
+#include <mcld/LD/ELFFileFormat.h>
+#include <mcld/LD/ELFObjectFileFormat.h>
+#include <mcld/LD/ELFDynObjFileFormat.h>
+#include <mcld/LD/ELFExecFileFormat.h>
+#include <mcld/Target/ELFAttribute.h>
+#include <mcld/Target/ELFDynamic.h>
+#include <mcld/Target/GNUInfo.h>
+#include <mcld/Support/FileOutputBuffer.h>
+#include <mcld/Support/MsgHandling.h>
#include <mcld/Object/ObjectBuilder.h>
+#include <mcld/Object/SectionMap.h>
+#include <mcld/Script/RpnEvaluator.h>
+#include <mcld/Script/Operand.h>
+#include <mcld/Script/OutputSectDesc.h>
+#include <mcld/Fragment/FillFragment.h>
+#include <mcld/MC/Attribute.h>
+
+#include <llvm/Support/Host.h>
namespace {
@@ -69,10 +83,11 @@
m_pExecFileFormat(NULL),
m_pObjectFileFormat(NULL),
m_pInfo(pInfo),
- m_ELFSegmentTable(9), // magic number
+ m_pELFSegmentTable(NULL),
m_pBRIslandFactory(NULL),
m_pStubFactory(NULL),
m_pEhFrameHdr(NULL),
+ m_pAttribute(NULL),
m_bHasTextRel(false),
m_bHasStaticTLS(false),
f_pPreInitArrayStart(NULL),
@@ -94,17 +109,21 @@
f_pBSSStart(NULL),
f_pEnd(NULL),
f_p_End(NULL) {
+ m_pELFSegmentTable = new ELFSegmentFactory();
m_pSymIndexMap = new HashTableType(1024);
+ m_pAttribute = new ELFAttribute(*this, pConfig);
}
GNULDBackend::~GNULDBackend()
{
+ delete m_pELFSegmentTable;
delete m_pInfo;
delete m_pDynObjFileFormat;
delete m_pExecFileFormat;
delete m_pObjectFileFormat;
delete m_pSymIndexMap;
delete m_pEhFrameHdr;
+ delete m_pAttribute;
delete m_pBRIslandFactory;
delete m_pStubFactory;
}
@@ -117,10 +136,10 @@
switch (config().targets().bitclass()) {
case 32u:
return sizeof(llvm::ELF::Elf32_Ehdr) +
- numOfSegments() * sizeof(llvm::ELF::Elf32_Phdr);
+ elfSegmentTable().size() * sizeof(llvm::ELF::Elf32_Phdr);
case 64u:
return sizeof(llvm::ELF::Elf64_Ehdr) +
- numOfSegments() * sizeof(llvm::ELF::Elf64_Phdr);
+ elfSegmentTable().size() * sizeof(llvm::ELF::Elf64_Phdr);
default:
fatal(diag::unsupported_bitclass) << config().targets().triple().str()
<< config().targets().bitclass();
@@ -160,7 +179,7 @@
ELFBinaryReader* GNULDBackend::createBinaryReader(IRBuilder& pBuilder)
{
- return new ELFBinaryReader(*this, pBuilder, config());
+ return new ELFBinaryReader(pBuilder, config());
}
ELFObjectWriter* GNULDBackend::createWriter()
@@ -572,11 +591,12 @@
// ----- segment symbols ----- //
if (NULL != f_pExecutableStart) {
- ELFSegment* exec_start = m_ELFSegmentTable.find(llvm::ELF::PT_LOAD, 0x0, 0x0);
- if (NULL != exec_start) {
+ ELFSegmentFactory::const_iterator exec_start =
+ elfSegmentTable().find(llvm::ELF::PT_LOAD, 0x0, 0x0);
+ if (elfSegmentTable().end() != exec_start) {
if (ResolveInfo::ThreadLocal != f_pExecutableStart->type()) {
f_pExecutableStart->setValue(f_pExecutableStart->value() +
- exec_start->vaddr());
+ (*exec_start)->vaddr());
}
}
else
@@ -584,24 +604,25 @@
}
if (NULL != f_pEText || NULL != f_p_EText || NULL !=f_p__EText) {
- ELFSegment* etext = m_ELFSegmentTable.find(llvm::ELF::PT_LOAD,
- llvm::ELF::PF_X,
- llvm::ELF::PF_W);
- if (NULL != etext) {
+ ELFSegmentFactory::const_iterator etext =
+ elfSegmentTable().find(llvm::ELF::PT_LOAD,
+ llvm::ELF::PF_X,
+ llvm::ELF::PF_W);
+ if (elfSegmentTable().end() != etext) {
if (NULL != f_pEText && ResolveInfo::ThreadLocal != f_pEText->type()) {
f_pEText->setValue(f_pEText->value() +
- etext->vaddr() +
- etext->memsz());
+ (*etext)->vaddr() +
+ (*etext)->memsz());
}
if (NULL != f_p_EText && ResolveInfo::ThreadLocal != f_p_EText->type()) {
f_p_EText->setValue(f_p_EText->value() +
- etext->vaddr() +
- etext->memsz());
+ (*etext)->vaddr() +
+ (*etext)->memsz());
}
if (NULL != f_p__EText && ResolveInfo::ThreadLocal != f_p__EText->type()) {
f_p__EText->setValue(f_p__EText->value() +
- etext->vaddr() +
- etext->memsz());
+ (*etext)->vaddr() +
+ (*etext)->memsz());
}
}
else {
@@ -616,35 +637,34 @@
if (NULL != f_pEData || NULL != f_p_EData || NULL != f_pBSSStart ||
NULL != f_pEnd || NULL != f_p_End) {
- ELFSegment* edata = m_ELFSegmentTable.find(llvm::ELF::PT_LOAD,
- llvm::ELF::PF_W,
- 0x0);
- if (NULL != edata) {
+ ELFSegmentFactory::const_iterator edata =
+ elfSegmentTable().find(llvm::ELF::PT_LOAD, llvm::ELF::PF_W, 0x0);
+ if (elfSegmentTable().end() != edata) {
if (NULL != f_pEData && ResolveInfo::ThreadLocal != f_pEData->type()) {
f_pEData->setValue(f_pEData->value() +
- edata->vaddr() +
- edata->filesz());
+ (*edata)->vaddr() +
+ (*edata)->filesz());
}
if (NULL != f_p_EData && ResolveInfo::ThreadLocal != f_p_EData->type()) {
f_p_EData->setValue(f_p_EData->value() +
- edata->vaddr() +
- edata->filesz());
+ (*edata)->vaddr() +
+ (*edata)->filesz());
}
if (NULL != f_pBSSStart && ResolveInfo::ThreadLocal != f_pBSSStart->type()) {
f_pBSSStart->setValue(f_pBSSStart->value() +
- edata->vaddr() +
- edata->filesz());
+ (*edata)->vaddr() +
+ (*edata)->filesz());
}
if (NULL != f_pEnd && ResolveInfo::ThreadLocal != f_pEnd->type()) {
f_pEnd->setValue(f_pEnd->value() +
- edata->vaddr() +
- edata->memsz());
+ (*edata)->vaddr() +
+ (*edata)->memsz());
}
if (NULL != f_p_End && ResolveInfo::ThreadLocal != f_p_End->type()) {
f_p_End->setValue(f_p_End->value() +
- edata->vaddr() +
- edata->memsz());
+ (*edata)->vaddr() +
+ (*edata)->memsz());
}
}
else {
@@ -672,11 +692,12 @@
return true;
// the value of a TLS symbol is the offset to the TLS segment
- ELFSegment* tls_seg = m_ELFSegmentTable.find(llvm::ELF::PT_TLS,
- llvm::ELF::PF_R, 0x0);
+ ELFSegmentFactory::iterator tls_seg =
+ elfSegmentTable().find(llvm::ELF::PT_TLS, llvm::ELF::PF_R, 0x0);
+ assert(tls_seg != elfSegmentTable().end());
uint64_t value = pSymbol.fragRef()->getOutputOffset();
uint64_t addr = pSymbol.fragRef()->frag()->getParent()->getSection().addr();
- pSymbol.setValue(value + addr - tls_seg->vaddr());
+ pSymbol.setValue(value + addr - (*tls_seg)->vaddr());
return true;
}
@@ -718,6 +739,18 @@
}
}
+/// sizeShstrtab - compute the size of .shstrtab
+void GNULDBackend::sizeShstrtab(Module& pModule)
+{
+ size_t shstrtab = 0;
+ // compute the size of .shstrtab section.
+ Module::const_iterator sect, sectEnd = pModule.end();
+ for (sect = pModule.begin(); sect != sectEnd; ++sect) {
+ shstrtab += (*sect)->name().size() + 1;
+ } // end of for
+ getOutputFormat()->getShStrTab().setSize(shstrtab);
+}
+
/// sizeNamePools - compute the size of regular name pools
/// In ELF executable files, regular name pools are .symtab, .strtab,
/// .dynsym, .dynstr, .hash and .shstrtab.
@@ -734,7 +767,6 @@
// first byte
size_t strtab = 1;
size_t dynstr = config().isCodeStatic()? 0 : 1;
- size_t shstrtab = 1;
size_t hash = 0;
size_t gnuhash = 0;
@@ -746,21 +778,34 @@
Module::const_sym_iterator symbol, symEnd;
/// Compute the size of .symtab, .strtab, and symtab_local_cnt
/// @{
- symEnd = symbols.end();
- for (symbol = symbols.begin(); symbol != symEnd; ++symbol) {
- ++symtab;
- if (hasEntryInStrTab(**symbol))
- strtab += (*symbol)->nameSize() + 1;
- }
- symtab_local_cnt = 1 + symbols.numOfFiles() + symbols.numOfLocals() +
- symbols.numOfLocalDyns();
+ /* TODO:
+ 1. discard locals and temporary locals
+ 2. check whether the symbol is used
+ */
+ switch (config().options().getStripSymbolMode()) {
+ case GeneralOptions::StripAllSymbols: {
+ symtab = strtab = 0;
+ break;
+ }
+ default: {
+ symEnd = symbols.end();
+ for (symbol = symbols.begin(); symbol != symEnd; ++symbol) {
+ ++symtab;
+ if (hasEntryInStrTab(**symbol))
+ strtab += (*symbol)->nameSize() + 1;
+ }
+ symtab_local_cnt = 1 + symbols.numOfFiles() + symbols.numOfLocals() +
+ symbols.numOfLocalDyns();
+ break;
+ }
+ } // end of switch
ELFFileFormat* file_format = getOutputFormat();
switch(config().codeGenType()) {
case LinkerConfig::DynObj: {
// soname
- dynstr += pModule.name().size() + 1;
+ dynstr += config().options().soname().size() + 1;
}
/** fall through **/
case LinkerConfig::Exec:
@@ -857,38 +902,9 @@
// index of the last local symbol
file_format->getSymTab().setInfo(symtab_local_cnt);
- // compute the size of .shstrtab section.
- Module::const_iterator sect, sectEnd = pModule.end();
- for (sect = pModule.begin(); sect != sectEnd; ++sect) {
- switch ((*sect)->kind()) {
- case LDFileFormat::Null:
- break;
- // take StackNote directly
- case LDFileFormat::StackNote:
- shstrtab += ((*sect)->name().size() + 1);
- break;
- case LDFileFormat::EhFrame:
- if (((*sect)->size() != 0) ||
- ((*sect)->hasEhFrame() &&
- config().codeGenType() == LinkerConfig::Object))
- shstrtab += ((*sect)->name().size() + 1);
- break;
- case LDFileFormat::Relocation:
- if (((*sect)->size() != 0) ||
- ((*sect)->hasRelocData() &&
- config().codeGenType() == LinkerConfig::Object))
- shstrtab += ((*sect)->name().size() + 1);
- break;
- default:
- if (((*sect)->size() != 0) ||
- ((*sect)->hasSectionData() &&
- config().codeGenType() == LinkerConfig::Object))
- shstrtab += ((*sect)->name().size() + 1);
- break;
- } // end of switch
- } // end of for
- shstrtab += (strlen(".shstrtab") + 1);
- file_format->getShStrTab().setSize(shstrtab);
+ // The size of .shstrtab should be decided after output sections are all
+ // set, so we just set it to 1 here.
+ file_format->getShStrTab().setSize(0x1);
break;
}
default:
@@ -948,32 +964,34 @@
/// the size of these tables should be computed before layout
/// layout should computes the start offset of these tables
void GNULDBackend::emitRegNamePools(const Module& pModule,
- MemoryArea& pOutput)
+ FileOutputBuffer& pOutput)
{
ELFFileFormat* file_format = getOutputFormat();
+ if (!file_format->hasSymTab())
+ return;
LDSection& symtab_sect = file_format->getSymTab();
LDSection& strtab_sect = file_format->getStrTab();
- MemoryRegion* symtab_region = pOutput.request(symtab_sect.offset(),
- symtab_sect.size());
- MemoryRegion* strtab_region = pOutput.request(strtab_sect.offset(),
- strtab_sect.size());
+ MemoryRegion symtab_region = pOutput.request(symtab_sect.offset(),
+ symtab_sect.size());
+ MemoryRegion strtab_region = pOutput.request(strtab_sect.offset(),
+ strtab_sect.size());
// set up symtab_region
llvm::ELF::Elf32_Sym* symtab32 = NULL;
llvm::ELF::Elf64_Sym* symtab64 = NULL;
if (config().targets().is32Bits())
- symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region->start();
+ symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region.begin();
else if (config().targets().is64Bits())
- symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region->start();
+ symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region.begin();
else {
fatal(diag::unsupported_bitclass) << config().targets().triple().str()
<< config().targets().bitclass();
}
// set up strtab_region
- char* strtab = (char*)strtab_region->start();
+ char* strtab = (char*)strtab_region.begin();
// emit the first ELF symbol
if (config().targets().is32Bits())
@@ -1014,7 +1032,7 @@
///
/// the size of these tables should be computed before layout
/// layout should computes the start offset of these tables
-void GNULDBackend::emitDynNamePools(Module& pModule, MemoryArea& pOutput)
+void GNULDBackend::emitDynNamePools(Module& pModule, FileOutputBuffer& pOutput)
{
ELFFileFormat* file_format = getOutputFormat();
if (!file_format->hasDynSymTab() ||
@@ -1029,26 +1047,26 @@
LDSection& strtab_sect = file_format->getDynStrTab();
LDSection& dyn_sect = file_format->getDynamic();
- MemoryRegion* symtab_region = pOutput.request(symtab_sect.offset(),
- symtab_sect.size());
- MemoryRegion* strtab_region = pOutput.request(strtab_sect.offset(),
- strtab_sect.size());
- MemoryRegion* dyn_region = pOutput.request(dyn_sect.offset(),
- dyn_sect.size());
+ MemoryRegion symtab_region = pOutput.request(symtab_sect.offset(),
+ symtab_sect.size());
+ MemoryRegion strtab_region = pOutput.request(strtab_sect.offset(),
+ strtab_sect.size());
+ MemoryRegion dyn_region = pOutput.request(dyn_sect.offset(),
+ dyn_sect.size());
// set up symtab_region
llvm::ELF::Elf32_Sym* symtab32 = NULL;
llvm::ELF::Elf64_Sym* symtab64 = NULL;
if (config().targets().is32Bits())
- symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region->start();
+ symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region.begin();
else if (config().targets().is64Bits())
- symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region->start();
+ symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region.begin();
else {
fatal(diag::unsupported_bitclass) << config().targets().triple().str()
<< config().targets().bitclass();
}
// set up strtab_region
- char* strtab = (char*)strtab_region->start();
+ char* strtab = (char*)strtab_region.begin();
// emit the first ELF symbol
if (config().targets().is32Bits())
@@ -1121,28 +1139,28 @@
dynamic().applySoname(strtabsize);
}
dynamic().applyEntries(*file_format);
- dynamic().emit(dyn_sect, *dyn_region);
+ dynamic().emit(dyn_sect, dyn_region);
// emit soname
if (LinkerConfig::DynObj == config().codeGenType()) {
- strcpy((strtab + strtabsize), pModule.name().c_str());
- strtabsize += pModule.name().size() + 1;
+ strcpy((strtab + strtabsize), config().options().soname().c_str());
+ strtabsize += config().options().soname().size() + 1;
}
}
/// emitELFHashTab - emit .hash
void GNULDBackend::emitELFHashTab(const Module::SymbolTable& pSymtab,
- MemoryArea& pOutput)
+ FileOutputBuffer& pOutput)
{
ELFFileFormat* file_format = getOutputFormat();
if (!file_format->hasHashTab())
return;
LDSection& hash_sect = file_format->getHashTab();
- MemoryRegion* hash_region = pOutput.request(hash_sect.offset(),
- hash_sect.size());
+ MemoryRegion hash_region = pOutput.request(hash_sect.offset(),
+ hash_sect.size());
// both 32 and 64 bits hash table use 32-bit entry
// set up hash_region
- uint32_t* word_array = (uint32_t*)hash_region->start();
+ uint32_t* word_array = (uint32_t*)hash_region.begin();
uint32_t& nbucket = word_array[0];
uint32_t& nchain = word_array[1];
@@ -1171,17 +1189,17 @@
/// emitGNUHashTab - emit .gnu.hash
void GNULDBackend::emitGNUHashTab(Module::SymbolTable& pSymtab,
- MemoryArea& pOutput)
+ FileOutputBuffer& pOutput)
{
ELFFileFormat* file_format = getOutputFormat();
if (!file_format->hasGNUHashTab())
return;
- MemoryRegion* gnuhash_region =
+ MemoryRegion gnuhash_region =
pOutput.request(file_format->getGNUHashTab().offset(),
file_format->getGNUHashTab().size());
- uint32_t* word_array = (uint32_t*)gnuhash_region->start();
+ uint32_t* word_array = (uint32_t*)gnuhash_region.begin();
// fixed-length fields
uint32_t& nbucket = word_array[0];
uint32_t& symidx = word_array[1];
@@ -1309,18 +1327,18 @@
}
/// emitInterp - emit the .interp
-void GNULDBackend::emitInterp(MemoryArea& pOutput)
+void GNULDBackend::emitInterp(FileOutputBuffer& pOutput)
{
if (getOutputFormat()->hasInterp()) {
const LDSection& interp = getOutputFormat()->getInterp();
- MemoryRegion *region = pOutput.request(interp.offset(), interp.size());
+ MemoryRegion region = pOutput.request(interp.offset(), interp.size());
const char* dyld_name;
if (config().options().hasDyld())
dyld_name = config().options().dyld().c_str();
else
dyld_name = m_pInfo->dyld();
- std::memcpy(region->start(), dyld_name, interp.size());
+ std::memcpy(region.begin(), dyld_name, interp.size());
}
}
@@ -1349,7 +1367,7 @@
// NULL section should be the "1st" section
if (LDFileFormat::Null == pSectHdr.kind())
- return 0;
+ return SHO_NULL;
if (&pSectHdr == &file_format->getStrTab())
return SHO_STRTAB;
@@ -1493,15 +1511,6 @@
if (pSymbol.resolveInfo()->isUndef() || pSymbol.isDyn())
return llvm::ELF::SHN_UNDEF;
- if (pSymbol.resolveInfo()->isLocal() &&
- LinkerConfig::Object != config().codeGenType()) {
- switch (pSymbol.type()) {
- case ResolveInfo::NoType:
- case ResolveInfo::File:
- return llvm::ELF::SHN_ABS;
- }
- }
-
if (pSymbol.resolveInfo()->isDefine() && !pSymbol.hasFragRef())
return llvm::ELF::SHN_ABS;
@@ -1598,18 +1607,19 @@
// description here.
(*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
Fragment* frag = new FillFragment(0x0, 1, (*com_sym)->size());
- (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
// allocate TLS common symbol in tbss section
tbss_offset += ObjectBuilder::AppendFragment(*frag,
*tbss_sect_data,
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
}
else {
bss_offset += ObjectBuilder::AppendFragment(*frag,
*bss_sect_data,
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
}
}
}
@@ -1624,18 +1634,19 @@
// description here.
(*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
Fragment* frag = new FillFragment(0x0, 1, (*com_sym)->size());
- (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
// allocate TLS common symbol in tbss section
tbss_offset += ObjectBuilder::AppendFragment(*frag,
*tbss_sect_data,
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
}
else {
bss_offset += ObjectBuilder::AppendFragment(*frag,
*bss_sect_data,
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
}
}
@@ -1670,35 +1681,177 @@
return true;
}
+/// readRelocation - read ELF32_Rel entry
+bool GNULDBackend::readRelocation(const llvm::ELF::Elf32_Rel& pRel,
+ Relocation::Type& pType,
+ uint32_t& pSymIdx,
+ uint32_t& pOffset) const
+{
+ uint32_t r_info = 0x0;
+ if (llvm::sys::IsLittleEndianHost) {
+ pOffset = pRel.r_offset;
+ r_info = pRel.r_info;
+ }
+ else {
+ pOffset = mcld::bswap32(pRel.r_offset);
+ r_info = mcld::bswap32(pRel.r_info);
+ }
+
+ pType = static_cast<unsigned char>(r_info);
+ pSymIdx = (r_info >> 8);
+ return true;
+}
+
+/// readRelocation - read ELF32_Rela entry
+bool GNULDBackend::readRelocation(const llvm::ELF::Elf32_Rela& pRel,
+ Relocation::Type& pType,
+ uint32_t& pSymIdx,
+ uint32_t& pOffset,
+ int32_t& pAddend) const
+{
+ uint32_t r_info = 0x0;
+ if (llvm::sys::IsLittleEndianHost) {
+ pOffset = pRel.r_offset;
+ r_info = pRel.r_info;
+ pAddend = pRel.r_addend;
+ }
+ else {
+ pOffset = mcld::bswap32(pRel.r_offset);
+ r_info = mcld::bswap32(pRel.r_info);
+ pAddend = mcld::bswap32(pRel.r_addend);
+ }
+
+ pType = static_cast<unsigned char>(r_info);
+ pSymIdx = (r_info >> 8);
+ return true;
+}
+
+/// readRelocation - read ELF64_Rel entry
+bool GNULDBackend::readRelocation(const llvm::ELF::Elf64_Rel& pRel,
+ Relocation::Type& pType,
+ uint32_t& pSymIdx,
+ uint64_t& pOffset) const
+{
+ uint64_t r_info = 0x0;
+ if (llvm::sys::IsLittleEndianHost) {
+ pOffset = pRel.r_offset;
+ r_info = pRel.r_info;
+ }
+ else {
+ pOffset = mcld::bswap64(pRel.r_offset);
+ r_info = mcld::bswap64(pRel.r_info);
+ }
+
+ pType = static_cast<uint32_t>(r_info);
+ pSymIdx = (r_info >> 32);
+ return true;
+}
+
+/// readRel - read ELF64_Rela entry
+bool GNULDBackend::readRelocation(const llvm::ELF::Elf64_Rela& pRel,
+ Relocation::Type& pType,
+ uint32_t& pSymIdx,
+ uint64_t& pOffset,
+ int64_t& pAddend) const
+{
+ uint64_t r_info = 0x0;
+ if (llvm::sys::IsLittleEndianHost) {
+ pOffset = pRel.r_offset;
+ r_info = pRel.r_info;
+ pAddend = pRel.r_addend;
+ }
+ else {
+ pOffset = mcld::bswap64(pRel.r_offset);
+ r_info = mcld::bswap64(pRel.r_info);
+ pAddend = mcld::bswap64(pRel.r_addend);
+ }
+
+ pType = static_cast<uint32_t>(r_info);
+ pSymIdx = (r_info >> 32);
+ return true;
+}
+
+/// emitRelocation - write data to the ELF32_Rel entry
+void GNULDBackend::emitRelocation(llvm::ELF::Elf32_Rel& pRel,
+ Relocation::Type pType,
+ uint32_t pSymIdx,
+ uint32_t pOffset) const
+{
+ pRel.r_offset = pOffset;
+ pRel.setSymbolAndType(pSymIdx, pType);
+}
+
+/// emitRelocation - write data to the ELF32_Rela entry
+void GNULDBackend::emitRelocation(llvm::ELF::Elf32_Rela& pRel,
+ Relocation::Type pType,
+ uint32_t pSymIdx,
+ uint32_t pOffset,
+ int32_t pAddend) const
+{
+ pRel.r_offset = pOffset;
+ pRel.r_addend = pAddend;
+ pRel.setSymbolAndType(pSymIdx, pType);
+}
+
+/// emitRelocation - write data to the ELF64_Rel entry
+void GNULDBackend::emitRelocation(llvm::ELF::Elf64_Rel& pRel,
+ Relocation::Type pType,
+ uint32_t pSymIdx,
+ uint64_t pOffset) const
+{
+ pRel.r_offset = pOffset;
+ pRel.setSymbolAndType(pSymIdx, pType);
+}
+
+/// emitRelocation - write data to the ELF64_Rela entry
+void GNULDBackend::emitRelocation(llvm::ELF::Elf64_Rela& pRel,
+ Relocation::Type pType,
+ uint32_t pSymIdx,
+ uint64_t pOffset,
+ int64_t pAddend) const
+{
+ pRel.r_offset = pOffset;
+ pRel.r_addend = pAddend;
+ pRel.setSymbolAndType(pSymIdx, pType);
+}
+
/// createProgramHdrs - base on output sections to create the program headers
void GNULDBackend::createProgramHdrs(Module& pModule)
{
ELFFileFormat *file_format = getOutputFormat();
- // make PT_PHDR
- m_ELFSegmentTable.produce(llvm::ELF::PT_PHDR);
-
// make PT_INTERP
if (file_format->hasInterp()) {
- ELFSegment* interp_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_INTERP);
- interp_seg->addSection(&file_format->getInterp());
+ // make PT_PHDR
+ elfSegmentTable().produce(llvm::ELF::PT_PHDR);
+
+ ELFSegment* interp_seg = elfSegmentTable().produce(llvm::ELF::PT_INTERP);
+ interp_seg->append(&file_format->getInterp());
}
- uint32_t cur_flag, prev_flag = getSegmentFlag(0);
+ uint32_t cur_flag, prev_flag = 0x0;
ELFSegment* load_seg = NULL;
// make possible PT_LOAD segments
- LinkerScript::AddressMap::iterator addrEnd
- = pModule.getScript().addressMap().end();
- Module::iterator sect, sect_end = pModule.end();
- for (sect = pModule.begin(); sect != sect_end; ++sect) {
+ LinkerScript& ldscript = pModule.getScript();
+ LinkerScript::AddressMap::iterator addrEnd= ldscript.addressMap().end();
+ SectionMap::iterator out, prev, outBegin, outEnd;
+ outBegin = ldscript.sectionMap().begin();
+ outEnd = ldscript.sectionMap().end();
+ for (out = outBegin, prev = outEnd; out != outEnd; prev = out, ++out) {
+ LDSection* sect = (*out)->getSection();
- if (0 == ((*sect)->flag() & llvm::ELF::SHF_ALLOC) &&
- LDFileFormat::Null != (*sect)->kind())
+ if (0 == (sect->flag() & llvm::ELF::SHF_ALLOC) &&
+ LDFileFormat::Null != sect->kind())
+ break;
+
+ // bypass empty sections
+ if (!(*out)->hasContent() &&
+ (*out)->getSection()->kind() != LDFileFormat::Null)
continue;
- cur_flag = getSegmentFlag((*sect)->flag());
+ cur_flag = getSegmentFlag(sect->flag());
bool createPT_LOAD = false;
- if (LDFileFormat::Null == (*sect)->kind()) {
+ if (LDFileFormat::Null == sect->kind()) {
// 1. create text segment
createPT_LOAD = true;
}
@@ -1707,31 +1860,35 @@
// 2. create data segment if w/o omagic set
createPT_LOAD = true;
}
- else if ((*sect)->kind() == LDFileFormat::BSS &&
+ else if (sect->kind() == LDFileFormat::BSS &&
load_seg->isDataSegment() &&
- addrEnd != pModule.getScript().addressMap().find(".bss")) {
+ addrEnd != ldscript.addressMap().find(".bss")) {
// 3. create bss segment if w/ -Tbss and there is a data segment
createPT_LOAD = true;
}
- else {
- if ((*sect != &(file_format->getText())) &&
- (*sect != &(file_format->getData())) &&
- (*sect != &(file_format->getBSS())) &&
- (addrEnd != pModule.getScript().addressMap().find((*sect)->name())))
- // 4. create PT_LOAD for sections in address map except for text, data,
- // and bss
- createPT_LOAD = true;
+ else if ((sect != &(file_format->getText())) &&
+ (sect != &(file_format->getData())) &&
+ (sect != &(file_format->getBSS())) &&
+ (addrEnd != ldscript.addressMap().find(sect->name()))) {
+ // 4. create PT_LOAD for sections in address map except for text, data,
+ // and bss
+ createPT_LOAD = true;
+ }
+ else if (LDFileFormat::Null == (*prev)->getSection()->kind() &&
+ !config().options().getScriptList().empty()) {
+ // 5. create PT_LOAD to hold NULL section if there is a default ldscript
+ createPT_LOAD = true;
}
if (createPT_LOAD) {
// create new PT_LOAD segment
- load_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_LOAD, cur_flag);
+ load_seg = elfSegmentTable().produce(llvm::ELF::PT_LOAD, cur_flag);
if (!config().options().nmagic() && !config().options().omagic())
load_seg->setAlign(abiPageSize());
}
assert(NULL != load_seg);
- load_seg->addSection((*sect));
+ load_seg->append(sect);
if (cur_flag != prev_flag)
load_seg->updateFlag(cur_flag);
@@ -1740,27 +1897,27 @@
// make PT_DYNAMIC
if (file_format->hasDynamic()) {
- ELFSegment* dyn_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_DYNAMIC,
+ ELFSegment* dyn_seg = elfSegmentTable().produce(llvm::ELF::PT_DYNAMIC,
llvm::ELF::PF_R |
llvm::ELF::PF_W);
- dyn_seg->addSection(&file_format->getDynamic());
+ dyn_seg->append(&file_format->getDynamic());
}
if (config().options().hasRelro()) {
// make PT_GNU_RELRO
- ELFSegment* relro_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_GNU_RELRO);
+ ELFSegment* relro_seg = elfSegmentTable().produce(llvm::ELF::PT_GNU_RELRO);
for (ELFSegmentFactory::iterator seg = elfSegmentTable().begin(),
- segEnd = elfSegmentTable().end(); seg != segEnd; ++seg) {
- if (llvm::ELF::PT_LOAD != (*seg).type())
+ segEnd = elfSegmentTable().end(); seg != segEnd; ++seg) {
+ if (llvm::ELF::PT_LOAD != (*seg)->type())
continue;
- for (ELFSegment::sect_iterator sect = (*seg).begin(),
- sectEnd = (*seg).end(); sect != sectEnd; ++sect) {
+ for (ELFSegment::iterator sect = (*seg)->begin(),
+ sectEnd = (*seg)->end(); sect != sectEnd; ++sect) {
unsigned int order = getSectionOrder(**sect);
if (SHO_RELRO_LOCAL == order ||
SHO_RELRO == order ||
SHO_RELRO_LAST == order) {
- relro_seg->addSection(*sect);
+ relro_seg->append(*sect);
}
}
}
@@ -1768,22 +1925,22 @@
// make PT_GNU_EH_FRAME
if (file_format->hasEhFrameHdr()) {
- ELFSegment* eh_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_GNU_EH_FRAME);
- eh_seg->addSection(&file_format->getEhFrameHdr());
+ ELFSegment* eh_seg = elfSegmentTable().produce(llvm::ELF::PT_GNU_EH_FRAME);
+ eh_seg->append(&file_format->getEhFrameHdr());
}
// make PT_TLS
if (file_format->hasTData() || file_format->hasTBSS()) {
- ELFSegment* tls_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_TLS);
+ ELFSegment* tls_seg = elfSegmentTable().produce(llvm::ELF::PT_TLS);
if (file_format->hasTData())
- tls_seg->addSection(&file_format->getTData());
+ tls_seg->append(&file_format->getTData());
if (file_format->hasTBSS())
- tls_seg->addSection(&file_format->getTBSS());
+ tls_seg->append(&file_format->getTBSS());
}
// make PT_GNU_STACK
if (file_format->hasStackNote()) {
- m_ELFSegmentTable.produce(llvm::ELF::PT_GNU_STACK,
+ elfSegmentTable().produce(llvm::ELF::PT_GNU_STACK,
llvm::ELF::PF_R |
llvm::ELF::PF_W |
getSegmentFlag(file_format->getStackNote().flag()));
@@ -1791,9 +1948,12 @@
// make PT_NOTE
ELFSegment *note_seg = NULL;
- prev_flag = getSegmentFlag(0);
- for (sect = pModule.begin(); sect != sect_end; ++sect) {
- if ((*sect)->kind() != LDFileFormat::Note ||
+ prev_flag = 0x0;
+ Module::iterator sect, sectBegin, sectEnd;
+ sectBegin = pModule.begin();
+ sectEnd = pModule.end();
+ for (sect = sectBegin; sect != sectEnd; ++sect) {
+ if ((*sect)->type() != llvm::ELF::SHT_NOTE ||
((*sect)->flag() & llvm::ELF::SHF_ALLOC) == 0)
continue;
@@ -1802,9 +1962,9 @@
// create 2 segments if needed.
if (note_seg == NULL ||
(cur_flag & llvm::ELF::PF_W) != (prev_flag & llvm::ELF::PF_W))
- note_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_NOTE, cur_flag);
+ note_seg = elfSegmentTable().produce(llvm::ELF::PT_NOTE, cur_flag);
- note_seg->addSection(*sect);
+ note_seg->append(*sect);
prev_flag = cur_flag;
}
@@ -1816,54 +1976,151 @@
void GNULDBackend::setupProgramHdrs(const LinkerScript& pScript)
{
// update segment info
- uint64_t seg_start_addr = getSegmentStartAddr(pScript);
- ELFSegmentFactory::iterator seg, seg_end = m_ELFSegmentTable.end();
- for (seg = m_ELFSegmentTable.begin(); seg != seg_end; ++seg) {
- ELFSegment& segment = *seg;
+ for (ELFSegmentFactory::iterator seg = elfSegmentTable().begin(),
+ segEnd = elfSegmentTable().end(); seg != segEnd; ++seg) {
- // update PT_PHDR
- if (llvm::ELF::PT_PHDR == segment.type()) {
- uint64_t offset = 0, phdr_size = 0;
+ // bypass if there is no section in this segment (e.g., PT_GNU_STACK)
+ if ((*seg)->size() == 0)
+ continue;
+
+ // bypass the PT_LOAD that only has NULL section now
+ if ((*seg)->type() == llvm::ELF::PT_LOAD &&
+ (*seg)->front()->kind() == LDFileFormat::Null &&
+ (*seg)->size() == 1)
+ continue;
+
+ (*seg)->setOffset((*seg)->front()->offset());
+ if ((*seg)->type() == llvm::ELF::PT_LOAD &&
+ (*seg)->front()->kind() == LDFileFormat::Null) {
+ const LDSection* second = *((*seg)->begin() + 1);
+ assert(second != NULL);
+ (*seg)->setVaddr(second->addr() - second->offset());
+ } else {
+ (*seg)->setVaddr((*seg)->front()->addr());
+ }
+ (*seg)->setPaddr((*seg)->vaddr());
+
+ ELFSegment::reverse_iterator sect, sectREnd = (*seg)->rend();
+ for (sect = (*seg)->rbegin(); sect != sectREnd; ++sect) {
+ if ((*sect)->kind() != LDFileFormat::BSS)
+ break;
+ }
+ if (sect != sectREnd) {
+ (*seg)->setFilesz((*sect)->offset() +
+ (*sect)->size() -
+ (*seg)->offset());
+ } else {
+ (*seg)->setFilesz(0x0);
+ }
+
+ (*seg)->setMemsz((*seg)->back()->addr() +
+ (*seg)->back()->size() -
+ (*seg)->vaddr());
+ } // end of for
+
+ // handle the case if text segment only has NULL section
+ LDSection* null_sect = &getOutputFormat()->getNULLSection();
+ ELFSegmentFactory::iterator null_seg =
+ elfSegmentTable().find(llvm::ELF::PT_LOAD, null_sect);
+
+ if ((*null_seg)->size() == 1) {
+ // find 2nd PT_LOAD
+ ELFSegmentFactory::iterator seg, segEnd = elfSegmentTable().end();
+ for (seg = null_seg + 1; seg != segEnd; ++seg) {
+ if ((*seg)->type() == llvm::ELF::PT_LOAD)
+ break;
+ }
+ if (seg != segEnd) {
+ uint64_t addr = (*seg)->front()->addr() - (*seg)->front()->offset();
+ uint64_t size = sectionStartOffset();
+ if (addr + size == (*seg)->front()->addr()) {
+ // if there is no space between the 2 segments, we can merge them.
+ (*seg)->setOffset(0x0);
+ (*seg)->setVaddr(addr);
+ (*seg)->setPaddr(addr);
+
+ ELFSegment::iterator sect, sectEnd = (*seg)->end();
+ for (sect = (*seg)->begin(); sect != sectEnd; ++sect) {
+ if ((*sect)->kind() == LDFileFormat::BSS) {
+ --sect;
+ break;
+ }
+ }
+ if (sect == sectEnd) {
+ (*seg)->setFilesz((*seg)->back()->offset() +
+ (*seg)->back()->size() -
+ (*seg)->offset());
+ } else if (*sect != (*seg)->front()) {
+ --sect;
+ (*seg)->setFilesz((*sect)->offset() +
+ (*sect)->size() -
+ (*seg)->offset());
+ } else {
+ (*seg)->setFilesz(0x0);
+ }
+
+ (*seg)->setMemsz((*seg)->back()->addr() +
+ (*seg)->back()->size() -
+ (*seg)->vaddr());
+
+ (*seg)->insert((*seg)->begin(), null_sect);
+ elfSegmentTable().erase(null_seg);
+
+ } else if (addr + size < (*seg)->vaddr()) {
+ (*null_seg)->setOffset(0x0);
+ (*null_seg)->setVaddr(addr);
+ (*null_seg)->setPaddr(addr);
+ (*null_seg)->setFilesz(size);
+ (*null_seg)->setMemsz(size);
+ } else {
+ // erase the non valid segment contains NULL.
+ elfSegmentTable().erase(null_seg);
+ }
+ }
+ }
+
+ // set up PT_PHDR
+ ELFSegmentFactory::iterator phdr =
+ elfSegmentTable().find(llvm::ELF::PT_PHDR, llvm::ELF::PF_R, 0x0);
+
+ if (phdr != elfSegmentTable().end()) {
+ ELFSegmentFactory::iterator null_seg =
+ elfSegmentTable().find(llvm::ELF::PT_LOAD, null_sect);
+ if (null_seg != elfSegmentTable().end()) {
+ uint64_t offset = 0x0, phdr_size = 0x0;
if (config().targets().is32Bits()) {
offset = sizeof(llvm::ELF::Elf32_Ehdr);
phdr_size = sizeof(llvm::ELF::Elf32_Phdr);
- }
- else {
+ } else {
offset = sizeof(llvm::ELF::Elf64_Ehdr);
phdr_size = sizeof(llvm::ELF::Elf64_Phdr);
}
- segment.setOffset(offset);
- segment.setVaddr(seg_start_addr + offset);
- segment.setPaddr(segment.vaddr());
- segment.setFilesz(numOfSegments() * phdr_size);
- segment.setMemsz(numOfSegments() * phdr_size);
- segment.setAlign(config().targets().bitclass() / 8);
- continue;
+ (*phdr)->setOffset(offset);
+ (*phdr)->setVaddr((*null_seg)->vaddr() + offset);
+ (*phdr)->setPaddr((*phdr)->vaddr());
+ (*phdr)->setFilesz(elfSegmentTable().size() * phdr_size);
+ (*phdr)->setMemsz(elfSegmentTable().size() * phdr_size);
+ (*phdr)->setAlign(config().targets().bitclass() / 8);
+ } else {
+ elfSegmentTable().erase(phdr);
}
-
- // bypass if there is no section in this segment (e.g., PT_GNU_STACK)
- if (segment.numOfSections() == 0)
- continue;
-
- segment.setOffset(segment.front()->offset());
- if (llvm::ELF::PT_LOAD == segment.type() &&
- LDFileFormat::Null == segment.front()->kind())
- segment.setVaddr(seg_start_addr);
- else
- segment.setVaddr(segment.front()->addr());
- segment.setPaddr(segment.vaddr());
-
- const LDSection* last_sect = segment.back();
- assert(NULL != last_sect);
- uint64_t file_size = last_sect->offset() - segment.offset();
- if (LDFileFormat::BSS != last_sect->kind())
- file_size += last_sect->size();
- segment.setFilesz(file_size);
-
- segment.setMemsz(last_sect->addr() - segment.vaddr() + last_sect->size());
}
}
+/// getSegmentFlag - give a section flag and return the corresponding segment
+/// flag
+uint32_t GNULDBackend::getSegmentFlag(const uint32_t pSectionFlag)
+{
+ uint32_t flag = 0x0;
+ if ((pSectionFlag & llvm::ELF::SHF_ALLOC) != 0x0)
+ flag |= llvm::ELF::PF_R;
+ if ((pSectionFlag & llvm::ELF::SHF_WRITE) != 0x0)
+ flag |= llvm::ELF::PF_W;
+ if ((pSectionFlag & llvm::ELF::SHF_EXECINSTR) != 0x0)
+ flag |= llvm::ELF::PF_X;
+ return flag;
+}
+
/// setupGNUStackInfo - setup the section flag of .note.GNU-stack in output
/// @ref gold linker: layout.cc:2608
void GNULDBackend::setupGNUStackInfo(Module& pModule)
@@ -1910,203 +2167,249 @@
}
}
-/// setupRelro - setup the offset constraint of PT_RELRO
-void GNULDBackend::setupRelro(Module& pModule)
+/// setOutputSectionOffset - helper function to set output sections' offset.
+void GNULDBackend::setOutputSectionOffset(Module& pModule)
{
- assert(config().options().hasRelro());
- // if -z relro is given, we need to adjust sections' offset again, and let
- // PT_GNU_RELRO end on a common page boundary
-
- Module::iterator sect = pModule.begin();
- for (Module::iterator sect_end = pModule.end(); sect != sect_end; ++sect) {
- // find the first non-relro section
- if (getSectionOrder(**sect) > SHO_RELRO_LAST)
- break;
- }
-
- // align the first non-relro section to page boundary
- uint64_t offset = (*sect)->offset();
- alignAddress(offset, commonPageSize());
- (*sect)->setOffset(offset);
-
- // It seems that compiler think .got and .got.plt are continuous (w/o any
- // padding between). If .got is the last section in PT_RELRO and it's not
- // continuous to its next section (i.e. .got.plt), we need to add padding
- // in front of .got instead.
- // FIXME: Maybe we can handle this in a more general way.
- LDSection& got = getOutputFormat()->getGOT();
- if ((getSectionOrder(got) == SHO_RELRO_LAST) &&
- (got.offset() + got.size() != offset)) {
- got.setOffset(offset - got.size());
- }
-
- // set up remaining section's offset
- setOutputSectionOffset(pModule, ++sect, pModule.end());
-}
-
-/// setOutputSectionOffset - helper function to set a group of output sections'
-/// offset, and set pSectBegin to pStartOffset if pStartOffset is not -1U.
-void GNULDBackend::setOutputSectionOffset(Module& pModule,
- Module::iterator pSectBegin,
- Module::iterator pSectEnd,
- uint64_t pStartOffset)
-{
- if (pSectBegin == pModule.end())
- return;
-
- assert(pSectEnd == pModule.end() ||
- (pSectEnd != pModule.end() &&
- (*pSectBegin)->index() <= (*pSectEnd)->index()));
-
- if (pStartOffset != -1U) {
- (*pSectBegin)->setOffset(pStartOffset);
- ++pSectBegin;
- }
-
- // set up the "cur" and "prev" iterator
- Module::iterator cur = pSectBegin;
- Module::iterator prev = pSectBegin;
- if (cur != pModule.begin())
- --prev;
- else
- ++cur;
-
- for (; cur != pSectEnd; ++cur, ++prev) {
- uint64_t offset = 0x0;
- switch ((*prev)->kind()) {
- case LDFileFormat::Null:
- offset = sectionStartOffset();
- break;
- case LDFileFormat::BSS:
- offset = (*prev)->offset();
- break;
- default:
- offset = (*prev)->offset() + (*prev)->size();
- break;
- }
-
- alignAddress(offset, (*cur)->align());
- (*cur)->setOffset(offset);
- }
-}
-
-/// setOutputSectionOffset - helper function to set output sections' address
-void GNULDBackend::setOutputSectionAddress(Module& pModule,
- Module::iterator pSectBegin,
- Module::iterator pSectEnd)
-{
- if (pSectBegin == pModule.end())
- return;
-
- assert(pSectEnd == pModule.end() ||
- (pSectEnd != pModule.end() &&
- (*pSectBegin)->index() <= (*pSectEnd)->index()));
-
- const LinkerScript& script = pModule.getScript();
- uint64_t seg_start_addr = getSegmentStartAddr(script);
- for (ELFSegmentFactory::iterator seg = elfSegmentTable().begin(),
- segEnd = elfSegmentTable().end(), prev = elfSegmentTable().end();
- seg != segEnd; prev = seg, ++seg) {
- if (llvm::ELF::PT_LOAD != (*seg).type())
+ LinkerScript& script = pModule.getScript();
+ uint64_t offset = 0x0;
+ LDSection* cur = NULL;
+ LDSection* prev = NULL;
+ SectionMap::iterator out, outBegin, outEnd;
+ outBegin = script.sectionMap().begin();
+ outEnd = script.sectionMap().end();
+ for (out = outBegin; out != outEnd; ++out, prev = cur) {
+ cur = (*out)->getSection();
+ if (cur->kind() == LDFileFormat::Null) {
+ cur->setOffset(0x0);
continue;
+ }
- uint64_t start_addr = 0x0;
- LinkerScript::AddressMap::const_iterator mapping;
- if ((*seg).front()->kind() == LDFileFormat::Null)
- mapping = script.addressMap().find(".text");
- else if ((*seg).isDataSegment())
- mapping = script.addressMap().find(".data");
- else if ((*seg).isBssSegment())
- mapping = script.addressMap().find(".bss");
- else
- mapping = script.addressMap().find((*seg).front()->name());
+ switch (prev->kind()) {
+ case LDFileFormat::Null:
+ offset = sectionStartOffset();
+ break;
+ case LDFileFormat::BSS:
+ offset = prev->offset();
+ break;
+ default:
+ offset = prev->offset() + prev->size();
+ break;
+ }
+ alignAddress(offset, cur->align());
+ cur->setOffset(offset);
+ }
+}
- if (mapping != script.addressMap().end()) {
+/// setOutputSectionAddress - helper function to set output sections' address.
+void GNULDBackend::setOutputSectionAddress(Module& pModule)
+{
+ RpnEvaluator evaluator(pModule, *this);
+ LinkerScript& script = pModule.getScript();
+ uint64_t vma = 0x0, offset = 0x0;
+ LDSection* cur = NULL;
+ LDSection* prev = NULL;
+ LinkerScript::AddressMap::iterator addr, addrEnd = script.addressMap().end();
+ ELFSegmentFactory::iterator seg, segEnd = elfSegmentTable().end();
+ SectionMap::Output::dot_iterator dot;
+ SectionMap::iterator out, outBegin, outEnd;
+ outBegin = script.sectionMap().begin();
+ outEnd = script.sectionMap().end();
+ for (out = outBegin; out != outEnd; prev = cur, ++out) {
+ cur = (*out)->getSection();
+
+ if (cur->kind() == LDFileFormat::Null) {
+ cur->setOffset(0x0);
+ continue;
+ }
+
+ // process dot assignments between 2 output sections
+ for (SectionMap::Output::dot_iterator it = (*out)->dot_begin(),
+ ie = (*out)->dot_end(); it != ie; ++it) {
+ (*it).assign(evaluator);
+ }
+
+ seg = elfSegmentTable().find(llvm::ELF::PT_LOAD, cur);
+ if (seg != segEnd && cur == (*seg)->front()) {
+ if ((*seg)->isBssSegment())
+ addr = script.addressMap().find(".bss");
+ else if ((*seg)->isDataSegment())
+ addr = script.addressMap().find(".data");
+ else
+ addr = script.addressMap().find(cur->name());
+ } else
+ addr = addrEnd;
+
+ if (addr != addrEnd) {
// use address mapping in script options
- start_addr = mapping.getEntry()->value();
- }
- else {
- if ((*seg).front()->kind() == LDFileFormat::Null) {
- // 1st PT_LOAD
- start_addr = seg_start_addr;
+ vma = addr.getEntry()->value();
+ } else if ((*out)->prolog().hasVMA()) {
+ // use address from output section description
+ evaluator.eval((*out)->prolog().vma(), vma);
+ } else if ((dot = (*out)->find_last_explicit_dot()) != (*out)->dot_end()) {
+ // assign address based on `.' symbol in ldscript
+ vma = (*dot).symbol().value();
+ alignAddress(vma, cur->align());
+ } else {
+ if ((*out)->prolog().type() == OutputSectDesc::NOLOAD) {
+ vma = prev->addr() + prev->size();
+ } else if ((cur->flag() & llvm::ELF::SHF_ALLOC) != 0) {
+ if (prev->kind() == LDFileFormat::Null) {
+ // Let SECTIONS starts at 0 if we have a default ldscript but don't
+ // have any initial value (VMA or `.').
+ if (!config().options().getScriptList().empty())
+ vma = 0x0;
+ else
+ vma = getSegmentStartAddr(script) + sectionStartOffset();
+ } else {
+ if ((prev->kind() == LDFileFormat::BSS))
+ vma = prev->addr();
+ else
+ vma = prev->addr() + prev->size();
+ }
+ alignAddress(vma, cur->align());
+ if (config().options().getScriptList().empty()) {
+ if (seg != segEnd && cur == (*seg)->front()) {
+ // Try to align p_vaddr at page boundary if not in script options.
+ // To do so will add more padding in file, but can save one page
+ // at runtime.
+ alignAddress(vma, (*seg)->align());
+ }
+ }
+ } else {
+ vma = 0x0;
}
- else if ((*prev).front()->kind() == LDFileFormat::Null) {
- // prev segment is 1st PT_LOAD
- start_addr = seg_start_addr + (*seg).front()->offset();
- }
- else {
- // Others
- start_addr = (*prev).front()->addr() + (*seg).front()->offset();
- }
- // Try to align p_vaddr at page boundary if not in script options.
- // To do so will add more padding in file, but can save one page
- // at runtime.
- alignAddress(start_addr, (*seg).align());
}
+ if (config().options().hasRelro()) {
+ // if -z relro is given, we need to adjust sections' offset again, and
+ // let PT_GNU_RELRO end on a abi page boundary
+
+ // check if current is the first non-relro section
+ SectionMap::iterator relro_last = out - 1;
+ if (relro_last != outEnd &&
+ (*relro_last)->order() <= SHO_RELRO_LAST &&
+ (*out)->order() > SHO_RELRO_LAST) {
+ // align the first non-relro section to page boundary
+ alignAddress(vma, abiPageSize());
+
+ // It seems that compiler think .got and .got.plt are continuous (w/o
+ // any padding between). If .got is the last section in PT_RELRO and
+ // it's not continuous to its next section (i.e. .got.plt), we need to
+ // add padding in front of .got instead.
+ // FIXME: Maybe we can handle this in a more general way.
+ LDSection& got = getOutputFormat()->getGOT();
+ if ((getSectionOrder(got) == SHO_RELRO_LAST) &&
+ (got.addr() + got.size() < vma)) {
+ uint64_t diff = vma - got.addr() - got.size();
+ got.setAddr(vma - got.size());
+ got.setOffset(got.offset() + diff);
+ }
+ }
+ } // end of if - for relro processing
+
+ cur->setAddr(vma);
+
+ switch (prev->kind()) {
+ case LDFileFormat::Null:
+ offset = sectionStartOffset();
+ break;
+ case LDFileFormat::BSS:
+ offset = prev->offset();
+ break;
+ default:
+ offset = prev->offset() + prev->size();
+ break;
+ }
+ alignAddress(offset, cur->align());
// in p75, http://www.sco.com/developers/devspecs/gabi41.pdf
// p_align: As "Program Loading" describes in this chapter of the
// processor supplement, loadable process segments must have congruent
// values for p_vaddr and p_offset, modulo the page size.
- if ((start_addr & ((*seg).align() - 1)) !=
- ((*seg).front()->offset() & ((*seg).align() - 1))) {
- uint64_t padding = (*seg).align() +
- (start_addr & ((*seg).align() - 1)) -
- ((*seg).front()->offset() & ((*seg).align() - 1));
- setOutputSectionOffset(pModule,
- pModule.begin() + (*seg).front()->index(),
- pModule.end(),
- (*seg).front()->offset() + padding);
- if (config().options().hasRelro())
- setupRelro(pModule);
+ // FIXME: Now make all sh_addr and sh_offset are congruent, modulo the page
+ // size. Otherwise, old objcopy (e.g., binutils 2.17) may fail with our
+ // output!
+ if ((cur->flag() & llvm::ELF::SHF_ALLOC) != 0 &&
+ (vma & (abiPageSize() - 1)) != (offset & (abiPageSize() - 1))) {
+ uint64_t padding = abiPageSize() +
+ (vma & (abiPageSize() - 1)) -
+ (offset & (abiPageSize() - 1));
+ offset += padding;
}
- for (ELFSegment::sect_iterator sect = (*seg).begin(),
- sectEnd = (*seg).end(); sect != sectEnd; ++sect) {
- if ((*sect)->index() < (*pSectBegin)->index())
- continue;
+ cur->setOffset(offset);
- if (LDFileFormat::Null == (*sect)->kind())
- continue;
+ // process dot assignments in the output section
+ bool changed = false;
+ Fragment* invalid = NULL;
+ for (SectionMap::Output::iterator in = (*out)->begin(),
+ inEnd = (*out)->end(); in != inEnd; ++in) {
- if (sect == pSectEnd)
- return;
+ if (invalid != NULL && !(*in)->dotAssignments().empty()) {
+ while (invalid != (*in)->dotAssignments().front().first) {
+ Fragment* prev = invalid->getPrevNode();
+ invalid->setOffset(prev->getOffset() + prev->size());
+ invalid = invalid->getNextNode();
+ }
+ invalid = NULL;
+ }
- if (sect != (*seg).begin())
- (*sect)->setAddr(start_addr + (*sect)->offset() -
- (*seg).front()->offset());
- else
- (*sect)->setAddr(start_addr);
+ for (SectionMap::Input::dot_iterator it = (*in)->dot_begin(),
+ ie = (*in)->dot_end(); it != ie; ++it) {
+ (*it).second.assign(evaluator);
+ if ((*it).first != NULL) {
+ uint64_t new_offset = (*it).second.symbol().value() - vma;
+ if (new_offset != (*it).first->getOffset()) {
+ (*it).first->setOffset(new_offset);
+ invalid = (*it).first->getNextNode();
+ changed = true;
+ }
+ }
+ } // for each dot assignment
+ } // for each input description
+
+ if (changed) {
+ while (invalid != NULL) {
+ Fragment* prev = invalid->getPrevNode();
+ invalid->setOffset(prev->getOffset() + prev->size());
+ invalid = invalid->getNextNode();
+ }
+
+ cur->setSize(cur->getSectionData()->back().getOffset() +
+ cur->getSectionData()->back().size());
}
- }
+
+ } // for each output section description
}
-/// layout - layout method
-void GNULDBackend::layout(Module& pModule)
+/// placeOutputSections - place output sections based on SectionMap
+void GNULDBackend::placeOutputSections(Module& pModule)
{
- std::vector<SHOEntry> output_list;
- // 1. determine what sections will go into final output, and push the needed
- // sections into output_list for later processing
+ typedef std::vector<LDSection*> Orphans;
+ Orphans orphans;
+ SectionMap& sectionMap = pModule.getScript().sectionMap();
+
for (Module::iterator it = pModule.begin(), ie = pModule.end(); it != ie;
- ++it) {
+ ++it) {
+ bool wanted = false;
+
switch ((*it)->kind()) {
// take NULL and StackNote directly
case LDFileFormat::Null:
case LDFileFormat::StackNote:
- output_list.push_back(std::make_pair(*it, getSectionOrder(**it)));
+ wanted = true;
break;
// ignore if section size is 0
case LDFileFormat::EhFrame:
if (((*it)->size() != 0) ||
((*it)->hasEhFrame() &&
config().codeGenType() == LinkerConfig::Object))
- output_list.push_back(std::make_pair(*it, getSectionOrder(**it)));
+ wanted = true;
break;
case LDFileFormat::Relocation:
if (((*it)->size() != 0) ||
((*it)->hasRelocData() &&
config().codeGenType() == LinkerConfig::Object))
- output_list.push_back(std::make_pair(*it, getSectionOrder(**it)));
+ wanted = true;
break;
case LDFileFormat::Regular:
case LDFileFormat::Target:
@@ -2120,7 +2423,7 @@
if (((*it)->size() != 0) ||
((*it)->hasSectionData() &&
config().codeGenType() == LinkerConfig::Object))
- output_list.push_back(std::make_pair(*it, getSectionOrder(**it)));
+ wanted = true;
break;
case LDFileFormat::Group:
if (LinkerConfig::Object == config().codeGenType()) {
@@ -2129,44 +2432,140 @@
}
break;
case LDFileFormat::Version:
- if (0 != (*it)->size()) {
- output_list.push_back(std::make_pair(*it, getSectionOrder(**it)));
+ if ((*it)->size() != 0) {
+ wanted = true;
warning(diag::warn_unsupported_symbolic_versioning) << (*it)->name();
}
break;
default:
- if (0 != (*it)->size()) {
+ if ((*it)->size() != 0) {
error(diag::err_unsupported_section) << (*it)->name() << (*it)->kind();
}
break;
+ } // end of switch
+
+ if (wanted) {
+ SectionMap::iterator out, outBegin, outEnd;
+ outBegin = sectionMap.begin();
+ outEnd = sectionMap.end();
+ for (out = outBegin; out != outEnd; ++out) {
+ bool matched = false;
+ if ((*it)->name().compare((*out)->name()) == 0) {
+ switch ((*out)->prolog().constraint()) {
+ case OutputSectDesc::NO_CONSTRAINT:
+ matched = true;
+ break;
+ case OutputSectDesc::ONLY_IF_RO:
+ matched = ((*it)->flag() & llvm::ELF::SHF_WRITE) == 0;
+ break;
+ case OutputSectDesc::ONLY_IF_RW:
+ matched = ((*it)->flag() & llvm::ELF::SHF_WRITE) != 0;
+ break;
+ } // end of switch
+
+ if (matched)
+ break;
+ }
+ } // for each output section description
+
+ if (out != outEnd) {
+ // set up the section
+ (*out)->setSection(*it);
+ (*out)->setOrder(getSectionOrder(**it));
+ } else {
+ orphans.push_back(*it);
+ }
}
- } // end of for
+ } // for each section in Module
- // 2. sort output section orders
- std::stable_sort(output_list.begin(), output_list.end(), SHOCompare());
+ // set up sections in SectionMap but do not exist at all.
+ uint32_t flag = 0x0;
+ unsigned int order = SHO_UNDEFINED;
+ OutputSectDesc::Type type = OutputSectDesc::LOAD;
+ for (SectionMap::reverse_iterator out = sectionMap.rbegin(),
+ outEnd = sectionMap.rend(); out != outEnd; ++out) {
+ if ((*out)->hasContent() ||
+ (*out)->getSection()->kind() == LDFileFormat::Null ||
+ (*out)->getSection()->kind() == LDFileFormat::StackNote) {
+ flag = (*out)->getSection()->flag();
+ order = (*out)->order();
+ type = (*out)->prolog().type();
+ } else {
+ (*out)->getSection()->setFlag(flag);
+ (*out)->setOrder(order);
+ (*out)->prolog().setType(type);
+ }
+ } // for each output section description
- // 3. update output sections in Module
- pModule.getSectionTable().clear();
- for(size_t index = 0; index < output_list.size(); ++index) {
- (output_list[index].first)->setIndex(index);
- pModule.getSectionTable().push_back(output_list[index].first);
+ // place orphan sections
+ for (Orphans::iterator it = orphans.begin(), ie = orphans.end(); it != ie;
+ ++it) {
+ size_t order = getSectionOrder(**it);
+ SectionMap::iterator out, outBegin, outEnd;
+ outBegin = sectionMap.begin();
+ outEnd = sectionMap.end();
+
+ if ((*it)->kind() == LDFileFormat::Null)
+ out = sectionMap.insert(outBegin, *it);
+ else {
+ for (out = outBegin; out != outEnd; ++out) {
+ if ((*out)->order() > order)
+ break;
+ }
+ out = sectionMap.insert(out, *it);
+ }
+ (*out)->setOrder(order);
+ } // for each orphan section
+
+ // sort output section orders if there is no default ldscript
+ if (config().options().getScriptList().empty()) {
+ std::stable_sort(sectionMap.begin(),
+ sectionMap.end(),
+ SectionMap::SHOCompare());
}
+ // when section ordering is fixed, now we can make sure dot assignments are
+ // all set appropriately
+ sectionMap.fixupDotSymbols();
+}
+
+/// layout - layout method
+void GNULDBackend::layout(Module& pModule)
+{
+ // 1. place output sections based on SectionMap from SECTIONS command
+ placeOutputSections(pModule);
+
+ // 2. update output sections in Module
+ SectionMap& sectionMap = pModule.getScript().sectionMap();
+ pModule.getSectionTable().clear();
+ for (SectionMap::iterator out = sectionMap.begin(), outEnd = sectionMap.end();
+ out != outEnd; ++out) {
+ if ((*out)->hasContent() ||
+ (*out)->getSection()->kind() == LDFileFormat::Null ||
+ (*out)->getSection()->kind() == LDFileFormat::StackNote ||
+ config().codeGenType() == LinkerConfig::Object) {
+ (*out)->getSection()->setIndex(pModule.size());
+ pModule.getSectionTable().push_back((*out)->getSection());
+ }
+ } // for each output section description
+
+ // 3. update the size of .shstrtab
+ sizeShstrtab(pModule);
+
// 4. create program headers
if (LinkerConfig::Object != config().codeGenType()) {
createProgramHdrs(pModule);
}
- // 5. set output section offset
- setOutputSectionOffset(pModule, pModule.begin(), pModule.end(), 0x0);
+ // 5. set output section address/offset
+ if (LinkerConfig::Object != config().codeGenType())
+ setOutputSectionAddress(pModule);
+ else
+ setOutputSectionOffset(pModule);
}
-/// preLayout - Backend can do any needed modification before layout
-void GNULDBackend::preLayout(Module& pModule, IRBuilder& pBuilder)
+void GNULDBackend::createAndSizeEhFrameHdr(Module& pModule)
{
- // prelayout target first
- doPreLayout(pBuilder);
-
if (LinkerConfig::Object != config().codeGenType() &&
config().options().hasEhFrameHdr() && getOutputFormat()->hasEhFrame()) {
// init EhFrameHdr and size the output section
@@ -2175,6 +2574,13 @@
format->getEhFrame());
m_pEhFrameHdr->sizeOutput();
}
+}
+
+/// preLayout - Backend can do any needed modification before layout
+void GNULDBackend::preLayout(Module& pModule, IRBuilder& pBuilder)
+{
+ // prelayout target first
+ doPreLayout(pBuilder);
// change .tbss and .tdata section symbol from Local to LocalDyn category
if (NULL != f_pTDATA)
@@ -2248,28 +2654,17 @@
/// postLayout - Backend can do any needed modification after layout
void GNULDBackend::postLayout(Module& pModule, IRBuilder& pBuilder)
{
- // 1. set up section address and segment attributes
if (LinkerConfig::Object != config().codeGenType()) {
- if (config().options().hasRelro()) {
- // 1.1 set up the offset constraint of PT_RELRO
- setupRelro(pModule);
- }
-
- // 1.2 set up the output sections' address
- setOutputSectionAddress(pModule, pModule.begin(), pModule.end());
-
- // 1.3 do relaxation
+ // do relaxation
relax(pModule, pBuilder);
-
- // 1.4 set up the attributes of program headers
+ // set up the attributes of program headers
setupProgramHdrs(pModule.getScript());
}
- // 2. target specific post layout
doPostLayout(pModule, pBuilder);
}
-void GNULDBackend::postProcessing(MemoryArea& pOutput)
+void GNULDBackend::postProcessing(FileOutputBuffer& pOutput)
{
if (LinkerConfig::Object != config().codeGenType() &&
config().options().hasEhFrameHdr() && getOutputFormat()->hasEhFrame()) {
@@ -2327,7 +2722,7 @@
/// isDynamicSymbol
/// @ref Google gold linker: symtab.cc:311
-bool GNULDBackend::isDynamicSymbol(const LDSymbol& pSymbol)
+bool GNULDBackend::isDynamicSymbol(const LDSymbol& pSymbol) const
{
// If a local symbol is in the LDContext's symbol table, it's a real local
// symbol. We should not add it
@@ -2348,7 +2743,7 @@
/// isDynamicSymbol
/// @ref Google gold linker: symtab.cc:311
-bool GNULDBackend::isDynamicSymbol(const ResolveInfo& pResolveInfo)
+bool GNULDBackend::isDynamicSymbol(const ResolveInfo& pResolveInfo) const
{
// If a local symbol is in the LDContext's symbol table, it's a real local
// symbol. We should not add it
@@ -2367,6 +2762,20 @@
return false;
}
+/// elfSegmentTable - return the reference of the elf segment table
+ELFSegmentFactory& GNULDBackend::elfSegmentTable()
+{
+ assert(m_pELFSegmentTable != NULL && "Do not create ELFSegmentTable!");
+ return *m_pELFSegmentTable;
+}
+
+/// elfSegmentTable - return the reference of the elf segment table
+const ELFSegmentFactory& GNULDBackend::elfSegmentTable() const
+{
+ assert(m_pELFSegmentTable != NULL && "Do not create ELFSegmentTable!");
+ return *m_pELFSegmentTable;
+}
+
/// commonPageSize - the common page size of the target machine.
/// @ref gold linker: target.h:135
uint64_t GNULDBackend::commonPageSize() const
@@ -2553,6 +2962,14 @@
return *f_pTBSS;
}
+llvm::StringRef GNULDBackend::getEntry(const Module& pModule) const
+{
+ if (pModule.getScript().hasEntry())
+ return pModule.getScript().entry();
+ else
+ return getInfo().entry();
+}
+
void GNULDBackend::checkAndSetHasTextRel(const LDSection& pSection)
{
if (m_bHasTextRel)
@@ -2567,6 +2984,28 @@
return;
}
+/// sortRelocation - sort the dynamic relocations to let dynamic linker
+/// process relocations more efficiently
+void GNULDBackend::sortRelocation(LDSection& pSection)
+{
+ if (!config().options().hasCombReloc())
+ return;
+
+ assert(pSection.kind() == LDFileFormat::Relocation);
+
+ switch (config().codeGenType()) {
+ case LinkerConfig::DynObj:
+ case LinkerConfig::Exec:
+ if (&pSection == &getOutputFormat()->getRelDyn() ||
+ &pSection == &getOutputFormat()->getRelaDyn()) {
+ if (pSection.hasRelocData())
+ pSection.getRelocData()->sort(RelocCompare(*this));
+ }
+ default:
+ return;
+ }
+}
+
/// initBRIslandFactory - initialize the branch island factory for relaxation
bool GNULDBackend::initBRIslandFactory()
{
@@ -2590,21 +3029,12 @@
if (!mayRelax())
return true;
+ getBRIslandFactory()->group(pModule);
+
bool finished = true;
do {
if (doRelax(pModule, pBuilder, finished)) {
- // If the sections (e.g., .text) are relaxed, the layout is also changed
- // We need to do the following:
-
- // 1. set up the offset
- setOutputSectionOffset(pModule, pModule.begin(), pModule.end());
-
- // 2. set up the offset constraint of PT_RELRO
- if (config().options().hasRelro())
- setupRelro(pModule);
-
- // 3. set up the output sections' address
- setOutputSectionAddress(pModule, pModule.begin(), pModule.end());
+ setOutputSectionAddress(pModule);
}
} while (!finished);
@@ -2625,3 +3055,42 @@
return !needGNUHash(*X) && needGNUHash(*Y);
}
+bool GNULDBackend::RelocCompare::operator()(const Relocation* X,
+ const Relocation* Y) const
+{
+ // 1. compare if relocation is relative
+ if (X->symInfo() == NULL) {
+ if (Y->symInfo() != NULL)
+ return true;
+ } else if (Y->symInfo() == NULL) {
+ return false;
+ } else {
+ // 2. compare the symbol index
+ size_t symIdxX = m_Backend.getSymbolIdx(X->symInfo()->outSymbol());
+ size_t symIdxY = m_Backend.getSymbolIdx(Y->symInfo()->outSymbol());
+ if (symIdxX < symIdxY)
+ return true;
+ if (symIdxX > symIdxY)
+ return false;
+ }
+
+ // 3. compare the relocation address
+ if (X->place() < Y->place())
+ return true;
+ if (X->place() > Y->place())
+ return false;
+
+ // 4. compare the relocation type
+ if (X->type() < Y->type())
+ return true;
+ if (X->type() > Y->type())
+ return false;
+
+ // 5. compare the addend
+ if (X->addend() < Y->addend())
+ return true;
+ if (X->addend() > Y->addend())
+ return false;
+
+ return false;
+}
diff --git a/lib/Target/Hexagon/Hexagon.h b/lib/Target/Hexagon/Hexagon.h
index 5a286ef..731a878 100644
--- a/lib/Target/Hexagon/Hexagon.h
+++ b/lib/Target/Hexagon/Hexagon.h
@@ -6,19 +6,17 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_HEXAGON_H
-#define MCLD_HEXAGON_H
+#ifndef MCLD_TARGET_HEXAGON_H
+#define MCLD_TARGET_HEXAGON_H
#include <string>
-#include <mcld/Target/TargetMachine.h>
namespace llvm {
-
class Target;
-
} // namespace of llvm
namespace mcld {
+class Target;
class TargetLDBackend;
extern mcld::Target TheHexagonTarget;
diff --git a/lib/Target/Hexagon/HexagonDiagnostic.cpp b/lib/Target/Hexagon/HexagonDiagnostic.cpp
index 01b8f9b..7fd58c0 100644
--- a/lib/Target/Hexagon/HexagonDiagnostic.cpp
+++ b/lib/Target/Hexagon/HexagonDiagnostic.cpp
@@ -6,18 +6,16 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include <llvm/ADT/Triple.h>
#include <mcld/Support/TargetRegistry.h>
#include <mcld/LD/DWARFLineInfo.h>
#include "Hexagon.h"
-using namespace mcld;
-
namespace mcld {
+//===----------------------------------------------------------------------===//
// createHexagonDiagnostic - the help function to create corresponding
// HexagonDiagnostic
-//
+//===----------------------------------------------------------------------===//
DiagnosticLineInfo*
createHexagonDiagLineInfo(const Target& pTarget, const std::string &pTriple)
{
@@ -26,6 +24,8 @@
} // namespace of mcld
+using namespace mcld;
+
//===----------------------------------------------------------------------===//
// InitializeHexagonDiagnostic
//===----------------------------------------------------------------------===//
diff --git a/lib/Target/Hexagon/HexagonELFMCLinker.cpp b/lib/Target/Hexagon/HexagonELFMCLinker.cpp
index 6cc4a01..bf5f7d7 100644
--- a/lib/Target/Hexagon/HexagonELFMCLinker.cpp
+++ b/lib/Target/Hexagon/HexagonELFMCLinker.cpp
@@ -7,14 +7,13 @@
//
//===----------------------------------------------------------------------===//
#include "HexagonELFMCLinker.h"
-#include <mcld/LinkerConfig.h>
using namespace mcld;
HexagonELFMCLinker::HexagonELFMCLinker(LinkerConfig& pConfig,
mcld::Module& pModule,
- MemoryArea& pOutput)
- : ELFMCLinker(pConfig, pModule, pOutput) {
+ FileHandle& pFileHandle)
+ : ELFMCLinker(pConfig, pModule, pFileHandle) {
}
HexagonELFMCLinker::~HexagonELFMCLinker()
diff --git a/lib/Target/Hexagon/HexagonELFMCLinker.h b/lib/Target/Hexagon/HexagonELFMCLinker.h
index c588ddf..6bbfe26 100644
--- a/lib/Target/Hexagon/HexagonELFMCLinker.h
+++ b/lib/Target/Hexagon/HexagonELFMCLinker.h
@@ -16,7 +16,7 @@
namespace mcld {
class Module;
-class MemoryArea;
+class FileHandle;
/** \class HexagonELFMCLinker
* \brief HexagonELFMCLinker sets up the environment for linking.
@@ -28,7 +28,7 @@
public:
HexagonELFMCLinker(LinkerConfig& pConfig,
mcld::Module& pModule,
- MemoryArea& pOutput);
+ FileHandle& pFileHandle);
~HexagonELFMCLinker();
};
diff --git a/lib/Target/Hexagon/HexagonGOT.cpp b/lib/Target/Hexagon/HexagonGOT.cpp
index 551b40f..637b078 100644
--- a/lib/Target/Hexagon/HexagonGOT.cpp
+++ b/lib/Target/Hexagon/HexagonGOT.cpp
@@ -27,22 +27,8 @@
{
}
-void HexagonGOT::reserve(size_t pNum)
+HexagonGOTEntry* HexagonGOT::create()
{
- for (size_t i = 0; i < pNum; i++) {
- new HexagonGOTEntry(0, m_SectionData);
- }
-}
-
-HexagonGOTEntry* HexagonGOT::consume()
-{
- if (NULL == m_pLast) {
- assert(!empty() && "Consume empty GOT entry!");
- m_pLast = llvm::cast<HexagonGOTEntry>(&m_SectionData->front());
- return m_pLast;
- }
-
- m_pLast = llvm::cast<HexagonGOTEntry>(m_pLast->getNextNode());
- return m_pLast;
+ return new HexagonGOTEntry(0, m_SectionData);
}
diff --git a/lib/Target/Hexagon/HexagonGOT.h b/lib/Target/Hexagon/HexagonGOT.h
index 4f9120c..c29239c 100644
--- a/lib/Target/Hexagon/HexagonGOT.h
+++ b/lib/Target/Hexagon/HexagonGOT.h
@@ -41,9 +41,7 @@
~HexagonGOT();
- void reserve(size_t pNum = 1);
-
- HexagonGOTEntry* consume();
+ HexagonGOTEntry* create();
private:
HexagonGOTEntry* m_pLast; ///< the last consumed entry
diff --git a/lib/Target/Hexagon/HexagonGOTPLT.cpp b/lib/Target/Hexagon/HexagonGOTPLT.cpp
index fee852f..cfceff5 100644
--- a/lib/Target/Hexagon/HexagonGOTPLT.cpp
+++ b/lib/Target/Hexagon/HexagonGOTPLT.cpp
@@ -23,12 +23,9 @@
HexagonGOTPLT::HexagonGOTPLT(LDSection& pSection)
: HexagonGOT(pSection)
{
- // Create GOT0 entries
- reserve(HexagonGOTPLT0Num);
-
// Skip GOT0 entries
for (size_t i = 0; i < HexagonGOTPLT0Num; ++i) {
- consume();
+ create();
}
pSection.setAlign(8);
}
diff --git a/lib/Target/Hexagon/HexagonGOTPLT.h b/lib/Target/Hexagon/HexagonGOTPLT.h
index ad49992..9fc67cd 100644
--- a/lib/Target/Hexagon/HexagonGOTPLT.h
+++ b/lib/Target/Hexagon/HexagonGOTPLT.h
@@ -14,7 +14,6 @@
#include <llvm/ADT/DenseMap.h>
#include "HexagonGOT.h"
-#include <mcld/Support/MemoryRegion.h>
namespace mcld {
diff --git a/lib/Target/Hexagon/HexagonLDBackend.cpp b/lib/Target/Hexagon/HexagonLDBackend.cpp
index fcf7fb3..5265c4b 100644
--- a/lib/Target/Hexagon/HexagonLDBackend.cpp
+++ b/lib/Target/Hexagon/HexagonLDBackend.cpp
@@ -21,7 +21,6 @@
#include <mcld/Fragment/AlignFragment.h>
#include <mcld/Fragment/FillFragment.h>
#include <mcld/Fragment/RegionFragment.h>
-#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/TargetRegistry.h>
@@ -30,7 +29,9 @@
#include <mcld/LD/BranchIslandFactory.h>
#include <mcld/LD/StubFactory.h>
#include <mcld/LD/LDContext.h>
-
+#include <mcld/LD/ELFFileFormat.h>
+#include <mcld/LD/ELFSegmentFactory.h>
+#include <mcld/LD/ELFSegment.h>
#include <cstring>
@@ -132,7 +133,7 @@
}
uint64_t HexagonLDBackend::emitSectionData(const LDSection& pSection,
- MemoryRegion& pRegion) const
+ MemoryRegion& pRegion) const
{
if (!pRegion.size())
return 0;
@@ -143,10 +144,9 @@
if ((LinkerConfig::Object != config().codeGenType()) &&
(!config().isCodeStatic())) {
- if (&pSection == &(FileFormat->getPLT())) {
- assert(m_pPLT && "emitSectionData failed, m_pPLT is NULL!");
+ if (FileFormat->hasPLT() && (&pSection == &(FileFormat->getPLT()))) {
- unsigned char* buffer = pRegion.getBuffer();
+ unsigned char* buffer = pRegion.begin();
m_pPLT->applyPLT0();
m_pPLT->applyPLT1();
@@ -168,11 +168,12 @@
}
return RegionSize;
}
- else if (&pSection == &(FileFormat->getGOT())) {
+ else if (FileFormat->hasGOT() && (&pSection == &(FileFormat->getGOT()))) {
RegionSize += emitGOTSectionData(pRegion);
return RegionSize;
}
- else if (&pSection == &(FileFormat->getGOTPLT())) {
+ else if (FileFormat->hasGOTPLT() &&
+ (&pSection == &(FileFormat->getGOTPLT()))) {
RegionSize += emitGOTPLTSectionData(pRegion, FileFormat);
return RegionSize;
}
@@ -180,7 +181,7 @@
const SectionData* sect_data = pSection.getSectionData();
SectionData::const_iterator frag_iter, frag_end = sect_data->end();
- uint8_t* out_offset = pRegion.start();
+ uint8_t* out_offset = pRegion.begin();
for (frag_iter = sect_data->begin(); frag_iter != frag_end; ++frag_iter) {
size_t size = frag_iter->size();
switch(frag_iter->getKind()) {
@@ -197,7 +198,7 @@
case Fragment::Region: {
const RegionFragment& region_frag =
llvm::cast<RegionFragment>(*frag_iter);
- const uint8_t* start = region_frag.getRegion().start();
+ const char* start = region_frag.getRegion().begin();
memcpy(out_offset, start, size);
break;
}
@@ -318,11 +319,12 @@
m_pGOT->finalizeSectionSize();
}
-uint64_t HexagonLDBackend::emitGOTSectionData(MemoryRegion& pRegion) const
+uint64_t
+HexagonLDBackend::emitGOTSectionData(MemoryRegion& pRegion) const
{
assert(m_pGOT && "emitGOTSectionData failed, m_pGOT is NULL!");
- uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.begin());
HexagonGOTEntry* got = 0;
unsigned int EntrySize = HexagonGOTEntry::EntrySize;
@@ -367,13 +369,13 @@
}
uint64_t HexagonLDBackend::emitGOTPLTSectionData(MemoryRegion& pRegion,
- const ELFFileFormat* FileFormat) const
+ const ELFFileFormat* FileFormat) const
{
assert(m_pGOTPLT && "emitGOTPLTSectionData failed, m_pGOTPLT is NULL!");
m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr());
m_pGOTPLT->applyAllGOTPLT(*m_pPLT);
- uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.begin());
HexagonGOTEntry* got = 0;
unsigned int EntrySize = HexagonGOTEntry::EntrySize;
@@ -395,19 +397,19 @@
const ELFFileFormat* file_format = getOutputFormat();
if (LinkerConfig::Object != config().codeGenType()) {
- if (&pSectHdr == &file_format->getGOT()) {
+ if (file_format->hasGOT() && (&pSectHdr == &file_format->getGOT())) {
if (config().options().hasNow())
return SHO_RELRO;
return SHO_RELRO_LAST;
}
- if (&pSectHdr == &file_format->getGOTPLT()) {
+ if (file_format->hasGOTPLT() && (&pSectHdr == &file_format->getGOTPLT())) {
if (config().options().hasNow())
return SHO_RELRO;
return SHO_NON_RELRO_FIRST;
}
- if (&pSectHdr == &file_format->getPLT())
+ if (file_format->hasPLT() && (&pSectHdr == &file_format->getPLT()))
return SHO_PLT;
}
@@ -658,33 +660,37 @@
if (m_psdabase)
m_psdabase->setValue(m_psdata->addr());
- ELFSegment *edata = m_ELFSegmentTable.find(llvm::ELF::PT_LOAD,
- llvm::ELF::PF_W, llvm::ELF::PF_X);
- if (NULL != edata) {
+ ELFSegmentFactory::const_iterator edata =
+ elfSegmentTable().find(llvm::ELF::PT_LOAD,
+ llvm::ELF::PF_W,
+ llvm::ELF::PF_X);
+ if (elfSegmentTable().end() != edata) {
if (NULL != f_pEData && ResolveInfo::ThreadLocal != f_pEData->type()) {
- f_pEData->setValue(edata->vaddr() + edata->filesz());
+ f_pEData->setValue((*edata)->vaddr() + (*edata)->filesz());
}
if (NULL != f_p_EData && ResolveInfo::ThreadLocal != f_p_EData->type()) {
- f_p_EData->setValue(edata->vaddr() + edata->filesz());
+ f_p_EData->setValue((*edata)->vaddr() + (*edata)->filesz());
}
if (NULL != f_pBSSStart &&
ResolveInfo::ThreadLocal != f_pBSSStart->type()) {
- f_pBSSStart->setValue(edata->vaddr() + edata->filesz());
+ f_pBSSStart->setValue((*edata)->vaddr() + (*edata)->filesz());
}
if (NULL != f_pEnd && ResolveInfo::ThreadLocal != f_pEnd->type()) {
- f_pEnd->setValue(((edata->vaddr() +
- edata->memsz()) + 7) & ~7);
+ f_pEnd->setValue((((*edata)->vaddr() +
+ (*edata)->memsz()) + 7) & ~7);
}
if (NULL != f_p_End && ResolveInfo::ThreadLocal != f_p_End->type()) {
- f_p_End->setValue(((edata->vaddr() +
- edata->memsz()) + 7) & ~7);
+ f_p_End->setValue((((*edata)->vaddr() +
+ (*edata)->memsz()) + 7) & ~7);
}
}
return true;
}
/// merge Input Sections
-bool HexagonLDBackend::mergeSection(Module& pModule, LDSection& pInputSection)
+bool HexagonLDBackend::mergeSection(Module& pModule,
+ const Input& pInputFile,
+ LDSection& pInputSection)
{
if ((pInputSection.flag() & llvm::ELF::SHF_HEX_GPREL) ||
(pInputSection.kind() == LDFileFormat::LinkOnce) ||
@@ -699,7 +705,7 @@
}
else {
ObjectBuilder builder(config(), pModule);
- return builder.MergeSection(pInputSection);
+ builder.MergeSection(pInputFile, pInputSection);
}
return true;
}
@@ -785,7 +791,6 @@
// description here.
(*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
Fragment* frag = new FillFragment(0x0, 1, (*com_sym)->size());
- (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
switch((*com_sym)->size()) {
case 1:
@@ -794,6 +799,7 @@
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_1->getSectionData()),
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
continue;
case 2:
if (maxGPSize <= 1)
@@ -801,6 +807,7 @@
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_2->getSectionData()),
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
continue;
case 4:
if (maxGPSize <= 3)
@@ -808,6 +815,7 @@
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_4->getSectionData()),
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
continue;
case 8:
if (maxGPSize <= 7)
@@ -815,6 +823,7 @@
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_8->getSectionData()),
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
continue;
default:
break;
@@ -825,12 +834,14 @@
tbss_offset += ObjectBuilder::AppendFragment(*frag,
*tbss_sect_data,
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
}
// FIXME: how to identify small and large common symbols?
else {
bss_offset += ObjectBuilder::AppendFragment(*frag,
*bss_sect_data,
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
}
}
}
@@ -845,7 +856,6 @@
// description here.
(*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
Fragment* frag = new FillFragment(0x0, 1, (*com_sym)->size());
- (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
switch((*com_sym)->size()) {
case 1:
@@ -854,6 +864,7 @@
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_1->getSectionData()),
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
continue;
case 2:
if (maxGPSize <= 1)
@@ -861,6 +872,7 @@
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_2->getSectionData()),
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
continue;
case 4:
if (maxGPSize <= 3)
@@ -868,6 +880,7 @@
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_4->getSectionData()),
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
continue;
case 8:
if (maxGPSize <= 7)
@@ -875,6 +888,7 @@
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_8->getSectionData()),
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
continue;
default:
break;
@@ -885,12 +899,14 @@
tbss_offset += ObjectBuilder::AppendFragment(*frag,
*tbss_sect_data,
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
}
// FIXME: how to identify small and large common symbols?
else {
bss_offset += ObjectBuilder::AppendFragment(*frag,
*bss_sect_data,
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
}
}
@@ -954,14 +970,14 @@
frag = new FillFragment(0x0, 1, size);
}
else {
- MemoryRegion* region = pInput.memArea()->request(offset, size);
- if (NULL == region) {
+ llvm::StringRef region = pInput.memArea()->request(offset, size);
+ if (region.size() == 0) {
// If the input section's size is zero, we got a NULL region.
// use a virtual fill fragment
frag = new FillFragment(0x0, 0, 0);
}
else {
- frag = new RegionFragment(*region);
+ frag = new RegionFragment(region);
}
}
@@ -1040,8 +1056,7 @@
//===----------------------------------------------------------------------===//
/// createHexagonLDBackend - the help funtion to create corresponding
/// HexagonLDBackend
-TargetLDBackend* createHexagonLDBackend(const llvm::Target& pTarget,
- const LinkerConfig& pConfig)
+TargetLDBackend* createHexagonLDBackend(const LinkerConfig& pConfig)
{
if (pConfig.targets().triple().isOSDarwin()) {
assert(0 && "MachO linker is not supported yet");
diff --git a/lib/Target/Hexagon/HexagonLDBackend.h b/lib/Target/Hexagon/HexagonLDBackend.h
index 30a9f35..e2bc2bb 100644
--- a/lib/Target/Hexagon/HexagonLDBackend.h
+++ b/lib/Target/Hexagon/HexagonLDBackend.h
@@ -126,7 +126,7 @@
bool finalizeTargetSymbols();
/// mergeSection - merge target dependent sections
- bool mergeSection(Module& pModule, LDSection& pSection);
+ bool mergeSection(Module& pModule, const Input& pInput, LDSection& pSection);
/// readSection - read target dependent sections
bool readSection(Input& pInput, SectionData& pSD);
diff --git a/lib/Target/Hexagon/HexagonMCLinker.cpp b/lib/Target/Hexagon/HexagonMCLinker.cpp
index 4f4f839..770ae94 100644
--- a/lib/Target/Hexagon/HexagonMCLinker.cpp
+++ b/lib/Target/Hexagon/HexagonMCLinker.cpp
@@ -21,9 +21,9 @@
MCLinker* createHexagonMCLinker(const std::string &pTriple,
LinkerConfig& pConfig,
mcld::Module& pModule,
- MemoryArea& pOutput)
+ FileHandle& pFileHandle)
{
- Triple theTriple(pTriple);
+ llvm::Triple theTriple(pTriple);
if (theTriple.isOSDarwin()) {
assert(0 && "MachO linker has not supported yet");
return NULL;
@@ -34,7 +34,7 @@
}
if (theTriple.isArch32Bit())
- return new HexagonELFMCLinker(pConfig, pModule, pOutput);
+ return new HexagonELFMCLinker(pConfig, pModule, pFileHandle);
assert(0 && "Hexagon_64 has not supported yet");
return NULL;
diff --git a/lib/Target/Hexagon/HexagonPLT.cpp b/lib/Target/Hexagon/HexagonPLT.cpp
index ceb8a58..6309408 100644
--- a/lib/Target/Hexagon/HexagonPLT.cpp
+++ b/lib/Target/Hexagon/HexagonPLT.cpp
@@ -49,7 +49,6 @@
m_PLT0Size = sizeof (hexagon_plt0);
// create PLT0
new HexagonPLT0(*m_SectionData);
- m_Last = m_SectionData->begin();
pSection.setAlign(16);
}
@@ -98,25 +97,9 @@
return (m_SectionData->size() > 1);
}
-void HexagonPLT::reserveEntry(size_t pNum)
+HexagonPLT1* HexagonPLT::create()
{
- PLTEntryBase* plt1_entry = NULL;
-
- for (size_t i = 0; i < pNum; ++i) {
- plt1_entry = new HexagonPLT1(*m_SectionData);
-
- if (NULL == plt1_entry)
- fatal(diag::fail_allocate_memory_plt);
- }
-}
-
-HexagonPLT1* HexagonPLT::consume()
-{
- ++m_Last;
- assert(m_Last != m_SectionData->end() &&
- "The number of PLT Entries and ResolveInfo doesn't match");
-
- return llvm::cast<HexagonPLT1>(&(*m_Last));
+ return new HexagonPLT1(*m_SectionData);
}
void HexagonPLT::applyPLT0()
@@ -200,7 +183,7 @@
uint64_t result = 0x0;
iterator it = begin();
- unsigned char* buffer = pRegion.getBuffer();
+ unsigned char* buffer = pRegion.begin();
memcpy(buffer, llvm::cast<HexagonPLT0>((*it)).getValue(), HexagonPLT0::EntrySize);
result += HexagonPLT0::EntrySize;
++it;
diff --git a/lib/Target/Hexagon/HexagonPLT.h b/lib/Target/Hexagon/HexagonPLT.h
index 8cf7e47..abdb4ea 100644
--- a/lib/Target/Hexagon/HexagonPLT.h
+++ b/lib/Target/Hexagon/HexagonPLT.h
@@ -13,6 +13,7 @@
#include "HexagonGOTPLT.h"
#include <mcld/Target/GOT.h>
#include <mcld/Target/PLT.h>
+#include <mcld/Support/MemoryRegion.h>
namespace {
@@ -44,7 +45,6 @@
class GOTEntry;
class LinkerConfig;
-class MemoryRegion;
class HexagonPLT1;
//===----------------------------------------------------------------------===//
@@ -76,9 +76,7 @@
// hasPLT1 - return if this PLT has any PLT1 entry
bool hasPLT1() const;
- void reserveEntry(size_t pNum = 1) ;
-
- HexagonPLT1* consume();
+ HexagonPLT1* create();
void applyPLT0();
@@ -91,9 +89,6 @@
private:
HexagonGOTPLT& m_GOTPLT;
- // the last consumed entry.
- SectionData::iterator m_Last;
-
const uint8_t *m_PLT0;
unsigned int m_PLT0Size;
diff --git a/lib/Target/Hexagon/HexagonRelocationFunctions.h b/lib/Target/Hexagon/HexagonRelocationFunctions.h
index a5e6b87..6f9acad 100644
--- a/lib/Target/Hexagon/HexagonRelocationFunctions.h
+++ b/lib/Target/Hexagon/HexagonRelocationFunctions.h
@@ -39,84 +39,59 @@
#define DECL_HEXAGON_APPLY_RELOC_FUNCS \
DECL_HEXAGON_APPLY_RELOC_FUNC(none) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocB22PCREL) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocB15PCREL) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocB7PCREL) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocLO16) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocHI16) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(reloc32) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(reloc16) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(reloc8) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocGPREL16_0) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocGPREL16_1) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocGPREL16_2) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocGPREL16_3) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocB13PCREL) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocB9PCREL) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocB32PCRELX) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(reloc32_6_X) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocB22PCRELX) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocB15PCRELX) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocB13PCRELX) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocB9PCRELX) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocB7PCRELX) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(reloc32PCREL) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocHexNX) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocHexGOTRELLO16) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocHexGOTRELHI16) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocHexGOTREL32) \
+DECL_HEXAGON_APPLY_RELOC_FUNC(relocPCREL) \
+DECL_HEXAGON_APPLY_RELOC_FUNC(relocGPREL) \
+DECL_HEXAGON_APPLY_RELOC_FUNC(relocAbs) \
DECL_HEXAGON_APPLY_RELOC_FUNC(relocPLTB22PCREL) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocHex6PCRELX) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocHexGOT326X) \
-DECL_HEXAGON_APPLY_RELOC_FUNC(relocHexGOT1611X) \
+DECL_HEXAGON_APPLY_RELOC_FUNC(relocGOTREL) \
+DECL_HEXAGON_APPLY_RELOC_FUNC(relocGOT) \
DECL_HEXAGON_APPLY_RELOC_FUNC(unsupport)
-
#define DECL_HEXAGON_APPLY_RELOC_FUNC_PTRS \
{ &none, 0, "R_HEX_NONE" }, \
- { &relocB22PCREL, 1, "R_HEX_B22_PCREL" }, \
- { &relocB15PCREL, 2, "R_HEX_B15_PCREL" }, \
- { &relocB7PCREL, 3, "R_HEX_B7_PCREL" }, \
- { &relocLO16, 4, "R_HEX_LO16" }, \
- { &relocHI16, 5, "R_HEX_HI16" }, \
- { &reloc32, 6, "R_HEX_32" }, \
- { &reloc16, 7, "R_HEX_16" }, \
- { &reloc8, 8, "R_HEX_8" }, \
- { &relocGPREL16_0, 9, "R_HEX_GPREL16_0" }, \
- { &relocGPREL16_1, 10, "R_HEX_GPREL16_1" }, \
- { &relocGPREL16_2, 11, "R_HEX_GPREL16_2" }, \
- { &relocGPREL16_3, 12, "R_HEX_GPREL16_3" }, \
+ { &relocPCREL, 1, "R_HEX_B22_PCREL" }, \
+ { &relocPCREL, 2, "R_HEX_B15_PCREL" }, \
+ { &relocPCREL, 3, "R_HEX_B7_PCREL" }, \
+ { &relocAbs, 4, "R_HEX_LO16" }, \
+ { &relocAbs, 5, "R_HEX_HI16" }, \
+ { &relocAbs, 6, "R_HEX_32" }, \
+ { &relocAbs, 7, "R_HEX_16" }, \
+ { &relocAbs, 8, "R_HEX_8" }, \
+ { &relocGPREL, 9, "R_HEX_GPREL16_0" }, \
+ { &relocGPREL, 10, "R_HEX_GPREL16_1" }, \
+ { &relocGPREL, 11, "R_HEX_GPREL16_2" }, \
+ { &relocGPREL, 12, "R_HEX_GPREL16_3" }, \
{ &unsupport, 13, "R_HEX_HL16" }, \
- { &relocB13PCREL, 14, "R_HEX_B13_PCREL" }, \
- { &relocB9PCREL, 15, "R_HEX_B9_PCREL" }, \
- { &relocB32PCRELX, 16, "R_HEX_B32_PCREL_X" }, \
- { &reloc32_6_X, 17, "R_HEX_32_6_X" }, \
- { &relocB22PCRELX, 18, "R_HEX_B22_PCREL_X" }, \
- { &relocB15PCRELX, 19, "R_HEX_B15_PCREL_X" }, \
- { &relocB13PCRELX, 20, "R_HEX_B13_PCREL_X" }, \
- { &relocB9PCRELX, 21, "R_HEX_B9_PCREL_X" }, \
- { &relocB7PCRELX, 22, "R_HEX_B7_PCREL_X" }, \
- { &relocHexNX, 23, "R_HEX_16_X" }, \
- { &relocHexNX, 24, "R_HEX_12_X" }, \
- { &relocHexNX, 25, "R_HEX_11_X" }, \
- { &relocHexNX, 26, "R_HEX_10_X" }, \
- { &relocHexNX, 27, "R_HEX_9_X" }, \
- { &relocHexNX, 28, "R_HEX_8_X" }, \
- { &relocHexNX, 29, "R_HEX_7_X" }, \
- { &relocHexNX, 30, "R_HEX_6_X" }, \
- { &reloc32PCREL, 31, "R_HEX_32_PCREL" }, \
- { &unsupport, 32, "R_HEX_COPY" }, \
- { &unsupport, 33, "R_HEX_GLOB_DAT" }, \
- { &unsupport, 34, "R_HEX_JMP_SLOT" }, \
- { &unsupport, 35, "R_HEX_RELATIVE" }, \
+ { &relocPCREL, 14, "R_HEX_B13_PCREL" }, \
+ { &relocPCREL, 15, "R_HEX_B9_PCREL" }, \
+ { &relocPCREL, 16, "R_HEX_B32_PCREL_X" }, \
+ { &relocAbs, 17, "R_HEX_32_6_X" }, \
+ { &relocPCREL, 18, "R_HEX_B22_PCREL_X" }, \
+ { &relocPCREL, 19, "R_HEX_B15_PCREL_X" }, \
+ { &relocPCREL, 20, "R_HEX_B13_PCREL_X" }, \
+ { &relocPCREL, 21, "R_HEX_B9_PCREL_X" }, \
+ { &relocPCREL, 22, "R_HEX_B7_PCREL_X" }, \
+ { &relocAbs, 23, "R_HEX_16_X" }, \
+ { &relocAbs, 24, "R_HEX_12_X" }, \
+ { &relocAbs, 25, "R_HEX_11_X" }, \
+ { &relocAbs, 26, "R_HEX_10_X" }, \
+ { &relocAbs, 27, "R_HEX_9_X" }, \
+ { &relocAbs, 28, "R_HEX_8_X" }, \
+ { &relocAbs, 29, "R_HEX_7_X" }, \
+ { &relocAbs, 30, "R_HEX_6_X" }, \
+ { &relocPCREL, 31, "R_HEX_32_PCREL" }, \
+ { &none, 32, "R_HEX_COPY" }, \
+ { &none, 33, "R_HEX_GLOB_DAT" }, \
+ { &none, 34, "R_HEX_JMP_SLOT" }, \
+ { &none, 35, "R_HEX_RELATIVE" }, \
{ &relocPLTB22PCREL, 36, "R_HEX_PLT_B22_PCREL" }, \
- { &relocHexGOTRELLO16, 37, "R_HEX_GOTREL_LO16" }, \
- { &relocHexGOTRELHI16, 38, "R_HEX_GOTREL_HI16" }, \
- { &relocHexGOTREL32, 39, "R_HEX_GOTREL_32" }, \
- { &unsupport, 40, "R_HEX_GOT_LO16" }, \
- { &unsupport, 41, "R_HEX_GOT_HI16" }, \
- { &unsupport, 42, "R_HEX_GOT_32" }, \
- { &unsupport, 43, "R_HEX_GOT_16" }, \
+ { &relocGOTREL, 37, "R_HEX_GOTREL_LO16" }, \
+ { &relocGOTREL, 38, "R_HEX_GOTREL_HI16" }, \
+ { &relocGOTREL, 39, "R_HEX_GOTREL_32" }, \
+ { &relocGOT, 40, "R_HEX_GOT_LO16" }, \
+ { &relocGOT, 41, "R_HEX_GOT_HI16" }, \
+ { &relocGOT, 42, "R_HEX_GOT_32" }, \
+ { &relocGOT, 43, "R_HEX_GOT_16" }, \
{ &unsupport, 44, "R_HEX_DTPMOD_32" }, \
{ &unsupport, 45, "R_HEX_DTPREL_LO16" }, \
{ &unsupport, 46, "R_HEX_DTPREL_HI16" }, \
@@ -138,13 +113,13 @@
{ &unsupport, 62, "R_HEX_TPREL_HI16" }, \
{ &unsupport, 63, "R_HEX_TPREL_32" }, \
{ &unsupport, 64, "R_HEX_TPREL_16" }, \
- { &relocHex6PCRELX, 65, "R_HEX_6_PCREL_X" }, \
- { &unsupport, 66, "R_HEX_GOTREL_32_6_X" }, \
- { &unsupport, 67, "R_HEX_GOTREL_16_X" }, \
- { &unsupport, 68, "R_HEX_GOTREL_11_X" }, \
- { &relocHexGOT326X, 69, "R_HEX_GOT_32_6_X" }, \
- { &relocHexGOT1611X, 70, "R_HEX_GOT_16_X" }, \
- { &relocHexGOT1611X, 71, "R_HEX_GOT_11_X" }, \
+ { &relocPCREL, 65, "R_HEX_6_PCREL_X" }, \
+ { &relocGOTREL, 66, "R_HEX_GOTREL_32_6_X" }, \
+ { &relocGOTREL, 67, "R_HEX_GOTREL_16_X" }, \
+ { &relocGOTREL, 68, "R_HEX_GOTREL_11_X" }, \
+ { &relocGOT, 69, "R_HEX_GOT_32_6_X" }, \
+ { &relocGOT, 70, "R_HEX_GOT_16_X" }, \
+ { &relocGOT, 71, "R_HEX_GOT_11_X" }, \
{ &unsupport, 72, "R_HEX_DTPREL_32_6_X" }, \
{ &unsupport, 73, "R_HEX_DTPREL_16_X" }, \
{ &unsupport, 74, "R_HEX_DTPREL_11_X" }, \
diff --git a/lib/Target/Hexagon/HexagonRelocator.cpp b/lib/Target/Hexagon/HexagonRelocator.cpp
index ba387cf..b82bbcd 100644
--- a/lib/Target/Hexagon/HexagonRelocator.cpp
+++ b/lib/Target/Hexagon/HexagonRelocator.cpp
@@ -6,34 +6,133 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-
-#include <llvm/ADT/Twine.h>
-#include <mcld/LD/LDSymbol.h>
-#include <llvm/Support/DataTypes.h>
-#include <llvm/Support/ELF.h>
-#include <mcld/Support/MsgHandling.h>
-
#include "HexagonRelocator.h"
#include "HexagonRelocationFunctions.h"
#include "HexagonEncodings.h"
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/DataTypes.h>
+#include <llvm/Support/ELF.h>
+
+#include <mcld/LD/ELFFileFormat.h>
+#include <mcld/LD/LDSymbol.h>
+#include <mcld/Support/MsgHandling.h>
using namespace mcld;
//===--------------------------------------------------------------------===//
+// Relocation Helper Functions
+//===--------------------------------------------------------------------===//
+/// helper_DynRel - Get an relocation entry in .rela.dyn
+static Relocation &helper_DynRel_init(ResolveInfo *pSym,
+ Fragment &pFrag,
+ uint64_t pOffset,
+ HexagonRelocator::Type pType,
+ HexagonRelocator &pParent) {
+ HexagonLDBackend &ld_backend = pParent.getTarget();
+ Relocation &rela_entry = *ld_backend.getRelaDyn().create();
+ rela_entry.setType(pType);
+ rela_entry.targetRef().assign(pFrag, pOffset);
+ if (pType == llvm::ELF::R_HEX_RELATIVE || NULL == pSym)
+ rela_entry.setSymInfo(0);
+ else
+ rela_entry.setSymInfo(pSym);
+
+ return rela_entry;
+}
+
+/// helper_use_relative_reloc - Check if symbol can use relocation
+/// R_HEX_RELATIVE
+static bool helper_use_relative_reloc(const ResolveInfo &pSym,
+ const HexagonRelocator &pFactory) {
+ // if symbol is dynamic or undefine or preemptible
+ if (pSym.isDyn() || pSym.isUndef() ||
+ pFactory.getTarget().isSymbolPreemptible(pSym))
+ return false;
+ return true;
+}
+
+static HexagonGOTEntry &helper_GOT_init(Relocation &pReloc,
+ bool pHasRel,
+ HexagonRelocator &pParent) {
+ // rsym - The relocation target symbol
+ ResolveInfo *rsym = pReloc.symInfo();
+ HexagonLDBackend &ld_backend = pParent.getTarget();
+ assert(NULL == pParent.getSymGOTMap().lookUp(*rsym));
+
+ HexagonGOTEntry *got_entry = ld_backend.getGOT().create();
+ pParent.getSymGOTMap().record(*rsym, *got_entry);
+
+ if (!pHasRel) {
+ // No corresponding dynamic relocation, initialize to the symbol value.
+ got_entry->setValue(HexagonRelocator::SymVal);
+ }
+ else {
+ // Initialize got_entry content and the corresponding dynamic relocation.
+ if (helper_use_relative_reloc(*rsym, pParent)) {
+ helper_DynRel_init(rsym, *got_entry, 0x0, llvm::ELF::R_HEX_RELATIVE,
+ pParent);
+ got_entry->setValue(HexagonRelocator::SymVal);
+ }
+ else {
+ helper_DynRel_init(rsym, *got_entry, 0x0, llvm::ELF::R_HEX_GLOB_DAT,
+ pParent);
+ got_entry->setValue(0);
+ }
+ }
+ return *got_entry;
+}
+
+static HexagonRelocator::Address helper_get_GOT_address(ResolveInfo &pSym,
+ HexagonRelocator &pParent) {
+ HexagonGOTEntry *got_entry = pParent.getSymGOTMap().lookUp(pSym);
+ assert(NULL != got_entry);
+ return pParent.getTarget().getGOT().addr() + got_entry->getOffset();
+}
+
+static PLTEntryBase &helper_PLT_init(Relocation &pReloc,
+ HexagonRelocator &pParent) {
+ // rsym - The relocation target symbol
+ ResolveInfo *rsym = pReloc.symInfo();
+ HexagonLDBackend &ld_backend = pParent.getTarget();
+ assert(NULL == pParent.getSymPLTMap().lookUp(*rsym));
+
+ PLTEntryBase *plt_entry = ld_backend.getPLT().create();
+ pParent.getSymPLTMap().record(*rsym, *plt_entry);
+
+ assert(NULL == pParent.getSymGOTPLTMap().lookUp(*rsym) &&
+ "PLT entry not exist, but DynRel entry exist!");
+ HexagonGOTEntry *gotplt_entry = ld_backend.getGOTPLT().create();
+ pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
+ // init the corresponding rel entry in .rela.plt
+ Relocation &rela_entry = *ld_backend.getRelaPLT().create();
+ rela_entry.setType(llvm::ELF::R_HEX_JMP_SLOT);
+ rela_entry.targetRef().assign(*gotplt_entry);
+ rela_entry.setSymInfo(rsym);
+
+ return *plt_entry;
+}
+
+static HexagonRelocator::Address helper_get_PLT_address(ResolveInfo& pSym,
+ HexagonRelocator &pParent) {
+ PLTEntryBase *plt_entry = pParent.getSymPLTMap().lookUp(pSym);
+ assert(NULL != plt_entry);
+ return pParent.getTarget().getPLT().addr() + plt_entry->getOffset();
+}
+
+//===--------------------------------------------------------------------===//
// Relocation Functions and Tables
//===--------------------------------------------------------------------===//
DECL_HEXAGON_APPLY_RELOC_FUNCS
-/// the prototype of applying function
-typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc,
- HexagonRelocator& pParent);
+ /// the prototype of applying function
+ typedef Relocator::Result (*ApplyFunctionType)(Relocation &pReloc,
+ HexagonRelocator &pParent);
// the table entry of applying functions
-struct ApplyFunctionTriple
-{
+struct ApplyFunctionTriple {
ApplyFunctionType func;
unsigned int type;
- const char* name;
+ const char *name;
};
// declare the table of applying functions
@@ -41,8 +140,9 @@
DECL_HEXAGON_APPLY_RELOC_FUNC_PTRS
};
-static uint32_t findBitMask(uint32_t insn, Instruction *encodings, int32_t numInsns) {
- for (int32_t i = 0; i < numInsns ; i++) {
+static uint32_t findBitMask(uint32_t insn, Instruction *encodings,
+ int32_t numInsns) {
+ for (int32_t i = 0; i < numInsns; i++) {
if (((insn & 0xc000) == 0) && !(encodings[i].isDuplex))
continue;
@@ -53,30 +153,25 @@
return encodings[i].insnBitMask;
}
assert(0);
+ // Should not be here, but add a return for -Werror=return-type
+ // error: control reaches end of non-void function
+ return -1;
}
-
-#define FINDBITMASK(INSN) \
- findBitMask((uint32_t)INSN,\
- insn_encodings,\
+#define FINDBITMASK(INSN) \
+ findBitMask((uint32_t) INSN, insn_encodings, \
sizeof(insn_encodings) / sizeof(Instruction))
//===--------------------------------------------------------------------===//
// HexagonRelocator
//===--------------------------------------------------------------------===//
-HexagonRelocator::HexagonRelocator(HexagonLDBackend& pParent,
- const LinkerConfig& pConfig)
- : Relocator(pConfig),
- m_Target(pParent) {
-}
+HexagonRelocator::HexagonRelocator(HexagonLDBackend &pParent,
+ const LinkerConfig &pConfig)
+ : Relocator(pConfig), m_Target(pParent) {}
-HexagonRelocator::~HexagonRelocator()
-{
-}
+HexagonRelocator::~HexagonRelocator() {}
-Relocator::Result
-HexagonRelocator::applyRelocation(Relocation& pRelocation)
-{
+Relocator::Result HexagonRelocator::applyRelocation(Relocation &pRelocation) {
Relocation::Type type = pRelocation.type();
if (type > 85) { // 86-255 relocs do not exists for Hexagon
@@ -87,30 +182,27 @@
return ApplyFunctions[type].func(pRelocation, *this);
}
-const char* HexagonRelocator::getName(Relocation::Type pType) const
-{
+const char *HexagonRelocator::getName(Relocation::Type pType) const {
return ApplyFunctions[pType].name;
}
-Relocator::Size HexagonRelocator::getSize(Relocation::Type pType) const
-{
+Relocator::Size HexagonRelocator::getSize(Relocation::Type pType) const {
return 32;
}
-void HexagonRelocator::scanRelocation(Relocation& pReloc,
- IRBuilder& pLinker,
- Module& pModule,
- LDSection& pSection)
-{
+void HexagonRelocator::scanRelocation(Relocation &pReloc, IRBuilder &pLinker,
+ Module &pModule, LDSection &pSection, Input &pInput) {
if (LinkerConfig::Object == config().codeGenType())
return;
- pReloc.updateAddend();
// rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
+ ResolveInfo *rsym = pReloc.symInfo();
assert(NULL != rsym &&
"ResolveInfo of relocation not set while scanRelocation");
+ if (config().isCodeStatic())
+ return;
+
assert(NULL != pSection.getLink());
if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC))
return;
@@ -123,106 +215,179 @@
// check if we should issue undefined reference for the relocation target
// symbol
if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
- fatal(diag::undefined_reference) << rsym->name();
+ issueUndefRef(pReloc, pSection, pInput);
}
-void HexagonRelocator::addCopyReloc(ResolveInfo& pSym,
- HexagonLDBackend& pTarget)
-{
- Relocation& rel_entry = *pTarget.getRelaDyn().consumeEntry();
+void HexagonRelocator::addCopyReloc(ResolveInfo &pSym,
+ HexagonLDBackend &pTarget) {
+ Relocation &rel_entry = *pTarget.getRelaDyn().create();
rel_entry.setType(pTarget.getCopyRelType());
assert(pSym.outSymbol()->hasFragRef());
rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef());
rel_entry.setSymInfo(&pSym);
}
-void HexagonRelocator::scanLocalReloc(Relocation& pReloc,
- IRBuilder& pBuilder,
- Module& pModule,
- LDSection& pSection)
-{
+void HexagonRelocator::scanLocalReloc(Relocation &pReloc, IRBuilder &pBuilder,
+ Module &pModule, LDSection &pSection) {
// rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
+ ResolveInfo *rsym = pReloc.symInfo();
- switch(pReloc.type()){
+ switch (pReloc.type()) {
- case llvm::ELF::R_HEX_32:
- case llvm::ELF::R_HEX_16:
- case llvm::ELF::R_HEX_8:
- // If buiding PIC object (shared library or PIC executable),
- // a dynamic relocations with RELATIVE type to this location is needed.
- // Reserve an entry in .rel.dyn
- if (config().isCodeIndep()) {
- getTarget().getRelaDyn().reserveEntry();
- // set Rel bit
- rsym->setReserved(rsym->reserved() | ReserveRel);
- getTarget().checkAndSetHasTextRel(*pSection.getLink());
- }
- return;
+ case llvm::ELF::R_HEX_LO16:
+ case llvm::ELF::R_HEX_HI16:
+ case llvm::ELF::R_HEX_16:
+ case llvm::ELF::R_HEX_8:
+ case llvm::ELF::R_HEX_32_6_X:
+ case llvm::ELF::R_HEX_16_X:
+ case llvm::ELF::R_HEX_12_X:
+ case llvm::ELF::R_HEX_11_X:
+ case llvm::ELF::R_HEX_10_X:
+ case llvm::ELF::R_HEX_9_X:
+ case llvm::ELF::R_HEX_8_X:
+ case llvm::ELF::R_HEX_7_X:
+ case llvm::ELF::R_HEX_6_X:
+ assert(!(rsym->reserved() & ReserveRel) &&
+ "Cannot apply this relocation for read only section");
+ return;
- default:
- break;
+ case llvm::ELF::R_HEX_32:
+ // If buiding PIC object (shared library or PIC executable),
+ // a dynamic relocations with RELATIVE type to this location is needed.
+ // Reserve an entry in .rel.dyn
+ if (config().isCodeIndep()) {
+ Relocation &reloc = helper_DynRel_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ llvm::ELF::R_HEX_RELATIVE,
+ *this);
+ // we need to set up the relocation addend at apply relocation, record the
+ // relocation
+ getRelRelMap().record(pReloc, reloc);
+
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ getTarget().checkAndSetHasTextRel(*pSection.getLink());
+ }
+ return;
+
+ default:
+ return;
}
}
-void HexagonRelocator::scanGlobalReloc(Relocation& pReloc,
- IRBuilder& pBuilder,
- Module& pModule,
- LDSection& pSection)
-{
+void HexagonRelocator::scanGlobalReloc(Relocation &pReloc, IRBuilder &pBuilder,
+ Module &pModule, LDSection &pSection) {
// rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
+ ResolveInfo *rsym = pReloc.symInfo();
+ HexagonLDBackend &ld_backend = getTarget();
- switch(pReloc.type()) {
- case llvm::ELF::R_HEX_PLT_B22_PCREL:
- // return if we already create plt for this symbol
- if (rsym->reserved() & ReservePLT)
- return;
+ switch (pReloc.type()) {
+ case llvm::ELF::R_HEX_LO16:
+ case llvm::ELF::R_HEX_HI16:
+ case llvm::ELF::R_HEX_16:
+ case llvm::ELF::R_HEX_8:
+ case llvm::ELF::R_HEX_32_6_X:
+ case llvm::ELF::R_HEX_16_X:
+ case llvm::ELF::R_HEX_12_X:
+ case llvm::ELF::R_HEX_11_X:
+ case llvm::ELF::R_HEX_10_X:
+ case llvm::ELF::R_HEX_9_X:
+ case llvm::ELF::R_HEX_8_X:
+ case llvm::ELF::R_HEX_7_X:
+ case llvm::ELF::R_HEX_6_X:
+ assert(!(rsym->reserved() & ReserveRel) &&
+ "Cannot apply this relocation for read only section");
+ return;
- // Symbol needs PLT entry, we need to reserve a PLT entry
- // and the corresponding GOT and dynamic relocation entry
- // in .got.plt and .rela.plt.
- getTarget().getPLT().reserveEntry();
- getTarget().getGOTPLT().reserve();
- getTarget().getRelaPLT().reserveEntry();
- // set PLT bit
- rsym->setReserved(rsym->reserved() | ReservePLT);
- return;
-
- case llvm::ELF::R_HEX_GOT_32_6_X:
- case llvm::ELF::R_HEX_GOT_16_X:
- case llvm::ELF::R_HEX_GOT_11_X:
- // Symbol needs GOT entry, reserve entry in .got
- // return if we already create GOT for this symbol
- if (rsym->reserved() & (ReserveGOT | GOTRel))
- return;
- // FIXME: check STT_GNU_IFUNC symbol
- getTarget().getGOT().reserve();
-
- // If the GOT is used in statically linked binaries,
- // the GOT entry is enough and no relocation is needed.
- if (config().isCodeStatic()) {
- rsym->setReserved(rsym->reserved() | ReserveGOT);
- return;
+ case llvm::ELF::R_HEX_32:
+ if (ld_backend.symbolNeedsPLT(*rsym)) {
+ //create PLT for this symbol if it does not have.
+ if (!(rsym->reserved() & ReservePLT)) {
+ helper_PLT_init(pReloc, *this);
+ rsym->setReserved(rsym->reserved() | ReservePLT);
}
- // If building shared object or the symbol is undefined, a dynamic
- // relocation is needed to relocate this GOT entry. Reserve an
- // entry in .rel.dyn
- if (LinkerConfig::DynObj ==
- config().codeGenType() || rsym->isUndef() || rsym->isDyn()) {
- getTarget().getRelaDyn().reserveEntry();
- // set GOTRel bit
- rsym->setReserved(rsym->reserved() | GOTRel);
- return;
- }
- // set GOT bit
- rsym->setReserved(rsym->reserved() | ReserveGOT);
- return;
-
- default: {
- break;
}
- } // end switch
+
+ if (ld_backend.symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT),
+ true)) {
+ if (ld_backend.symbolNeedsCopyReloc(pReloc, *rsym)) {
+ LDSymbol &cpy_sym =
+ defineSymbolforCopyReloc(pBuilder, *rsym, ld_backend);
+ addCopyReloc(*cpy_sym.resolveInfo(), ld_backend);
+ }
+ else {
+ Relocation &reloc = helper_DynRel_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ llvm::ELF::R_HEX_RELATIVE,
+ *this);
+ // we need to set up the relocation addend at apply relocation, record the
+ // relocation
+ getRelRelMap().record(pReloc, reloc);
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ ld_backend.checkAndSetHasTextRel(*pSection.getLink());
+ }
+ }
+ return;
+
+ case llvm::ELF::R_HEX_GOTREL_LO16:
+ case llvm::ELF::R_HEX_GOTREL_HI16:
+ case llvm::ELF::R_HEX_GOTREL_32:
+ case llvm::ELF::R_HEX_GOTREL_32_6_X:
+ case llvm::ELF::R_HEX_GOTREL_16_X:
+ case llvm::ELF::R_HEX_GOTREL_11_X:
+ // This assumes that GOT exists
+ return;
+
+ case llvm::ELF::R_HEX_GOT_LO16:
+ case llvm::ELF::R_HEX_GOT_HI16:
+ case llvm::ELF::R_HEX_GOT_32:
+ case llvm::ELF::R_HEX_GOT_16:
+ case llvm::ELF::R_HEX_GOT_32_6_X:
+ case llvm::ELF::R_HEX_GOT_16_X:
+ case llvm::ELF::R_HEX_GOT_11_X:
+ // Symbol needs GOT entry, reserve entry in .got
+ // return if we already create GOT for this symbol
+ if (rsym->reserved() & ReserveGOT)
+ return;
+ // If the GOT is used in statically linked binaries,
+ // the GOT entry is enough and no relocation is needed.
+ if (config().isCodeStatic())
+ helper_GOT_init(pReloc, false, *this);
+ else
+ helper_GOT_init(pReloc, true, *this);
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
+ return;
+
+ case llvm::ELF::R_HEX_B22_PCREL:
+ case llvm::ELF::R_HEX_B15_PCREL:
+ case llvm::ELF::R_HEX_B7_PCREL:
+ case llvm::ELF::R_HEX_B13_PCREL:
+ case llvm::ELF::R_HEX_B9_PCREL:
+ case llvm::ELF::R_HEX_B32_PCREL_X:
+ case llvm::ELF::R_HEX_B22_PCREL_X:
+ case llvm::ELF::R_HEX_B15_PCREL_X:
+ case llvm::ELF::R_HEX_B13_PCREL_X:
+ case llvm::ELF::R_HEX_B9_PCREL_X:
+ case llvm::ELF::R_HEX_B7_PCREL_X:
+ case llvm::ELF::R_HEX_32_PCREL:
+ case llvm::ELF::R_HEX_6_PCREL_X:
+ case llvm::ELF::R_HEX_PLT_B22_PCREL:
+ if (rsym->reserved() & ReservePLT)
+ return;
+ if (ld_backend.symbolNeedsPLT(*rsym) ||
+ pReloc.type() == llvm::ELF::R_HEX_PLT_B22_PCREL) {
+ helper_PLT_init(pReloc, *this);
+ rsym->setReserved(rsym->reserved() | ReservePLT);
+ }
+ return;
+
+ default:
+ break;
+
+ } // end of switch
}
/// defineSymbolforCopyReloc
@@ -230,13 +395,11 @@
/// section and all other reference to this symbol should refer to this
/// copy.
/// @note This is executed at `scan relocation' stage.
-LDSymbol& HexagonRelocator::defineSymbolforCopyReloc(IRBuilder& pBuilder,
- const ResolveInfo& pSym,
- HexagonLDBackend& pTarget)
-{
+LDSymbol &HexagonRelocator::defineSymbolforCopyReloc(
+ IRBuilder &pBuilder, const ResolveInfo &pSym, HexagonLDBackend &pTarget) {
// get or create corresponding BSS LDSection
- LDSection* bss_sect_hdr = NULL;
- ELFFileFormat* file_format = pTarget.getOutputFormat();
+ LDSection *bss_sect_hdr = NULL;
+ ELFFileFormat *file_format = pTarget.getOutputFormat();
if (ResolveInfo::ThreadLocal == pSym.type())
bss_sect_hdr = &file_format->getTBSS();
else
@@ -244,7 +407,7 @@
// get or create corresponding BSS SectionData
assert(NULL != bss_sect_hdr);
- SectionData* bss_section = NULL;
+ SectionData *bss_section = NULL;
if (bss_sect_hdr->hasSectionData())
bss_section = bss_sect_hdr->getSectionData();
else
@@ -255,45 +418,36 @@
uint32_t addralign = config().targets().bitclass() / 8;
// allocate space in BSS for the copy symbol
- Fragment* frag = new FillFragment(0x0, 1, pSym.size());
- uint64_t size = ObjectBuilder::AppendFragment(*frag,
- *bss_section,
- addralign);
+ Fragment *frag = new FillFragment(0x0, 1, pSym.size());
+ uint64_t size = ObjectBuilder::AppendFragment(*frag, *bss_section, addralign);
bss_sect_hdr->setSize(bss_sect_hdr->size() + size);
// change symbol binding to Global if it's a weak symbol
- ResolveInfo::Binding binding = (ResolveInfo::Binding)pSym.binding();
+ ResolveInfo::Binding binding = (ResolveInfo::Binding) pSym.binding();
if (binding == ResolveInfo::Weak)
binding = ResolveInfo::Global;
// Define the copy symbol in the bss section and resolve it
- LDSymbol* cpy_sym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
- pSym.name(),
- (ResolveInfo::Type)pSym.type(),
- ResolveInfo::Define,
- binding,
- pSym.size(), // size
- 0x0, // value
- FragmentRef::Create(*frag, 0x0),
- (ResolveInfo::Visibility)pSym.other());
+ LDSymbol *cpy_sym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
+ pSym.name(), (ResolveInfo::Type) pSym.type(), ResolveInfo::Define,
+ binding, pSym.size(), // size
+ 0x0, // value
+ FragmentRef::Create(*frag, 0x0), (ResolveInfo::Visibility) pSym.other());
// output all other alias symbols if any
Module &pModule = pBuilder.getModule();
- Module::AliasList* alias_list = pModule.getAliasList(pSym);
- if (NULL!=alias_list) {
- Module::alias_iterator it, it_e=alias_list->end();
- for (it=alias_list->begin(); it!=it_e; ++it) {
- const ResolveInfo* alias = *it;
- if (alias!=&pSym && alias->isDyn()) {
+ Module::AliasList *alias_list = pModule.getAliasList(pSym);
+ if (NULL != alias_list) {
+ Module::alias_iterator it, it_e = alias_list->end();
+ for (it = alias_list->begin(); it != it_e; ++it) {
+ const ResolveInfo *alias = *it;
+ if (alias != &pSym && alias->isDyn()) {
pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
- alias->name(),
- (ResolveInfo::Type)alias->type(),
- ResolveInfo::Define,
- binding,
- alias->size(), // size
- 0x0, // value
- FragmentRef::Create(*frag, 0x0),
- (ResolveInfo::Visibility)alias->other());
+ alias->name(), (ResolveInfo::Type) alias->type(),
+ ResolveInfo::Define, binding, alias->size(), // size
+ 0x0, // value
+ FragmentRef::Create(*frag, 0x0),
+ (ResolveInfo::Visibility) alias->other());
}
}
}
@@ -301,587 +455,359 @@
return *cpy_sym;
}
-void HexagonRelocator::partialScanRelocation(Relocation& pReloc,
- Module& pModule,
- const LDSection& pSection)
-{
+void HexagonRelocator::partialScanRelocation(Relocation &pReloc,
+ Module &pModule,
+ const LDSection &pSection) {
pReloc.updateAddend();
// if we meet a section symbol
if (pReloc.symInfo()->type() == ResolveInfo::Section) {
- LDSymbol* input_sym = pReloc.symInfo()->outSymbol();
+ LDSymbol *input_sym = pReloc.symInfo()->outSymbol();
// 1. update the relocation target offset
assert(input_sym->hasFragRef());
// 2. get the output LDSection which the symbol defined in
- const LDSection& out_sect =
- input_sym->fragRef()->frag()->getParent()->getSection();
- ResolveInfo* sym_info =
- pModule.getSectionSymbolSet().get(out_sect)->resolveInfo();
+ const LDSection &out_sect =
+ input_sym->fragRef()->frag()->getParent()->getSection();
+ ResolveInfo *sym_info =
+ pModule.getSectionSymbolSet().get(out_sect)->resolveInfo();
// set relocation target symbol to the output section symbol's resolveInfo
pReloc.setSymInfo(sym_info);
}
}
-/// helper_DynRel - Get an relocation entry in .rela.dyn
-static
-Relocation& helper_DynRel(ResolveInfo* pSym,
- Fragment& pFrag,
- uint64_t pOffset,
- HexagonRelocator::Type pType,
- HexagonRelocator& pParent)
-{
- HexagonLDBackend& ld_backend = pParent.getTarget();
- Relocation& rela_entry = *ld_backend.getRelaDyn().consumeEntry();
- rela_entry.setType(pType);
- rela_entry.targetRef().assign(pFrag, pOffset);
- if (pType == llvm::ELF::R_HEX_RELATIVE || NULL == pSym)
- rela_entry.setSymInfo(0);
- else
- rela_entry.setSymInfo(pSym);
-
- return rela_entry;
-}
-
-
-/// helper_use_relative_reloc - Check if symbol can use relocation
-/// R_HEX_RELATIVE
-static bool
-helper_use_relative_reloc(const ResolveInfo& pSym,
- const HexagonRelocator& pFactory)
-
-{
- // if symbol is dynamic or undefine or preemptible
- if (pSym.isDyn() ||
- pSym.isUndef() ||
- pFactory.getTarget().isSymbolPreemptible(pSym))
- return false;
- return true;
-}
-
-static
-HexagonGOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- // rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
- HexagonLDBackend& ld_backend = pParent.getTarget();
-
- HexagonGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
- if (NULL != got_entry)
- return *got_entry;
-
- // not found
- got_entry = ld_backend.getGOT().consume();
- pParent.getSymGOTMap().record(*rsym, *got_entry);
-
- // If we first get this GOT entry, we should initialize it.
- if (rsym->reserved() & HexagonRelocator::ReserveGOT) {
- // No corresponding dynamic relocation, initialize to the symbol value.
- got_entry->setValue(pReloc.symValue());
- }
- else if (rsym->reserved() & HexagonRelocator::GOTRel) {
- // Initialize got_entry content and the corresponding dynamic relocation.
- if (helper_use_relative_reloc(*rsym, pParent)) {
- helper_DynRel(rsym, *got_entry, 0x0, llvm::ELF::R_HEX_RELATIVE, pParent);
- got_entry->setValue(pReloc.symValue());
- }
- else {
- helper_DynRel(rsym, *got_entry, 0x0, llvm::ELF::R_HEX_GLOB_DAT, pParent);
- got_entry->setValue(0);
- }
- }
- else {
- fatal(diag::reserve_entry_number_mismatch_got);
- }
- return *got_entry;
-}
-
-static
-HexagonRelocator::Address helper_GOT_ORG(HexagonRelocator& pParent)
-{
- return pParent.getTarget().getGOT().addr();
-}
-
-static
-HexagonRelocator::Address helper_GOT(Relocation& pReloc, HexagonRelocator& pParent)
-{
- HexagonGOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent);
- return helper_GOT_ORG(pParent) + got_entry.getOffset();
-}
-
-static
-PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- // rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
- HexagonLDBackend& ld_backend = pParent.getTarget();
-
- PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(*rsym);
- if (NULL != plt_entry)
- return *plt_entry;
-
- // not found
- plt_entry = ld_backend.getPLT().consume();
- pParent.getSymPLTMap().record(*rsym, *plt_entry);
- // If we first get this PLT entry, we should initialize it.
- if (rsym->reserved() & HexagonRelocator::ReservePLT) {
- HexagonGOTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym);
- assert(NULL == gotplt_entry && "PLT entry not exist, but DynRel entry exist!");
- gotplt_entry = ld_backend.getGOTPLT().consume();
- pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
- // init the corresponding rel entry in .rel.plt
- Relocation& rela_entry = *ld_backend.getRelaPLT().consumeEntry();
- rela_entry.setType(llvm::ELF::R_HEX_JMP_SLOT);
- rela_entry.targetRef().assign(*gotplt_entry);
- rela_entry.setSymInfo(rsym);
- }
- else {
- fatal(diag::reserve_entry_number_mismatch_plt);
- }
-
- return *plt_entry;
-}
-
-static
-HexagonRelocator::Address helper_PLT_ORG(HexagonRelocator& pParent)
-{
- return pParent.getTarget().getPLT().addr();
-}
-
-static
-HexagonRelocator::Address helper_PLT(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- PLTEntryBase& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
- return helper_PLT_ORG(pParent) + plt_entry.getOffset();
-}
-
//=========================================//
// Each relocation function implementation //
//=========================================//
// R_HEX_NONE
-HexagonRelocator::Result none(Relocation& pReloc, HexagonRelocator& pParent)
-{
+HexagonRelocator::Result none(Relocation &pReloc, HexagonRelocator &pParent) {
return HexagonRelocator::OK;
}
-// R_HEX_B15_PCREL: Word32_B15 : 0x00df20fe (S + A - P) >> 2 : Signed Verify
-HexagonRelocator::Result relocB15PCREL(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
+//R_HEX_32 and its class of relocations use only addend and symbol value
+// S + A : result is unsigned truncate.
+// Exception: R_HEX_32_6_X : unsigned verify
+HexagonRelocator::Result applyAbs(Relocation &pReloc) {
HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord P = pReloc.place();
-
- int32_t result = (int32_t) ((S + A - P) >> 2);
- int32_t range = 1 << 14;
- if ( (result < range) && (result > -range)) {
- pReloc.target() = pReloc.target() | ApplyMask<int32_t>(0x00df20fe,result);
- return HexagonRelocator::OK;
- }
- return HexagonRelocator::Overflow;
-}
-
-// R_HEX_B22_PCREL: Word32_B22 : 0x01ff3ffe (S + A - P) >> 2 : Signed Verify
-HexagonRelocator::Result relocB22PCREL(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord P = pReloc.place();
-
- int32_t result = (int32_t) ((S + A - P) >> 2);
- int32_t range = 1 << 21;
- uint32_t bitMask = FINDBITMASK(pReloc.target());
- if ( (result < range) && (result > -range)) {
- pReloc.target() = pReloc.target() | ApplyMask<int32_t>(bitMask, result);
- return HexagonRelocator::OK;
- }
- return HexagonRelocator::Overflow;
-}
-
-// R_HEX_B7_PCREL: Word32_B7 : 0x0001f18 (S + A - P) >> 2 : Signed Verify
-HexagonRelocator::Result relocB7PCREL(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord P = pReloc.place();
-
- int32_t result = (int32_t) ((S + A - P) >> 2);
- int32_t range = 1 << 6;
- if ( (result < range) && (result > -range)) {
- pReloc.target() = pReloc.target() | ApplyMask<int32_t>(0x00001f18, result);
- return HexagonRelocator::OK;
- }
- return HexagonRelocator::Overflow;
-}
-
-// R_HEX_32: Word32 : 0xffffffff : (S + A) : Unsigned Truncate
-HexagonRelocator::Result reloc32(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord S = pReloc.symValue();
- ResolveInfo* rsym = pReloc.symInfo();
- bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel(
- *rsym,
- (rsym->reserved() & HexagonRelocator::ReservePLT),
- true);
+ uint32_t result = (uint32_t)(S + A);
+ uint32_t bitMask = 0;
+ uint32_t effectiveBits = 0;
+ uint32_t alignment = 1;
+ uint32_t shift = 0;
- // A local symbol may need REL Type dynamic relocation
+ switch (pReloc.type()) {
+ case llvm::ELF::R_HEX_LO16:
+ bitMask = 0x00c03fff;
+ break;
+
+ case llvm::ELF::R_HEX_HI16:
+ shift = 16;
+ bitMask = 0x00c03fff;
+ break;
+
+ case llvm::ELF::R_HEX_32:
+ bitMask = 0xffffffff;
+ break;
+
+ case llvm::ELF::R_HEX_16:
+ bitMask = 0x0000ffff;
+ alignment = 2;
+ break;
+
+ case llvm::ELF::R_HEX_8:
+ bitMask = 0x000000ff;
+ alignment = 1;
+ break;
+
+ case llvm::ELF::R_HEX_12_X:
+ bitMask = 0x000007e0;
+ break;
+
+ case llvm::ELF::R_HEX_32_6_X:
+ bitMask = 0xfff3fff;
+ shift = 6;
+ effectiveBits = 26;
+ break;
+
+ case llvm::ELF::R_HEX_16_X:
+ case llvm::ELF::R_HEX_11_X:
+ case llvm::ELF::R_HEX_10_X:
+ case llvm::ELF::R_HEX_9_X:
+ case llvm::ELF::R_HEX_8_X:
+ case llvm::ELF::R_HEX_7_X:
+ case llvm::ELF::R_HEX_6_X:
+ bitMask = FINDBITMASK(pReloc.target());
+ break;
+
+ default:
+ // show proper error
+ fatal(diag::unsupported_relocation) << (int)
+ pReloc.type() << "mclinker@googlegroups.com";
+
+ }
+
+ if ((shift != 0) && (result % alignment != 0))
+ return HexagonRelocator::BadReloc;
+
+ result >>= shift;
+
+ if (effectiveBits) {
+ uint32_t range = 1 << effectiveBits;
+ if (result > (range - 1))
+ return HexagonRelocator::Overflow;
+ }
+
+ pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
+ return HexagonRelocator::OK;
+}
+
+//R_HEX_B22_PCREL and its class of relocations, use
+// S + A - P : result is signed verify.
+// Exception: R_HEX_B32_PCREL_X : signed truncate
+// Another Exception: R_HEX_6_PCREL_X is unsigned truncate
+HexagonRelocator::Result applyRel(Relocation &pReloc, int64_t pResult) {
+ uint32_t bitMask = 0;
+ uint32_t effectiveBits = 0;
+ uint32_t alignment = 1;
+ uint32_t result;
+ uint32_t shift = 0;
+
+ switch (pReloc.type()) {
+ case llvm::ELF::R_HEX_B22_PCREL:
+ bitMask = 0x01ff3ffe;
+ effectiveBits = 22;
+ alignment = 4;
+ shift = 2;
+ break;
+
+ case llvm::ELF::R_HEX_B15_PCREL:
+ bitMask = 0x00df20fe;
+ effectiveBits = 15;
+ alignment = 4;
+ shift = 2;
+ break;
+
+ case llvm::ELF::R_HEX_B7_PCREL:
+ bitMask = 0x00001f18;
+ effectiveBits = 7;
+ alignment = 4;
+ shift = 2;
+ break;
+
+ case llvm::ELF::R_HEX_B13_PCREL:
+ bitMask = 0x00202ffe;
+ effectiveBits = 13;
+ alignment = 4;
+ shift = 2;
+ break;
+
+ case llvm::ELF::R_HEX_B9_PCREL:
+ bitMask = 0x003000fe;
+ effectiveBits = 9;
+ alignment = 4;
+ shift = 2;
+ break;
+
+ case llvm::ELF::R_HEX_B32_PCREL_X:
+ bitMask = 0xfff3fff;
+ shift = 6;
+ break;
+
+ case llvm::ELF::R_HEX_B22_PCREL_X:
+ bitMask = 0x01ff3ffe;
+ effectiveBits = 22;
+ pResult &= 0x3f;
+ break;
+
+ case llvm::ELF::R_HEX_B15_PCREL_X:
+ bitMask = 0x00df20fe;
+ effectiveBits = 15;
+ pResult &= 0x3f;
+ break;
+
+ case llvm::ELF::R_HEX_B13_PCREL_X:
+ bitMask = 0x00202ffe;
+ effectiveBits = 13;
+ pResult &= 0x3f;
+ break;
+
+ case llvm::ELF::R_HEX_B9_PCREL_X:
+ bitMask = 0x003000fe;
+ effectiveBits = 9;
+ pResult &= 0x3f;
+ break;
+
+ case llvm::ELF::R_HEX_B7_PCREL_X:
+ bitMask = 0x00001f18;
+ effectiveBits = 7;
+ pResult &= 0x3f;
+ break;
+
+ case llvm::ELF::R_HEX_32_PCREL:
+ bitMask = 0xffffffff;
+ effectiveBits = 32;
+ break;
+
+ case llvm::ELF::R_HEX_6_PCREL_X:
+ // This is unique since it has a unsigned operand and its truncated
+ bitMask = FINDBITMASK(pReloc.target());
+ result = pReloc.addend() + pReloc.symValue() - pReloc.place();
+ pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
+ return HexagonRelocator::OK;
+
+ default:
+ // show proper error
+ fatal(diag::unsupported_relocation) << (int)
+ pReloc.type() << "mclinker@googlegroups.com";
+ }
+
+ if ((shift != 0) && (pResult % alignment != 0))
+ return HexagonRelocator::BadReloc;
+
+ pResult >>= shift;
+
+ if (effectiveBits) {
+ int64_t range = 1LL << (effectiveBits - 1);
+ if ((pResult > (range - 1)) || (pResult < -range))
+ return HexagonRelocator::Overflow;
+ }
+
+ pReloc.target() |= (uint32_t) ApplyMask<int32_t>(bitMask, pResult);
+ return HexagonRelocator::OK;
+}
+
+HexagonRelocator::Result relocAbs(Relocation &pReloc,
+ HexagonRelocator &pParent) {
+ ResolveInfo *rsym = pReloc.symInfo();
+ HexagonRelocator::Address S = pReloc.symValue();
+ HexagonRelocator::DWord A = pReloc.addend();
+
+ Relocation* rel_entry = pParent.getRelRelMap().lookUp(pReloc);
+ bool has_dyn_rel = (NULL != rel_entry);
+
+ // if the flag of target section is not ALLOC, we eprform only static
+ // relocation.
+ if (0 == (llvm::ELF::SHF_ALLOC &
+ pReloc.targetRef().frag()->getParent()->getSection().flag())) {
+ return applyAbs(pReloc);
+ }
+
+ // a local symbol with .rela type relocation
if (rsym->isLocal() && has_dyn_rel) {
- FragmentRef &target_fragref = pReloc.targetRef();
- Fragment *target_frag = target_fragref.frag();
- HexagonRelocator::Type pType = llvm::ELF::R_HEX_RELATIVE;
- Relocation& rel_entry = helper_DynRel(rsym, *target_frag,
- target_fragref.offset(), pType, pParent);
- rel_entry.setAddend(S + A);
+ rel_entry->setAddend(S + A);
+ return HexagonRelocator::OK;
}
- uint32_t result = (uint32_t) (S + A);
+ if (!rsym->isLocal()) {
+ if (rsym->reserved() & HexagonRelocator::ReservePLT) {
+ S = helper_get_PLT_address(*rsym, pParent);
+ }
- pReloc.target() = result | pReloc.target();
- return HexagonRelocator::OK;
+ if (has_dyn_rel) {
+ if (llvm::ELF::R_HEX_32 == pReloc.type() &&
+ helper_use_relative_reloc(*rsym, pParent)) {
+ rel_entry->setAddend(S + A);
+ } else {
+ rel_entry->setAddend(A);
+ return HexagonRelocator::OK;
+ }
+ }
+ }
+
+ return applyAbs(pReloc);
}
-// R_HEX_16: Word32 : 0xffff : (S + A) : Unsigned Truncate
-HexagonRelocator::Result reloc16(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
+HexagonRelocator::Result relocPCREL(Relocation &pReloc,
+ HexagonRelocator &pParent) {
+ ResolveInfo *rsym = pReloc.symInfo();
+ int64_t result;
+
+ HexagonRelocator::Address S = pReloc.symValue();
HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord S = pReloc.symValue();
+ HexagonRelocator::DWord P = pReloc.place();
- uint32_t result = (uint32_t) (S + A);
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(0x0000ffff, result);
+ FragmentRef &target_fragref = pReloc.targetRef();
+ Fragment *target_frag = target_fragref.frag();
+ LDSection &target_sect = target_frag->getParent()->getSection();
- return HexagonRelocator::OK;
+ result = (int64_t)(S + A - P);
+
+ // for relocs inside non ALLOC, just apply
+ if (0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
+ return applyRel(pReloc, result);
+ }
+
+ if (!rsym->isLocal()) {
+ if (rsym->reserved() & HexagonRelocator::ReservePLT) {
+ S = helper_get_PLT_address(*rsym, pParent);
+ result = (int64_t)(S + A - P);
+ applyRel(pReloc, result);
+ return HexagonRelocator::OK;
+ }
+ }
+
+ return applyRel(pReloc, result);
}
-// R_HEX_8: Word32 : 0xff : (S + A) : Unsigned Truncate
-HexagonRelocator::Result reloc8(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
+// R_HEX_GPREL16_0 and its class : Unsigned Verify
+HexagonRelocator::Result relocGPREL(Relocation &pReloc,
+ HexagonRelocator &pParent) {
+ HexagonRelocator::Address S = pReloc.symValue();
HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord S = pReloc.symValue();
+ HexagonRelocator::DWord GP = pParent.getTarget().getGP();
- uint32_t result = (uint32_t) (S + A);
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(0x000000ff, result);
+ uint32_t result = (uint32_t)(S + A - GP);
+ uint32_t shift = 0;
+ uint32_t alignment = 1;
- return HexagonRelocator::OK;
-}
+ switch (pReloc.type()) {
+ case llvm::ELF::R_HEX_GPREL16_0:
+ break;
-// R_HEX_LO16: Word32_LO : 0x00c03fff (S + A) : Unsigned Truncate
-HexagonRelocator::Result relocLO16(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
+ case llvm::ELF::R_HEX_GPREL16_1:
+ shift = 1;
+ alignment = 2;
+ break;
- uint32_t result = (uint32_t) (S + A);
-// result = ((result & 0x3fff) | ((result << 6) & 0x00c00000));
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(0x00c03fff, result);
- return HexagonRelocator::OK;
-}
+ case llvm::ELF::R_HEX_GPREL16_2:
+ shift = 2;
+ alignment = 4;
+ break;
-// R_HEX_HI16: Word32_LO : 0x00c03fff (S + A) >> 16 : Unsigned Truncate
-HexagonRelocator::Result relocHI16(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
+ case llvm::ELF::R_HEX_GPREL16_3:
+ shift = 3;
+ alignment = 8;
+ break;
- uint32_t result = (uint32_t) ((S + A) >> 16);
-// result = ((result & 0x3fff) | ((result << 6) & 0x00c00000));
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(0x00c03fff, result);
- return HexagonRelocator::OK;
-}
-
-// R_HEX_GPREL16_0 : Word32_GP : 0x061f2ff (S + A - GP) : Unsigned Verify
-HexagonRelocator::Result relocGPREL16_0(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonLDBackend& ld_backend = pParent.getTarget();
- HexagonRelocator::DWord GP = ld_backend.getGP();
-
- int64_t result = (int64_t) (S + A - GP);
- int64_t range = 1ULL << 32;
- uint32_t bitMask = FINDBITMASK(pReloc.target());
- if (result <= range) {
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(bitMask, result);
- return HexagonRelocator::OK;
- }
- return HexagonRelocator::Overflow;
-}
-
-// R_HEX_GPREL16_1 : Word32_GP : 0x061f2ff (S + A - GP)>>1 : Unsigned Verify
-HexagonRelocator::Result relocGPREL16_1(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonLDBackend& ld_backend = pParent.getTarget();
- HexagonRelocator::DWord GP = ld_backend.getGP();
-
- int64_t result = (int64_t) ((S + A - GP) >> 1);
- int64_t range = 1LL << 32;
- uint32_t bitMask = FINDBITMASK(pReloc.target());
- if (result <= range) {
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(bitMask, result);
- return HexagonRelocator::OK;
- }
- return HexagonRelocator::Overflow;
-}
-
-// R_HEX_GPREL16_2 : Word32_GP : 0x061f2ff (S + A - GP)>>2 : Unsigned Verify
-HexagonRelocator::Result relocGPREL16_2(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonLDBackend& ld_backend = pParent.getTarget();
- HexagonRelocator::DWord GP = ld_backend.getGP();
-
- int64_t result = (int64_t) ((S + A - GP) >> 2);
- int64_t range = 1LL << 32;
- uint32_t bitMask = FINDBITMASK(pReloc.target());
- if (result <= range) {
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(bitMask, result);
- return HexagonRelocator::OK;
- }
- return HexagonRelocator::Overflow;
-}
-
-// R_HEX_GPREL16_3 : Word32_GP : 0x061f2ff (S + A - GP)>>3 : Unsigned Verify
-HexagonRelocator::Result relocGPREL16_3(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonLDBackend& ld_backend = pParent.getTarget();
- HexagonRelocator::DWord GP = ld_backend.getGP();
-
- int64_t result = (int64_t) ((S + A - GP) >> 3);
- int64_t range = 1LL << 32;
- uint32_t bitMask = FINDBITMASK(pReloc.target());
- if (result <= range) {
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(bitMask, result);
- return HexagonRelocator::OK;
- }
- return HexagonRelocator::Overflow;
-}
-
-// R_HEX_B13_PCREL : Word32_B13 : 0x00202ffe (S + A - P)>>2 : Signed Verify
-HexagonRelocator::Result relocB13PCREL(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord P = pReloc.place();
-
- int32_t result = ((S + A - P) >> 2);
- int32_t range = 1L << 12;
- if (result < range && result > -range) {
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(0x00202ffe, result);
- return HexagonRelocator::OK;
- }
- return HexagonRelocator::Overflow;
-}
-
-// R_HEX_B9_PCREL : Word32_B9 : 0x00300ffe (S + A - P)>>2 : Signed Verify
-HexagonRelocator::Result relocB9PCREL(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord P = pReloc.place();
-
- int32_t result = ((S + A - P) >> 2);
- int32_t range = 1L << 8;
- uint32_t bitMask = FINDBITMASK(pReloc.target());
- if (result < range && result > -range) {
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(bitMask, result);
- return HexagonRelocator::OK;
- }
- return HexagonRelocator::Overflow;
-}
-
-// R_HEX_B32_PCREL_X : Word32_X26 : 0x0fff3fff (S + A - P)>>6 : Truncate
-HexagonRelocator::Result relocB32PCRELX(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord P = pReloc.place();
-
- int32_t result = ((S + A - P) >> 6);
- pReloc.target() = pReloc.target() | ApplyMask<int32_t>(0xfff3fff, result);
-
- return HexagonRelocator::OK;
-}
-
-// R_HEX_32_6_X : Word32_X26 : 0x0fff3fff (S + A)>>6 : Unsigned Verify
-HexagonRelocator::Result reloc32_6_X(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
-
- int64_t result = ((S + A) >> 6);
- int64_t range = 1LL << 32;
-
- if (result > range)
- return HexagonRelocator::Overflow;
-
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(0xfff3fff, result);
-
- return HexagonRelocator::OK;
-}
-
-// R_HEX_B22_PCREL_X : Word32_B22 : 0x01ff3ffe
-// ((S + A - P) & 0x3f)>>2 : Signed Verify
-HexagonRelocator::Result relocB22PCRELX(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord P = pReloc.place();
-
- int32_t result = ((S + A - P) & 0x3f);
- int32_t range = 1 << 21;
-
- if (result < range && result > -range) {
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(0x01ff3ffe, result);
- return HexagonRelocator::OK;
+ default:
+ // show proper error
+ fatal(diag::unsupported_relocation) << (int)
+ pReloc.type() << "mclinker@googlegroups.com";
}
- return HexagonRelocator::Overflow;
-}
-
-// R_HEX_B15_PCREL_X : Word32_B15 : 0x00df20fe
-// ((S + A - P) & 0x3f)>>2 : Signed Verify
-HexagonRelocator::Result relocB15PCRELX(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord P = pReloc.place();
-
- int32_t result = ((S + A - P) & 0x3f);
- int32_t range = 1 << 14;
-
- if (result < range && result > -range) {
- pReloc.target() = pReloc.target() | ApplyMask<int32_t>(0x00df20fe, result);
- return HexagonRelocator::OK;
- }
-
- return HexagonRelocator::Overflow;
-}
-
-// R_HEX_B13_PCREL_X : Word32_B13 : 0x00202ffe
-// ((S + A - P) & 0x3f)>>2 : Signed Verify
-HexagonRelocator::Result relocB13PCRELX(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord P = pReloc.place();
-
- int32_t result = ((S + A - P) & 0x3f);
- int32_t range = 1 << 12;
-
- if (result < range && result > -range) {
- pReloc.target() = pReloc.target() | ApplyMask<int32_t>(0x00202ffe, result);
- return HexagonRelocator::OK;
- }
-
- return HexagonRelocator::Overflow;
-}
-
-// R_HEX_B9_PCREL_X : Word32_B9 : 0x003000fe
-// ((S + A - P) & 0x3f)>>2 : Signed Verify
-HexagonRelocator::Result relocB9PCRELX(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord P = pReloc.place();
-
- int32_t result = ((S + A - P) & 0x3f);
- int32_t range = 1 << 8;
-
- uint32_t bitMask = FINDBITMASK(pReloc.target());
- if (result < range && result > -range) {
- pReloc.target() = pReloc.target() | ApplyMask<int32_t>(bitMask, result);
- return HexagonRelocator::OK;
- }
-
- return HexagonRelocator::Overflow;
-}
-
-// R_HEX_B7_PCREL_X : Word32_B7 : 0x00001f18
-// ((S + A - P) & 0x3f)>>2 : Signed Verify
-HexagonRelocator::Result relocB7PCRELX(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord P = pReloc.place();
-
- int32_t result = ((S + A - P) & 0x3f);
- int32_t range = 1 << 6;
-
- if (result < range && result > -range) {
- pReloc.target() = pReloc.target() | ApplyMask<int32_t>(0x00001f18, result);
- return HexagonRelocator::OK;
- }
-
- return HexagonRelocator::Overflow;
-}
-
-// R_HEX_32_PCREL : Word32 : 0xffffffff (S + A - P) : Signed Verify
-HexagonRelocator::Result reloc32PCREL(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord P = pReloc.place();
-
- int64_t result = S + A - P;
- int32_t range = 1 << 31;
-
- if (result < range && result > -range) {
- pReloc.target() = pReloc.target() | ApplyMask<int32_t>(0xffffffff, result);
- return HexagonRelocator::OK;
- }
-
- return HexagonRelocator::Overflow;
-}
-
-// R_HEX_N_X : Word32_U6 : (S + A) : Unsigned Truncate
-HexagonRelocator::Result relocHexNX(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- uint32_t result = (S + A);
+ uint32_t range = 1 << 16;
uint32_t bitMask = FINDBITMASK(pReloc.target());
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(bitMask, result);
- return HexagonRelocator::OK;
+ if ((shift != 0) && (result % alignment != 0))
+ return HexagonRelocator::BadReloc;
+
+ result >>= shift;
+
+ if (result < range - 1) {
+ pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
+ return HexagonRelocator::OK;
+ }
+ return HexagonRelocator::Overflow;
}
// R_HEX_PLT_B22_PCREL: PLT(S) + A - P
-HexagonRelocator::Result relocPLTB22PCREL(Relocation& pReloc, HexagonRelocator& pParent)
-{
+HexagonRelocator::Result relocPLTB22PCREL(Relocation &pReloc,
+ HexagonRelocator &pParent) {
// PLT_S depends on if there is a PLT entry.
HexagonRelocator::Address PLT_S;
if ((pReloc.symInfo()->reserved() & HexagonRelocator::ReservePLT))
- PLT_S = helper_PLT(pReloc, pParent);
+ PLT_S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
else
PLT_S = pReloc.symValue();
HexagonRelocator::Address P = pReloc.place();
@@ -891,97 +817,142 @@
return HexagonRelocator::OK;
}
-// R_HEX_GOTREL_LO16: Word32_LO : 0x00c03fff (S + A - GOT) : Unsigned Truncate
-HexagonRelocator::Result relocHexGOTRELLO16(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::Address GOT = pParent.getTarget().getGOTSymbolAddr();
-
- uint32_t result = (uint32_t) (S + A - GOT);
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(0x00c03fff, result);
- return HexagonRelocator::OK;
-}
-
-// R_HEX_GOTREL_HI16 : Word32_LO : 0x00c03fff (S + A - GOT) >> 16 : Unsigned Truncate
-HexagonRelocator::Result relocHexGOTRELHI16(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::Address GOT = pParent.getTarget().getGOTSymbolAddr();
-
- uint32_t result = (uint32_t) ((S + A - GOT) >> 16);
-
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(0x00c03fff, result);
- return HexagonRelocator::OK;
-}
-
-// R_HEX_GOTREL_32 : Word32 (S + A - GOT) : Unsigned Truncate
-HexagonRelocator::Result relocHexGOTREL32(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::Address GOT = pParent.getTarget().getGOTSymbolAddr();
-
- uint32_t result = (uint32_t) (S + A - GOT);
-
- pReloc.target() = pReloc.target() | result;
- return HexagonRelocator::OK;
-}
-
-// R_HEX_6_PCREL_X : (S + A - P)
-HexagonRelocator::Result relocHex6PCRELX(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- HexagonRelocator::Address S = pReloc.symValue();
- HexagonRelocator::DWord A = pReloc.addend();
- HexagonRelocator::DWord P = pReloc.place();
-
- int32_t result = (S + A - P);
- uint32_t bitMask = FINDBITMASK(pReloc.target());
-
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(bitMask, result);
- return HexagonRelocator::OK;
-}
-
-// R_HEX_GOT_32_6_X : (G) >> 6
-HexagonRelocator::Result relocHexGOT326X(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- if (!(pReloc.symInfo()->reserved()
- & (HexagonRelocator::ReserveGOT | HexagonRelocator::GOTRel))) {
+//R_HEX_GOT_LO16 and its class : (G) Signed Truncate
+//Exception: R_HEX_GOT_16(_X): signed verify
+// Exception: R_HEX_GOT_11_X : unsigned truncate
+HexagonRelocator::Result relocGOT(Relocation &pReloc,
+ HexagonRelocator &pParent) {
+ if (!(pReloc.symInfo()->reserved() & HexagonRelocator::ReserveGOT)) {
return HexagonRelocator::BadReloc;
}
- HexagonRelocator::Address GOT_S = helper_GOT(pReloc, pParent);
- HexagonRelocator::Address GOT = pParent.getTarget().getGOTSymbolAddr();
- int32_t result = (GOT_S - GOT) >> 6;
- uint32_t bitMask = FINDBITMASK(pReloc.target());
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(bitMask, result);
- return HexagonRelocator::OK;
-}
-// R_HEX_GOT_16_X : (G)
-// R_HEX_GOT_11_X : (G)
-HexagonRelocator::Result relocHexGOT1611X(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
- if (!(pReloc.symInfo()->reserved()
- & (HexagonRelocator::ReserveGOT | HexagonRelocator::GOTRel))) {
- return HexagonRelocator::BadReloc;
+ // set got entry value if needed
+ HexagonGOTEntry *got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
+ assert(NULL != got_entry);
+ if (HexagonRelocator::SymVal == got_entry->getValue())
+ got_entry->setValue(pReloc.symValue());
+
+ HexagonRelocator::Address GOT_S =
+ helper_get_GOT_address(*pReloc.symInfo(), pParent);
+ HexagonRelocator::Address GOT = pParent.getTarget().getGOTSymbolAddr();
+ int32_t result = (int32_t)(GOT_S - GOT);
+ uint32_t effectiveBits = 0;
+ uint32_t alignment = 1;
+ uint32_t bitMask = 0;
+ uint32_t result_u;
+ uint32_t shift = 0;
+
+ switch (pReloc.type()) {
+ case llvm::ELF::R_HEX_GOT_LO16:
+ bitMask = 0x00c03fff;
+ break;
+
+ case llvm::ELF::R_HEX_GOT_HI16:
+ bitMask = 0x00c03fff;
+ shift = 16;
+ alignment = 4;
+ break;
+
+ case llvm::ELF::R_HEX_GOT_32:
+ bitMask = 0xffffffff;
+ break;
+
+ case llvm::ELF::R_HEX_GOT_16:
+ bitMask = FINDBITMASK(pReloc.target());
+ effectiveBits = 16;
+ break;
+
+ case llvm::ELF::R_HEX_GOT_32_6_X:
+ bitMask = 0xfff3fff;
+ shift = 6;
+ break;
+
+ case llvm::ELF::R_HEX_GOT_16_X:
+ bitMask = FINDBITMASK(pReloc.target());
+ effectiveBits = 6;
+ break;
+
+ case llvm::ELF::R_HEX_GOT_11_X:
+ bitMask = FINDBITMASK(pReloc.target());
+ result_u = GOT_S - GOT;
+ pReloc.target() |= ApplyMask<uint32_t>(bitMask, result_u);
+ return HexagonRelocator::OK;
+
+ default:
+ // show proper error
+ fatal(diag::unsupported_relocation) << (int)
+ pReloc.type() << "mclinker@googlegroups.com";
}
- HexagonRelocator::Address GOT_S = helper_GOT(pReloc, pParent);
- HexagonRelocator::Address GOT = pParent.getTarget().getGOTSymbolAddr();
- int32_t result = (GOT_S - GOT);
- uint32_t bitMask = FINDBITMASK(pReloc.target());
- pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(bitMask, result);
+
+ if ((shift != 0) && (result % alignment != 0))
+ return HexagonRelocator::BadReloc;
+
+ result >>= shift;
+
+ if (effectiveBits) {
+ int32_t range = 1 << (effectiveBits - 1);
+ if ((result > range - 1) || (result < -range))
+ return HexagonRelocator::Overflow;
+ }
+ pReloc.target() |= ApplyMask<int32_t>(bitMask, result);
return HexagonRelocator::OK;
}
-HexagonRelocator::Result unsupport(Relocation& pReloc,
- HexagonRelocator& pParent)
-{
+// R_HEX_GOTREL_LO16: and its class of relocs
+// (S + A - GOT) : Signed Truncate
+HexagonRelocator::Result relocGOTREL(Relocation &pReloc,
+ HexagonRelocator &pParent) {
+ HexagonRelocator::Address S = pReloc.symValue();
+ HexagonRelocator::DWord A = pReloc.addend();
+ HexagonRelocator::Address GOT = pParent.getTarget().getGOTSymbolAddr();
+
+ uint32_t bitMask = 0;
+ uint32_t alignment = 1;
+ uint32_t shift = 0;
+
+ uint32_t result = (uint32_t)(S + A - GOT);
+
+ switch (pReloc.type()) {
+ case llvm::ELF::R_HEX_GOTREL_LO16:
+ bitMask = 0x00c03fff;
+ break;
+
+ case llvm::ELF::R_HEX_GOTREL_HI16:
+ bitMask = 0x00c03fff;
+ shift = 16;
+ alignment = 4;
+ break;
+
+ case llvm::ELF::R_HEX_GOTREL_32:
+ bitMask = 0xffffffff;
+ break;
+
+ case llvm::ELF::R_HEX_GOTREL_32_6_X:
+ bitMask = 0x0fff3fff;
+ shift = 6;
+ break;
+
+ case llvm::ELF::R_HEX_GOTREL_16_X:
+ case llvm::ELF::R_HEX_GOTREL_11_X:
+ bitMask = FINDBITMASK(pReloc.target());
+ break;
+
+ default:
+ // show proper error
+ fatal(diag::unsupported_relocation) << (int)
+ pReloc.type() << "mclinker@googlegroups.com";
+ }
+
+ if (result % alignment != 0)
+ return HexagonRelocator::BadReloc;
+
+ result >>= shift;
+
+ pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
+ return HexagonRelocator::OK;
+}
+
+HexagonRelocator::Result unsupport(Relocation &pReloc,
+ HexagonRelocator &pParent) {
return HexagonRelocator::Unsupport;
}
diff --git a/lib/Target/Hexagon/HexagonRelocator.h b/lib/Target/Hexagon/HexagonRelocator.h
index e65be9f..02e99c9 100644
--- a/lib/Target/Hexagon/HexagonRelocator.h
+++ b/lib/Target/Hexagon/HexagonRelocator.h
@@ -15,7 +15,7 @@
#include <mcld/LD/Relocator.h>
#include <mcld/Target/GOT.h>
#include <mcld/Target/PLT.h>
-#include <mcld/Target/SymbolEntryMap.h>
+#include <mcld/Target/KeyEntryMap.h>
#include "HexagonLDBackend.h"
namespace mcld {
@@ -30,55 +30,45 @@
class HexagonRelocator : public Relocator
{
public:
- typedef SymbolEntryMap<PLTEntryBase> SymPLTMap;
- typedef SymbolEntryMap<HexagonGOTEntry> SymGOTMap;
- typedef SymbolEntryMap<HexagonGOTEntry> SymGOTPLTMap;
-
+ typedef KeyEntryMap<ResolveInfo, PLTEntryBase> SymPLTMap;
+ typedef KeyEntryMap<ResolveInfo, HexagonGOTEntry> SymGOTMap;
+ typedef KeyEntryMap<ResolveInfo, HexagonGOTEntry> SymGOTPLTMap;
+ typedef KeyEntryMap<Relocation, Relocation> RelRelMap;
public:
/** \enum ReservedEntryType
* \brief The reserved entry type of reserved space in ResolveInfo.
*
* This is used for sacnRelocation to record what kinds of entries are
- * reserved for this resolved symbol
+ * reserved for this resolved symbol. In Hexagon, there are three kinds
+ * of entries, GOT, PLT, and dynamic relocation.
*
- * In Hexagon, there are three kinds of entries, GOT, PLT, and dynamic
- * relocation.
- *
- * GOT may needs a corresponding relocation to relocate itself, so we
- * separate GOT to two situations: GOT and GOTRel. Besides, for the same
- * symbol, there might be two kinds of entries reserved for different location.
- * For example, reference to the same symbol, one may use GOT and the other may
- * use dynamic relocation.
- *
- * bit: 3 2 1 0
- * | PLT | GOTRel | GOT | Rel |
+ * bit: 3 2 1 0
+ * | | PLT | GOT | Rel |
*
* value Name - Description
*
* 0000 None - no reserved entry
* 0001 ReserveRel - reserve an dynamic relocation entry
* 0010 ReserveGOT - reserve an GOT entry
- * 0011 GOTandRel - For different relocation, we've reserved GOT and
- * Rel for different location.
- * 0100 GOTRel - reserve an GOT entry and the corresponding Dyncamic
- * relocation entry which relocate this GOT entry
- * 0101 GOTRelandRel - For different relocation, we've reserved GOTRel
- * and relocation entry for different location.
- * 1000 ReservePLT - reserve an PLT entry and the corresponding GOT,
- * Dynamic relocation entries
- * 1001 PLTandRel - For different relocation, we've reserved PLT and
- * Rel for different location.
+ * 0100 ReservePLT - reserve an PLT entry and the corresponding GOT,
+ *
*/
enum ReservedEntryType {
None = 0,
ReserveRel = 1,
ReserveGOT = 2,
- GOTandRel = 3,
- GOTRel = 4,
- GOTRelandRel = 5,
- ReservePLT = 8,
- PLTandRel = 9
+ ReservePLT = 4,
+ };
+
+ /** \enum EntryValue
+ * \brief The value of the entries. The symbol value will be decided at after
+ * layout, so we mark the entry during scanRelocation and fill up the actual
+ * value when applying relocations.
+ */
+ enum EntryValue {
+ Default = 0,
+ SymVal = 1
};
HexagonRelocator(HexagonLDBackend& pParent, const LinkerConfig& pConfig);
@@ -95,7 +85,8 @@
void scanRelocation(Relocation& pReloc,
IRBuilder& pBuilder,
Module& pModule,
- LDSection& pSection);
+ LDSection& pSection,
+ Input& pInput);
// Handle partial linking
void partialScanRelocation(Relocation& pReloc,
@@ -121,6 +112,9 @@
const SymGOTPLTMap& getSymGOTPLTMap() const { return m_SymGOTPLTMap; }
SymGOTPLTMap& getSymGOTPLTMap() { return m_SymGOTPLTMap; }
+ const RelRelMap& getRelRelMap() const { return m_RelRelMap; }
+ RelRelMap& getRelRelMap() { return m_RelRelMap; }
+
protected:
/// addCopyReloc - add a copy relocation into .rela.dyn for pSym
/// @param pSym - A resolved copy symbol that defined in BSS section
@@ -148,6 +142,7 @@
SymPLTMap m_SymPLTMap;
SymGOTMap m_SymGOTMap;
SymGOTPLTMap m_SymGOTPLTMap;
+ RelRelMap m_RelRelMap;
};
} // namespace of mcld
diff --git a/lib/Target/Hexagon/HexagonTargetMachine.cpp b/lib/Target/Hexagon/HexagonTargetMachine.cpp
index 4e4f1c2..33067b9 100644
--- a/lib/Target/Hexagon/HexagonTargetMachine.cpp
+++ b/lib/Target/Hexagon/HexagonTargetMachine.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "HexagonTargetMachine.h"
#include "Hexagon.h"
-#include <mcld/Target/TargetMachine.h>
#include <mcld/Support/TargetRegistry.h>
extern "C" void MCLDInitializeHexagonLDTarget() {
@@ -17,13 +16,14 @@
X(mcld::TheHexagonTarget);
}
-mcld::HexagonTargetMachine::HexagonTargetMachine(llvm::TargetMachine& pPM,
- const mcld::Target &pTarget,
- const std::string& pTriple)
- : mcld::MCLDTargetMachine(pPM, pTarget, pTriple) {
-}
+using namespace mcld;
-mcld::HexagonTargetMachine::~HexagonTargetMachine()
-{
+//===----------------------------------------------------------------------===//
+// HexagonTargetMachine
+//===----------------------------------------------------------------------===//
+HexagonTargetMachine::HexagonTargetMachine(llvm::TargetMachine& pPM,
+ const llvm::Target& pLLVMTarget,
+ const mcld::Target& pMCLDTarget,
+ const std::string& pTriple)
+ : MCLDTargetMachine(pPM, pLLVMTarget, pMCLDTarget, pTriple) {
}
-
diff --git a/lib/Target/Hexagon/HexagonTargetMachine.h b/lib/Target/Hexagon/HexagonTargetMachine.h
index a374475..9b131c1 100644
--- a/lib/Target/Hexagon/HexagonTargetMachine.h
+++ b/lib/Target/Hexagon/HexagonTargetMachine.h
@@ -9,7 +9,7 @@
#ifndef MCLD_HEXAGON_TARGET_MACHINE_H
#define MCLD_HEXAGON_TARGET_MACHINE_H
#include "Hexagon.h"
-#include <mcld/Target/TargetMachine.h>
+#include <mcld/CodeGen/TargetMachine.h>
namespace mcld {
@@ -17,10 +17,9 @@
{
public:
HexagonTargetMachine(llvm::TargetMachine &pTM,
- const mcld::Target &pTarget,
+ const llvm::Target &pLLVMTarget,
+ const mcld::Target &pMCLDTarget,
const std::string &pTriple);
-
- virtual ~HexagonTargetMachine();
};
} // namespace of mcld
diff --git a/lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp b/lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp
index 0b113aa..e0d660b 100644
--- a/lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp
+++ b/lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp
@@ -6,7 +6,7 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include <mcld/Target/TargetMachine.h>
+#include <mcld/Support/Target.h>
#include <mcld/Support/TargetRegistry.h>
namespace mcld {
@@ -15,7 +15,7 @@
extern "C" void MCLDInitializeHexagonLDTargetInfo() {
// register into mcld::TargetRegistry
- mcld::RegisterTarget X(TheHexagonTarget, "hexagon");
+ mcld::RegisterTarget<llvm::Triple::hexagon> X(TheHexagonTarget, "hexagon");
}
} // namespace of mcld
diff --git a/lib/Target/Mips/Mips.h b/lib/Target/Mips/Mips.h
index a63be45..35be4b4 100644
--- a/lib/Target/Mips/Mips.h
+++ b/lib/Target/Mips/Mips.h
@@ -9,11 +9,12 @@
#ifndef MCLD_MIPS_H
#define MCLD_MIPS_H
-#include "mcld/Support/TargetRegistry.h"
-
namespace mcld {
-extern mcld::Target TheMipselTarget;
+class Target;
+
+extern Target TheMipselTarget;
+extern Target TheMips64elTarget;
} // namespace of mcld
diff --git a/lib/Target/Mips/MipsDiagnostic.cpp b/lib/Target/Mips/MipsDiagnostic.cpp
index 2d5b7d9..e03ea3c 100644
--- a/lib/Target/Mips/MipsDiagnostic.cpp
+++ b/lib/Target/Mips/MipsDiagnostic.cpp
@@ -6,30 +6,30 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include <llvm/ADT/Triple.h>
#include <mcld/Support/TargetRegistry.h>
#include <mcld/LD/DWARFLineInfo.h>
#include "Mips.h"
-using namespace mcld;
+namespace {
-
-namespace mcld {
//===----------------------------------------------------------------------===//
// createMipsDiagnostic - the help function to create corresponding
// MipsDiagnostic
-DiagnosticLineInfo* createMipsDiagLineInfo(const mcld::Target& pTarget,
- const std::string &pTriple)
+//===----------------------------------------------------------------------===//
+mcld::DiagnosticLineInfo* createMipsDiagLineInfo(const mcld::Target& pTarget,
+ const std::string &pTriple)
{
- return new DWARFLineInfo();
+ return new mcld::DWARFLineInfo();
}
} // namespace of mcld
-//==========================
+//===----------------------------------------------------------------------===//
// InitializeMipsDiagnostic
+//===----------------------------------------------------------------------===//
extern "C" void MCLDInitializeMipsDiagnosticLineInfo() {
- // Register the linker frontend
- mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheMipselTarget, createMipsDiagLineInfo);
+ mcld::TargetRegistry::RegisterDiagnosticLineInfo(mcld::TheMipselTarget,
+ createMipsDiagLineInfo);
+ mcld::TargetRegistry::RegisterDiagnosticLineInfo(mcld::TheMips64elTarget,
+ createMipsDiagLineInfo);
}
-
diff --git a/lib/Target/Mips/MipsELFDynamic.cpp b/lib/Target/Mips/MipsELFDynamic.cpp
index e34d698..b532b03 100644
--- a/lib/Target/Mips/MipsELFDynamic.cpp
+++ b/lib/Target/Mips/MipsELFDynamic.cpp
@@ -6,61 +6,55 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "MipsELFDynamic.h"
-
-#include "MipsLDBackend.h"
+#include <llvm/Support/ELF.h>
+#include <mcld/LinkerConfig.h>
#include <mcld/LD/ELFFileFormat.h>
+#include <mcld/LD/ELFSegment.h>
+#include <mcld/LD/ELFSegmentFactory.h>
#include <mcld/Target/GNULDBackend.h>
+#include "MipsELFDynamic.h"
+#include "MipsLDBackend.h"
using namespace mcld;
-// MIPS mandatory dynamic section entries
-enum {
- MIPS_RLD_VERSION = 0x70000001,
- MIPS_FLAGS = 0x70000005,
- MIPS_BASE_ADDRESS = 0x70000006,
- MIPS_LOCAL_GOTNO = 0x7000000a,
- MIPS_SYMTABNO = 0x70000011,
- MIPS_GOTSYM = 0x70000013
-};
-
MipsELFDynamic::MipsELFDynamic(const MipsGNULDBackend& pParent,
const LinkerConfig& pConfig)
: ELFDynamic(pParent, pConfig),
- m_pParent(pParent)
-{
-}
-
-MipsELFDynamic::~MipsELFDynamic()
+ m_pParent(pParent),
+ m_pConfig(pConfig)
{
}
void MipsELFDynamic::reserveTargetEntries(const ELFFileFormat& pFormat)
{
- // reservePLTGOT
if (pFormat.hasGOT())
reserveOne(llvm::ELF::DT_PLTGOT);
- reserveOne(MIPS_RLD_VERSION);
- reserveOne(MIPS_FLAGS);
- reserveOne(MIPS_BASE_ADDRESS);
- reserveOne(MIPS_LOCAL_GOTNO);
- reserveOne(MIPS_SYMTABNO);
- reserveOne(MIPS_GOTSYM);
+ reserveOne(llvm::ELF::DT_MIPS_RLD_VERSION);
+ reserveOne(llvm::ELF::DT_MIPS_FLAGS);
+ reserveOne(llvm::ELF::DT_MIPS_BASE_ADDRESS);
+ reserveOne(llvm::ELF::DT_MIPS_LOCAL_GOTNO);
+ reserveOne(llvm::ELF::DT_MIPS_SYMTABNO);
+ reserveOne(llvm::ELF::DT_MIPS_GOTSYM);
+
+ if (pFormat.hasGOTPLT())
+ reserveOne(llvm::ELF::DT_MIPS_PLTGOT);
}
void MipsELFDynamic::applyTargetEntries(const ELFFileFormat& pFormat)
{
- // applyPLTGOT
if (pFormat.hasGOT())
applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOT().addr());
- applyOne(MIPS_RLD_VERSION, 1);
- applyOne(MIPS_FLAGS, 0);
- applyOne(MIPS_BASE_ADDRESS, 0);
- applyOne(MIPS_LOCAL_GOTNO, getLocalGotNum(pFormat));
- applyOne(MIPS_SYMTABNO, getSymTabNum(pFormat));
- applyOne(MIPS_GOTSYM, getGotSym(pFormat));
+ applyOne(llvm::ELF::DT_MIPS_RLD_VERSION, 1);
+ applyOne(llvm::ELF::DT_MIPS_FLAGS, llvm::ELF::RHF_NOTPOT);
+ applyOne(llvm::ELF::DT_MIPS_BASE_ADDRESS, getBaseAddress());
+ applyOne(llvm::ELF::DT_MIPS_LOCAL_GOTNO, getLocalGotNum(pFormat));
+ applyOne(llvm::ELF::DT_MIPS_SYMTABNO, getSymTabNum(pFormat));
+ applyOne(llvm::ELF::DT_MIPS_GOTSYM, getGotSym(pFormat));
+
+ if (pFormat.hasGOTPLT())
+ applyOne(llvm::ELF::DT_MIPS_PLTGOT, pFormat.getGOTPLT().addr());
}
size_t MipsELFDynamic::getSymTabNum(const ELFFileFormat& pFormat) const
@@ -87,3 +81,14 @@
return m_pParent.getGOT().getLocalNum();
}
+
+uint64_t MipsELFDynamic::getBaseAddress()
+{
+ if (LinkerConfig::Exec != m_pConfig.codeGenType())
+ return 0;
+
+ ELFSegmentFactory::const_iterator baseSeg =
+ m_pParent.elfSegmentTable().find(llvm::ELF::PT_LOAD, 0x0, 0x0);
+
+ return m_pParent.elfSegmentTable().end() == baseSeg ? 0 : (*baseSeg)->vaddr();
+}
diff --git a/lib/Target/Mips/MipsELFDynamic.h b/lib/Target/Mips/MipsELFDynamic.h
index 6efbf71..bb7e579 100644
--- a/lib/Target/Mips/MipsELFDynamic.h
+++ b/lib/Target/Mips/MipsELFDynamic.h
@@ -22,10 +22,10 @@
{
public:
MipsELFDynamic(const MipsGNULDBackend& pParent, const LinkerConfig& pConfig);
- ~MipsELFDynamic();
private:
const MipsGNULDBackend& m_pParent;
+ const LinkerConfig& m_pConfig;
private:
void reserveTargetEntries(const ELFFileFormat& pFormat);
@@ -34,6 +34,7 @@
size_t getSymTabNum(const ELFFileFormat& pFormat) const;
size_t getGotSym(const ELFFileFormat& pFormat) const;
size_t getLocalGotNum(const ELFFileFormat& pFormat) const;
+ uint64_t getBaseAddress();
};
} // namespace of mcld
diff --git a/lib/Target/Mips/MipsELFMCLinker.cpp b/lib/Target/Mips/MipsELFMCLinker.cpp
index 3964ee8..077177a 100644
--- a/lib/Target/Mips/MipsELFMCLinker.cpp
+++ b/lib/Target/Mips/MipsELFMCLinker.cpp
@@ -7,14 +7,13 @@
//
//===----------------------------------------------------------------------===//
#include "MipsELFMCLinker.h"
-#include <mcld/LinkerConfig.h>
using namespace mcld;
MipsELFMCLinker::MipsELFMCLinker(LinkerConfig& pConfig,
mcld::Module& pModule,
- MemoryArea& pOutput)
- : ELFMCLinker(pConfig, pModule, pOutput) {
+ FileHandle& pFileHandle)
+ : ELFMCLinker(pConfig, pModule, pFileHandle) {
}
MipsELFMCLinker::~MipsELFMCLinker()
diff --git a/lib/Target/Mips/MipsELFMCLinker.h b/lib/Target/Mips/MipsELFMCLinker.h
index 2c240ad..cdffdd5 100644
--- a/lib/Target/Mips/MipsELFMCLinker.h
+++ b/lib/Target/Mips/MipsELFMCLinker.h
@@ -16,7 +16,7 @@
namespace mcld {
class Module;
-class MemoryArea;
+class FileHandle;
/** \class MipsELFMCLinker
* \brief MipsELFMCLinker sets up the environment for linking.
@@ -26,7 +26,7 @@
public:
MipsELFMCLinker(LinkerConfig& pConfig,
mcld::Module& pModule,
- MemoryArea& pOutput);
+ FileHandle& pFileHandle);
~MipsELFMCLinker();
};
diff --git a/lib/Target/Mips/MipsEmulation.cpp b/lib/Target/Mips/MipsEmulation.cpp
index bdb1783..5e5d192 100644
--- a/lib/Target/Mips/MipsEmulation.cpp
+++ b/lib/Target/Mips/MipsEmulation.cpp
@@ -21,7 +21,11 @@
// set up bitclass and endian
pConfig.targets().setEndian(TargetOptions::Little);
- pConfig.targets().setBitClass(32);
+
+ llvm::Triple::ArchType arch = pConfig.targets().triple().getArch();
+ assert(arch == llvm::Triple::mipsel || arch == llvm::Triple::mips64el);
+ unsigned bitclass = arch == llvm::Triple::mipsel ? 32 : 64;
+ pConfig.targets().setBitClass(bitclass);
// set up target-dependent constraints of attributes
pConfig.attribute().constraint().enableWholeArchive();
@@ -58,7 +62,8 @@
// MipsEmulation
//===----------------------------------------------------------------------===//
extern "C" void MCLDInitializeMipsEmulation() {
- // Register the emulation
- mcld::TargetRegistry::RegisterEmulation(mcld::TheMipselTarget, mcld::emulateMipsLD);
+ mcld::TargetRegistry::RegisterEmulation(mcld::TheMipselTarget,
+ mcld::emulateMipsLD);
+ mcld::TargetRegistry::RegisterEmulation(mcld::TheMips64elTarget,
+ mcld::emulateMipsLD);
}
-
diff --git a/lib/Target/Mips/MipsGNUInfo.cpp b/lib/Target/Mips/MipsGNUInfo.cpp
new file mode 100644
index 0000000..521a800
--- /dev/null
+++ b/lib/Target/Mips/MipsGNUInfo.cpp
@@ -0,0 +1,77 @@
+//===- MipsGNUInfo.cpp ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "MipsGNUInfo.h"
+
+namespace mcld {
+
+//===----------------------------------------------------------------------===//
+// MipsGNUInfo
+//===----------------------------------------------------------------------===//
+MipsGNUInfo::MipsGNUInfo(const llvm::Triple& pTriple)
+ : GNUInfo(pTriple),
+ m_ABIVersion(0),
+ m_PICFlags(0)
+{}
+
+void MipsGNUInfo::setABIVersion(uint8_t ver)
+{
+ m_ABIVersion = ver;
+}
+
+void MipsGNUInfo::setPICFlags(uint64_t flags)
+{
+ m_PICFlags = flags;
+}
+
+uint32_t MipsGNUInfo::machine() const
+{
+ return llvm::ELF::EM_MIPS;
+}
+
+uint8_t MipsGNUInfo::ABIVersion() const
+{
+ return m_ABIVersion;
+}
+
+uint64_t MipsGNUInfo::defaultTextSegmentAddr() const
+{
+ if (m_Triple.isArch32Bit())
+ return 0x400000;
+ else
+ return 0x120000000ull;
+}
+
+uint64_t MipsGNUInfo::flags() const
+{
+ uint64_t val = llvm::ELF::EF_MIPS_NOREORDER | m_PICFlags;
+
+ if (m_Triple.isArch32Bit())
+ val |= llvm::ELF::EF_MIPS_ARCH_32R2 | llvm::ELF::EF_MIPS_ABI_O32;
+ else
+ val |= llvm::ELF::EF_MIPS_ARCH_64R2;
+
+ return val;
+}
+
+const char* MipsGNUInfo::entry() const
+{
+ return "__start";
+}
+
+const char* MipsGNUInfo::dyld() const
+{
+ return m_Triple.isArch32Bit() ? "/lib/ld.so.1" : "/lib64/ld.so.1";
+}
+
+uint64_t MipsGNUInfo::abiPageSize() const
+{
+ return 0x10000;
+}
+
+} // end mcld namespace
diff --git a/lib/Target/Mips/MipsGNUInfo.h b/lib/Target/Mips/MipsGNUInfo.h
index 9c829d5..2e43d80 100644
--- a/lib/Target/Mips/MipsGNUInfo.h
+++ b/lib/Target/Mips/MipsGNUInfo.h
@@ -8,52 +8,33 @@
//===----------------------------------------------------------------------===//
#ifndef MCLD_TARGET_MIPS_GNU_INFO_H
#define MCLD_TARGET_MIPS_GNU_INFO_H
-#include <mcld/Target/GNUInfo.h>
-
#include <llvm/Support/ELF.h>
+#include <mcld/Target/GNUInfo.h>
namespace mcld {
class MipsGNUInfo : public GNUInfo
{
public:
- enum {
- // The original o32 abi.
- E_MIPS_ABI_O32 = 0x00001000,
- // O32 extended to work on 64 bit architectures.
- E_MIPS_ABI_O64 = 0x00002000,
- // EABI in 32 bit mode.
- E_MIPS_ABI_EABI32 = 0x00003000,
- // EABI in 64 bit mode.
- E_MIPS_ABI_EABI64 = 0x00004000
- };
+ MipsGNUInfo(const llvm::Triple& pTriple);
-public:
- MipsGNUInfo(const llvm::Triple& pTriple) : GNUInfo(pTriple) { }
+ void setABIVersion(uint8_t ver);
+ void setPICFlags(uint64_t flags);
- uint32_t machine() const { return llvm::ELF::EM_MIPS; }
+ // GNUInfo
+ uint32_t machine() const;
+ uint8_t ABIVersion() const;
+ uint64_t defaultTextSegmentAddr() const;
+ uint64_t flags() const;
+ const char* entry() const;
+ const char* dyld() const;
+ uint64_t abiPageSize() const;
- uint64_t defaultTextSegmentAddr() const { return 0x80000; }
-
- uint64_t flags() const
- {
- // TODO: (simon) The correct flag's set depend on command line
- // arguments and flags from input .o files.
- return llvm::ELF::EF_MIPS_ARCH_32R2 |
- llvm::ELF::EF_MIPS_NOREORDER |
- llvm::ELF::EF_MIPS_PIC |
- llvm::ELF::EF_MIPS_CPIC |
- E_MIPS_ABI_O32;
- }
-
- const char* entry() const { return "__start"; }
-
- const char* dyld() const { return "/lib/ld.so.1"; }
-
- uint64_t abiPageSize() const { return 0x10000; }
+private:
+ uint8_t m_ABIVersion;
+ uint64_t m_PICFlags;
};
} // namespace of mcld
#endif
-
diff --git a/lib/Target/Mips/MipsGOT.cpp b/lib/Target/Mips/MipsGOT.cpp
index 037e75a..dddf12b 100644
--- a/lib/Target/Mips/MipsGOT.cpp
+++ b/lib/Target/Mips/MipsGOT.cpp
@@ -11,7 +11,6 @@
#include <llvm/Support/ELF.h>
#include <mcld/LD/ResolveInfo.h>
-#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Target/OutputRelocSection.h>
@@ -19,7 +18,9 @@
#include "MipsRelocator.h"
namespace {
- const size_t MipsGOT0Num = 1;
+ const uint32_t Mips32ModulePtr = 1 << 31;
+ const uint64_t Mips64ModulePtr = 1ull << 63;
+ const size_t MipsGOT0Num = 2;
const size_t MipsGOTGpOffset = 0x7FF0;
const size_t MipsGOTSize = MipsGOTGpOffset + 0x7FFF;
}
@@ -27,13 +28,6 @@
using namespace mcld;
//===----------------------------------------------------------------------===//
-// MipsGOTEntry
-//===----------------------------------------------------------------------===//
-MipsGOTEntry::MipsGOTEntry(uint64_t pContent, SectionData* pParent)
- : GOT::Entry<4>(pContent, pParent)
-{}
-
-//===----------------------------------------------------------------------===//
// MipsGOT::GOTMultipart
//===----------------------------------------------------------------------===//
MipsGOT::GOTMultipart::GOTMultipart(size_t local, size_t global)
@@ -57,7 +51,7 @@
assert(m_ConsumedLocal < m_LocalNum &&
"Consumed too many local GOT entries");
++m_ConsumedLocal;
- m_pLastLocal = llvm::cast<MipsGOTEntry>(m_pLastLocal->getNextNode());
+ m_pLastLocal = m_pLastLocal->getNextNode();
}
void MipsGOT::GOTMultipart::consumeGlobal()
@@ -65,7 +59,29 @@
assert(m_ConsumedGlobal < m_GlobalNum &&
"Consumed too many global GOT entries");
++m_ConsumedGlobal;
- m_pLastGlobal = llvm::cast<MipsGOTEntry>(m_pLastGlobal->getNextNode());
+ m_pLastGlobal = m_pLastGlobal->getNextNode();
+}
+
+//===----------------------------------------------------------------------===//
+// MipsGOT::LocalEntry
+//===----------------------------------------------------------------------===//
+MipsGOT::LocalEntry::LocalEntry(const ResolveInfo* pInfo,
+ Relocation::DWord addend, bool isGot16)
+ : m_pInfo(pInfo),
+ m_Addend(addend),
+ m_IsGot16(isGot16)
+{
+}
+
+bool MipsGOT::LocalEntry::operator<(const LocalEntry &O) const
+{
+ if (m_pInfo != O.m_pInfo)
+ return m_pInfo < O.m_pInfo;
+
+ if (m_Addend != O.m_Addend)
+ return m_Addend < O.m_Addend;
+
+ return m_IsGot16 < O.m_IsGot16;
}
//===----------------------------------------------------------------------===//
@@ -78,16 +94,15 @@
{
}
-SizeTraits<32>::Address MipsGOT::getGPDispAddress() const
+uint64_t MipsGOT::getGPDispAddress() const
{
return addr() + MipsGOTGpOffset;
}
void MipsGOT::reserve(size_t pNum)
{
- for (size_t i = 0; i < pNum; i++) {
- new MipsGOTEntry(0, m_SectionData);
- }
+ for (size_t i = 0; i < pNum; i++)
+ createEntry(0, m_SectionData);
}
bool MipsGOT::hasGOT1() const
@@ -104,10 +119,10 @@
{
for (MultipartListType::iterator it = m_MultipartList.begin();
it != m_MultipartList.end(); ++it) {
- reserve(MipsGOT0Num);
- it->m_pLastLocal = llvm::cast<MipsGOTEntry>(&m_SectionData->back());
+ reserveHeader();
+ it->m_pLastLocal = &m_SectionData->back();
reserve(it->m_LocalNum);
- it->m_pLastGlobal = llvm::cast<MipsGOTEntry>(&m_SectionData->back());
+ it->m_pLastGlobal = &m_SectionData->back();
reserve(it->m_GlobalNum);
if (it == m_MultipartList.begin())
@@ -137,20 +152,6 @@
return itX == m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end();
}
-uint64_t MipsGOT::emit(MemoryRegion& pRegion)
-{
- uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
-
- uint64_t result = 0;
- for (iterator it = begin(), ie = end();
- it != ie; ++it, ++buffer) {
- MipsGOTEntry* got = &(llvm::cast<MipsGOTEntry>((*it)));
- *buffer = static_cast<uint32_t>(got->getValue());
- result += got->size();
- }
- return result;
-}
-
void MipsGOT::initGOTList()
{
m_SymbolOrderMap.clear();
@@ -170,8 +171,8 @@
{
m_MultipartList.back().m_Inputs.insert(m_pInput);
- for (SymbolSetType::iterator it = m_InputLocalSymbols.begin(),
- end = m_InputLocalSymbols.end();
+ for (LocalSymbolSetType::iterator it = m_InputLocalSymbols.begin(),
+ end = m_InputLocalSymbols.end();
it != end; ++it)
m_MergedLocalSymbols.insert(*it);
@@ -193,7 +194,7 @@
gotCount += 1;
- return (gotCount * mcld::MipsGOTEntry::EntrySize) > MipsGOTSize;
+ return gotCount * getEntrySize() > MipsGOTSize;
}
void MipsGOT::split()
@@ -234,23 +235,27 @@
{
}
-bool MipsGOT::reserveLocalEntry(ResolveInfo& pInfo)
+bool MipsGOT::reserveLocalEntry(ResolveInfo& pInfo, int reloc,
+ Relocation::DWord pAddend)
{
- if (pInfo.type() != ResolveInfo::Section) {
- if (m_InputLocalSymbols.count(&pInfo))
- return false;
+ LocalEntry entry(&pInfo, pAddend, reloc == llvm::ELF::R_MIPS_GOT16);
- if (m_MergedLocalSymbols.count(&pInfo)) {
- m_InputLocalSymbols.insert(&pInfo);
- return false;
- }
+ if (m_InputLocalSymbols.count(entry))
+ // Do nothing, if we have seen this symbol
+ // in the current input already.
+ return false;
+
+ if (m_MergedLocalSymbols.count(entry)) {
+ // We have seen this symbol in previous inputs.
+ // Remember that it exists in the current input too.
+ m_InputLocalSymbols.insert(entry);
+ return false;
}
if (isGOTFull())
split();
- if (pInfo.type() != ResolveInfo::Section)
- m_InputLocalSymbols.insert(&pInfo);
+ m_InputLocalSymbols.insert(entry);
++m_MultipartList.back().m_LocalNum;
return true;
@@ -285,7 +290,7 @@
return m_CurrentGOTPart > 0;
}
-MipsGOTEntry* MipsGOT::consumeLocal()
+Fragment* MipsGOT::consumeLocal()
{
assert(m_CurrentGOTPart < m_MultipartList.size() && "GOT number is out of range!");
@@ -297,7 +302,7 @@
return m_MultipartList[m_CurrentGOTPart].m_pLastLocal;
}
-MipsGOTEntry* MipsGOT::consumeGlobal()
+Fragment* MipsGOT::consumeGlobal()
{
assert(m_CurrentGOTPart < m_MultipartList.size() && "GOT number is out of range!");
@@ -309,7 +314,7 @@
return m_MultipartList[m_CurrentGOTPart].m_pLastGlobal;
}
-SizeTraits<32>::Address MipsGOT::getGPAddr(const Input& pInput) const
+uint64_t MipsGOT::getGPAddr(const Input& pInput) const
{
uint64_t gotSize = 0;
for (MultipartListType::const_iterator it = m_MultipartList.begin();
@@ -322,32 +327,59 @@
gotSize += getGlobalNum() - it->m_GlobalNum;
}
- return addr() + gotSize * MipsGOTEntry::EntrySize + MipsGOTGpOffset;
+ return addr() + gotSize * getEntrySize() + MipsGOTGpOffset;
}
-SizeTraits<32>::Offset MipsGOT::getGPRelOffset(const Input& pInput,
- const MipsGOTEntry& pEntry) const
+uint64_t MipsGOT::getGPRelOffset(const Input& pInput,
+ const Fragment& pEntry) const
{
- SizeTraits<32>::Address gpAddr = getGPAddr(pInput);
- return addr() + pEntry.getOffset() - gpAddr;
+ return addr() + pEntry.getOffset() - getGPAddr(pInput);
}
-void MipsGOT::recordEntry(const ResolveInfo* pInfo, MipsGOTEntry* pEntry)
+void MipsGOT::recordGlobalEntry(const ResolveInfo* pInfo, Fragment* pEntry)
{
GotEntryKey key;
key.m_GOTPage = m_CurrentGOTPart;
key.m_pInfo = pInfo;
- m_GotEntriesMap[key] = pEntry;
+ key.m_Addend = 0;
+ m_GotGlobalEntriesMap[key] = pEntry;
}
-MipsGOTEntry* MipsGOT::lookupEntry(const ResolveInfo* pInfo)
+Fragment* MipsGOT::lookupGlobalEntry(const ResolveInfo* pInfo)
{
GotEntryKey key;
key.m_GOTPage= m_CurrentGOTPart;
key.m_pInfo = pInfo;
- GotEntryMapType::iterator it = m_GotEntriesMap.find(key);
+ key.m_Addend = 0;
+ GotEntryMapType::iterator it = m_GotGlobalEntriesMap.find(key);
- if (it == m_GotEntriesMap.end())
+ if (it == m_GotGlobalEntriesMap.end())
+ return NULL;
+
+ return it->second;
+}
+
+void MipsGOT::recordLocalEntry(const ResolveInfo* pInfo,
+ Relocation::DWord pAddend,
+ Fragment* pEntry)
+{
+ GotEntryKey key;
+ key.m_GOTPage = m_CurrentGOTPart;
+ key.m_pInfo = pInfo;
+ key.m_Addend = pAddend;
+ m_GotLocalEntriesMap[key] = pEntry;
+}
+
+Fragment* MipsGOT::lookupLocalEntry(const ResolveInfo* pInfo,
+ Relocation::DWord pAddend)
+{
+ GotEntryKey key;
+ key.m_GOTPage= m_CurrentGOTPart;
+ key.m_pInfo = pInfo;
+ key.m_Addend = pAddend;
+ GotEntryMapType::iterator it = m_GotLocalEntriesMap.find(key);
+
+ if (it == m_GotLocalEntriesMap.end())
return NULL;
return it->second;
@@ -363,3 +395,85 @@
{
return m_SymbolOrderMap.size();
}
+
+//===----------------------------------------------------------------------===//
+// Mips32GOT
+//===----------------------------------------------------------------------===//
+Mips32GOT::Mips32GOT(LDSection& pSection)
+ : MipsGOT(pSection)
+{}
+
+void Mips32GOT::setEntryValue(Fragment* entry, uint64_t pValue)
+{
+ llvm::cast<Mips32GOTEntry>(entry)->setValue(pValue);
+}
+
+uint64_t Mips32GOT::emit(MemoryRegion& pRegion)
+{
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.begin());
+
+ uint64_t result = 0;
+ for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) {
+ Mips32GOTEntry* got = &(llvm::cast<Mips32GOTEntry>((*it)));
+ *buffer = static_cast<uint32_t>(got->getValue());
+ result += got->size();
+ }
+ return result;
+}
+
+Fragment* Mips32GOT::createEntry(uint64_t pValue, SectionData* pParent)
+{
+ return new Mips32GOTEntry(pValue, pParent);
+}
+
+size_t Mips32GOT::getEntrySize() const
+{
+ return Mips32GOTEntry::EntrySize;
+}
+
+void Mips32GOT::reserveHeader()
+{
+ createEntry(0, m_SectionData);
+ createEntry(Mips32ModulePtr, m_SectionData);
+}
+
+//===----------------------------------------------------------------------===//
+// Mips64GOT
+//===----------------------------------------------------------------------===//
+Mips64GOT::Mips64GOT(LDSection& pSection)
+ : MipsGOT(pSection)
+{}
+
+void Mips64GOT::setEntryValue(Fragment* entry, uint64_t pValue)
+{
+ llvm::cast<Mips64GOTEntry>(entry)->setValue(pValue);
+}
+
+uint64_t Mips64GOT::emit(MemoryRegion& pRegion)
+{
+ uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.begin());
+
+ uint64_t result = 0;
+ for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) {
+ Mips64GOTEntry* got = &(llvm::cast<Mips64GOTEntry>((*it)));
+ *buffer = static_cast<uint64_t>(got->getValue());
+ result += got->size();
+ }
+ return result;
+}
+
+Fragment* Mips64GOT::createEntry(uint64_t pValue, SectionData* pParent)
+{
+ return new Mips64GOTEntry(pValue, pParent);
+}
+
+size_t Mips64GOT::getEntrySize() const
+{
+ return Mips64GOTEntry::EntrySize;
+}
+
+void Mips64GOT::reserveHeader()
+{
+ createEntry(0, m_SectionData);
+ createEntry(Mips64ModulePtr, m_SectionData);
+}
diff --git a/lib/Target/Mips/MipsGOT.h b/lib/Target/Mips/MipsGOT.h
index 7f3051d..e3a9b9e 100644
--- a/lib/Target/Mips/MipsGOT.h
+++ b/lib/Target/Mips/MipsGOT.h
@@ -15,29 +15,21 @@
#include <gtest.h>
#endif
-#include <llvm/ADT/DenseMap.h>
-#include <llvm/ADT/DenseSet.h>
-
#include <mcld/ADT/SizeTraits.h>
#include <mcld/Target/GOT.h>
+#include <mcld/Fragment/Relocation.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <llvm/ADT/DenseMap.h>
+#include <llvm/ADT/DenseSet.h>
+#include <set>
-namespace mcld
-{
+namespace mcld {
+
class Input;
class LDSection;
class LDSymbol;
-class MemoryRegion;
class OutputRelocSection;
-/** \class MipsGOTEntry
- * \brief GOT Entry with size of 4 bytes
- */
-class MipsGOTEntry : public GOT::Entry<4>
-{
-public:
- MipsGOTEntry(uint64_t pContent, SectionData* pParent);
-};
-
/** \class MipsGOT
* \brief Mips Global Offset Table.
*/
@@ -46,15 +38,20 @@
public:
MipsGOT(LDSection& pSection);
- /// Address of _gp_disp symbol.
- SizeTraits<32>::Address getGPDispAddress() const;
+ /// Assign value to the GOT entry.
+ virtual void setEntryValue(Fragment* entry, uint64_t pValue) = 0;
- uint64_t emit(MemoryRegion& pRegion);
+ /// Emit the global offset table.
+ virtual uint64_t emit(MemoryRegion& pRegion) = 0;
+
+ /// Address of _gp_disp symbol.
+ uint64_t getGPDispAddress() const;
void initializeScan(const Input& pInput);
void finalizeScan(const Input& pInput);
- bool reserveLocalEntry(ResolveInfo& pInfo);
+ bool reserveLocalEntry(ResolveInfo& pInfo, int reloc,
+ Relocation::DWord pAddend);
bool reserveGlobalEntry(ResolveInfo& pInfo);
size_t getLocalNum() const; ///< number of local symbols in primary GOT
@@ -62,31 +59,20 @@
bool isPrimaryGOTConsumed();
- MipsGOTEntry* consumeLocal();
- MipsGOTEntry* consumeGlobal();
+ Fragment* consumeLocal();
+ Fragment* consumeGlobal();
- SizeTraits<32>::Address getGPAddr(const Input& pInput) const;
- SizeTraits<32>::Offset getGPRelOffset(const Input& pInput,
- const MipsGOTEntry& pEntry) const;
+ uint64_t getGPAddr(const Input& pInput) const;
+ uint64_t getGPRelOffset(const Input& pInput, const Fragment& pEntry) const;
- void recordEntry(const ResolveInfo* pInfo, MipsGOTEntry* pEntry);
- MipsGOTEntry* lookupEntry(const ResolveInfo* pInfo);
+ void recordGlobalEntry(const ResolveInfo* pInfo, Fragment* pEntry);
+ Fragment* lookupGlobalEntry(const ResolveInfo* pInfo);
- void setLocal(const ResolveInfo* pInfo) {
- m_GOTTypeMap[pInfo] = false;
- }
-
- void setGlobal(const ResolveInfo* pInfo) {
- m_GOTTypeMap[pInfo] = true;
- }
-
- bool isLocal(const ResolveInfo* pInfo) {
- return m_GOTTypeMap[pInfo] == false;
- }
-
- bool isGlobal(const ResolveInfo* pInfo) {
- return m_GOTTypeMap[pInfo] == true;
- }
+ void recordLocalEntry(const ResolveInfo* pInfo,
+ Relocation::DWord pAddend,
+ Fragment* pEntry);
+ Fragment* lookupLocalEntry(const ResolveInfo* pInfo,
+ Relocation::DWord pAddend);
/// hasGOT1 - return if this got section has any GOT1 entry
bool hasGOT1() const;
@@ -99,6 +85,16 @@
/// Compare two symbols to define order in the .dynsym.
bool dynSymOrderCompare(const LDSymbol* pX, const LDSymbol* pY) const;
+protected:
+ /// Create GOT entry.
+ virtual Fragment* createEntry(uint64_t pValue, SectionData* pParent) = 0;
+
+ /// Size of GOT entry.
+ virtual size_t getEntrySize() const = 0;
+
+ /// Reserve GOT header entries.
+ virtual void reserveHeader() = 0;
+
private:
/** \class GOTMultipart
* \brief GOTMultipart counts local and global entries in the GOT.
@@ -115,8 +111,8 @@
size_t m_ConsumedLocal; ///< consumed local entries
size_t m_ConsumedGlobal; ///< consumed global entries
- MipsGOTEntry* m_pLastLocal; ///< the last consumed local entry
- MipsGOTEntry* m_pLastGlobal; ///< the last consumed global entry
+ Fragment* m_pLastLocal; ///< the last consumed local entry
+ Fragment* m_pLastGlobal; ///< the last consumed global entry
InputSetType m_Inputs;
@@ -126,17 +122,46 @@
void consumeGlobal();
};
+ /** \class LocalEntry
+ * \brief LocalEntry local GOT entry descriptor.
+ */
+ struct LocalEntry
+ {
+ const ResolveInfo* m_pInfo;
+ Relocation::DWord m_Addend;
+ bool m_IsGot16;
+
+ LocalEntry(const ResolveInfo* pInfo,
+ Relocation::DWord addend, bool isGot16);
+
+ bool operator<(const LocalEntry &O) const;
+ };
+
typedef std::vector<GOTMultipart> MultipartListType;
+ // Set of global symbols.
typedef llvm::DenseSet<const ResolveInfo*> SymbolSetType;
+ // Map of symbols. If value is true, the symbol is referenced
+ // in the current input only. If value is false, the symbol
+ // is referenced in the other modules merged to the current GOT.
typedef llvm::DenseMap<const ResolveInfo*, bool> SymbolUniqueMapType;
+ // Set of local symbols.
+ typedef std::set<LocalEntry> LocalSymbolSetType;
+
MultipartListType m_MultipartList; ///< list of GOT's descriptors
const Input* m_pInput; ///< current input
- SymbolSetType m_MergedGlobalSymbols; ///< merged global symbols from
- SymbolUniqueMapType m_InputGlobalSymbols; ///< input global symbols
- SymbolSetType m_MergedLocalSymbols;
- SymbolSetType m_InputLocalSymbols;
+
+ // Global symbols merged to the current GOT
+ // except symbols from the current input.
+ SymbolSetType m_MergedGlobalSymbols;
+ // Global symbols from the current input.
+ SymbolUniqueMapType m_InputGlobalSymbols;
+ // Local symbols merged to the current GOT
+ // except symbols from the current input.
+ LocalSymbolSetType m_MergedLocalSymbols;
+ // Local symbols from the current input.
+ LocalSymbolSetType m_InputLocalSymbols;
size_t m_CurrentGOTPart;
@@ -144,33 +169,72 @@
SymbolOrderMapType m_SymbolOrderMap;
void initGOTList();
+
void changeInput();
bool isGOTFull() const;
void split();
void reserve(size_t pNum);
private:
- typedef llvm::DenseMap<const ResolveInfo*, bool> SymbolTypeMapType;
-
- SymbolTypeMapType m_GOTTypeMap;
-
-private:
struct GotEntryKey
{
size_t m_GOTPage;
const ResolveInfo* m_pInfo;
+ Relocation::DWord m_Addend;
bool operator<(const GotEntryKey& key) const
{
- if (m_GOTPage == key.m_GOTPage)
- return m_pInfo < key.m_pInfo;
- else
+ if (m_GOTPage != key.m_GOTPage)
return m_GOTPage < key.m_GOTPage;
+
+ if (m_pInfo != key.m_pInfo)
+ return m_pInfo < key.m_pInfo;
+
+ return m_Addend < key.m_Addend;
}
};
- typedef std::map<GotEntryKey, MipsGOTEntry*> GotEntryMapType;
- GotEntryMapType m_GotEntriesMap;
+ typedef std::map<GotEntryKey, Fragment*> GotEntryMapType;
+ GotEntryMapType m_GotLocalEntriesMap;
+ GotEntryMapType m_GotGlobalEntriesMap;
+};
+
+/** \class Mips32GOT
+ * \brief Mips 32-bit Global Offset Table.
+ */
+class Mips32GOT : public MipsGOT
+{
+public:
+ Mips32GOT(LDSection& pSection);
+
+private:
+ typedef GOT::Entry<4> Mips32GOTEntry;
+
+ // MipsGOT
+ virtual void setEntryValue(Fragment* entry, uint64_t pValue);
+ virtual uint64_t emit(MemoryRegion& pRegion);
+ virtual Fragment* createEntry(uint64_t pValue, SectionData* pParent);
+ virtual size_t getEntrySize() const;
+ virtual void reserveHeader();
+};
+
+/** \class Mips64GOT
+ * \brief Mips 64-bit Global Offset Table.
+ */
+class Mips64GOT : public MipsGOT
+{
+public:
+ Mips64GOT(LDSection& pSection);
+
+private:
+ typedef GOT::Entry<8> Mips64GOTEntry;
+
+ // MipsGOT
+ virtual void setEntryValue(Fragment* entry, uint64_t pValue);
+ virtual uint64_t emit(MemoryRegion& pRegion);
+ virtual Fragment* createEntry(uint64_t pValue, SectionData* pParent);
+ virtual size_t getEntrySize() const;
+ virtual void reserveHeader();
};
} // namespace of mcld
diff --git a/lib/Target/Mips/MipsGOTPLT.cpp b/lib/Target/Mips/MipsGOTPLT.cpp
new file mode 100644
index 0000000..1f65490
--- /dev/null
+++ b/lib/Target/Mips/MipsGOTPLT.cpp
@@ -0,0 +1,79 @@
+//===- MipsGOTPLT.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/Support/Casting.h>
+#include "MipsGOTPLT.h"
+
+namespace {
+ typedef mcld::GOT::Entry<4> GOTPLTEntry;
+
+ const size_t MipsGOTPLT0Num = 2;
+}
+
+namespace mcld {
+
+//===----------------------------------------------------------------------===//
+// MipsGOTPLT
+//===----------------------------------------------------------------------===//
+MipsGOTPLT::MipsGOTPLT(LDSection& pSection)
+ : GOT(pSection)
+{
+ // Create header's entries.
+ new GOTPLTEntry(0, m_SectionData);
+ new GOTPLTEntry(0, m_SectionData);
+ m_Last = ++m_SectionData->begin();
+}
+
+void MipsGOTPLT::reserve(size_t pNum)
+{
+ for (size_t i = 0; i < pNum; i++)
+ new GOTPLTEntry(0, m_SectionData);
+}
+
+uint64_t MipsGOTPLT::emit(MemoryRegion& pRegion)
+{
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.begin());
+
+ uint64_t result = 0;
+ for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) {
+ GOTPLTEntry* got = &(llvm::cast<GOTPLTEntry>((*it)));
+ *buffer = static_cast<uint32_t>(got->getValue());
+ result += got->size();
+ }
+ return result;
+}
+
+Fragment* MipsGOTPLT::consume()
+{
+ ++m_Last;
+ assert(m_Last != m_SectionData->end() &&
+ "There is no reserved GOTPLT entries");
+ return &(*m_Last);
+}
+
+bool MipsGOTPLT::hasGOT1() const
+{
+ return m_SectionData->size() > MipsGOTPLT0Num;
+}
+
+uint64_t MipsGOTPLT::getEntryAddr(size_t num) const
+{
+ return addr() + (MipsGOTPLT0Num + num) * GOTPLTEntry::EntrySize;
+}
+
+void MipsGOTPLT::applyAllGOTPLT(uint64_t pltAddr)
+{
+ iterator it = begin();
+ llvm::cast<GOTPLTEntry>(*it++).setValue(0); // PLT lazy resolver
+ llvm::cast<GOTPLTEntry>(*it++).setValue(0); // Module pointer
+
+ for (; it != end(); ++it)
+ llvm::cast<GOTPLTEntry>(*it).setValue(pltAddr);
+}
+
+} //end mcld namespace
diff --git a/lib/Target/Mips/MipsGOTPLT.h b/lib/Target/Mips/MipsGOTPLT.h
new file mode 100644
index 0000000..ccf521e
--- /dev/null
+++ b/lib/Target/Mips/MipsGOTPLT.h
@@ -0,0 +1,53 @@
+//===- MipsGOTPLT.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MIPS_GOTPLT_H
+#define MCLD_MIPS_GOTPLT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Target/GOT.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <llvm/ADT/DenseMap.h>
+
+namespace mcld {
+
+class LDSection;
+
+/** \class MipsGOTPLT
+ * \brief Mips .got.plt section.
+ */
+class MipsGOTPLT : public GOT
+{
+public:
+ MipsGOTPLT(LDSection &pSection);
+
+ // hasGOT1 - return if this section has any GOT1 entry
+ bool hasGOT1() const;
+
+ uint64_t getEntryAddr(size_t num) const;
+
+ uint64_t emit(MemoryRegion& pRegion);
+
+ Fragment* consume();
+
+ void applyAllGOTPLT(uint64_t pltAddr);
+
+public:
+ // GOT
+ void reserve(size_t pNum = 1);
+
+private:
+ // the last consumed entry.
+ SectionData::iterator m_Last;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Mips/MipsLA25Stub.cpp b/lib/Target/Mips/MipsLA25Stub.cpp
new file mode 100644
index 0000000..fcbc011
--- /dev/null
+++ b/lib/Target/Mips/MipsLA25Stub.cpp
@@ -0,0 +1,109 @@
+//===- MipsLA25Stub.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/ResolveInfo.h>
+#include "MipsLA25Stub.h"
+#include "MipsLDBackend.h"
+
+namespace {
+
+const uint32_t STUB[] = {
+ 0x3c190000, // lui $25,%hi(func)
+ 0x08000000, // j func
+ 0x27390000, // add $25,$25,%lo(func)
+ 0x00000000 // nop
+};
+
+enum {
+ // Fake relocations for patching LA25 stubs.
+ R_MIPS_LA25_LUI = 200,
+ R_MIPS_LA25_J = 201,
+ R_MIPS_LA25_ADD = 202
+};
+
+}
+
+namespace mcld {
+
+//===----------------------------------------------------------------------===//
+// MipsLA25Stub
+//===----------------------------------------------------------------------===//
+
+MipsLA25Stub::MipsLA25Stub(const MipsGNULDBackend& pTarget)
+ : m_Target(pTarget),
+ m_Name("MipsLA25_Prototype"),
+ m_pData(STUB),
+ m_Size(sizeof(STUB))
+{
+ addFixup(0, 0x0, R_MIPS_LA25_LUI);
+ addFixup(4, 0x0, R_MIPS_LA25_J);
+ addFixup(8, 0x0, R_MIPS_LA25_ADD);
+}
+
+MipsLA25Stub::MipsLA25Stub(const MipsGNULDBackend& pTarget,
+ const uint32_t* pData,
+ size_t pSize,
+ const_fixup_iterator pBegin,
+ const_fixup_iterator pEnd)
+ : m_Target(pTarget),
+ m_Name("pic"),
+ m_pData(pData),
+ m_Size(pSize)
+{
+ for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it)
+ addFixup(**it);
+}
+
+bool MipsLA25Stub::isMyDuty(const Relocation& pReloc,
+ uint64_t pSource,
+ uint64_t pTargetSymValue) const
+{
+ if (llvm::ELF::R_MIPS_26 != pReloc.type())
+ return false;
+
+ const ResolveInfo* rsym = pReloc.symInfo();
+
+ if (!rsym->isDefine())
+ return false;
+
+ if (rsym->isDyn() || rsym->isUndef())
+ return false;
+
+ if (!m_Target.hasNonPICBranch(rsym))
+ return false;
+
+ return true;
+}
+
+const std::string& MipsLA25Stub::name() const
+{
+ return m_Name;
+}
+
+const uint8_t* MipsLA25Stub::getContent() const
+{
+ return reinterpret_cast<const uint8_t*>(m_pData);
+}
+
+size_t MipsLA25Stub::size() const
+{
+ return m_Size;
+}
+
+size_t MipsLA25Stub::alignment() const
+{
+ return 4;
+}
+
+Stub* MipsLA25Stub::doClone()
+{
+ return new MipsLA25Stub(m_Target, m_pData, m_Size,
+ fixup_begin(), fixup_end());
+}
+
+} //end mcld namespace
diff --git a/lib/Target/Mips/MipsLA25Stub.h b/lib/Target/Mips/MipsLA25Stub.h
new file mode 100644
index 0000000..126cfd7
--- /dev/null
+++ b/lib/Target/Mips/MipsLA25Stub.h
@@ -0,0 +1,64 @@
+//===- MipsLA25Stub.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MIPS_LA25_STUB_H
+#define MCLD_MIPS_LA25_STUB_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Fragment/Stub.h>
+
+namespace mcld
+{
+
+class MipsGNULDBackend;
+class Relocation;
+
+//===----------------------------------------------------------------------===//
+// MipsLA25Stub
+//===----------------------------------------------------------------------===//
+/** \class MipsLA25Stub
+ * \brief Mips stub for a non-PIC interface to a PIC function.
+ */
+class MipsLA25Stub : public Stub
+{
+public:
+ MipsLA25Stub(const MipsGNULDBackend& pTarget);
+
+private:
+ // Stub
+ Stub* doClone();
+ bool isMyDuty(const Relocation& pReloc,
+ uint64_t pSource,
+ uint64_t pTargetSymValue) const;
+ const std::string& name() const;
+ const uint8_t* getContent() const;
+ size_t size() const;
+ size_t alignment() const;
+
+private:
+ MipsLA25Stub(const MipsLA25Stub&);
+ MipsLA25Stub& operator=(const MipsLA25Stub&);
+
+ MipsLA25Stub(const MipsGNULDBackend& pTarget,
+ const uint32_t* pData,
+ size_t pSize,
+ const_fixup_iterator pBegin,
+ const_fixup_iterator pEnd);
+
+private:
+ const MipsGNULDBackend& m_Target;
+ const std::string m_Name;
+ const uint32_t* m_pData;
+ const size_t m_Size;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Mips/MipsLDBackend.cpp b/lib/Target/Mips/MipsLDBackend.cpp
index e26a89e..a6fd40b 100644
--- a/lib/Target/Mips/MipsLDBackend.cpp
+++ b/lib/Target/Mips/MipsLDBackend.cpp
@@ -9,15 +9,22 @@
#include "Mips.h"
#include "MipsGNUInfo.h"
#include "MipsELFDynamic.h"
+#include "MipsLA25Stub.h"
#include "MipsLDBackend.h"
#include "MipsRelocator.h"
#include <llvm/ADT/Triple.h>
+#include <llvm/Support/Casting.h>
#include <llvm/Support/ELF.h>
+#include <llvm/Support/Host.h>
#include <mcld/Module.h>
#include <mcld/LinkerConfig.h>
#include <mcld/IRBuilder.h>
+#include <mcld/LD/BranchIslandFactory.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/LD/StubFactory.h>
+#include <mcld/LD/ELFFileFormat.h>
#include <mcld/MC/Attribute.h>
#include <mcld/Fragment/FillFragment.h>
#include <mcld/Support/MemoryRegion.h>
@@ -37,9 +44,14 @@
: GNULDBackend(pConfig, pInfo),
m_pRelocator(NULL),
m_pGOT(NULL),
+ m_pPLT(NULL),
+ m_pGOTPLT(NULL),
+ m_pInfo(*pInfo),
+ m_pRelPlt(NULL),
m_pRelDyn(NULL),
m_pDynamic(NULL),
m_pGOTSymbol(NULL),
+ m_pPLTSymbol(NULL),
m_pGpDispSymbol(NULL)
{
}
@@ -47,24 +59,52 @@
MipsGNULDBackend::~MipsGNULDBackend()
{
delete m_pRelocator;
- delete m_pGOT;
+ delete m_pPLT;
+ delete m_pRelPlt;
delete m_pRelDyn;
delete m_pDynamic;
}
-void MipsGNULDBackend::initTargetSections(Module& pModule, ObjectBuilder& pBuilder)
+bool MipsGNULDBackend::needsLA25Stub(Relocation::Type pType,
+ const mcld::ResolveInfo* pSym)
{
- if (LinkerConfig::Object != config().codeGenType()) {
- ELFFileFormat* file_format = getOutputFormat();
+ if (config().isCodeIndep())
+ return false;
- // initialize .got
- LDSection& got = file_format->getGOT();
- m_pGOT = new MipsGOT(got);
+ if (llvm::ELF::R_MIPS_26 != pType)
+ return false;
- // initialize .rel.dyn
- LDSection& reldyn = file_format->getRelDyn();
- m_pRelDyn = new OutputRelocSection(pModule, reldyn);
- }
+ if (pSym->isLocal())
+ return false;
+
+ return true;
+}
+
+void MipsGNULDBackend::addNonPICBranchSym(ResolveInfo* rsym)
+{
+ m_HasNonPICBranchSyms.insert(rsym);
+}
+
+bool MipsGNULDBackend::hasNonPICBranch(const ResolveInfo* rsym) const
+{
+ return m_HasNonPICBranchSyms.count(rsym);
+}
+
+void MipsGNULDBackend::initTargetSections(Module& pModule,
+ ObjectBuilder& pBuilder)
+{
+ if (LinkerConfig::Object == config().codeGenType())
+ return;
+
+ ELFFileFormat* file_format = getOutputFormat();
+
+ // initialize .rel.plt
+ LDSection& relplt = file_format->getRelPlt();
+ m_pRelPlt = new OutputRelocSection(pModule, relplt);
+
+ // initialize .rel.dyn
+ LDSection& reldyn = file_format->getRelDyn();
+ m_pRelDyn = new OutputRelocSection(pModule, reldyn);
}
void MipsGNULDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule)
@@ -81,6 +121,19 @@
FragmentRef::Null(), // FragRef
ResolveInfo::Hidden);
+ // Define the symbol _PROCEDURE_LINKAGE_TABLE_ if there is a symbol with the
+ // same name in input
+ m_pPLTSymbol =
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "_PROCEDURE_LINKAGE_TABLE_",
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ FragmentRef::Null(), // FragRef
+ ResolveInfo::Hidden);
+
m_pGpDispSymbol = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"_gp_disp",
ResolveInfo::Section,
@@ -90,18 +143,6 @@
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
-
- if (NULL != m_pGpDispSymbol) {
- m_pGpDispSymbol->resolveInfo()->setReserved(MipsRelocator::ReserveGpDisp);
- }
-}
-
-bool MipsGNULDBackend::initRelocator()
-{
- if (NULL == m_pRelocator) {
- m_pRelocator = new MipsRelocator(*this, config());
- }
- return true;
}
Relocator* MipsGNULDBackend::getRelocator()
@@ -128,7 +169,25 @@
defineGOTSymbol(pBuilder);
}
+ if (m_pGOTPLT->hasGOT1()) {
+ m_pGOTPLT->finalizeSectionSize();
+
+ defineGOTPLTSymbol(pBuilder);
+ }
+
+ if (m_pPLT->hasPLT1())
+ m_pPLT->finalizeSectionSize();
+
ELFFileFormat* file_format = getOutputFormat();
+
+ // set .rel.plt size
+ if (!m_pRelPlt->empty()) {
+ assert(!config().isCodeStatic() &&
+ "static linkage should not result in a dynamic relocation section");
+ file_format->getRelPlt().setSize(
+ m_pRelPlt->numOfRelocs() * getRelEntrySize());
+ }
+
// set .rel.dyn size
if (!m_pRelDyn->empty()) {
assert(!config().isCodeStatic() &&
@@ -141,6 +200,32 @@
void MipsGNULDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder)
{
+ const ELFFileFormat *format = getOutputFormat();
+
+ if (format->hasGOTPLT()) {
+ assert(m_pGOTPLT && "doPostLayout failed, m_pGOTPLT is NULL!");
+ m_pGOTPLT->applyAllGOTPLT(m_pPLT->addr());
+ }
+
+ if (format->hasPLT()) {
+ assert(m_pPLT && "doPostLayout failed, m_pPLT is NULL!");
+ m_pPLT->applyAllPLT(*m_pGOTPLT);
+ }
+
+ m_pInfo.setABIVersion(m_pPLT && m_pPLT->hasPLT1() ? 1 : 0);
+
+ // FIXME: (simon) We need to iterate all input sections
+ // check that flags are consistent and merge them properly.
+ uint64_t picFlags = llvm::ELF::EF_MIPS_CPIC;
+ if (config().targets().triple().isArch64Bit()) {
+ picFlags |= llvm::ELF::EF_MIPS_PIC;
+ }
+ else {
+ if (LinkerConfig::DynObj == config().codeGenType())
+ picFlags |= llvm::ELF::EF_MIPS_PIC;
+ }
+
+ m_pInfo.setPICFlags(picFlags);
}
/// dynamic - the dynamic section of the target machine.
@@ -166,10 +251,16 @@
const ELFFileFormat* file_format = getOutputFormat();
- if (&pSection == &(file_format->getGOT())) {
- assert(NULL != m_pGOT && "emitSectionData failed, m_pGOT is NULL!");
- uint64_t result = m_pGOT->emit(pRegion);
- return result;
+ if (file_format->hasGOT() && (&pSection == &(file_format->getGOT()))) {
+ return m_pGOT->emit(pRegion);
+ }
+
+ if (file_format->hasPLT() && (&pSection == &(file_format->getPLT()))) {
+ return m_pPLT->emit(pRegion);
+ }
+
+ if (file_format->hasGOTPLT() && (&pSection == &(file_format->getGOTPLT()))) {
+ return m_pGOTPLT->emit(pRegion);
}
fatal(diag::unrecognized_output_sectoin)
@@ -218,6 +309,102 @@
DynsymGOTCompare(*m_pGOT));
}
+namespace llvm {
+namespace ELF {
+// SHT_MIPS_OPTIONS section's block descriptor.
+struct Elf_Options {
+ unsigned char kind; // Determines interpretation of variable
+ // part of descriptor. See ODK_xxx enumeration.
+ unsigned char size; // Byte size of descriptor, including this header.
+ Elf64_Half section; // Section header index of section affected,
+ // or 0 for global options.
+ Elf64_Word info; // Kind-specific information.
+};
+
+// Type of SHT_MIPS_OPTIONS section's block.
+enum {
+ ODK_NULL = 0, // Undefined.
+ ODK_REGINFO = 1, // Register usage and GP value.
+ ODK_EXCEPTIONS = 2, // Exception processing information.
+ ODK_PAD = 3, // Section padding information.
+ ODK_HWPATCH = 4, // Hardware workarounds performed.
+ ODK_FILL = 5, // Fill value used by the linker.
+ ODK_TAGS = 6, // Reserved space for desktop tools.
+ ODK_HWAND = 7, // Hardware workarounds, AND bits when merging.
+ ODK_HWOR = 8, // Hardware workarounds, OR bits when merging.
+ ODK_GP_GROUP = 9, // GP group to use for text/data sections.
+ ODK_IDENT = 10 // ID information.
+};
+
+// Content of ODK_REGINFO block in SHT_MIPS_OPTIONS section on 32 bit ABI.
+struct Elf32_RegInfo {
+ Elf32_Word ri_gprmask; // Mask of general purpose registers used.
+ Elf32_Word ri_cprmask[4]; // Mask of co-processor registers used.
+ Elf32_Addr ri_gp_value; // GP register value for this object file.
+};
+
+// Content of ODK_REGINFO block in SHT_MIPS_OPTIONS section on 64 bit ABI.
+struct Elf64_RegInfo {
+ Elf32_Word ri_gprmask; // Mask of general purpose registers used.
+ Elf32_Word ri_pad; // Padding.
+ Elf32_Word ri_cprmask[4]; // Mask of co-processor registers used.
+ Elf64_Addr ri_gp_value; // GP register value for this object file.
+};
+
+}
+}
+
+bool MipsGNULDBackend::readSection(Input& pInput, SectionData& pSD)
+{
+ llvm::StringRef name(pSD.getSection().name());
+
+ if (name.startswith(".sdata")) {
+ uint64_t offset = pInput.fileOffset() + pSD.getSection().offset();
+ uint64_t size = pSD.getSection().size();
+
+ Fragment* frag = IRBuilder::CreateRegion(pInput, offset, size);
+ ObjectBuilder::AppendFragment(*frag, pSD);
+ return true;
+ }
+
+ if (pSD.getSection().type() == llvm::ELF::SHT_MIPS_OPTIONS) {
+ uint32_t offset = pInput.fileOffset() + pSD.getSection().offset();
+ uint32_t size = pSD.getSection().size();
+
+ llvm::StringRef region = pInput.memArea()->request(offset, size);
+ if (region.size() > 0) {
+ const llvm::ELF::Elf_Options* optb =
+ reinterpret_cast<const llvm::ELF::Elf_Options*>(region.begin());
+ const llvm::ELF::Elf_Options* opte =
+ reinterpret_cast<const llvm::ELF::Elf_Options*>(region.begin() + size);
+
+ for (const llvm::ELF::Elf_Options* opt = optb; opt < opte; opt += opt->size) {
+ switch (opt->kind) {
+ default:
+ // Nothing to do.
+ break;
+ case llvm::ELF::ODK_REGINFO:
+ if (config().targets().triple().isArch32Bit()) {
+ const llvm::ELF::Elf32_RegInfo* reg =
+ reinterpret_cast<const llvm::ELF::Elf32_RegInfo*>(opt + 1);
+ m_GP0Map[&pInput] = reg->ri_gp_value;
+ }
+ else {
+ const llvm::ELF::Elf64_RegInfo* reg =
+ reinterpret_cast<const llvm::ELF::Elf64_RegInfo*>(opt + 1);
+ m_GP0Map[&pInput] = reg->ri_gp_value;
+ }
+ break;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ return GNULDBackend::readSection(pInput, pSD);
+}
+
MipsGOT& MipsGNULDBackend::getGOT()
{
assert(NULL != m_pGOT);
@@ -230,6 +417,42 @@
return *m_pGOT;
}
+MipsPLT& MipsGNULDBackend::getPLT()
+{
+ assert(NULL != m_pPLT);
+ return *m_pPLT;
+}
+
+const MipsPLT& MipsGNULDBackend::getPLT() const
+{
+ assert(NULL != m_pPLT);
+ return *m_pPLT;
+}
+
+MipsGOTPLT& MipsGNULDBackend::getGOTPLT()
+{
+ assert(NULL != m_pGOTPLT);
+ return *m_pGOTPLT;
+}
+
+const MipsGOTPLT& MipsGNULDBackend::getGOTPLT() const
+{
+ assert(NULL != m_pGOTPLT);
+ return *m_pGOTPLT;
+}
+
+OutputRelocSection& MipsGNULDBackend::getRelPLT()
+{
+ assert(NULL != m_pRelPlt);
+ return *m_pRelPlt;
+}
+
+const OutputRelocSection& MipsGNULDBackend::getRelPLT() const
+{
+ assert(NULL != m_pRelPlt);
+ return *m_pRelPlt;
+}
+
OutputRelocSection& MipsGNULDBackend::getRelDyn()
{
assert(NULL != m_pRelDyn);
@@ -247,9 +470,15 @@
{
const ELFFileFormat* file_format = getOutputFormat();
- if (&pSectHdr == &file_format->getGOT())
+ if (file_format->hasGOT() && (&pSectHdr == &file_format->getGOT()))
return SHO_DATA;
+ if (file_format->hasGOTPLT() && (&pSectHdr == &file_format->getGOTPLT()))
+ return SHO_DATA;
+
+ if (file_format->hasPLT() && (&pSectHdr == &file_format->getPLT()))
+ return SHO_PLT;
+
return SHO_UNDEFINED;
}
@@ -313,19 +542,20 @@
// description here.
(*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
Fragment* frag = new FillFragment(0x0, 1, (*com_sym)->size());
- (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
// allocate TLS common symbol in tbss section
tbss_offset += ObjectBuilder::AppendFragment(*frag,
*tbss_sect_data,
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
}
// FIXME: how to identify small and large common symbols?
else {
bss_offset += ObjectBuilder::AppendFragment(*frag,
*bss_sect_data,
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
}
}
}
@@ -340,19 +570,20 @@
// description here.
(*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
Fragment* frag = new FillFragment(0x0, 1, (*com_sym)->size());
- (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
// allocate TLS common symbol in tbss section
tbss_offset += ObjectBuilder::AppendFragment(*frag,
*tbss_sect_data,
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
}
// FIXME: how to identify small and large common symbols?
else {
bss_offset += ObjectBuilder::AppendFragment(*frag,
*bss_sect_data,
(*com_sym)->value());
+ (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
}
}
@@ -362,6 +593,11 @@
return true;
}
+uint64_t MipsGNULDBackend::getGP0(const Input& pInput) const
+{
+ return m_GP0Map.lookup(&pInput);
+}
+
void MipsGNULDBackend::defineGOTSymbol(IRBuilder& pBuilder)
{
// If we do not reserve any GOT entries, we do not need to re-define GOT
@@ -394,6 +630,33 @@
}
}
+void MipsGNULDBackend::defineGOTPLTSymbol(IRBuilder& pBuilder)
+{
+ // define symbol _PROCEDURE_LINKAGE_TABLE_
+ if ( m_pPLTSymbol != NULL ) {
+ pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
+ "_PROCEDURE_LINKAGE_TABLE_",
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ FragmentRef::Create(*(m_pPLT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+ else {
+ m_pPLTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
+ "_PROCEDURE_LINKAGE_TABLE_",
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ FragmentRef::Create(*(m_pPLT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+}
+
/// doCreateProgramHdrs - backend can implement this function to create the
/// target-dependent segments
void MipsGNULDBackend::doCreateProgramHdrs(Module& pModule)
@@ -401,27 +664,343 @@
// TODO
}
+bool MipsGNULDBackend::relaxRelocation(IRBuilder& pBuilder, Relocation& pRel)
+{
+ uint64_t sym_value = 0x0;
+
+ LDSymbol* symbol = pRel.symInfo()->outSymbol();
+ if (symbol->hasFragRef()) {
+ uint64_t value = symbol->fragRef()->getOutputOffset();
+ uint64_t addr = symbol->fragRef()->frag()->getParent()->getSection().addr();
+ sym_value = addr + value;
+ }
+
+ Stub* stub =
+ getStubFactory()->create(pRel, sym_value, pBuilder, *getBRIslandFactory());
+
+ if (NULL == stub)
+ return false;
+
+ assert(NULL != stub->symInfo());
+ // increase the size of .symtab and .strtab
+ LDSection& symtab = getOutputFormat()->getSymTab();
+ LDSection& strtab = getOutputFormat()->getStrTab();
+ symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf32_Sym));
+ strtab.setSize(strtab.size() + stub->symInfo()->nameSize() + 1);
+
+ return true;
+}
+
+bool MipsGNULDBackend::doRelax(Module& pModule, IRBuilder& pBuilder,
+ bool& pFinished)
+{
+ assert(NULL != getStubFactory() && NULL != getBRIslandFactory());
+
+ bool isRelaxed = false;
+
+ for (Module::obj_iterator input = pModule.obj_begin();
+ input != pModule.obj_end(); ++input) {
+ LDContext* context = (*input)->context();
+
+ for (LDContext::sect_iterator rs = context->relocSectBegin();
+ rs != context->relocSectEnd(); ++rs) {
+ LDSection* sec = *rs;
+
+ if (LDFileFormat::Ignore == sec->kind() || !sec->hasRelocData())
+ continue;
+
+ for (RelocData::iterator reloc = sec->getRelocData()->begin();
+ reloc != sec->getRelocData()->end(); ++reloc) {
+ if (llvm::ELF::R_MIPS_26 != reloc->type())
+ continue;
+
+ if (relaxRelocation(pBuilder, *llvm::cast<Relocation>(reloc)))
+ isRelaxed = true;
+ }
+ }
+ }
+
+ SectionData* textData = getOutputFormat()->getText().getSectionData();
+
+ // find the first fragment w/ invalid offset due to stub insertion
+ Fragment* invalid = NULL;
+ pFinished = true;
+ for (BranchIslandFactory::iterator ii = getBRIslandFactory()->begin(),
+ ie = getBRIslandFactory()->end();
+ ii != ie; ++ii)
+ {
+ BranchIsland& island = *ii;
+ if (island.end() == textData->end())
+ break;
+
+ Fragment* exit = island.end();
+ if ((island.offset() + island.size()) > exit->getOffset()) {
+ invalid = exit;
+ pFinished = false;
+ break;
+ }
+ }
+
+ // reset the offset of invalid fragments
+ while (NULL != invalid) {
+ invalid->setOffset(invalid->getPrevNode()->getOffset() +
+ invalid->getPrevNode()->size());
+ invalid = invalid->getNextNode();
+ }
+
+ // reset the size of .text
+ if (isRelaxed)
+ getOutputFormat()->getText().setSize(textData->back().getOffset() +
+ textData->back().size());
+
+ return isRelaxed;
+}
+
+bool MipsGNULDBackend::initTargetStubs()
+{
+ if (NULL == getStubFactory())
+ return false;
+
+ getStubFactory()->addPrototype(new MipsLA25Stub(*this));
+ return true;
+}
+
+bool MipsGNULDBackend::readRelocation(const llvm::ELF::Elf32_Rel& pRel,
+ Relocation::Type& pType,
+ uint32_t& pSymIdx,
+ uint32_t& pOffset) const
+{
+ return GNULDBackend::readRelocation(pRel, pType, pSymIdx, pOffset);
+}
+
+bool MipsGNULDBackend::readRelocation(const llvm::ELF::Elf32_Rela& pRel,
+ Relocation::Type& pType,
+ uint32_t& pSymIdx,
+ uint32_t& pOffset,
+ int32_t& pAddend) const
+{
+ return GNULDBackend::readRelocation(pRel, pType, pSymIdx, pOffset, pAddend);
+}
+
+bool MipsGNULDBackend::readRelocation(const llvm::ELF::Elf64_Rel& pRel,
+ Relocation::Type& pType,
+ uint32_t& pSymIdx,
+ uint64_t& pOffset) const
+{
+ uint64_t r_info = 0x0;
+ if (llvm::sys::IsLittleEndianHost) {
+ pOffset = pRel.r_offset;
+ r_info = pRel.r_info;
+ }
+ else {
+ pOffset = mcld::bswap64(pRel.r_offset);
+ r_info = mcld::bswap64(pRel.r_info);
+ }
+
+ // MIPS 64 little endian (we do not support big endian now)
+ // has a "special" encoding of r_info relocation
+ // field. Instead of one 64 bit little endian number, it is a little
+ // endian 32 bit number followed by a 32 bit big endian number.
+ pType = mcld::bswap32(r_info >> 32);
+ pSymIdx = r_info & 0xffffffff;
+ return true;
+}
+
+bool MipsGNULDBackend::readRelocation(const llvm::ELF::Elf64_Rela& pRel,
+ Relocation::Type& pType,
+ uint32_t& pSymIdx,
+ uint64_t& pOffset,
+ int64_t& pAddend) const
+{
+ uint64_t r_info = 0x0;
+ if (llvm::sys::IsLittleEndianHost) {
+ pOffset = pRel.r_offset;
+ r_info = pRel.r_info;
+ pAddend = pRel.r_addend;
+ }
+ else {
+ pOffset = mcld::bswap64(pRel.r_offset);
+ r_info = mcld::bswap64(pRel.r_info);
+ pAddend = mcld::bswap64(pRel.r_addend);
+ }
+
+ pType = mcld::bswap32(r_info >> 32);
+ pSymIdx = r_info & 0xffffffff;
+ return true;
+}
+
+void MipsGNULDBackend::emitRelocation(llvm::ELF::Elf32_Rel& pRel,
+ Relocation::Type pType,
+ uint32_t pSymIdx,
+ uint32_t pOffset) const
+{
+ GNULDBackend::emitRelocation(pRel, pType, pSymIdx, pOffset);
+}
+
+void MipsGNULDBackend::emitRelocation(llvm::ELF::Elf32_Rela& pRel,
+ Relocation::Type pType,
+ uint32_t pSymIdx,
+ uint32_t pOffset,
+ int32_t pAddend) const
+{
+ GNULDBackend::emitRelocation(pRel, pType, pSymIdx, pOffset, pAddend);
+}
+
+void MipsGNULDBackend::emitRelocation(llvm::ELF::Elf64_Rel& pRel,
+ Relocation::Type pType,
+ uint32_t pSymIdx,
+ uint64_t pOffset) const
+{
+ uint64_t r_info = mcld::bswap32(pType);
+ r_info <<= 32;
+ r_info |= pSymIdx;
+
+ pRel.r_info = r_info;
+ pRel.r_offset = pOffset;
+}
+
+void MipsGNULDBackend::emitRelocation(llvm::ELF::Elf64_Rela& pRel,
+ Relocation::Type pType,
+ uint32_t pSymIdx,
+ uint64_t pOffset,
+ int64_t pAddend) const
+{
+ uint64_t r_info = mcld::bswap32(pType);
+ r_info <<= 32;
+ r_info |= pSymIdx;
+
+ pRel.r_info = r_info;
+ pRel.r_offset = pOffset;
+ pRel.r_addend = pAddend;
+}
+
+//===----------------------------------------------------------------------===//
+// Mips32GNULDBackend
+//===----------------------------------------------------------------------===//
+Mips32GNULDBackend::Mips32GNULDBackend(const LinkerConfig& pConfig,
+ MipsGNUInfo* pInfo)
+ : MipsGNULDBackend(pConfig, pInfo)
+{}
+
+bool Mips32GNULDBackend::initRelocator()
+{
+ if (NULL == m_pRelocator)
+ m_pRelocator = new Mips32Relocator(*this, config());
+
+ return true;
+}
+
+void Mips32GNULDBackend::initTargetSections(Module& pModule,
+ ObjectBuilder& pBuilder)
+{
+ MipsGNULDBackend::initTargetSections(pModule, pBuilder);
+
+ if (LinkerConfig::Object == config().codeGenType())
+ return;
+
+ ELFFileFormat* fileFormat = getOutputFormat();
+
+ // initialize .got
+ LDSection& got = fileFormat->getGOT();
+ m_pGOT = new Mips32GOT(got);
+
+ // initialize .got.plt
+ LDSection& gotplt = fileFormat->getGOTPLT();
+ m_pGOTPLT = new MipsGOTPLT(gotplt);
+
+ // initialize .plt
+ LDSection& plt = fileFormat->getPLT();
+ m_pPLT = new MipsPLT(plt);
+}
+
+size_t Mips32GNULDBackend::getRelEntrySize()
+{
+ return 8;
+}
+
+size_t Mips32GNULDBackend::getRelaEntrySize()
+{
+ return 12;
+}
+
+//===----------------------------------------------------------------------===//
+// Mips64GNULDBackend
+//===----------------------------------------------------------------------===//
+Mips64GNULDBackend::Mips64GNULDBackend(const LinkerConfig& pConfig,
+ MipsGNUInfo* pInfo)
+ : MipsGNULDBackend(pConfig, pInfo)
+{}
+
+bool Mips64GNULDBackend::initRelocator()
+{
+ if (NULL == m_pRelocator)
+ m_pRelocator = new Mips64Relocator(*this, config());
+
+ return true;
+}
+
+void Mips64GNULDBackend::initTargetSections(Module& pModule,
+ ObjectBuilder& pBuilder)
+{
+ MipsGNULDBackend::initTargetSections(pModule, pBuilder);
+
+ if (LinkerConfig::Object == config().codeGenType())
+ return;
+
+ ELFFileFormat* fileFormat = getOutputFormat();
+
+ // initialize .got
+ LDSection& got = fileFormat->getGOT();
+ m_pGOT = new Mips64GOT(got);
+
+ // initialize .got.plt
+ LDSection& gotplt = fileFormat->getGOTPLT();
+ m_pGOTPLT = new MipsGOTPLT(gotplt);
+
+ // initialize .plt
+ LDSection& plt = fileFormat->getPLT();
+ m_pPLT = new MipsPLT(plt);
+}
+
+size_t Mips64GNULDBackend::getRelEntrySize()
+{
+ return 16;
+}
+
+size_t Mips64GNULDBackend::getRelaEntrySize()
+{
+ return 24;
+}
+
//===----------------------------------------------------------------------===//
/// createMipsLDBackend - the help funtion to create corresponding MipsLDBackend
///
-static TargetLDBackend* createMipsLDBackend(const llvm::Target& pTarget,
- const LinkerConfig& pConfig)
+static TargetLDBackend* createMipsLDBackend(const LinkerConfig& pConfig)
{
- if (pConfig.targets().triple().isOSDarwin()) {
+ const llvm::Triple& triple = pConfig.targets().triple();
+
+ if (triple.isOSDarwin()) {
assert(0 && "MachO linker is not supported yet");
}
- if (pConfig.targets().triple().isOSWindows()) {
+ if (triple.isOSWindows()) {
assert(0 && "COFF linker is not supported yet");
}
- return new MipsGNULDBackend(pConfig, new MipsGNUInfo(pConfig.targets().triple()));
+
+ llvm::Triple::ArchType arch = triple.getArch();
+
+ if (llvm::Triple::mips64el == arch)
+ return new Mips64GNULDBackend(pConfig, new MipsGNUInfo(triple));
+
+ assert (arch == llvm::Triple::mipsel);
+ return new Mips32GNULDBackend(pConfig, new MipsGNUInfo(triple));
}
//===----------------------------------------------------------------------===//
// Force static initialization.
//===----------------------------------------------------------------------===//
extern "C" void MCLDInitializeMipsLDBackend() {
- // Register the linker backend
mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheMipselTarget,
createMipsLDBackend);
+ mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheMips64elTarget,
+ createMipsLDBackend);
}
-
diff --git a/lib/Target/Mips/MipsLDBackend.h b/lib/Target/Mips/MipsLDBackend.h
index 831d830..5c4d12b 100644
--- a/lib/Target/Mips/MipsLDBackend.h
+++ b/lib/Target/Mips/MipsLDBackend.h
@@ -11,6 +11,8 @@
#include <mcld/Target/GNULDBackend.h>
#include "MipsELFDynamic.h"
#include "MipsGOT.h"
+#include "MipsGOTPLT.h"
+#include "MipsPLT.h"
namespace mcld {
@@ -20,9 +22,9 @@
class MemoryArea;
class MipsGNUInfo;
-//===----------------------------------------------------------------------===//
-/// MipsGNULDBackend - linker backend of Mips target of GNU ELF format
-///
+/** \class MipsGNULDBackend
+ * \brief Base linker backend of Mips target of GNU ELF format.
+ */
class MipsGNULDBackend : public GNULDBackend
{
public:
@@ -32,6 +34,11 @@
MipsGNULDBackend(const LinkerConfig& pConfig, MipsGNUInfo* pInfo);
~MipsGNULDBackend();
+ bool needsLA25Stub(Relocation::Type pType, const mcld::ResolveInfo* pSym);
+
+ void addNonPICBranchSym(ResolveInfo* rsym);
+ bool hasNonPICBranch(const ResolveInfo* rsym) const;
+
public:
/// initTargetSections - initialize target dependent sections in output
void initTargetSections(Module& pModule, ObjectBuilder& pBuilder);
@@ -39,9 +46,6 @@
/// initTargetSymbols - initialize target dependent symbols in output.
void initTargetSymbols(IRBuilder& pBuilder, Module& pModule);
- /// initRelocator - create and initialize Relocator.
- bool initRelocator();
-
/// getRelocator - return relocator.
Relocator* getRelocator();
@@ -82,14 +86,26 @@
/// orderSymbolTable - order symbol table before emitting
void orderSymbolTable(Module& pModule);
+ /// readSection - read a target dependent section.
+ bool readSection(Input& pInput, SectionData& pSD);
+
MipsGOT& getGOT();
const MipsGOT& getGOT() const;
+ MipsPLT& getPLT();
+ const MipsPLT& getPLT() const;
+
+ MipsGOTPLT& getGOTPLT();
+ const MipsGOTPLT& getGOTPLT() const;
+
+ OutputRelocSection& getRelPLT();
+ const OutputRelocSection& getRelPLT() const;
+
OutputRelocSection& getRelDyn();
const OutputRelocSection& getRelDyn() const;
- LDSymbol* getGOTSymbo() { return m_pGOTSymbol; }
- const LDSymbol* getGOTSymbo() const { return m_pGOTSymbol; }
+ LDSymbol* getGOTSymbol() { return m_pGOTSymbol; }
+ const LDSymbol* getGOTSymbol() const { return m_pGOTSymbol; }
LDSymbol* getGpDispSymbol() { return m_pGpDispSymbol; }
const LDSymbol* getGpDispSymbol() const { return m_pGpDispSymbol; }
@@ -107,8 +123,15 @@
/// sections.
bool allocateCommonSymbols(Module& pModule);
+ /// getGP0 - the gp value used to create the relocatable objects
+ /// in the specified input.
+ uint64_t getGP0(const Input& pInput) const;
+
private:
void defineGOTSymbol(IRBuilder& pBuilder);
+ void defineGOTPLTSymbol(IRBuilder& pBuilder);
+
+ bool relaxRelocation(IRBuilder& pBuilder, Relocation& pRel);
/// emitSymbol32 - emit an ELF32 symbol, override parent's function
void emitSymbol32(llvm::ELF::Elf32_Sym& pSym32,
@@ -117,32 +140,134 @@
size_t pStrtabsize,
size_t pSymtabIdx);
- /// getRelEntrySize - the size in BYTE of rel type relocation
- size_t getRelEntrySize()
- { return 8; }
-
- /// getRelEntrySize - the size in BYTE of rela type relocation
- size_t getRelaEntrySize()
- { return 12; }
-
/// doCreateProgramHdrs - backend can implement this function to create the
/// target-dependent segments
void doCreateProgramHdrs(Module& pModule);
-private:
- Relocator* m_pRelocator;
+ /// mayRelax - Backends should override this function if they need relaxation
+ bool mayRelax() { return true; }
+ /// doRelax - Backend can orevride this function to add its relaxation
+ /// implementation. Return true if the output (e.g., .text) is "relaxed"
+ /// (i.e. layout is changed), and set pFinished to true if everything is fit,
+ /// otherwise set it to false.
+ bool doRelax(Module& pModule, IRBuilder& pBuilder, bool& pFinished);
+
+ /// initTargetStubs
+ bool initTargetStubs();
+
+ /// readRelocation - read ELF32_Rel entry
+ bool readRelocation(const llvm::ELF::Elf32_Rel& pRel,
+ Relocation::Type& pType,
+ uint32_t& pSymIdx,
+ uint32_t& pOffset) const;
+
+ /// readRelocation - read ELF32_Rela entry
+ bool readRelocation(const llvm::ELF::Elf32_Rela& pRel,
+ Relocation::Type& pType,
+ uint32_t& pSymIdx,
+ uint32_t& pOffset,
+ int32_t& pAddend) const;
+
+ /// readRelocation - read ELF64_Rel entry
+ bool readRelocation(const llvm::ELF::Elf64_Rel& pRel,
+ Relocation::Type& pType,
+ uint32_t& pSymIdx,
+ uint64_t& pOffset) const;
+
+ /// readRel - read ELF64_Rela entry
+ bool readRelocation(const llvm::ELF::Elf64_Rela& pRel,
+ Relocation::Type& pType,
+ uint32_t& pSymIdx,
+ uint64_t& pOffset,
+ int64_t& pAddend) const;
+
+ /// emitRelocation - write data to the ELF32_Rel entry
+ void emitRelocation(llvm::ELF::Elf32_Rel& pRel,
+ Relocation::Type pType,
+ uint32_t pSymIdx,
+ uint32_t pOffset) const;
+
+ /// emitRelocation - write data to the ELF32_Rela entry
+ void emitRelocation(llvm::ELF::Elf32_Rela& pRel,
+ Relocation::Type pType,
+ uint32_t pSymIdx,
+ uint32_t pOffset,
+ int32_t pAddend) const;
+
+ /// emitRelocation - write data to the ELF64_Rel entry
+ void emitRelocation(llvm::ELF::Elf64_Rel& pRel,
+ Relocation::Type pType,
+ uint32_t pSymIdx,
+ uint64_t pOffset) const;
+
+ /// emitRelocation - write data to the ELF64_Rela entry
+ void emitRelocation(llvm::ELF::Elf64_Rela& pRel,
+ Relocation::Type pType,
+ uint32_t pSymIdx,
+ uint64_t pOffset,
+ int64_t pAddend) const;
+
+private:
+ typedef llvm::DenseSet<const ResolveInfo*> ResolveInfoSetType;
+ typedef llvm::DenseMap<const Input*, llvm::ELF::Elf64_Addr> GP0MapType;
+
+protected:
+ Relocator* m_pRelocator;
MipsGOT* m_pGOT; // .got
+ MipsPLT* m_pPLT; // .plt
+ MipsGOTPLT* m_pGOTPLT; // .got.plt
+
+private:
+ MipsGNUInfo& m_pInfo;
+
+ OutputRelocSection* m_pRelPlt; // .rel.plt
OutputRelocSection* m_pRelDyn; // .rel.dyn
MipsELFDynamic* m_pDynamic;
LDSymbol* m_pGOTSymbol;
+ LDSymbol* m_pPLTSymbol;
LDSymbol* m_pGpDispSymbol;
SymbolListType m_GlobalGOTSyms;
+ ResolveInfoSetType m_HasNonPICBranchSyms;
+ GP0MapType m_GP0Map;
+};
+
+/** \class Mips32GNULDBackend
+ * \brief Base linker backend of Mips 32-bit target of GNU ELF format.
+ */
+class Mips32GNULDBackend : public MipsGNULDBackend
+{
+public:
+ Mips32GNULDBackend(const LinkerConfig& pConfig, MipsGNUInfo* pInfo);
+
+private:
+ // MipsGNULDBackend
+
+ bool initRelocator();
+ void initTargetSections(Module& pModule, ObjectBuilder& pBuilder);
+ size_t getRelEntrySize();
+ size_t getRelaEntrySize();
+};
+
+/** \class Mips64GNULDBackend
+ * \brief Base linker backend of Mips 64-bit target of GNU ELF format.
+ */
+class Mips64GNULDBackend : public MipsGNULDBackend
+{
+public:
+ Mips64GNULDBackend(const LinkerConfig& pConfig, MipsGNUInfo* pInfo);
+
+private:
+ // MipsGNULDBackend
+
+ bool initRelocator();
+ void initTargetSections(Module& pModule, ObjectBuilder& pBuilder);
+ size_t getRelEntrySize();
+ size_t getRelaEntrySize();
};
} // namespace of mcld
#endif
-
diff --git a/lib/Target/Mips/MipsMCLinker.cpp b/lib/Target/Mips/MipsMCLinker.cpp
index 5805f12..49940b7 100644
--- a/lib/Target/Mips/MipsMCLinker.cpp
+++ b/lib/Target/Mips/MipsMCLinker.cpp
@@ -6,25 +6,21 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "MipsELFMCLinker.h"
-
#include "Mips.h"
+#include "MipsELFMCLinker.h"
#include <llvm/ADT/Triple.h>
#include <mcld/Module.h>
#include <mcld/Support/TargetRegistry.h>
-using namespace mcld;
+namespace {
-namespace mcld {
//===----------------------------------------------------------------------===//
-/// createMipsMCLinker - the help funtion to create
+/// createMipsMCLinker - the help funtion to create corresponding MipsMCLinker
//===----------------------------------------------------------------------===//
-/// corresponding MipsMCLinker
-///
-MCLinker* createMipsMCLinker(const std::string &pTriple,
- LinkerConfig& pConfig,
- mcld::Module& pModule,
- MemoryArea& pOutput)
+mcld::MCLinker* createMipsMCLinker(const std::string &pTriple,
+ mcld::LinkerConfig& pConfig,
+ mcld::Module& pModule,
+ mcld::FileHandle& pFileHandle)
{
llvm::Triple theTriple(pTriple);
if (theTriple.isOSDarwin()) {
@@ -36,7 +32,7 @@
return NULL;
}
- return new MipsELFMCLinker(pConfig, pModule, pOutput);
+ return new mcld::MipsELFMCLinker(pConfig, pModule, pFileHandle);
}
} // namespace of mcld
@@ -45,6 +41,8 @@
// MipsMCLinker
//===----------------------------------------------------------------------===//
extern "C" void MCLDInitializeMipsMCLinker() {
- // Register the linker frontend
- mcld::TargetRegistry::RegisterMCLinker(TheMipselTarget, createMipsMCLinker);
+ mcld::TargetRegistry::RegisterMCLinker(mcld::TheMipselTarget,
+ createMipsMCLinker);
+ mcld::TargetRegistry::RegisterMCLinker(mcld::TheMips64elTarget,
+ createMipsMCLinker);
}
diff --git a/lib/Target/Mips/MipsPLT.cpp b/lib/Target/Mips/MipsPLT.cpp
new file mode 100644
index 0000000..a00b7c8
--- /dev/null
+++ b/lib/Target/Mips/MipsPLT.cpp
@@ -0,0 +1,169 @@
+//===- MipsPLT.cpp --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/Support/Casting.h>
+#include <llvm/Support/ELF.h>
+#include <mcld/Support/MsgHandling.h>
+#include "MipsGOTPLT.h"
+#include "MipsPLT.h"
+
+namespace {
+
+const uint32_t PLT0[] = {
+ 0x3c1c0000, // lui $28, %hi(&GOTPLT[0])
+ 0x8f990000, // lw $25, %lo(&GOTPLT[0])($28)
+ 0x279c0000, // addiu $28, $28, %lo(&GOTPLT[0])
+ 0x031cc023, // subu $24, $24, $28
+ 0x03e07821, // move $15, $31
+ 0x0018c082, // srl $24, $24, 2
+ 0x0320f809, // jalr $25
+ 0x2718fffe // subu $24, $24, 2
+};
+
+const uint32_t PLTA[] = {
+ 0x3c0f0000, // lui $15, %hi(.got.plt entry)
+ 0x8df90000, // l[wd] $25, %lo(.got.plt entry)($15)
+ 0x03200008, // jr $25
+ 0x25f80000 // addiu $24, $15, %lo(.got.plt entry)
+};
+
+}
+
+namespace mcld {
+
+//===----------------------------------------------------------------------===//
+// MipsPLT0 Entry
+//===----------------------------------------------------------------------===//
+class MipsPLT0 : public PLT::Entry<sizeof(PLT0)>
+{
+public:
+ MipsPLT0(SectionData& pParent)
+ : PLT::Entry<sizeof(PLT0)>(pParent)
+ {}
+};
+
+//===----------------------------------------------------------------------===//
+// MipsPLTA Entry
+//===----------------------------------------------------------------------===//
+class MipsPLTA : public PLT::Entry<sizeof(PLTA)>
+{
+public:
+ MipsPLTA(SectionData& pParent)
+ : PLT::Entry<sizeof(PLTA)>(pParent)
+ {}
+};
+
+//===----------------------------------------------------------------------===//
+// MipsPLT
+//===----------------------------------------------------------------------===//
+MipsPLT::MipsPLT(LDSection& pSection)
+ : PLT(pSection)
+{
+ new MipsPLT0(*m_SectionData);
+ m_Last = m_SectionData->begin();
+}
+
+void MipsPLT::finalizeSectionSize()
+{
+ uint64_t size = sizeof(PLT0) +
+ (m_SectionData->size() - 1) * sizeof(PLTA);
+ m_Section.setSize(size);
+
+ uint32_t offset = 0;
+ SectionData::iterator frag, fragEnd = m_SectionData->end();
+ for (frag = m_SectionData->begin(); frag != fragEnd; ++frag) {
+ frag->setOffset(offset);
+ offset += frag->size();
+ }
+}
+
+bool MipsPLT::hasPLT1() const
+{
+ return m_SectionData->size() > 1;
+}
+
+uint64_t MipsPLT::emit(MemoryRegion& pRegion)
+{
+ uint64_t result = 0x0;
+ iterator it = begin();
+
+ unsigned char* buffer = pRegion.begin();
+ memcpy(buffer, llvm::cast<MipsPLT0>((*it)).getValue(), MipsPLT0::EntrySize);
+ result += MipsPLT0::EntrySize;
+ ++it;
+
+ MipsPLTA* plta = 0;
+ for (iterator ie = end(); it != ie; ++it) {
+ plta = &(llvm::cast<MipsPLTA>(*it));
+ memcpy(buffer + result, plta->getValue(), MipsPLTA::EntrySize);
+ result += MipsPLTA::EntrySize;
+ }
+ return result;
+}
+
+void MipsPLT::reserveEntry(size_t pNum)
+{
+ for (size_t i = 0; i < pNum; ++i) {
+ Fragment* entry = new (std::nothrow) MipsPLTA(*m_SectionData);
+
+ if (NULL == entry)
+ fatal(diag::fail_allocate_memory_plt);
+ }
+}
+
+Fragment* MipsPLT::consume()
+{
+ ++m_Last;
+ assert(m_Last != m_SectionData->end() &&
+ "The number of PLT Entries and ResolveInfo doesn't match");
+ return &(*m_Last);
+}
+
+void MipsPLT::applyAllPLT(MipsGOTPLT& pGOTPLT)
+{
+ assert(m_Section.addr() && ".plt base address is NULL!");
+
+ size_t count = 0;
+ for (iterator it = m_SectionData->begin(); it != m_SectionData->end(); ++it) {
+ PLTEntryBase* plt = &(llvm::cast<PLTEntryBase>(*it));
+
+ if (it == m_SectionData->begin()) {
+ uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
+
+ if (!data)
+ fatal(diag::fail_allocate_memory_plt);
+
+ memcpy(data, PLT0, plt->size());
+
+ uint64_t gotAddr = pGOTPLT.addr();
+
+ data[0] |= ((gotAddr + 0x8000) >> 16) & 0xffff;
+ data[1] |= gotAddr & 0xffff;
+ data[2] |= gotAddr & 0xffff;
+
+ plt->setValue(reinterpret_cast<unsigned char*>(data));
+ } else {
+ uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
+
+ if (!data)
+ fatal(diag::fail_allocate_memory_plt);
+
+ memcpy(data, PLTA, plt->size());
+
+ uint64_t gotEntryAddr = pGOTPLT.getEntryAddr(count++);
+
+ data[0] |= ((gotEntryAddr + 0x8000) >> 16) & 0xffff;
+ data[1] |= gotEntryAddr & 0xffff;
+ data[3] |= gotEntryAddr & 0xffff;
+
+ plt->setValue(reinterpret_cast<unsigned char*>(data));
+ }
+ }
+}
+
+} //end mcld namespace
diff --git a/lib/Target/Mips/MipsPLT.h b/lib/Target/Mips/MipsPLT.h
new file mode 100644
index 0000000..f2ad0c8
--- /dev/null
+++ b/lib/Target/Mips/MipsPLT.h
@@ -0,0 +1,51 @@
+//===- MipsPLT.h ----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TARGET_MIPS_PLT_H
+#define MCLD_TARGET_MIPS_PLT_H
+
+#include <mcld/Target/PLT.h>
+#include <mcld/Support/MemoryRegion.h>
+
+namespace mcld {
+
+class MipsGOTPLT;
+
+//===----------------------------------------------------------------------===//
+// MipsPLT
+//===----------------------------------------------------------------------===//
+/** \class MipsPLT
+ * \brief Mips Procedure Linkage Table
+ */
+class MipsPLT : public PLT
+{
+public:
+ MipsPLT(LDSection& pSection);
+
+ // hasPLT1 - return if this PLT has any PLTA/PLTB entries
+ bool hasPLT1() const;
+
+ uint64_t emit(MemoryRegion& pRegion);
+
+ Fragment* consume();
+
+ void applyAllPLT(MipsGOTPLT& pGOTPLT);
+
+public:
+ // PLT
+ void reserveEntry(size_t pNum = 1);
+ void finalizeSectionSize();
+
+private:
+ // the last consumed entry.
+ SectionData::iterator m_Last;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Mips/MipsRelocationFunctions.h b/lib/Target/Mips/MipsRelocationFunctions.h
index f1461a0..3634686 100644
--- a/lib/Target/Mips/MipsRelocationFunctions.h
+++ b/lib/Target/Mips/MipsRelocationFunctions.h
@@ -8,70 +8,285 @@
//===----------------------------------------------------------------------===//
#define DECL_MIPS_APPLY_RELOC_FUNC(Name) \
-static MipsRelocator::Result Name(Relocation& pEntry, \
+static MipsRelocator::Result Name(MipsRelocationInfo& pReloc, \
MipsRelocator& pParent);
#define DECL_MIPS_APPLY_RELOC_FUNCS \
DECL_MIPS_APPLY_RELOC_FUNC(none) \
DECL_MIPS_APPLY_RELOC_FUNC(abs32) \
+DECL_MIPS_APPLY_RELOC_FUNC(rel26) \
DECL_MIPS_APPLY_RELOC_FUNC(hi16) \
DECL_MIPS_APPLY_RELOC_FUNC(lo16) \
+DECL_MIPS_APPLY_RELOC_FUNC(gprel16) \
DECL_MIPS_APPLY_RELOC_FUNC(got16) \
DECL_MIPS_APPLY_RELOC_FUNC(call16) \
DECL_MIPS_APPLY_RELOC_FUNC(gprel32) \
+DECL_MIPS_APPLY_RELOC_FUNC(abs64) \
+DECL_MIPS_APPLY_RELOC_FUNC(gotdisp) \
+DECL_MIPS_APPLY_RELOC_FUNC(gotoff) \
DECL_MIPS_APPLY_RELOC_FUNC(gothi16) \
-DECL_MIPS_APPLY_RELOC_FUNC(gotlo16)
+DECL_MIPS_APPLY_RELOC_FUNC(gotlo16) \
+DECL_MIPS_APPLY_RELOC_FUNC(sub) \
+DECL_MIPS_APPLY_RELOC_FUNC(jalr) \
+DECL_MIPS_APPLY_RELOC_FUNC(la25lui) \
+DECL_MIPS_APPLY_RELOC_FUNC(la25j) \
+DECL_MIPS_APPLY_RELOC_FUNC(la25add) \
+DECL_MIPS_APPLY_RELOC_FUNC(pc32) \
+DECL_MIPS_APPLY_RELOC_FUNC(unsupport)
#define DECL_MIPS_APPLY_RELOC_FUNC_PTRS \
- { &none, 0, "R_MIPS_NONE", 0}, \
- { &none, 1, "R_MIPS_16", 16}, \
- { &abs32, 2, "R_MIPS_32", 32}, \
- { &none, 3, "R_MIPS_REL32", 32}, \
- { &none, 4, "R_MIPS_26", 64}, \
- { &hi16, 5, "R_MIPS_HI16", 16}, \
- { &lo16, 6, "R_MIPS_LO16", 16}, \
- { &none, 7, "R_MIPS_GPREL16", 16}, \
- { &none, 8, "R_MIPS_LITERAL", 16}, \
- { &got16, 9, "R_MIPS_GOT16", 16}, \
- { &none, 10, "R_MIPS_PC16", 16}, \
- { &call16, 11, "R_MIPS_CALL16", 16}, \
- { &gprel32, 12, "R_MIPS_GPREL32", 32}, \
- { &none, 13, "R_MIPS_UNUSED1", 0}, \
- { &none, 14, "R_MIPS_UNUSED2", 0}, \
- { &none, 15, "R_MIPS_UNUSED3", 0}, \
- { &none, 16, "R_MIPS_SHIFT5", 32}, \
- { &none, 17, "R_MIPS_SHIFT6", 32}, \
- { &none, 18, "R_MIPS_64", 64}, \
- { &none, 19, "R_MIPS_GOT_DISP", 16}, \
- { &none, 20, "R_MIPS_GOT_PAGE", 16}, \
- { &none, 21, "R_MIPS_GOT_OFST", 16}, \
- { &gothi16, 22, "R_MIPS_GOT_HI16", 16}, \
- { &gotlo16, 23, "R_MIPS_GOT_LO16", 16}, \
- { &none, 24, "R_MIPS_SUB", 64}, \
- { &none, 25, "R_MIPS_INSERT_A", 0}, \
- { &none, 26, "R_MIPS_INSERT_B", 0}, \
- { &none, 27, "R_MIPS_DELETE", 0}, \
- { &none, 28, "R_MIPS_HIGHER", 16}, \
- { &none, 29, "R_MIPS_HIGHEST", 16}, \
- { &gothi16, 30, "R_MIPS_CALL_HI16", 16}, \
- { &gotlo16, 31, "R_MIPS_CALL_LO16", 16}, \
- { &none, 32, "R_MIPS_SCN_DISP", 32}, \
- { &none, 33, "R_MIPS_REL16", 0}, \
- { &none, 34, "R_MIPS_ADD_IMMEDIATE", 0}, \
- { &none, 35, "R_MIPS_PJUMP", 0}, \
- { &none, 36, "R_MIPS_RELGOT", 0}, \
- { &none, 37, "R_MIPS_JALR", 32}, \
- { &none, 38, "R_MIPS_TLS_DTPMOD32", 32}, \
- { &none, 39, "R_MIPS_TLS_DTPREL32", 32}, \
- { &none, 40, "R_MIPS_TLS_DTPMOD64", 0}, \
- { &none, 41, "R_MIPS_TLS_DTPREL64", 0}, \
- { &none, 42, "R_MIPS_TLS_GD", 16}, \
- { &none, 43, "R_MIPS_TLS_LDM", 16}, \
- { &none, 44, "R_MIPS_TLS_DTPREL_HI16", 16}, \
- { &none, 45, "R_MIPS_TLS_DTPREL_LO16", 16}, \
- { &none, 46, "R_MIPS_TLS_GOTTPREL", 16}, \
- { &none, 47, "R_MIPS_TLS_TPREL32", 32}, \
- { &none, 48, "R_MIPS_TLS_TPREL64", 0}, \
- { &none, 49, "R_MIPS_TLS_TPREL_HI16", 16}, \
- { &none, 50, "R_MIPS_TLS_TPREL_LO16", 16}, \
- { &none, 51, "R_MIPS_GLOB_DAT", 0}
+ { &none, 0, "R_MIPS_NONE", 0}, \
+ { &unsupport, 1, "R_MIPS_16", 16}, \
+ { &abs32, 2, "R_MIPS_32", 32}, \
+ { &unsupport, 3, "R_MIPS_REL32", 32}, \
+ { &rel26, 4, "R_MIPS_26", 26}, \
+ { &hi16, 5, "R_MIPS_HI16", 16}, \
+ { &lo16, 6, "R_MIPS_LO16", 16}, \
+ { &gprel16, 7, "R_MIPS_GPREL16", 16}, \
+ { &unsupport, 8, "R_MIPS_LITERAL", 16}, \
+ { &got16, 9, "R_MIPS_GOT16", 16}, \
+ { &unsupport, 10, "R_MIPS_PC16", 16}, \
+ { &call16, 11, "R_MIPS_CALL16", 16}, \
+ { &gprel32, 12, "R_MIPS_GPREL32", 32}, \
+ { &none, 13, "R_MIPS_UNUSED1", 0}, \
+ { &none, 14, "R_MIPS_UNUSED2", 0}, \
+ { &none, 15, "R_MIPS_UNUSED3", 0}, \
+ { &unsupport, 16, "R_MIPS_SHIFT5", 32}, \
+ { &unsupport, 17, "R_MIPS_SHIFT6", 32}, \
+ { &abs64, 18, "R_MIPS_64", 64}, \
+ { &gotdisp, 19, "R_MIPS_GOT_DISP", 16}, \
+ { &gotdisp, 20, "R_MIPS_GOT_PAGE", 16}, \
+ { &gotoff, 21, "R_MIPS_GOT_OFST", 16}, \
+ { &gothi16, 22, "R_MIPS_GOT_HI16", 16}, \
+ { &gotlo16, 23, "R_MIPS_GOT_LO16", 16}, \
+ { &sub, 24, "R_MIPS_SUB", 64}, \
+ { &unsupport, 25, "R_MIPS_INSERT_A", 0}, \
+ { &unsupport, 26, "R_MIPS_INSERT_B", 0}, \
+ { &unsupport, 27, "R_MIPS_DELETE", 0}, \
+ { &unsupport, 28, "R_MIPS_HIGHER", 16}, \
+ { &unsupport, 29, "R_MIPS_HIGHEST", 16}, \
+ { &gothi16, 30, "R_MIPS_CALL_HI16", 16}, \
+ { &gotlo16, 31, "R_MIPS_CALL_LO16", 16}, \
+ { &unsupport, 32, "R_MIPS_SCN_DISP", 32}, \
+ { &unsupport, 33, "R_MIPS_REL16", 0}, \
+ { &unsupport, 34, "R_MIPS_ADD_IMMEDIATE", 0}, \
+ { &unsupport, 35, "R_MIPS_PJUMP", 0}, \
+ { &unsupport, 36, "R_MIPS_RELGOT", 0}, \
+ { &jalr, 37, "R_MIPS_JALR", 32}, \
+ { &unsupport, 38, "R_MIPS_TLS_DTPMOD32", 32}, \
+ { &unsupport, 39, "R_MIPS_TLS_DTPREL32", 32}, \
+ { &unsupport, 40, "R_MIPS_TLS_DTPMOD64", 0}, \
+ { &unsupport, 41, "R_MIPS_TLS_DTPREL64", 0}, \
+ { &unsupport, 42, "R_MIPS_TLS_GD", 16}, \
+ { &unsupport, 43, "R_MIPS_TLS_LDM", 16}, \
+ { &unsupport, 44, "R_MIPS_TLS_DTPREL_HI16", 16}, \
+ { &unsupport, 45, "R_MIPS_TLS_DTPREL_LO16", 16}, \
+ { &unsupport, 46, "R_MIPS_TLS_GOTTPREL", 16}, \
+ { &unsupport, 47, "R_MIPS_TLS_TPREL32", 32}, \
+ { &unsupport, 48, "R_MIPS_TLS_TPREL64", 0}, \
+ { &unsupport, 49, "R_MIPS_TLS_TPREL_HI16", 16}, \
+ { &unsupport, 50, "R_MIPS_TLS_TPREL_LO16", 16}, \
+ { &unsupport, 51, "R_MIPS_GLOB_DAT", 0}, \
+ { &unsupport, 52, "", 0}, \
+ { &unsupport, 53, "", 0}, \
+ { &unsupport, 54, "", 0}, \
+ { &unsupport, 55, "", 0}, \
+ { &unsupport, 56, "", 0}, \
+ { &unsupport, 57, "", 0}, \
+ { &unsupport, 58, "", 0}, \
+ { &unsupport, 59, "", 0}, \
+ { &unsupport, 60, "", 0}, \
+ { &unsupport, 61, "", 0}, \
+ { &unsupport, 62, "", 0}, \
+ { &unsupport, 63, "", 0}, \
+ { &unsupport, 64, "", 0}, \
+ { &unsupport, 65, "", 0}, \
+ { &unsupport, 66, "", 0}, \
+ { &unsupport, 67, "", 0}, \
+ { &unsupport, 68, "", 0}, \
+ { &unsupport, 69, "", 0}, \
+ { &unsupport, 70, "", 0}, \
+ { &unsupport, 71, "", 0}, \
+ { &unsupport, 72, "", 0}, \
+ { &unsupport, 73, "", 0}, \
+ { &unsupport, 74, "", 0}, \
+ { &unsupport, 75, "", 0}, \
+ { &unsupport, 76, "", 0}, \
+ { &unsupport, 77, "", 0}, \
+ { &unsupport, 78, "", 0}, \
+ { &unsupport, 79, "", 0}, \
+ { &unsupport, 80, "", 0}, \
+ { &unsupport, 81, "", 0}, \
+ { &unsupport, 82, "", 0}, \
+ { &unsupport, 83, "", 0}, \
+ { &unsupport, 84, "", 0}, \
+ { &unsupport, 85, "", 0}, \
+ { &unsupport, 86, "", 0}, \
+ { &unsupport, 87, "", 0}, \
+ { &unsupport, 88, "", 0}, \
+ { &unsupport, 89, "", 0}, \
+ { &unsupport, 90, "", 0}, \
+ { &unsupport, 91, "", 0}, \
+ { &unsupport, 92, "", 0}, \
+ { &unsupport, 93, "", 0}, \
+ { &unsupport, 94, "", 0}, \
+ { &unsupport, 95, "", 0}, \
+ { &unsupport, 96, "", 0}, \
+ { &unsupport, 97, "", 0}, \
+ { &unsupport, 98, "", 0}, \
+ { &unsupport, 99, "", 0}, \
+ { &unsupport, 100, "R_MIPS16_26", 0}, \
+ { &unsupport, 101, "R_MIPS16_GPREL", 0}, \
+ { &unsupport, 102, "R_MIPS16_GOT16", 0}, \
+ { &unsupport, 103, "R_MIPS16_CALL16", 0}, \
+ { &unsupport, 104, "R_MIPS16_HI16", 0}, \
+ { &unsupport, 105, "R_MIPS16_LO16", 0}, \
+ { &unsupport, 106, "R_MIPS16_TLS_GD", 0}, \
+ { &unsupport, 107, "R_MIPS16_TLS_LDM", 0}, \
+ { &unsupport, 108, "R_MIPS16_TLS_DTPREL_HI16", 0}, \
+ { &unsupport, 109, "R_MIPS16_TLS_DTPREL_LO16", 0}, \
+ { &unsupport, 110, "R_MIPS16_TLS_GOTTPREL", 0}, \
+ { &unsupport, 111, "R_MIPS16_TLS_TPREL_HI16", 0}, \
+ { &unsupport, 112, "R_MIPS16_TLS_TPREL_LO16", 0}, \
+ { &unsupport, 113, "", 0}, \
+ { &unsupport, 114, "", 0}, \
+ { &unsupport, 115, "", 0}, \
+ { &unsupport, 116, "", 0}, \
+ { &unsupport, 117, "", 0}, \
+ { &unsupport, 118, "", 0}, \
+ { &unsupport, 119, "", 0}, \
+ { &unsupport, 120, "", 0}, \
+ { &unsupport, 121, "", 0}, \
+ { &unsupport, 122, "", 0}, \
+ { &unsupport, 123, "", 0}, \
+ { &unsupport, 124, "", 0}, \
+ { &unsupport, 125, "", 0}, \
+ { &unsupport, 126, "R_MIPS_COPY", 0}, \
+ { &unsupport, 127, "R_MIPS_JUMP_SLOT", 0}, \
+ { &unsupport, 128, "", 0}, \
+ { &unsupport, 129, "", 0}, \
+ { &unsupport, 130, "", 0}, \
+ { &unsupport, 131, "", 0}, \
+ { &unsupport, 132, "", 0}, \
+ { &unsupport, 133, "R_MICROMIPS_26_S1", 0}, \
+ { &unsupport, 134, "R_MICROMIPS_HI16", 0}, \
+ { &unsupport, 135, "R_MICROMIPS_LO16", 0}, \
+ { &unsupport, 136, "R_MICROMIPS_GPREL16", 0}, \
+ { &unsupport, 137, "R_MICROMIPS_LITERAL", 0}, \
+ { &unsupport, 138, "R_MICROMIPS_GOT16", 0}, \
+ { &unsupport, 139, "R_MICROMIPS_PC7_S1", 0}, \
+ { &unsupport, 140, "R_MICROMIPS_PC10_S1", 0}, \
+ { &unsupport, 141, "R_MICROMIPS_PC16_S1", 0}, \
+ { &unsupport, 142, "R_MICROMIPS_CALL16", 0}, \
+ { &unsupport, 143, "R_MICROMIPS_GOT_DISP", 0}, \
+ { &unsupport, 144, "R_MICROMIPS_GOT_PAGE", 0}, \
+ { &unsupport, 145, "R_MICROMIPS_GOT_OFST", 0}, \
+ { &unsupport, 146, "R_MICROMIPS_GOT_HI16", 0}, \
+ { &unsupport, 147, "R_MICROMIPS_GOT_LO16", 0}, \
+ { &unsupport, 148, "R_MICROMIPS_SUB", 0}, \
+ { &unsupport, 149, "R_MICROMIPS_HIGHER", 0}, \
+ { &unsupport, 150, "R_MICROMIPS_HIGHEST", 0}, \
+ { &unsupport, 151, "R_MICROMIPS_CALL_HI16", 0}, \
+ { &unsupport, 152, "R_MICROMIPS_CALL_LO16", 0}, \
+ { &unsupport, 153, "R_MICROMIPS_SCN_DISP", 0}, \
+ { &unsupport, 154, "R_MICROMIPS_JALR", 0}, \
+ { &unsupport, 155, "R_MICROMIPS_HI0_LO16", 0}, \
+ { &unsupport, 156, "", 0}, \
+ { &unsupport, 157, "", 0}, \
+ { &unsupport, 158, "", 0}, \
+ { &unsupport, 159, "", 0}, \
+ { &unsupport, 160, "", 0}, \
+ { &unsupport, 161, "", 0}, \
+ { &unsupport, 162, "R_MICROMIPS_TLS_GD", 0}, \
+ { &unsupport, 163, "R_MICROMIPS_TLS_LDM", 0}, \
+ { &unsupport, 164, "R_MICROMIPS_TLS_DTPREL_HI16", 0}, \
+ { &unsupport, 165, "R_MICROMIPS_TLS_DTPREL_LO16", 0}, \
+ { &unsupport, 166, "R_MICROMIPS_TLS_GOTTPREL", 0}, \
+ { &unsupport, 167, "", 0}, \
+ { &unsupport, 168, "", 0}, \
+ { &unsupport, 169, "R_MICROMIPS_TLS_TPREL_HI16", 0}, \
+ { &unsupport, 170, "R_MICROMIPS_TLS_TPREL_LO16", 0}, \
+ { &unsupport, 171, "", 0}, \
+ { &unsupport, 172, "R_MICROMIPS_GPREL7_S2", 0}, \
+ { &unsupport, 173, "R_MICROMIPS_PC23_S2", 0}, \
+ { &unsupport, 174, "", 0}, \
+ { &unsupport, 175, "", 0}, \
+ { &unsupport, 176, "", 0}, \
+ { &unsupport, 177, "", 0}, \
+ { &unsupport, 178, "", 0}, \
+ { &unsupport, 179, "", 0}, \
+ { &unsupport, 180, "", 0}, \
+ { &unsupport, 181, "", 0}, \
+ { &unsupport, 182, "", 0}, \
+ { &unsupport, 183, "", 0}, \
+ { &unsupport, 184, "", 0}, \
+ { &unsupport, 185, "", 0}, \
+ { &unsupport, 186, "", 0}, \
+ { &unsupport, 187, "", 0}, \
+ { &unsupport, 188, "", 0}, \
+ { &unsupport, 189, "", 0}, \
+ { &unsupport, 190, "", 0}, \
+ { &unsupport, 191, "", 0}, \
+ { &unsupport, 192, "", 0}, \
+ { &unsupport, 193, "", 0}, \
+ { &unsupport, 194, "", 0}, \
+ { &unsupport, 195, "", 0}, \
+ { &unsupport, 196, "", 0}, \
+ { &unsupport, 197, "", 0}, \
+ { &unsupport, 198, "", 0}, \
+ { &unsupport, 199, "", 0}, \
+ { &la25lui, 200, "R_MIPS_LA25_LUI", 16}, \
+ { &la25j, 201, "R_MIPS_LA25_J", 26}, \
+ { &la25add, 202, "R_MIPS_LA25_ADD", 16}, \
+ { &unsupport, 203, "", 0}, \
+ { &unsupport, 204, "", 0}, \
+ { &unsupport, 205, "", 0}, \
+ { &unsupport, 206, "", 0}, \
+ { &unsupport, 207, "", 0}, \
+ { &unsupport, 208, "", 0}, \
+ { &unsupport, 209, "", 0}, \
+ { &unsupport, 210, "", 0}, \
+ { &unsupport, 211, "", 0}, \
+ { &unsupport, 212, "", 0}, \
+ { &unsupport, 213, "", 0}, \
+ { &unsupport, 214, "", 0}, \
+ { &unsupport, 215, "", 0}, \
+ { &unsupport, 216, "", 0}, \
+ { &unsupport, 217, "", 0}, \
+ { &unsupport, 218, "", 0}, \
+ { &unsupport, 219, "", 0}, \
+ { &unsupport, 220, "", 0}, \
+ { &unsupport, 221, "", 0}, \
+ { &unsupport, 222, "", 0}, \
+ { &unsupport, 223, "", 0}, \
+ { &unsupport, 224, "", 0}, \
+ { &unsupport, 225, "", 0}, \
+ { &unsupport, 226, "", 0}, \
+ { &unsupport, 227, "", 0}, \
+ { &unsupport, 228, "", 0}, \
+ { &unsupport, 229, "", 0}, \
+ { &unsupport, 230, "", 0}, \
+ { &unsupport, 231, "", 0}, \
+ { &unsupport, 232, "", 0}, \
+ { &unsupport, 233, "", 0}, \
+ { &unsupport, 234, "", 0}, \
+ { &unsupport, 235, "", 0}, \
+ { &unsupport, 236, "", 0}, \
+ { &unsupport, 237, "", 0}, \
+ { &unsupport, 238, "", 0}, \
+ { &unsupport, 239, "", 0}, \
+ { &unsupport, 240, "", 0}, \
+ { &unsupport, 241, "", 0}, \
+ { &unsupport, 242, "", 0}, \
+ { &unsupport, 243, "", 0}, \
+ { &unsupport, 244, "", 0}, \
+ { &unsupport, 245, "", 0}, \
+ { &unsupport, 246, "", 0}, \
+ { &unsupport, 247, "", 0}, \
+ { &pc32, 248, "R_MIPS_PC32", 0}, \
+ { &unsupport, 249, "", 0}, \
+ { &unsupport, 250, "R_MIPS_GNU_REL16_S2", 0}, \
+ { &unsupport, 251, "", 0}, \
+ { &unsupport, 252, "", 0}, \
+ { &unsupport, 253, "R_MIPS_GNU_VTINHERIT", 0}, \
+ { &unsupport, 254, "R_MIPS_GNU_VTENTRY", 0}
diff --git a/lib/Target/Mips/MipsRelocator.cpp b/lib/Target/Mips/MipsRelocator.cpp
index 8f08862..314a6ad 100644
--- a/lib/Target/Mips/MipsRelocator.cpp
+++ b/lib/Target/Mips/MipsRelocator.cpp
@@ -6,26 +6,155 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-
-#include <llvm/ADT/Twine.h>
-#include <llvm/Support/ELF.h>
-#include <mcld/Support/MsgHandling.h>
-#include <mcld/Target/OutputRelocSection.h>
-#include <mcld/LinkerConfig.h>
-#include <mcld/IRBuilder.h>
-
#include "MipsRelocator.h"
#include "MipsRelocationFunctions.h"
+#include <mcld/IRBuilder.h>
+#include <mcld/LinkerConfig.h>
+#include <mcld/Object/ObjectBuilder.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Target/OutputRelocSection.h>
+#include <mcld/LD/ELFFileFormat.h>
+
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ELF.h>
+
+namespace llvm {
+namespace ELF {
+
+// FIXME: Consider upstream these relocation types to LLVM.
+enum {
+ R_MIPS_LA25_LUI = 200,
+ R_MIPS_LA25_J = 201,
+ R_MIPS_LA25_ADD = 202,
+ R_MIPS_PC32 = 248,
+};
+
+} // end namespace ELF
+} // end namespace llvm
+
using namespace mcld;
//===----------------------------------------------------------------------===//
+// MipsRelocationInfo
+//===----------------------------------------------------------------------===//
+class mcld::MipsRelocationInfo
+{
+public:
+ static bool HasSubType(const Relocation& pParent, Relocation::Type pType)
+ {
+ if (llvm::ELF::R_MIPS_NONE == pType)
+ return true;
+
+ for (Relocation::Type type = pParent.type();
+ llvm::ELF::R_MIPS_NONE != (type & 0xff); type >>= 8) {
+ if ((type & 0xff) == pType)
+ return true;
+ }
+
+ return false;
+ }
+
+ MipsRelocationInfo(Relocation& pParent, bool pIsRel)
+ : m_Parent(&pParent),
+ m_Type(pParent.type()),
+ m_Addend(0),
+ m_Symbol(pParent.symValue()),
+ m_Result(pParent.target())
+ {
+ if (pIsRel && (type() < llvm::ELF::R_MIPS_LA25_LUI ||
+ type() > llvm::ELF::R_MIPS_LA25_ADD))
+ m_Addend = pParent.target();
+ else
+ m_Addend = pParent.addend();
+ }
+
+ bool isNone() const
+ {
+ return llvm::ELF::R_MIPS_NONE == type();
+ }
+
+ bool isLast() const
+ {
+ return llvm::ELF::R_MIPS_NONE == (m_Type >> 8);
+ }
+
+ MipsRelocationInfo next() const
+ {
+ return MipsRelocationInfo(*m_Parent, m_Type >> 8, result(), result(), 0);
+ }
+
+ const Relocation& parent() const
+ {
+ return *m_Parent;
+ }
+
+ Relocation& parent()
+ {
+ return *m_Parent;
+ }
+
+ Relocation::Type type() const
+ {
+ return m_Type & 0xff;
+ }
+
+ Relocation::DWord A() const
+ {
+ return m_Addend;
+ }
+
+ Relocation::DWord S() const
+ {
+ return m_Symbol;
+ }
+
+ Relocation::DWord P() const
+ {
+ return parent().place();
+ }
+
+ Relocation::DWord result() const
+ {
+ return m_Result;
+ }
+
+ Relocation::DWord& result()
+ {
+ return m_Result;
+ }
+
+private:
+ Relocation* m_Parent;
+ Relocation::Type m_Type;
+ Relocation::DWord m_Addend;
+ Relocation::DWord m_Symbol;
+ Relocation::DWord m_Result;
+
+ MipsRelocationInfo(Relocation& pParent, Relocation::Type pType,
+ Relocation::DWord pResult,
+ Relocation::DWord pAddend, Relocation::DWord pSymbol)
+ : m_Parent(&pParent),
+ m_Type(pType),
+ m_Addend(pAddend),
+ m_Symbol(pSymbol),
+ m_Result(pResult)
+ {}
+
+ bool isFirst() const {
+ return m_Type == parent().type();
+ }
+};
+
+//===----------------------------------------------------------------------===//
// Relocation Functions and Tables
//===----------------------------------------------------------------------===//
DECL_MIPS_APPLY_RELOC_FUNCS
/// the prototype of applying function
-typedef Relocator::Result (*ApplyFunctionType)(Relocation&, MipsRelocator&);
+typedef Relocator::Result (*ApplyFunctionType)(MipsRelocationInfo&,
+ MipsRelocator& pParent);
+
// the table entry of applying functions
struct ApplyFunctionTriple
@@ -49,78 +178,102 @@
: Relocator(pConfig),
m_Target(pParent),
m_pApplyingInput(NULL),
- m_AHL(0)
+ m_CurrentLo16Reloc(NULL)
{
}
Relocator::Result
-MipsRelocator::applyRelocation(Relocation& pRelocation)
+MipsRelocator::applyRelocation(Relocation& pReloc)
{
- Relocation::Type type = pRelocation.type();
-
- if (type >= sizeof(ApplyFunctions) / sizeof(ApplyFunctions[0])) {
- return Unknown;
+ // If m_CurrentLo16Reloc is not NULL we are processing
+ // postponed relocation. Otherwise check relocation type
+ // and postpone it for later handling.
+ if (NULL == m_CurrentLo16Reloc && isPostponed(pReloc)) {
+ postponeRelocation(pReloc);
+ return OK;
}
- // apply the relocation
- return ApplyFunctions[type].func(pRelocation, *this);
+ for (MipsRelocationInfo info(pReloc, isRel());
+ !info.isNone(); info = info.next()) {
+ if (info.type() >= sizeof(ApplyFunctions) / sizeof(ApplyFunctions[0]))
+ return Unknown;
+
+ const ApplyFunctionTriple & triple = ApplyFunctions[info.type()];
+
+ Result res = triple.func(info, *this);
+ if (OK != res)
+ return res;
+
+ if (info.isLast()) {
+ uint64_t mask = 0xFFFFFFFFFFFFFFFFULL >> (64 - triple.size);
+ pReloc.target() &= ~mask;
+ pReloc.target() |= info.result() & mask;
+ }
+ }
+
+ return OK;
}
const char* MipsRelocator::getName(Relocation::Type pType) const
{
- return ApplyFunctions[pType].name;
+ return ApplyFunctions[pType & 0xff].name;
}
Relocator::Size MipsRelocator::getSize(Relocation::Type pType) const
{
- return ApplyFunctions[pType].size;
+ return ApplyFunctions[pType & 0xff].size;
}
void MipsRelocator::scanRelocation(Relocation& pReloc,
IRBuilder& pBuilder,
Module& pModule,
- LDSection& pSection)
+ LDSection& pSection,
+ Input& pInput)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
// Skip relocation against _gp_disp
- if (NULL != getTarget().getGpDispSymbol()) {
- if (pReloc.symInfo() == getTarget().getGpDispSymbol()->resolveInfo())
- return;
- }
-
- pReloc.updateAddend();
+ if (NULL != getTarget().getGpDispSymbol() &&
+ rsym == getTarget().getGpDispSymbol()->resolveInfo())
+ return;
assert(NULL != pSection.getLink());
if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC))
return;
- // We test isLocal or if pInputSym is not a dynamic symbol
- // We assume -Bsymbolic to bind all symbols internaly via !rsym->isDyn()
- // Don't put undef symbols into local entries.
- if ((rsym->isLocal() || !getTarget().isDynamicSymbol(*rsym) ||
- !rsym->isDyn()) && !rsym->isUndef())
- scanLocalReloc(pReloc, pBuilder, pSection);
- else
- scanGlobalReloc(pReloc, pBuilder, pSection);
+ for (MipsRelocationInfo info(pReloc, isRel());
+ !info.isNone(); info = info.next()) {
+ // We test isLocal or if pInputSym is not a dynamic symbol
+ // We assume -Bsymbolic to bind all symbols internaly via !rsym->isDyn()
+ // Don't put undef symbols into local entries.
+ if (isLocalReloc(*rsym))
+ scanLocalReloc(info, pBuilder, pSection);
+ else
+ scanGlobalReloc(info, pBuilder, pSection);
- // check if we shoule issue undefined reference for the relocation target
- // symbol
+ if (getTarget().needsLA25Stub(info.type(), info.parent().symInfo()))
+ getTarget().addNonPICBranchSym(pReloc.symInfo());
+ }
+
+ // Check if we should issue undefined reference
+ // for the relocation target symbol.
if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
- fatal(diag::undefined_reference) << rsym->name();
+ issueUndefRef(pReloc, pSection, pInput);
}
bool MipsRelocator::initializeScan(Input& pInput)
{
- getTarget().getGOT().initializeScan(pInput);
+ if (LinkerConfig::Object != config().codeGenType())
+ getTarget().getGOT().initializeScan(pInput);
return true;
}
bool MipsRelocator::finalizeScan(Input& pInput)
{
- getTarget().getGOT().finalizeScan(pInput);
+ if (LinkerConfig::Object != config().codeGenType())
+ getTarget().getGOT().finalizeScan(pInput);
return true;
}
@@ -136,17 +289,18 @@
return true;
}
-void MipsRelocator::scanLocalReloc(Relocation& pReloc,
+void MipsRelocator::scanLocalReloc(MipsRelocationInfo& pReloc,
IRBuilder& pBuilder,
const LDSection& pSection)
{
- ResolveInfo* rsym = pReloc.symInfo();
+ ResolveInfo* rsym = pReloc.parent().symInfo();
switch (pReloc.type()){
case llvm::ELF::R_MIPS_NONE:
case llvm::ELF::R_MIPS_16:
break;
case llvm::ELF::R_MIPS_32:
+ case llvm::ELF::R_MIPS_64:
if (LinkerConfig::DynObj == config().codeGenType()) {
// TODO: (simon) The gold linker does not create an entry in .rel.dyn
// section if the symbol section flags contains SHF_EXECINSTR.
@@ -155,10 +309,6 @@
getTarget().getRelDyn().reserveEntry();
rsym->setReserved(rsym->reserved() | ReserveRel);
getTarget().checkAndSetHasTextRel(*pSection.getLink());
-
- // Remeber this rsym is a local GOT entry (as if it needs an entry).
- // Actually we don't allocate an GOT entry.
- getTarget().getGOT().setLocal(rsym);
}
break;
case llvm::ELF::R_MIPS_REL32:
@@ -168,9 +318,6 @@
case llvm::ELF::R_MIPS_PC16:
case llvm::ELF::R_MIPS_SHIFT5:
case llvm::ELF::R_MIPS_SHIFT6:
- case llvm::ELF::R_MIPS_64:
- case llvm::ELF::R_MIPS_GOT_PAGE:
- case llvm::ELF::R_MIPS_GOT_OFST:
case llvm::ELF::R_MIPS_SUB:
case llvm::ELF::R_MIPS_INSERT_A:
case llvm::ELF::R_MIPS_INSERT_B:
@@ -193,17 +340,18 @@
case llvm::ELF::R_MIPS_CALL_HI16:
case llvm::ELF::R_MIPS_GOT_LO16:
case llvm::ELF::R_MIPS_CALL_LO16:
- if (getTarget().getGOT().reserveLocalEntry(*rsym)) {
+ case llvm::ELF::R_MIPS_GOT_DISP:
+ case llvm::ELF::R_MIPS_GOT_PAGE:
+ case llvm::ELF::R_MIPS_GOT_OFST:
+ if (getTarget().getGOT().reserveLocalEntry(*rsym,
+ pReloc.type(), pReloc.A())) {
if (getTarget().getGOT().hasMultipleGOT())
getTarget().checkAndSetHasTextRel(*pSection.getLink());
- // Remeber this rsym is a local GOT entry
- getTarget().getGOT().setLocal(rsym);
}
break;
case llvm::ELF::R_MIPS_GPREL32:
case llvm::ELF::R_MIPS_GPREL16:
case llvm::ELF::R_MIPS_LITERAL:
- case llvm::ELF::R_MIPS_GOT_DISP:
break;
case llvm::ELF::R_MIPS_TLS_DTPMOD32:
case llvm::ELF::R_MIPS_TLS_DTPREL32:
@@ -219,17 +367,18 @@
case llvm::ELF::R_MIPS_TLS_TPREL_HI16:
case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
break;
+ case llvm::ELF::R_MIPS_PC32:
+ break;
default:
- fatal(diag::unknown_relocation) << (int)pReloc.type()
- << pReloc.symInfo()->name();
+ fatal(diag::unknown_relocation) << (int)pReloc.type() << rsym->name();
}
}
-void MipsRelocator::scanGlobalReloc(Relocation& pReloc,
+void MipsRelocator::scanGlobalReloc(MipsRelocationInfo& pReloc,
IRBuilder& pBuilder,
const LDSection& pSection)
{
- ResolveInfo* rsym = pReloc.symInfo();
+ ResolveInfo* rsym = pReloc.parent().symInfo();
switch (pReloc.type()){
case llvm::ELF::R_MIPS_NONE:
@@ -250,12 +399,15 @@
case llvm::ELF::R_MIPS_LO16:
if (getTarget().symbolNeedsDynRel(*rsym, false, true)) {
getTarget().getRelDyn().reserveEntry();
- rsym->setReserved(rsym->reserved() | ReserveRel);
- getTarget().checkAndSetHasTextRel(*pSection.getLink());
-
- // Remeber this rsym is a global GOT entry (as if it needs an entry).
- // Actually we don't allocate an GOT entry.
- getTarget().getGOT().setGlobal(rsym);
+ if (getTarget().symbolNeedsCopyReloc(pReloc.parent(), *rsym)) {
+ LDSymbol& cpySym = defineSymbolforCopyReloc(pBuilder, *rsym);
+ addCopyReloc(*cpySym.resolveInfo());
+ }
+ else {
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ getTarget().checkAndSetHasTextRel(*pSection.getLink());
+ }
}
break;
case llvm::ELF::R_MIPS_GOT16:
@@ -270,18 +422,25 @@
if (getTarget().getGOT().reserveGlobalEntry(*rsym)) {
if (getTarget().getGOT().hasMultipleGOT())
getTarget().checkAndSetHasTextRel(*pSection.getLink());
- // Remeber this rsym is a global GOT entry
- getTarget().getGOT().setGlobal(rsym);
}
break;
case llvm::ELF::R_MIPS_LITERAL:
case llvm::ELF::R_MIPS_GPREL32:
fatal(diag::invalid_global_relocation) << (int)pReloc.type()
- << pReloc.symInfo()->name();
+ << rsym->name();
break;
case llvm::ELF::R_MIPS_GPREL16:
break;
case llvm::ELF::R_MIPS_26:
+ // Create a PLT entry if the symbol requires it and does not have it.
+ if (getTarget().symbolNeedsPLT(*rsym) &&
+ !(rsym->reserved() & ReservePLT)) {
+ getTarget().getPLT().reserveEntry();
+ getTarget().getGOTPLT().reserve();
+ getTarget().getRelPLT().reserveEntry();
+ rsym->setReserved(rsym->reserved() | ReservePLT);
+ }
+ break;
case llvm::ELF::R_MIPS_PC16:
break;
case llvm::ELF::R_MIPS_16:
@@ -303,8 +462,8 @@
case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
break;
case llvm::ELF::R_MIPS_REL32:
- break;
case llvm::ELF::R_MIPS_JALR:
+ case llvm::ELF::R_MIPS_PC32:
break;
case llvm::ELF::R_MIPS_COPY:
case llvm::ELF::R_MIPS_GLOB_DAT:
@@ -312,156 +471,320 @@
fatal(diag::dynamic_relocation) << (int)pReloc.type();
break;
default:
- fatal(diag::unknown_relocation) << (int)pReloc.type()
- << pReloc.symInfo()->name();
+ fatal(diag::unknown_relocation) << (int)pReloc.type() << rsym->name();
}
}
-//===----------------------------------------------------------------------===//
-// Relocation helper function
-//===----------------------------------------------------------------------===//
-static const char * const GP_DISP_NAME = "_gp_disp";
-
-// Find next R_MIPS_LO16 relocation paired to pReloc.
-static
-Relocation* helper_FindLo16Reloc(Relocation& pReloc)
+bool MipsRelocator::isPostponed(const Relocation& pReloc) const
{
- Relocation* reloc = static_cast<Relocation*>(pReloc.getNextNode());
- while (NULL != reloc)
- {
- if (llvm::ELF::R_MIPS_LO16 == reloc->type() &&
- reloc->symInfo() == pReloc.symInfo())
- return reloc;
+ if (MipsRelocationInfo::HasSubType(pReloc, llvm::ELF::R_MIPS_HI16))
+ return true;
- reloc = static_cast<Relocation*>(reloc->getNextNode());
+ if (MipsRelocationInfo::HasSubType(pReloc, llvm::ELF::R_MIPS_GOT16) &&
+ pReloc.symInfo()->isLocal())
+ return true;
+
+ return false;
+}
+
+void MipsRelocator::addCopyReloc(ResolveInfo& pSym)
+{
+ Relocation& relEntry = *getTarget().getRelDyn().consumeEntry();
+ relEntry.setType(llvm::ELF::R_MIPS_COPY);
+ assert(pSym.outSymbol()->hasFragRef());
+ relEntry.targetRef().assign(*pSym.outSymbol()->fragRef());
+ relEntry.setSymInfo(&pSym);
+}
+
+LDSymbol& MipsRelocator::defineSymbolforCopyReloc(IRBuilder& pBuilder,
+ const ResolveInfo& pSym)
+{
+ // Get or create corresponding BSS LDSection
+ ELFFileFormat* fileFormat = getTarget().getOutputFormat();
+ LDSection* bssSectHdr =
+ ResolveInfo::ThreadLocal == pSym.type() ? &fileFormat->getTBSS()
+ : &fileFormat->getBSS();
+
+ // Get or create corresponding BSS SectionData
+ SectionData* bssData =
+ bssSectHdr->hasSectionData() ? bssSectHdr->getSectionData()
+ : IRBuilder::CreateSectionData(*bssSectHdr);
+
+ // Determine the alignment by the symbol value
+ // FIXME: here we use the largest alignment
+ uint32_t addrAlign = config().targets().bitclass() / 8;
+
+ // Allocate space in BSS for the copy symbol
+ Fragment* frag = new FillFragment(0x0, 1, pSym.size());
+ uint64_t size = ObjectBuilder::AppendFragment(*frag, *bssData, addrAlign);
+ bssSectHdr->setSize(bssSectHdr->size() + size);
+
+ // Change symbol binding to Global if it's a weak symbol
+ ResolveInfo::Binding binding = (ResolveInfo::Binding)pSym.binding();
+ if (binding == ResolveInfo::Weak)
+ binding = ResolveInfo::Global;
+
+ // Define the copy symbol in the bss section and resolve it
+ LDSymbol* cpySym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
+ pSym.name(),
+ (ResolveInfo::Type)pSym.type(),
+ ResolveInfo::Define,
+ binding,
+ pSym.size(), // size
+ 0x0, // value
+ FragmentRef::Create(*frag, 0x0),
+ (ResolveInfo::Visibility)pSym.other());
+
+ // Output all other alias symbols if any
+ Module::AliasList* alias_list = pBuilder.getModule().getAliasList(pSym);
+ if (NULL == alias_list)
+ return *cpySym;
+
+ for (Module::alias_iterator it = alias_list->begin(), ie = alias_list->end();
+ it != ie; ++it) {
+ const ResolveInfo* alias = *it;
+ if (alias == &pSym || !alias->isDyn())
+ continue;
+
+ pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
+ alias->name(),
+ (ResolveInfo::Type)alias->type(),
+ ResolveInfo::Define,
+ binding,
+ alias->size(), // size
+ 0x0, // value
+ FragmentRef::Create(*frag, 0x0),
+ (ResolveInfo::Visibility)alias->other());
}
- return NULL;
+
+ return *cpySym;
}
-// Check the symbol is _gp_disp.
-static
-bool helper_isGpDisp(const Relocation& pReloc)
+void MipsRelocator::postponeRelocation(Relocation& pReloc)
{
- const ResolveInfo* rsym = pReloc.symInfo();
- return 0 == strcmp(GP_DISP_NAME, rsym->name());
+ ResolveInfo* rsym = pReloc.symInfo();
+ m_PostponedRelocs[rsym].insert(&pReloc);
}
-static
-Relocator::Address helper_GetGP(MipsRelocator& pParent)
+void MipsRelocator::applyPostponedRelocations(MipsRelocationInfo& pLo16Reloc)
{
- return pParent.getTarget().getGOT().getGPAddr(pParent.getApplyingInput());
+ m_CurrentLo16Reloc = &pLo16Reloc;
+
+ ResolveInfo* rsym = pLo16Reloc.parent().symInfo();
+
+ RelocationSet & relocs = m_PostponedRelocs[rsym];
+ for (RelocationSet::iterator it = relocs.begin(); it != relocs.end(); ++it)
+ (*it)->apply(*this);
+
+ m_PostponedRelocs.erase(rsym);
+
+ m_CurrentLo16Reloc = NULL;
}
-static
-void helper_SetupRelDynForGOTEntry(MipsGOTEntry& got_entry,
- Relocation& pReloc,
- ResolveInfo* rsym,
- MipsRelocator& pParent)
+bool MipsRelocator::isGpDisp(const Relocation& pReloc) const
{
- MipsGNULDBackend& ld_backend = pParent.getTarget();
-
- Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
- rel_entry.setType(llvm::ELF::R_MIPS_REL32);
- rel_entry.targetRef() = *FragmentRef::Create(got_entry, 0);
- rel_entry.setSymInfo(rsym);
+ return 0 == strcmp("_gp_disp", pReloc.symInfo()->name());
}
-static
-MipsGOTEntry& helper_GetGOTEntry(Relocation& pReloc, MipsRelocator& pParent)
+bool MipsRelocator::isRel() const
+{
+ return config().targets().is32Bits();
+}
+
+bool MipsRelocator::isLocalReloc(ResolveInfo& pSym) const
+{
+ if (pSym.isUndef())
+ return false;
+
+ return pSym.isLocal() ||
+ !getTarget().isDynamicSymbol(pSym) ||
+ !pSym.isDyn();
+}
+
+Relocator::Address MipsRelocator::getGPAddress()
+{
+ return getTarget().getGOT().getGPAddr(getApplyingInput());
+}
+
+Relocator::Address MipsRelocator::getGP0()
+{
+ return getTarget().getGP0(getApplyingInput());
+}
+
+Fragment& MipsRelocator::getLocalGOTEntry(MipsRelocationInfo& pReloc,
+ Relocation::DWord entryValue)
{
// rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
- MipsGNULDBackend& ld_backend = pParent.getTarget();
- MipsGOT& got = ld_backend.getGOT();
- MipsGOTEntry* got_entry;
+ ResolveInfo* rsym = pReloc.parent().symInfo();
+ MipsGOT& got = getTarget().getGOT();
- if (got.isLocal(rsym) && ResolveInfo::Section == rsym->type()) {
- // Local section symbols consume local got entries.
- got_entry = got.consumeLocal();
- if (got.isPrimaryGOTConsumed())
- helper_SetupRelDynForGOTEntry(*got_entry, pReloc, NULL, pParent);
+ assert(isLocalReloc(*rsym) &&
+ "Attempt to get a global GOT entry for the local relocation");
+
+ Fragment* got_entry = got.lookupLocalEntry(rsym, entryValue);
+
+ // Found a mapping, then return the mapped entry immediately.
+ if (NULL != got_entry)
return *got_entry;
- }
- got_entry = got.lookupEntry(rsym);
- if (NULL != got_entry) {
- // found a mapping, then return the mapped entry immediately
- return *got_entry;
- }
-
- // not found
- if (got.isLocal(rsym))
- got_entry = got.consumeLocal();
- else
- got_entry = got.consumeGlobal();
-
- got.recordEntry(rsym, got_entry);
-
- // If we first get this GOT entry, we should initialize it.
- if (!got.isLocal(rsym) || ResolveInfo::Section != rsym->type()) {
- if (!got.isPrimaryGOTConsumed())
- got_entry->setValue(pReloc.symValue());
- }
+ // Not found.
+ got_entry = got.consumeLocal();
if (got.isPrimaryGOTConsumed())
- helper_SetupRelDynForGOTEntry(*got_entry, pReloc,
- got.isLocal(rsym) ? NULL : rsym, pParent);
+ setupRelDynEntry(*FragmentRef::Create(*got_entry, 0), NULL);
+ else
+ got.setEntryValue(got_entry, entryValue);
+
+ got.recordLocalEntry(rsym, entryValue, got_entry);
return *got_entry;
}
-static
-Relocator::Address helper_GetGOTOffset(Relocation& pReloc,
- MipsRelocator& pParent)
+Fragment& MipsRelocator::getGlobalGOTEntry(MipsRelocationInfo& pReloc)
{
- MipsGNULDBackend& ld_backend = pParent.getTarget();
- MipsGOT& got = ld_backend.getGOT();
- MipsGOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent);
- return got.getGPRelOffset(pParent.getApplyingInput(), got_entry);
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.parent().symInfo();
+ MipsGOT& got = getTarget().getGOT();
+
+ assert(!isLocalReloc(*rsym) &&
+ "Attempt to get a local GOT entry for the global relocation");
+
+ Fragment* got_entry = got.lookupGlobalEntry(rsym);
+
+ // Found a mapping, then return the mapped entry immediately.
+ if (NULL != got_entry)
+ return *got_entry;
+
+ // Not found.
+ got_entry = got.consumeGlobal();
+
+ if (got.isPrimaryGOTConsumed())
+ setupRelDynEntry(*FragmentRef::Create(*got_entry, 0), rsym);
+ else
+ got.setEntryValue(got_entry, pReloc.parent().symValue());
+
+ got.recordGlobalEntry(rsym, got_entry);
+
+ return *got_entry;
}
-static
-int32_t helper_CalcAHL(const Relocation& pHiReloc, const Relocation& pLoReloc)
+Relocator::Address MipsRelocator::getGOTOffset(MipsRelocationInfo& pReloc)
{
- assert((pHiReloc.type() == llvm::ELF::R_MIPS_HI16 ||
- pHiReloc.type() == llvm::ELF::R_MIPS_GOT16) &&
- pLoReloc.type() == llvm::ELF::R_MIPS_LO16 &&
- "Incorrect type of relocation for AHL calculation");
+ ResolveInfo* rsym = pReloc.parent().symInfo();
+ MipsGOT& got = getTarget().getGOT();
- // Note the addend is section symbol offset here
- assert (pHiReloc.addend() == pLoReloc.addend());
+ if (isLocalReloc(*rsym)) {
+ uint64_t value = pReloc.S();
- int32_t AHI = pHiReloc.target();
- int32_t ALO = pLoReloc.target();
- int32_t AHL = ((AHI & 0xFFFF) << 16) + (int16_t)(ALO & 0xFFFF) +
- pLoReloc.addend();
+ if (ResolveInfo::Section == rsym->type())
+ value += pReloc.A();
+
+ return got.getGPRelOffset(getApplyingInput(),
+ getLocalGOTEntry(pReloc, value));
+ }
+ else {
+ return got.getGPRelOffset(getApplyingInput(), getGlobalGOTEntry(pReloc));
+ }
+}
+
+void MipsRelocator::createDynRel(MipsRelocationInfo& pReloc)
+{
+ Relocator::DWord A = pReloc.A();
+ Relocator::DWord S = pReloc.S();
+
+ ResolveInfo* rsym = pReloc.parent().symInfo();
+
+ if (isLocalReloc(*rsym)) {
+ setupRelDynEntry(pReloc.parent().targetRef(), NULL);
+ pReloc.result() = A + S;
+ }
+ else {
+ setupRelDynEntry(pReloc.parent().targetRef(), rsym);
+ // Don't add symbol value that will be resolved by the dynamic linker.
+ pReloc.result() = A;
+ }
+}
+
+uint64_t MipsRelocator::calcAHL(const MipsRelocationInfo& pHiReloc)
+{
+ assert(NULL != m_CurrentLo16Reloc &&
+ "There is no saved R_MIPS_LO16 relocation");
+
+ uint64_t AHI = pHiReloc.A() & 0xFFFF;
+ uint64_t ALO = m_CurrentLo16Reloc->A() & 0xFFFF;
+ uint64_t AHL = (AHI << 16) + int16_t(ALO);
+
return AHL;
}
-static
-void helper_DynRel(Relocation& pReloc, MipsRelocator& pParent)
+bool MipsRelocator::isN64ABI() const
{
- ResolveInfo* rsym = pReloc.symInfo();
- MipsGNULDBackend& ld_backend = pParent.getTarget();
- MipsGOT& got = ld_backend.getGOT();
+ return config().targets().is64Bits();
+}
- Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
+uint64_t MipsRelocator::getPLTAddress(ResolveInfo& rsym)
+{
+ assert((rsym.reserved() & MipsRelocator::ReservePLT) &&
+ "Symbol does not require a PLT entry");
- rel_entry.setType(llvm::ELF::R_MIPS_REL32);
- rel_entry.targetRef() = pReloc.targetRef();
+ SymPLTMap::const_iterator it = m_SymPLTMap.find(&rsym);
- Relocator::DWord A = pReloc.target() + pReloc.addend();
- Relocator::DWord S = pReloc.symValue();
+ Fragment* plt;
- if (got.isLocal(rsym)) {
- rel_entry.setSymInfo(NULL);
- pReloc.target() = A + S;
+ if (it != m_SymPLTMap.end()) {
+ plt = it->second.first;
}
else {
- rel_entry.setSymInfo(rsym);
- // Don't add symbol value that will be resolved by the dynamic linker
- pReloc.target() = A;
+ plt = getTarget().getPLT().consume();
+
+ Fragment* got = getTarget().getGOTPLT().consume();
+ Relocation* rel = getTarget().getRelPLT().consumeEntry();
+
+ rel->setType(llvm::ELF::R_MIPS_JUMP_SLOT);
+ rel->targetRef().assign(*got);
+ rel->setSymInfo(&rsym);
+
+ m_SymPLTMap[&rsym] = PLTDescriptor(plt, got);
}
+
+ return getTarget().getPLT().addr() + plt->getOffset();
+}
+
+//===----------------------------------------------------------------------===//
+// Mips32Relocator
+//===----------------------------------------------------------------------===//
+Mips32Relocator::Mips32Relocator(Mips32GNULDBackend& pParent,
+ const LinkerConfig& pConfig)
+ : MipsRelocator(pParent, pConfig)
+{}
+
+void Mips32Relocator::setupRelDynEntry(FragmentRef& pFragRef, ResolveInfo* pSym)
+{
+ Relocation& relEntry = *getTarget().getRelDyn().consumeEntry();
+ relEntry.setType(llvm::ELF::R_MIPS_REL32);
+ relEntry.targetRef() = pFragRef;
+ relEntry.setSymInfo(pSym);
+}
+
+//===----------------------------------------------------------------------===//
+// Mips64Relocator
+//===----------------------------------------------------------------------===//
+Mips64Relocator::Mips64Relocator(Mips64GNULDBackend& pParent,
+ const LinkerConfig& pConfig)
+ : MipsRelocator(pParent, pConfig)
+{}
+
+void Mips64Relocator::setupRelDynEntry(FragmentRef& pFragRef, ResolveInfo* pSym)
+{
+ Relocation::Type type = llvm::ELF::R_MIPS_REL32 |
+ llvm::ELF::R_MIPS_64 << 8;
+ // FIXME (simon): Fix dynamic relocations.
+ type = llvm::ELF::R_MIPS_NONE;
+
+ Relocation& relEntry = *getTarget().getRelDyn().consumeEntry();
+ relEntry.setType(type);
+ relEntry.targetRef() = pFragRef;
+ relEntry.setSymInfo(pSym);
}
//=========================================//
@@ -470,35 +793,60 @@
// R_MIPS_NONE and those unsupported/deprecated relocation type
static
-MipsRelocator::Result none(Relocation& pReloc, MipsRelocator& pParent)
+MipsRelocator::Result none(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
{
return MipsRelocator::OK;
}
// R_MIPS_32: S + A
static
-MipsRelocator::Result abs32(Relocation& pReloc, MipsRelocator& pParent)
+MipsRelocator::Result abs32(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
{
- ResolveInfo* rsym = pReloc.symInfo();
+ ResolveInfo* rsym = pReloc.parent().symInfo();
- Relocator::DWord A = pReloc.target() + pReloc.addend();
- Relocator::DWord S = pReloc.symValue();
+ Relocator::DWord A = pReloc.A();
+ Relocator::DWord S = pReloc.S();
- LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
+ LDSection& target_sect =
+ pReloc.parent().targetRef().frag()->getParent()->getSection();
+
// If the flag of target section is not ALLOC, we will not scan this relocation
// but perform static relocation. (e.g., applying .debug section)
if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
- pReloc.target() = S + A;
+ pReloc.result() = S + A;
return MipsRelocator::OK;
}
if (rsym->reserved() & MipsRelocator::ReserveRel) {
- helper_DynRel(pReloc, pParent);
-
+ pParent.createDynRel(pReloc);
return MipsRelocator::OK;
}
- pReloc.target() = (S + A);
+ pReloc.result() = S + A;
+
+ return MipsRelocator::OK;
+}
+
+// R_MIPS_26:
+// local : ((A | ((P + 4) & 0x3F000000)) + S) >> 2
+// external: (sign–extend(A) + S) >> 2
+static
+MipsRelocator::Result rel26(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
+{
+ ResolveInfo* rsym = pReloc.parent().symInfo();
+
+ int32_t A = ((pReloc.parent().target() & 0x03FFFFFF) << 2);
+ int32_t P = pReloc.P();
+ int32_t S = rsym->reserved() & MipsRelocator::ReservePLT
+ ? pParent.getPLTAddress(*rsym)
+ : pReloc.S();
+
+ if (rsym->isLocal())
+ pReloc.result() = A | ((P + 4) & 0x3F000000);
+ else
+ pReloc.result() = mcld::signExtend<28>(A);
+
+ pReloc.result() = (pReloc.result() + S) >> 2;
return MipsRelocator::OK;
}
@@ -507,29 +855,23 @@
// local/external: ((AHL + S) - (short)(AHL + S)) >> 16
// _gp_disp : ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16
static
-MipsRelocator::Result hi16(Relocation& pReloc, MipsRelocator& pParent)
+MipsRelocator::Result hi16(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
{
- Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
- assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_HI16");
+ uint64_t AHL = pParent.calcAHL(pReloc);
- int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc);
- int32_t res = 0;
-
- pParent.setAHL(AHL);
-
- if (helper_isGpDisp(pReloc)) {
- int32_t P = pReloc.place();
- int32_t GP = helper_GetGP(pParent);
- res = ((AHL + GP - P) - (int16_t)(AHL + GP - P)) >> 16;
+ if (pParent.isGpDisp(pReloc.parent())) {
+ int32_t P = pReloc.P();
+ int32_t GP = pParent.getGPAddress();
+ pReloc.result() = ((AHL + GP - P) - (int16_t)(AHL + GP - P)) >> 16;
}
else {
- int32_t S = pReloc.symValue();
- res = ((AHL + S) - (int16_t)(AHL + S)) >> 16;
+ int32_t S = pReloc.S();
+ if (pParent.isN64ABI())
+ pReloc.result() = (pReloc.A() + S + 0x8000ull) >> 16;
+ else
+ pReloc.result() = ((AHL + S) - (int16_t)(AHL + S)) >> 16;
}
- pReloc.target() &= 0xFFFF0000;
- pReloc.target() |= (res & 0xFFFF);
-
return MipsRelocator::OK;
}
@@ -537,27 +879,45 @@
// local/external: AHL + S
// _gp_disp : AHL + GP - P + 4
static
-MipsRelocator::Result lo16(Relocation& pReloc, MipsRelocator& pParent)
+MipsRelocator::Result lo16(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
{
- int32_t res = 0;
+ // AHL is a combination of HI16 and LO16 addends. But R_MIPS_LO16
+ // uses low 16 bits of the AHL. That is why we do not need R_MIPS_HI16
+ // addend here.
+ int32_t AHL = (pReloc.A() & 0xFFFF);
- if (helper_isGpDisp(pReloc)) {
- int32_t P = pReloc.place();
- int32_t GP = helper_GetGP(pParent);
- int32_t AHL = pParent.getAHL();
- res = AHL + GP - P + 4;
+ if (pParent.isGpDisp(pReloc.parent())) {
+ int32_t P = pReloc.P();
+ int32_t GP = pParent.getGPAddress();
+ pReloc.result() = AHL + GP - P + 4;
}
else {
- int32_t S = pReloc.symValue();
- // The previous AHL may be for other hi/lo pairs.
- // We need to calcuate the lo part now. It is easy.
- // Remember to add the section offset to ALO.
- int32_t ALO = (pReloc.target() & 0xFFFF) + pReloc.addend();
- res = ALO + S;
+ int32_t S = pReloc.S();
+ pReloc.result() = AHL + S;
}
- pReloc.target() &= 0xFFFF0000;
- pReloc.target() |= (res & 0xFFFF);
+ pParent.applyPostponedRelocations(pReloc);
+
+ return MipsRelocator::OK;
+}
+
+// R_MIPS_GPREL16:
+// external: sign–extend(A) + S - GP
+// local : sign–extend(A) + S + GP0 – GP
+static
+MipsRelocator::Result gprel16(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
+{
+ // Remember to add the section offset to A.
+ uint64_t A = pReloc.A();
+ uint64_t S = pReloc.S();
+ uint64_t GP0 = pParent.getGP0();
+ uint64_t GP = pParent.getGPAddress();
+
+ ResolveInfo* rsym = pReloc.parent().symInfo();
+ if (rsym->isLocal())
+ pReloc.result() = A + S + GP0 - GP;
+ else
+ pReloc.result() = A + S - GP;
return MipsRelocator::OK;
}
@@ -566,52 +926,35 @@
// local : G (calculate AHL and put high 16 bit to GOT)
// external: G
static
-MipsRelocator::Result got16(Relocation& pReloc, MipsRelocator& pParent)
+MipsRelocator::Result got16(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
{
- MipsGNULDBackend& ld_backend = pParent.getTarget();
- MipsGOT& got = ld_backend.getGOT();
- ResolveInfo* rsym = pReloc.symInfo();
- Relocator::Address G = 0;
-
- if (rsym->isLocal()) {
- Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
- assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_GOT16");
-
- int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc);
- int32_t S = pReloc.symValue();
-
- pParent.setAHL(AHL);
-
+ if (pReloc.parent().symInfo()->isLocal()) {
+ int32_t AHL = pParent.calcAHL(pReloc);
+ int32_t S = pReloc.S();
int32_t res = (AHL + S + 0x8000) & 0xFFFF0000;
- MipsGOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent);
- got_entry.setValue(res);
- G = got.getGPRelOffset(pParent.getApplyingInput(), got_entry);
+ MipsGOT& got = pParent.getTarget().getGOT();
+
+ Fragment& got_entry = pParent.getLocalGOTEntry(pReloc, res);
+
+ pReloc.result() = got.getGPRelOffset(pParent.getApplyingInput(), got_entry);
}
else {
- G = helper_GetGOTOffset(pReloc, pParent);
+ pReloc.result() = pParent.getGOTOffset(pReloc);
}
- pReloc.target() &= 0xFFFF0000;
- pReloc.target() |= (G & 0xFFFF);
-
return MipsRelocator::OK;
}
// R_MIPS_GOTHI16:
// external: (G - (short)G) >> 16 + A
static
-MipsRelocator::Result gothi16(Relocation& pReloc, MipsRelocator& pParent)
+MipsRelocator::Result gothi16(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
{
- int32_t res = 0;
+ Relocator::Address G = pParent.getGOTOffset(pReloc);
+ int32_t A = pReloc.A();
- Relocator::Address G = helper_GetGOTOffset(pReloc, pParent);
- int32_t A = pReloc.target() + pReloc.addend();
-
- res = (G - (int16_t)G) >> (16 + A);
-
- pReloc.target() &= 0xFFFF0000;
- pReloc.target() |= (res & 0xFFFF);
+ pReloc.result() = (G - (int16_t)G) >> (16 + A);
return MipsRelocator::OK;
}
@@ -619,41 +962,145 @@
// R_MIPS_GOTLO16:
// external: G & 0xffff
static
-MipsRelocator::Result gotlo16(Relocation& pReloc, MipsRelocator& pParent)
+MipsRelocator::Result gotlo16(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
{
- Relocator::Address G = helper_GetGOTOffset(pReloc, pParent);
+ pReloc.result() = pParent.getGOTOffset(pReloc) & 0xffff;
- pReloc.target() &= 0xFFFF0000;
- pReloc.target() |= (G & 0xFFFF);
+ return MipsRelocator::OK;
+}
+
+// R_MIPS_SUB:
+// external/local: S - A
+static
+MipsRelocator::Result sub(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
+{
+ uint64_t S = pReloc.S();
+ uint64_t A = pReloc.A();
+
+ pReloc.result() = S - A;
return MipsRelocator::OK;
}
// R_MIPS_CALL16: G
static
-MipsRelocator::Result call16(Relocation& pReloc, MipsRelocator& pParent)
+MipsRelocator::Result call16(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
{
- Relocator::Address G = helper_GetGOTOffset(pReloc, pParent);
-
- pReloc.target() &= 0xFFFF0000;
- pReloc.target() |= (G & 0xFFFF);
+ pReloc.result() = pParent.getGOTOffset(pReloc);
return MipsRelocator::OK;
}
// R_MIPS_GPREL32: A + S + GP0 - GP
static
-MipsRelocator::Result gprel32(Relocation& pReloc, MipsRelocator& pParent)
+MipsRelocator::Result gprel32(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
{
// Remember to add the section offset to A.
- int32_t A = pReloc.target() + pReloc.addend();
- int32_t S = pReloc.symValue();
- int32_t GP = helper_GetGP(pParent);
+ uint64_t A = pReloc.A();
+ uint64_t S = pReloc.S();
+ uint64_t GP0 = pParent.getGP0();
+ uint64_t GP = pParent.getGPAddress();
- // llvm does not emits SHT_MIPS_REGINFO section.
- // Assume that GP0 is zero.
- pReloc.target() = (A + S - GP) & 0xFFFFFFFF;
+ pReloc.result() = A + S + GP0 - GP;
return MipsRelocator::OK;
}
+// R_MIPS_64: S + A
+static
+MipsRelocator::Result abs64(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
+{
+ // FIXME (simon): Consider to merge with abs32() or use the same function
+ // but with another mask size.
+ ResolveInfo* rsym = pReloc.parent().symInfo();
+
+ Relocator::DWord A = pReloc.A();
+ Relocator::DWord S = pReloc.S();
+
+ LDSection& target_sect =
+ pReloc.parent().targetRef().frag()->getParent()->getSection();
+
+ // If the flag of target section is not ALLOC, we will not scan this relocation
+ // but perform static relocation. (e.g., applying .debug section)
+ if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
+ pReloc.result() = S + A;
+ return MipsRelocator::OK;
+ }
+
+ if (rsym->reserved() & MipsRelocator::ReserveRel) {
+ pParent.createDynRel(pReloc);
+ return MipsRelocator::OK;
+ }
+
+ pReloc.result() = S + A;
+
+ return MipsRelocator::OK;
+}
+
+// R_MIPS_GOT_DISP / R_MIPS_GOT_PAGE: G
+static
+MipsRelocator::Result gotdisp(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
+{
+ pReloc.result() = pParent.getGOTOffset(pReloc);
+
+ return MipsRelocator::OK;
+}
+
+// R_MIPS_GOT_OFST:
+static
+MipsRelocator::Result gotoff(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
+{
+ // FIXME (simon): Needs to be implemented.
+ return MipsRelocator::OK;
+}
+
+// R_MIPS_JALR:
+static
+MipsRelocator::Result jalr(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
+{
+ return MipsRelocator::OK;
+}
+
+// R_MIPS_LA25_LUI
+static
+MipsRelocator::Result la25lui(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
+{
+ int32_t S = pReloc.S();
+
+ pReloc.result() = (S + 0x8000) >> 16;
+
+ return MipsRelocator::OK;
+}
+
+// R_MIPS_LA25_J
+static
+MipsRelocator::Result la25j(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
+{
+ int32_t S = pReloc.S();
+
+ pReloc.result() = S >> 2;
+
+ return MipsRelocator::OK;
+}
+
+// R_MIPS_LA25_ADD
+static
+MipsRelocator::Result la25add(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
+{
+ pReloc.result() = pReloc.S();
+
+ return MipsRelocator::OK;
+}
+
+// R_MIPS_PC32:
+static
+MipsRelocator::Result pc32(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
+{
+ return MipsRelocator::OK;
+}
+
+static
+MipsRelocator::Result unsupport(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
+{
+ return MipsRelocator::Unsupport;
+}
diff --git a/lib/Target/Mips/MipsRelocator.h b/lib/Target/Mips/MipsRelocator.h
index 96e73e2..4e24329 100644
--- a/lib/Target/Mips/MipsRelocator.h
+++ b/lib/Target/Mips/MipsRelocator.h
@@ -12,12 +12,15 @@
#include <gtest.h>
#endif
+#include <llvm/ADT/DenseMapInfo.h>
#include <mcld/LD/Relocator.h>
#include <mcld/Support/GCFactory.h>
#include "MipsLDBackend.h"
namespace mcld {
+class MipsRelocationInfo;
+
/** \class MipsRelocator
* \brief MipsRelocator creates and destroys the Mips relocations.
*/
@@ -28,7 +31,7 @@
None = 0, // no reserved entry
ReserveRel = 1, // reserve a dynamic relocation entry
ReserveGot = 2, // reserve a GOT entry
- ReserveGpDisp = 8 // reserve _gp_disp symbol
+ ReservePLT = 4 // reserve a PLT entry
};
public:
@@ -40,7 +43,8 @@
void scanRelocation(Relocation& pReloc,
IRBuilder& pBuilder,
Module& pModule,
- LDSection& pSection);
+ LDSection& pSection,
+ Input& pInput);
/// initializeScan - do initialization before scan relocations in pInput
/// @return - return true for initialization success
@@ -58,7 +62,7 @@
/// @return - return true for finalization success
bool finalizeApply(Input& pInput);
- Result applyRelocation(Relocation& pRelocation);
+ Result applyRelocation(Relocation& pReloc);
const Input& getApplyingInput() const
{ return *m_pApplyingInput; }
@@ -69,31 +73,124 @@
const MipsGNULDBackend& getTarget() const
{ return m_Target; }
- // Get last calculated AHL.
- int32_t getAHL() const
- { return m_AHL; }
+ /// postponeRelocation - save R_MIPS_LO16 paired relocations
+ /// like R_MISP_HI16 and R_MIPS_GOT16 for a future processing.
+ void postponeRelocation(Relocation& pReloc);
- // Set last calculated AHL.
- void setAHL(int32_t pAHL)
- { m_AHL = pAHL; }
+ /// applyPostponedRelocations - apply all postponed relocations
+ /// paired with the R_MIPS_LO16 one.
+ void applyPostponedRelocations(MipsRelocationInfo& pLo16Reloc);
+
+ /// isGpDisp - return true if relocation is against _gp_disp symbol.
+ bool isGpDisp(const Relocation& pReloc) const;
+
+ /// getGPAddress - return address of _gp symbol.
+ Address getGPAddress();
+
+ /// getGP0 - the gp value used to create the relocatable objects
+ /// in the processing input.
+ Address getGP0();
+
+ /// getLocalGOTEntry - initialize and return a local GOT entry
+ /// for this relocation.
+ Fragment& getLocalGOTEntry(MipsRelocationInfo& pReloc,
+ Relocation::DWord entryValue);
+
+ /// getGlobalGOTEntry - initialize and return a global GOT entry
+ /// for this relocation.
+ Fragment& getGlobalGOTEntry(MipsRelocationInfo& pReloc);
+
+ /// getGOTOffset - return offset of corresponded GOT entry.
+ Address getGOTOffset(MipsRelocationInfo& pReloc);
+
+ /// createDynRel - initialize dynamic relocation for the relocation.
+ void createDynRel(MipsRelocationInfo& pReloc);
+
+ /// getPLTOffset - initialize PLT-related entries for the symbol
+ /// @return - return address of PLT entry
+ uint64_t getPLTAddress(ResolveInfo& rsym);
+
+ /// calcAHL - calculate combined addend used
+ /// by R_MIPS_HI16 and R_MIPS_GOT16 relocations.
+ uint64_t calcAHL(const MipsRelocationInfo& pHiReloc);
+
+ /// isN64ABI - check current ABI
+ bool isN64ABI() const;
const char* getName(Relocation::Type pType) const;
Size getSize(Relocation::Type pType) const;
-private:
- void scanLocalReloc(Relocation& pReloc,
- IRBuilder& pBuilder,
- const LDSection& pSection);
+protected:
+ /// setupRelDynEntry - create dynamic relocation entry.
+ virtual void setupRelDynEntry(FragmentRef& pFragRef, ResolveInfo* pSym) = 0;
- void scanGlobalReloc(Relocation& pReloc,
- IRBuilder& pBuilder,
- const LDSection& pSection);
+ /// isLocalReloc - handle relocation as a local symbol
+ bool isLocalReloc(ResolveInfo& pSym) const;
+
+private:
+ typedef std::pair<Fragment*, Fragment*> PLTDescriptor;
+ typedef llvm::DenseMap<const ResolveInfo*, PLTDescriptor> SymPLTMap;
+ typedef llvm::DenseSet<Relocation*> RelocationSet;
+ typedef llvm::DenseMap<const ResolveInfo*, RelocationSet> SymRelocSetMap;
private:
MipsGNULDBackend& m_Target;
+ SymPLTMap m_SymPLTMap;
Input* m_pApplyingInput;
- int32_t m_AHL;
+ SymRelocSetMap m_PostponedRelocs;
+ MipsRelocationInfo* m_CurrentLo16Reloc;
+
+private:
+ void scanLocalReloc(MipsRelocationInfo& pReloc,
+ IRBuilder& pBuilder,
+ const LDSection& pSection);
+
+ void scanGlobalReloc(MipsRelocationInfo& pReloc,
+ IRBuilder& pBuilder,
+ const LDSection& pSection);
+
+ /// isPostponed - relocation applying needs to be postponed.
+ bool isPostponed(const Relocation& pReloc) const;
+
+ /// addCopyReloc - add a copy relocation into .rel.dyn for pSym
+ /// @param pSym - A resolved copy symbol that defined in BSS section
+ void addCopyReloc(ResolveInfo& pSym);
+
+ /// defineSymbolforCopyReloc - allocate a space in BSS section and
+ /// and force define the copy of pSym to BSS section
+ /// @return the output LDSymbol of the copy symbol
+ LDSymbol& defineSymbolforCopyReloc(IRBuilder& pBuilder,
+ const ResolveInfo& pSym);
+
+ /// isRel - returns true if REL relocation record format is expected
+ bool isRel() const;
+};
+
+/** \class Mips32Relocator
+ * \brief Mips32Relocator creates and destroys the Mips 32-bit relocations.
+ */
+class Mips32Relocator : public MipsRelocator
+{
+public:
+ Mips32Relocator(Mips32GNULDBackend& pParent, const LinkerConfig& pConfig);
+
+private:
+ // MipsRelocator
+ void setupRelDynEntry(FragmentRef& pFragRef, ResolveInfo* pSym);
+};
+
+/** \class Mips64Relocator
+ * \brief Mips64Relocator creates and destroys the Mips 64-bit relocations.
+ */
+class Mips64Relocator : public MipsRelocator
+{
+public:
+ Mips64Relocator(Mips64GNULDBackend& pParent, const LinkerConfig& pConfig);
+
+private:
+ // MipsRelocator
+ void setupRelDynEntry(FragmentRef& pFragRef, ResolveInfo* pSym);
};
} // namespace of mcld
diff --git a/lib/Target/Mips/MipsTargetMachine.cpp b/lib/Target/Mips/MipsTargetMachine.cpp
index 03db780..2e57868 100644
--- a/lib/Target/Mips/MipsTargetMachine.cpp
+++ b/lib/Target/Mips/MipsTargetMachine.cpp
@@ -7,23 +7,24 @@
//
//===----------------------------------------------------------------------===//
#include "MipsTargetMachine.h"
-
#include "Mips.h"
-#include <mcld/Target/TargetMachine.h>
#include <mcld/Support/TargetRegistry.h>
+typedef mcld::RegisterTargetMachine<mcld::MipsBaseTargetMachine> RegMipsTarget;
+
extern "C" void MCLDInitializeMipsLDTarget() {
- // Register createTargetMachine function pointer to mcld::Target
- mcld::RegisterTargetMachine<mcld::MipsBaseTargetMachine>
- X(mcld::TheMipselTarget);
+ RegMipsTarget X1(mcld::TheMipselTarget);
+ RegMipsTarget X2(mcld::TheMips64elTarget);
}
-mcld::MipsBaseTargetMachine::MipsBaseTargetMachine(llvm::TargetMachine& pPM,
- const mcld::Target &pTarget,
- const std::string& pTriple)
- : mcld::MCLDTargetMachine(pPM, pTarget, pTriple) {
-}
+using namespace mcld;
-mcld::MipsBaseTargetMachine::~MipsBaseTargetMachine()
-{
+//===----------------------------------------------------------------------===//
+// MipsBaseTargetMachine
+//===----------------------------------------------------------------------===//
+MipsBaseTargetMachine::MipsBaseTargetMachine(llvm::TargetMachine& pPM,
+ const llvm::Target &pLLVMTarget,
+ const mcld::Target &pMCLDTarget,
+ const std::string& pTriple)
+ : MCLDTargetMachine(pPM, pLLVMTarget, pMCLDTarget, pTriple) {
}
diff --git a/lib/Target/Mips/MipsTargetMachine.h b/lib/Target/Mips/MipsTargetMachine.h
index 6cfae73..964a6d1 100644
--- a/lib/Target/Mips/MipsTargetMachine.h
+++ b/lib/Target/Mips/MipsTargetMachine.h
@@ -9,8 +9,7 @@
#ifndef MIPS_TARGET_MACHINE_H
#define MIPS_TARGET_MACHINE_H
-#include "Mips.h"
-#include <mcld/Target/TargetMachine.h>
+#include <mcld/CodeGen/TargetMachine.h>
namespace mcld {
@@ -18,10 +17,9 @@
{
public:
MipsBaseTargetMachine(llvm::TargetMachine &pTM,
- const mcld::Target &pTarget,
+ const llvm::Target &pLLVMTarget,
+ const mcld::Target &pMCLDTarget,
const std::string &pTriple);
-
- virtual ~MipsBaseTargetMachine();
};
} // namespace of mcld
diff --git a/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp b/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp
index 3991c45..4ae7a61 100644
--- a/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp
+++ b/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp
@@ -6,16 +6,19 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/Target/TargetMachine.h"
-#include "mcld/Support/TargetRegistry.h"
+#include <mcld/Support/Target.h>
+#include <mcld/Support/TargetRegistry.h>
namespace mcld {
mcld::Target TheMipselTarget;
+mcld::Target TheMips64elTarget;
extern "C" void MCLDInitializeMipsLDTargetInfo() {
- // register into mcld::TargetRegistry
- mcld::RegisterTarget X(TheMipselTarget, "mipsel");
+ mcld::RegisterTarget<llvm::Triple::mipsel>
+ X1(TheMipselTarget, "mipsel");
+ mcld::RegisterTarget<llvm::Triple::mips64el>
+ X2(TheMips64elTarget, "mips64el");
}
} // namespace of mcld
diff --git a/lib/Target/OutputRelocSection.cpp b/lib/Target/OutputRelocSection.cpp
index 603350b..07670a3 100644
--- a/lib/Target/OutputRelocSection.cpp
+++ b/lib/Target/OutputRelocSection.cpp
@@ -34,6 +34,13 @@
{
}
+Relocation* OutputRelocSection::create()
+{
+ Relocation* reloc = Relocation::Create();
+ m_pRelocData->append(*reloc);
+ return reloc;
+}
+
void OutputRelocSection::reserveEntry(size_t pNum)
{
for(size_t i=0; i<pNum; i++)
diff --git a/lib/Target/Target.cpp b/lib/Target/Target.cpp
deleted file mode 100644
index ba69e03..0000000
--- a/lib/Target/Target.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-//===- Target.cpp ---------------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/Support/TargetRegistry.h>
-#include <mcld/Target/TargetMachine.h>
-#include <llvm/Support/TargetRegistry.h>
-#include <llvm/Target/TargetMachine.h>
-
-using namespace llvm;
-
-mcld::Target::Target()
- : TargetMachineCtorFn(NULL),
- MCLinkerCtorFn(NULL),
- TargetLDBackendCtorFn(NULL),
- DiagnosticLineInfoCtorFn(NULL),
- m_pT(NULL)
-{
-}
-
diff --git a/lib/Target/X86/TargetInfo/X86TargetInfo.cpp b/lib/Target/X86/TargetInfo/X86TargetInfo.cpp
index 3c02314..8e3a7c0 100644
--- a/lib/Target/X86/TargetInfo/X86TargetInfo.cpp
+++ b/lib/Target/X86/TargetInfo/X86TargetInfo.cpp
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/Target/TargetMachine.h"
-#include "mcld/Support/TargetRegistry.h"
+#include <mcld/Support/Target.h>
+#include <mcld/Support/TargetRegistry.h>
namespace mcld {
@@ -16,8 +16,10 @@
extern "C" void MCLDInitializeX86LDTargetInfo() {
// register into mcld::TargetRegistry
- mcld::RegisterTarget X(TheX86_32Target, "x86");
- mcld::RegisterTarget Y(TheX86_64Target, "x86-64");
+ mcld::RegisterTarget<llvm::Triple::x86>
+ X(TheX86_32Target, "x86");
+ mcld::RegisterTarget<llvm::Triple::x86_64>
+ Y(TheX86_64Target, "x86-64");
}
} // namespace of mcld
diff --git a/lib/Target/X86/X86.h b/lib/Target/X86/X86.h
index 0f7d65d..5927f44 100644
--- a/lib/Target/X86/X86.h
+++ b/lib/Target/X86/X86.h
@@ -6,12 +6,17 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_X86_H
-#define MCLD_X86_H
+#ifndef MCLD_TARGET_X86_H
+#define MCLD_TARGET_X86_H
#include <string>
-#include "mcld/Target/TargetMachine.h"
+
+namespace llvm {
+class Target;
+} // namespace of llvm
namespace mcld {
+
+class Target;
class TargetLDBackend;
extern mcld::Target TheX86_32Target;
diff --git a/lib/Target/X86/X86Diagnostic.cpp b/lib/Target/X86/X86Diagnostic.cpp
index 9287ca7..9dab719 100644
--- a/lib/Target/X86/X86Diagnostic.cpp
+++ b/lib/Target/X86/X86Diagnostic.cpp
@@ -6,21 +6,16 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include <llvm/ADT/Triple.h>
#include <mcld/Support/TargetRegistry.h>
#include <mcld/LD/DWARFLineInfo.h>
#include "X86.h"
using namespace mcld;
-//===----------------------------------------------------------------------===//
-// X86Diagnostic
-
-
namespace mcld {
//===----------------------------------------------------------------------===//
// createX86Diagnostic - the help function to create corresponding X86Diagnostic
-//
+//===----------------------------------------------------------------------===//
DiagnosticLineInfo* createX86DiagLineInfo(const mcld::Target& pTarget,
const std::string &pTriple)
{
@@ -29,8 +24,9 @@
} // namespace of mcld
-//==========================
+//===----------------------------------------------------------------------===//
// InitializeX86Diagnostic
+//===----------------------------------------------------------------------===//
extern "C" void MCLDInitializeX86DiagnosticLineInfo() {
// Register the linker frontend
mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheX86_32Target, createX86DiagLineInfo);
diff --git a/lib/Target/X86/X86ELFMCLinker.cpp b/lib/Target/X86/X86ELFMCLinker.cpp
index 868d61c..a57fe37 100644
--- a/lib/Target/X86/X86ELFMCLinker.cpp
+++ b/lib/Target/X86/X86ELFMCLinker.cpp
@@ -7,14 +7,13 @@
//
//===----------------------------------------------------------------------===//
#include "X86ELFMCLinker.h"
-#include <mcld/LinkerConfig.h>
using namespace mcld;
X86ELFMCLinker::X86ELFMCLinker(LinkerConfig& pConfig,
mcld::Module& pModule,
- MemoryArea& pOutput)
- : ELFMCLinker(pConfig, pModule, pOutput) {
+ FileHandle& pFileHandle)
+ : ELFMCLinker(pConfig, pModule, pFileHandle) {
}
X86ELFMCLinker::~X86ELFMCLinker()
diff --git a/lib/Target/X86/X86ELFMCLinker.h b/lib/Target/X86/X86ELFMCLinker.h
index 173f7dc..4b64d28 100644
--- a/lib/Target/X86/X86ELFMCLinker.h
+++ b/lib/Target/X86/X86ELFMCLinker.h
@@ -16,7 +16,7 @@
namespace mcld {
class Module;
-class MemoryArea;
+class FileHandle;
/** \class X86ELFMCLinker
* \brief X86ELFMCLinker sets up the environment for linking.
@@ -28,7 +28,7 @@
public:
X86ELFMCLinker(LinkerConfig& pConfig,
mcld::Module& pModule,
- MemoryArea& pOutput);
+ FileHandle& pFileHandle);
~X86ELFMCLinker();
};
diff --git a/lib/Target/X86/X86Emulation.cpp b/lib/Target/X86/X86Emulation.cpp
index 99e15da..d91d46d 100644
--- a/lib/Target/X86/X86Emulation.cpp
+++ b/lib/Target/X86/X86Emulation.cpp
@@ -22,10 +22,10 @@
// set up bitclass and endian
pConfig.targets().setEndian(TargetOptions::Little);
unsigned int bitclass;
- Triple::ArchType arch = pConfig.targets().triple().getArch();
- assert (arch == Triple::x86 || arch == Triple::x86_64);
- if (arch == Triple::x86 ||
- pConfig.targets().triple().getEnvironment() == Triple::GNUX32) {
+ llvm::Triple::ArchType arch = pConfig.targets().triple().getArch();
+ assert (arch == llvm::Triple::x86 || arch == llvm::Triple::x86_64);
+ if (arch == llvm::Triple::x86 ||
+ pConfig.targets().triple().getEnvironment() == llvm::Triple::GNUX32) {
bitclass = 32;
}
else {
diff --git a/lib/Target/X86/X86GOT.cpp b/lib/Target/X86/X86GOT.cpp
index b77cfd3..bac4bee 100644
--- a/lib/Target/X86/X86GOT.cpp
+++ b/lib/Target/X86/X86GOT.cpp
@@ -19,7 +19,7 @@
// X86_32GOT
//===----------------------------------------------------------------------===//
X86_32GOT::X86_32GOT(LDSection& pSection)
- : GOT(pSection), m_pLast(NULL)
+ : GOT(pSection)
{
}
@@ -27,23 +27,9 @@
{
}
-void X86_32GOT::reserve(size_t pNum)
+X86_32GOTEntry* X86_32GOT::create()
{
- for (size_t i = 0; i < pNum; i++) {
- new X86_32GOTEntry(0, m_SectionData);
- }
-}
-
-X86_32GOTEntry* X86_32GOT::consume()
-{
- if (NULL == m_pLast) {
- assert(!empty() && "Consume empty GOT entry!");
- m_pLast = llvm::cast<X86_32GOTEntry>(&m_SectionData->front());
- return m_pLast;
- }
-
- m_pLast = llvm::cast<X86_32GOTEntry>(m_pLast->getNextNode());
- return m_pLast;
+ return new X86_32GOTEntry(0, m_SectionData);
}
//===----------------------------------------------------------------------===//
@@ -58,22 +44,8 @@
{
}
-void X86_64GOT::reserve(size_t pNum)
+X86_64GOTEntry* X86_64GOT::create()
{
- for (size_t i = 0; i < pNum; i++) {
- new X86_64GOTEntry(0, m_SectionData);
- }
-}
-
-X86_64GOTEntry* X86_64GOT::consume()
-{
- if (NULL == m_pLast) {
- assert(!empty() && "Consume empty GOT entry!");
- m_pLast = llvm::cast<X86_64GOTEntry>(&m_SectionData->front());
- return m_pLast;
- }
-
- m_pLast = llvm::cast<X86_64GOTEntry>(m_pLast->getNextNode());
- return m_pLast;
+ return new X86_64GOTEntry(0, m_SectionData);
}
diff --git a/lib/Target/X86/X86GOT.h b/lib/Target/X86/X86GOT.h
index df557f3..67c3163 100644
--- a/lib/Target/X86/X86GOT.h
+++ b/lib/Target/X86/X86GOT.h
@@ -41,12 +41,7 @@
~X86_32GOT();
- void reserve(size_t pNum = 1);
-
- X86_32GOTEntry* consume();
-
-private:
- X86_32GOTEntry* m_pLast; ///< the last consumed entry
+ X86_32GOTEntry* create();
};
/** \class X86_64GOTEntry
@@ -71,9 +66,7 @@
~X86_64GOT();
- void reserve(size_t pNum = 1);
-
- X86_64GOTEntry* consume();
+ X86_64GOTEntry* create();
private:
X86_64GOTEntry* m_pLast; ///< the last consumed entry
diff --git a/lib/Target/X86/X86GOTPLT.cpp b/lib/Target/X86/X86GOTPLT.cpp
index 961e0dc..7baa5cb 100644
--- a/lib/Target/X86/X86GOTPLT.cpp
+++ b/lib/Target/X86/X86GOTPLT.cpp
@@ -23,13 +23,9 @@
X86_32GOTPLT::X86_32GOTPLT(LDSection& pSection)
: X86_32GOT(pSection)
{
- // Create GOT0 entries
- reserve(X86GOTPLT0Num);
-
- // Skip GOT0 entries
- for (size_t i = 0; i < X86GOTPLT0Num; ++i) {
- consume();
- }
+ // create GOT0 entries
+ for (size_t i = 0; i < X86GOTPLT0Num; ++i)
+ create();
}
X86_32GOTPLT::~X86_32GOTPLT()
@@ -67,13 +63,8 @@
X86_64GOTPLT::X86_64GOTPLT(LDSection& pSection)
: X86_64GOT(pSection)
{
- // Create GOT0 entries
- reserve(X86GOTPLT0Num);
-
- // Skip GOT0 entries
- for (size_t i = 0; i < X86GOTPLT0Num; ++i) {
- consume();
- }
+ for (size_t i = 0; i < X86GOTPLT0Num; ++i)
+ create();
}
X86_64GOTPLT::~X86_64GOTPLT()
diff --git a/lib/Target/X86/X86LDBackend.cpp b/lib/Target/X86/X86LDBackend.cpp
index 87c1192..04e858c 100644
--- a/lib/Target/X86/X86LDBackend.cpp
+++ b/lib/Target/X86/X86LDBackend.cpp
@@ -12,18 +12,19 @@
#include "X86Relocator.h"
#include "X86GNUInfo.h"
+#include <llvm/ADT/StringRef.h>
#include <llvm/ADT/Triple.h>
#include <llvm/Support/Casting.h>
#include <mcld/LinkerConfig.h>
#include <mcld/IRBuilder.h>
+#include <mcld/LD/ELFFileFormat.h>
#include <mcld/Fragment/FillFragment.h>
#include <mcld/Fragment/RegionFragment.h>
-#include <mcld/Fragment/FragmentLinker.h>
-#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/TargetRegistry.h>
#include <mcld/Object/ObjectBuilder.h>
+#include <llvm/Support/Dwarf.h>
#include <cstring>
@@ -44,13 +45,13 @@
m_pGOTSymbol(NULL),
m_CopyRel(pCopyRel)
{
- Triple::ArchType arch = pConfig.targets().triple().getArch();
- assert (arch == Triple::x86 || arch == Triple::x86_64);
- if (arch == Triple::x86 ||
- pConfig.targets().triple().getEnvironment() == Triple::GNUX32) {
+ llvm::Triple::ArchType arch = pConfig.targets().triple().getArch();
+ assert (arch == llvm::Triple::x86 || arch == llvm::Triple::x86_64);
+ if (arch == llvm::Triple::x86 ||
+ pConfig.targets().triple().getEnvironment() == llvm::Triple::GNUX32) {
m_RelEntrySize = 8;
m_RelaEntrySize = 12;
- if (arch == Triple::x86)
+ if (arch == llvm::Triple::x86)
m_PointerRel = llvm::ELF::R_386_32;
else
m_PointerRel = llvm::ELF::R_X86_64_32;
@@ -105,6 +106,9 @@
setRelPLTSize();
}
}
+
+ if (config().options().genUnwindInfo())
+ addEhFrameForPLT(pBuilder.getModule());
}
void X86GNULDBackend::doPostLayout(Module& pModule,
@@ -168,10 +172,8 @@
unsigned int EntrySize = 0;
uint64_t RegionSize = 0;
- if (&pSection == &(FileFormat->getPLT())) {
- assert(m_pPLT && "emitSectionData failed, m_pPLT is NULL!");
-
- unsigned char* buffer = pRegion.getBuffer();
+ if (FileFormat->hasPLT() && (&pSection == &(FileFormat->getPLT()))) {
+ unsigned char* buffer = pRegion.begin();
m_pPLT->applyPLT0();
m_pPLT->applyPLT1();
@@ -192,15 +194,13 @@
++it;
}
}
-
- else if (&pSection == &(FileFormat->getGOT())) {
+ else if (FileFormat->hasGOT() && (&pSection == &(FileFormat->getGOT()))) {
RegionSize += emitGOTSectionData(pRegion);
}
-
- else if (&pSection == &(FileFormat->getGOTPLT())) {
+ else if (FileFormat->hasGOTPLT() &&
+ (&pSection == &(FileFormat->getGOTPLT()))) {
RegionSize += emitGOTPLTSectionData(pRegion, FileFormat);
}
-
else {
fatal(diag::unrecognized_output_sectoin)
<< pSection.name()
@@ -250,19 +250,19 @@
{
const ELFFileFormat* file_format = getOutputFormat();
- if (&pSectHdr == &file_format->getGOT()) {
+ if (file_format->hasGOT() && (&pSectHdr == &file_format->getGOT())) {
if (config().options().hasNow())
return SHO_RELRO;
return SHO_RELRO_LAST;
}
- if (&pSectHdr == &file_format->getGOTPLT()) {
+ if (file_format->hasGOTPLT() && (&pSectHdr == &file_format->getGOTPLT())) {
if (config().options().hasNow())
return SHO_RELRO;
return SHO_NON_RELRO_FIRST;
}
- if (&pSectHdr == &file_format->getPLT())
+ if (file_format->hasPLT() && (&pSectHdr == &file_format->getPLT()))
return SHO_PLT;
return SHO_UNDEFINED;
@@ -286,6 +286,51 @@
}
}
+void X86GNULDBackend::addEhFrameForPLT(Module& pModule)
+{
+ LDSection* plt_sect = pModule.getSection(".plt");
+ if (!plt_sect || plt_sect->size() == 0u)
+ return;
+
+ LDSection* eh_sect = pModule.getSection(".eh_frame");
+ if (!eh_sect || !eh_sect->hasEhFrame())
+ return;
+
+ EhFrame* eh_frame = eh_sect->getEhFrame();
+ SectionData::FragmentListType& frag_list =
+ eh_frame->getSectionData()->getFragmentList();
+ llvm::StringRef cie_region = createCIERegionForPLT();
+ llvm::StringRef fde_region = createFDERegionForPLT();
+ EhFrame::CIE* cie = new EhFrame::GeneratedCIE(cie_region);
+ EhFrame::FDE* fde = new EhFrame::GeneratedFDE(fde_region, *cie);
+ // Augmentation data only contains FDE encoding.
+ uint8_t aug_data = (uint8_t)(llvm::dwarf::DW_EH_PE_pcrel |
+ llvm::dwarf::DW_EH_PE_sdata4);
+ cie->setFDEEncode(aug_data);
+ cie->setAugmentationData(std::string(1, aug_data));
+
+ EhFrame::cie_iterator i = eh_frame->cie_begin();
+ for (EhFrame::cie_iterator e = eh_frame->cie_end(); i != e; ++i) {
+ EhFrame::CIE& exist_cie = **i;
+ if (exist_cie == *cie) {
+ // Insert the FDE fragment
+ SectionData::iterator cur_iter(exist_cie);
+ frag_list.insertAfter(cur_iter, fde);
+ fde->setCIE(exist_cie);
+
+ // Cleanup the CIE we created
+ cie->clearFDEs();
+ delete cie;
+ break;
+ }
+ }
+ if (i == eh_frame->cie_end()) {
+ // Newly insert
+ eh_frame->addCIE(*cie);
+ eh_frame->addFDE(*fde);
+ }
+}
+
/// finalizeSymbol - finalize the symbol value
bool X86GNULDBackend::finalizeTargetSymbols()
{
@@ -335,6 +380,7 @@
// initialize .plt
LDSection& plt = file_format->getPLT();
+ plt.setAlign(16u);
m_pPLT = new X86_32PLT(plt,
*m_pGOTPLT,
config());
@@ -375,6 +421,59 @@
return *m_pGOTPLT;
}
+llvm::StringRef X86_32GNULDBackend::createCIERegionForPLT()
+{
+ using namespace llvm::dwarf;
+ static const uint8_t data[4+4+16] = {
+ 0x14, 0, 0, 0, // length
+ 0, 0, 0, 0, // ID
+ 1, // version
+ 'z', 'R', '\0', // augmentation string
+ 1, // code alignment factor
+ 0x7c, // data alignment factor
+ 8, // return address column
+ 1, // augmentation data size
+ DW_EH_PE_pcrel | DW_EH_PE_sdata4, // FDE encoding
+ DW_CFA_def_cfa, 4, 4,
+ DW_CFA_offset + 8, 1,
+ DW_CFA_nop,
+ DW_CFA_nop
+ };
+ return llvm::StringRef((const char*)data, 4+4+16);
+}
+
+llvm::StringRef X86_32GNULDBackend::createFDERegionForPLT()
+{
+ using namespace llvm::dwarf;
+ static const uint8_t data[4+4+32] = {
+ 0x24, 0, 0, 0, // length
+ 0, 0, 0, 0, // offset to CIE
+ 0, 0, 0, 0, // offset to PLT
+ 0, 0, 0, 0, // size of PLT
+ 0, // augmentation data size
+ DW_CFA_def_cfa_offset, 8,
+ DW_CFA_advance_loc + 6,
+ DW_CFA_def_cfa_offset, 12,
+ DW_CFA_advance_loc + 10,
+ DW_CFA_def_cfa_expression,
+ 11,
+ DW_OP_breg4, 4,
+ DW_OP_breg8, 0,
+ DW_OP_lit15,
+ DW_OP_and,
+ DW_OP_lit11,
+ DW_OP_ge,
+ DW_OP_lit2,
+ DW_OP_shl,
+ DW_OP_plus,
+ DW_CFA_nop,
+ DW_CFA_nop,
+ DW_CFA_nop,
+ DW_CFA_nop
+ };
+ return llvm::StringRef((const char*)data, 4+4+32);
+}
+
void X86_32GNULDBackend::setRelDynSize()
{
ELFFileFormat* file_format = getOutputFormat();
@@ -408,7 +507,7 @@
{
assert(m_pGOT && "emitGOTSectionData failed, m_pGOT is NULL!");
- uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.begin());
X86_32GOTEntry* got = 0;
unsigned int EntrySize = X86_32GOTEntry::EntrySize;
@@ -431,7 +530,7 @@
m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr());
m_pGOTPLT->applyAllGOTPLT(*m_pPLT);
- uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.begin());
X86_32GOTEntry* got = 0;
unsigned int EntrySize = X86_32GOTEntry::EntrySize;
@@ -492,6 +591,59 @@
return *m_pGOTPLT;
}
+llvm::StringRef X86_64GNULDBackend::createCIERegionForPLT()
+{
+ using namespace llvm::dwarf;
+ static const uint8_t data[4+4+16] = {
+ 0x14, 0, 0, 0, // length
+ 0, 0, 0, 0, // ID
+ 1, // CIE version
+ 'z', 'R', '\0', // augmentation string
+ 1, // code alignment factor
+ 0x78, // data alignment factor
+ 16, // return address column
+ 1, // augmentation data size
+ DW_EH_PE_pcrel | DW_EH_PE_sdata4, // FDE encoding
+ DW_CFA_def_cfa, 7, 8,
+ DW_CFA_offset + 16, 1,
+ DW_CFA_nop,
+ DW_CFA_nop
+ };
+ return llvm::StringRef((const char*)data, 4+4+16);
+}
+
+llvm::StringRef X86_64GNULDBackend::createFDERegionForPLT()
+{
+ using namespace llvm::dwarf;
+ static const uint8_t data[4+4+32] = {
+ 0x24, 0, 0, 0, // length
+ 0, 0, 0, 0, // ID
+ 0, 0, 0, 0, // offset to PLT
+ 0, 0, 0, 0, // size of PLT
+ 0, // augmentation data size
+ DW_CFA_def_cfa_offset, 16,
+ DW_CFA_advance_loc + 6,
+ DW_CFA_def_cfa_offset, 24,
+ DW_CFA_advance_loc + 10,
+ DW_CFA_def_cfa_expression,
+ 11,
+ DW_OP_breg7, 8,
+ DW_OP_breg16, 0,
+ DW_OP_lit15,
+ DW_OP_and,
+ DW_OP_lit11,
+ DW_OP_ge,
+ DW_OP_lit3,
+ DW_OP_shl,
+ DW_OP_plus,
+ DW_CFA_nop,
+ DW_CFA_nop,
+ DW_CFA_nop,
+ DW_CFA_nop
+ };
+ return llvm::StringRef((const char*)data, 4+4+32);
+}
+
void X86_64GNULDBackend::setRelDynSize()
{
ELFFileFormat* file_format = getOutputFormat();
@@ -521,6 +673,7 @@
// initialize .plt
LDSection& plt = file_format->getPLT();
+ plt.setAlign(16u);
m_pPLT = new X86_64PLT(plt,
*m_pGOTPLT,
config());
@@ -556,7 +709,7 @@
{
assert(m_pGOT && "emitGOTSectionData failed, m_pGOT is NULL!");
- uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.getBuffer());
+ uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.begin());
X86_64GOTEntry* got = 0;
unsigned int EntrySize = X86_64GOTEntry::EntrySize;
@@ -579,7 +732,7 @@
m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr());
m_pGOTPLT->applyAllGOTPLT(*m_pPLT);
- uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.getBuffer());
+ uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.begin());
X86_64GOTEntry* got = 0;
unsigned int EntrySize = X86_64GOTEntry::EntrySize;
@@ -600,8 +753,7 @@
//===----------------------------------------------------------------------===//
/// createX86LDBackend - the help funtion to create corresponding X86LDBackend
///
-TargetLDBackend* createX86LDBackend(const llvm::Target& pTarget,
- const LinkerConfig& pConfig)
+TargetLDBackend* createX86LDBackend(const LinkerConfig& pConfig)
{
if (pConfig.targets().triple().isOSDarwin()) {
assert(0 && "MachO linker is not supported yet");
@@ -619,11 +771,11 @@
createX86COFFObjectWriter);
**/
}
- Triple::ArchType arch = pConfig.targets().triple().getArch();
- if (arch == Triple::x86)
+ llvm::Triple::ArchType arch = pConfig.targets().triple().getArch();
+ if (arch == llvm::Triple::x86)
return new X86_32GNULDBackend(pConfig,
new X86_32GNUInfo(pConfig.targets().triple()));
- assert (arch == Triple::x86_64);
+ assert (arch == llvm::Triple::x86_64);
return new X86_64GNULDBackend(pConfig,
new X86_64GNUInfo(pConfig.targets().triple()));
}
diff --git a/lib/Target/X86/X86LDBackend.h b/lib/Target/X86/X86LDBackend.h
index a3e8635..4ef5311 100644
--- a/lib/Target/X86/X86LDBackend.h
+++ b/lib/Target/X86/X86LDBackend.h
@@ -130,6 +130,10 @@
virtual void setRelDynSize() = 0;
virtual void setRelPLTSize() = 0;
+ void addEhFrameForPLT(Module& pModule);
+ virtual llvm::StringRef createCIERegionForPLT() = 0;
+ virtual llvm::StringRef createFDERegionForPLT() = 0;
+
protected:
Relocator* m_pRelocator;
X86PLT* m_pPLT;
@@ -183,6 +187,9 @@
void setRelDynSize();
void setRelPLTSize();
+ llvm::StringRef createCIERegionForPLT();
+ llvm::StringRef createFDERegionForPLT();
+
private:
X86_32GOT* m_pGOT;
X86_32GOTPLT* m_pGOTPLT;
@@ -223,6 +230,9 @@
void setRelDynSize();
void setRelPLTSize();
+ llvm::StringRef createCIERegionForPLT();
+ llvm::StringRef createFDERegionForPLT();
+
private:
X86_64GOT* m_pGOT;
X86_64GOTPLT* m_pGOTPLT;
diff --git a/lib/Target/X86/X86MCLinker.cpp b/lib/Target/X86/X86MCLinker.cpp
index bad20a9..46d7bb5 100644
--- a/lib/Target/X86/X86MCLinker.cpp
+++ b/lib/Target/X86/X86MCLinker.cpp
@@ -22,9 +22,9 @@
MCLinker* createX86MCLinker(const std::string &pTriple,
LinkerConfig& pConfig,
mcld::Module& pModule,
- MemoryArea& pOutput)
+ FileHandle& pFileHandle)
{
- Triple theTriple(pTriple);
+ llvm::Triple theTriple(pTriple);
if (theTriple.isOSDarwin()) {
assert(0 && "MachO linker has not supported yet");
return NULL;
@@ -34,7 +34,7 @@
return NULL;
}
- return new X86ELFMCLinker(pConfig, pModule, pOutput);
+ return new X86ELFMCLinker(pConfig, pModule, pFileHandle);
}
} // namespace of mcld
diff --git a/lib/Target/X86/X86PLT.cpp b/lib/Target/X86/X86PLT.cpp
index 669a047..d73693b 100644
--- a/lib/Target/X86/X86PLT.cpp
+++ b/lib/Target/X86/X86PLT.cpp
@@ -90,9 +90,7 @@
m_PLT1Size = sizeof (x86_64_plt1);
// create PLT0
new X86_64PLT0(*m_SectionData);
- m_Last = m_SectionData->begin();
}
- m_Last = m_SectionData->begin();
}
X86PLT::~X86PLT()
@@ -128,29 +126,12 @@
return (m_SectionData->size() > 1);
}
-void X86PLT::reserveEntry(size_t pNum)
+PLTEntryBase* X86PLT::create()
{
- PLTEntryBase* plt1_entry = NULL;
-
- for (size_t i = 0; i < pNum; ++i) {
-
- if (LinkerConfig::DynObj == m_Config.codeGenType())
- plt1_entry = new X86_32DynPLT1(*m_SectionData);
- else
- plt1_entry = new X86_32ExecPLT1(*m_SectionData);
-
- if (NULL == plt1_entry)
- fatal(diag::fail_allocate_memory_plt);
- }
-}
-
-PLTEntryBase* X86PLT::consume()
-{
- // This will skip PLT0.
- ++m_Last;
- assert(m_Last != m_SectionData->end() &&
- "The number of PLT Entries and ResolveInfo doesn't match");
- return llvm::cast<PLTEntryBase>(&(*m_Last));
+ if (LinkerConfig::DynObj == m_Config.codeGenType())
+ return new X86_32DynPLT1(*m_SectionData);
+ else
+ return new X86_32ExecPLT1(*m_SectionData);
}
PLTEntryBase* X86PLT::getPLT0() const
diff --git a/lib/Target/X86/X86PLT.h b/lib/Target/X86/X86PLT.h
index 2f4176c..2578d67 100644
--- a/lib/Target/X86/X86PLT.h
+++ b/lib/Target/X86/X86PLT.h
@@ -119,9 +119,7 @@
// hasPLT1 - return if this PLT has any PLT1 entry
bool hasPLT1() const;
- void reserveEntry(size_t pNum = 1) ;
-
- PLTEntryBase* consume();
+ PLTEntryBase* create();
virtual void applyPLT0() = 0;
@@ -134,9 +132,6 @@
PLTEntryBase* getPLT0() const;
protected:
- // the last consumed entry.
- SectionData::iterator m_Last;
-
const uint8_t *m_PLT0;
const uint8_t *m_PLT1;
unsigned int m_PLT0Size;
diff --git a/lib/Target/X86/X86RelocationFunctions.h b/lib/Target/X86/X86RelocationFunctions.h
index 9209242..a4568bb 100644
--- a/lib/Target/X86/X86RelocationFunctions.h
+++ b/lib/Target/X86/X86RelocationFunctions.h
@@ -43,11 +43,11 @@
{ &unsupport, 12, "", 0 }, \
{ &unsupport, 13, "", 0 }, \
{ &unsupport, 14, "R_386_TLS_TPOFF", 0 }, \
- { &tls_ie, 15, "R_386_TLS_IE", 0 }, \
- { &tls_gotie, 16, "R_386_TLS_GOTIE", 0 }, \
- { &tls_le, 17, "R_386_TLS_LE", 0 }, \
- { &tls_gd, 18, "R_386_TLS_GD", 0 }, \
- { &tls_ldm, 19, "R_386_TLS_LDM", 0 }, \
+ { &tls_ie, 15, "R_386_TLS_IE", 32 }, \
+ { &tls_gotie, 16, "R_386_TLS_GOTIE", 32 }, \
+ { &tls_le, 17, "R_386_TLS_LE", 32 }, \
+ { &tls_gd, 18, "R_386_TLS_GD", 32 }, \
+ { &tls_ldm, 19, "R_386_TLS_LDM", 32 }, \
{ &abs, 20, "R_386_16", 16 }, \
{ &rel, 21, "R_386_PC16", 16 }, \
{ &abs, 22, "R_386_8", 8 }, \
@@ -60,7 +60,7 @@
{ &unsupport, 29, "R_386_TLS_LDM_PUSH", 0 }, \
{ &unsupport, 30, "R_386_TLS_LDM_CALL", 0 }, \
{ &unsupport, 31, "R_386_TLS_LDM_POP", 0 }, \
- { &tls_ldo_32, 32, "R_386_TLS_LDO_32", 0 }, \
+ { &tls_ldo_32, 32, "R_386_TLS_LDO_32", 32 }, \
{ &unsupport, 33, "R_386_TLS_IE_32", 0 }, \
{ &unsupport, 34, "R_386_TLS_LE_32", 0 }, \
{ &unsupport, 35, "R_386_TLS_DTPMOD32", 0 }, \
@@ -72,7 +72,7 @@
{ &unsupport, 41, "R_386_TLS_DESC", 0 }, \
{ &unsupport, 42, "R_386_IRELATIVE", 0 }, \
{ &unsupport, 43, "R_386_NUM", 0 }, \
- { &none, 44, "R_386_TLS_OPT", 0 }
+ { &none, 44, "R_386_TLS_OPT", 32 }
#define DECL_X86_64_APPLY_RELOC_FUNC(Name) \
static X86Relocator::Result Name(Relocation& pEntry, X86_64Relocator& pParent);
diff --git a/lib/Target/X86/X86Relocator.cpp b/lib/Target/X86/X86Relocator.cpp
index af8c932..6e3234f 100644
--- a/lib/Target/X86/X86Relocator.cpp
+++ b/lib/Target/X86/X86Relocator.cpp
@@ -13,6 +13,9 @@
#include <mcld/IRBuilder.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/LD/LDSymbol.h>
+#include <mcld/LD/ELFFileFormat.h>
+#include <mcld/LD/ELFSegmentFactory.h>
+#include <mcld/LD/ELFSegment.h>
#include <mcld/Object/ObjectBuilder.h>
#include <llvm/ADT/Twine.h>
@@ -22,7 +25,126 @@
using namespace mcld;
//===--------------------------------------------------------------------===//
-// Relocation Functions and Tables
+// X86_32 Relocation helper function
+//===--------------------------------------------------------------------===//
+/// helper_DynRel - Get an relocation entry in .rel.dyn
+static
+Relocation& helper_DynRel_init(ResolveInfo* pSym,
+ Fragment& pFrag,
+ uint64_t pOffset,
+ X86Relocator::Type pType,
+ X86_32Relocator& pParent)
+{
+ X86_32GNULDBackend& ld_backend = pParent.getTarget();
+ Relocation& rel_entry = *ld_backend.getRelDyn().create();
+ rel_entry.setType(pType);
+ rel_entry.targetRef().assign(pFrag, pOffset);
+ if (pType == llvm::ELF::R_386_RELATIVE || NULL == pSym)
+ rel_entry.setSymInfo(NULL);
+ else
+ rel_entry.setSymInfo(pSym);
+
+ return rel_entry;
+}
+
+/// helper_use_relative_reloc - Check if symbol ceuse relocation
+/// R_386_RELATIVE
+static bool
+helper_use_relative_reloc(const ResolveInfo& pSym,
+ const X86_32Relocator& pFactory)
+
+{
+ // if symbol is dynamic or undefine or preemptible
+ if (pSym.isDyn() ||
+ pSym.isUndef() ||
+ pFactory.getTarget().isSymbolPreemptible(pSym))
+ return false;
+ return true;
+}
+
+static
+X86_32GOTEntry& helper_GOT_init(Relocation& pReloc,
+ bool pHasRel,
+ X86_32Relocator& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ X86_32GNULDBackend& ld_backend = pParent.getTarget();
+ assert(NULL == pParent.getSymGOTMap().lookUp(*rsym));
+
+ X86_32GOTEntry* got_entry = ld_backend.getGOT().create();
+ pParent.getSymGOTMap().record(*rsym, *got_entry);
+
+ if (!pHasRel) {
+ // No corresponding dynamic relocation, initialize to the symbol value.
+ got_entry->setValue(X86Relocator::SymVal);
+ }
+ else {
+ // Initialize got_entry content and the corresponding dynamic relocation.
+ if (helper_use_relative_reloc(*rsym, pParent)) {
+ helper_DynRel_init(rsym, *got_entry, 0x0, llvm::ELF::R_386_RELATIVE,
+ pParent);
+ got_entry->setValue(X86Relocator::SymVal);
+ }
+ else {
+ helper_DynRel_init(rsym, *got_entry, 0x0, llvm::ELF::R_386_GLOB_DAT,
+ pParent);
+ got_entry->setValue(0x0);
+ }
+ }
+ return *got_entry;
+}
+
+static
+X86Relocator::Address helper_GOT_ORG(X86_32Relocator& pParent)
+{
+ return pParent.getTarget().getGOTPLT().addr();
+}
+
+static
+X86Relocator::Address helper_get_GOT_address(Relocation& pReloc,
+ X86_32Relocator& pParent)
+{
+ X86_32GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
+ assert(NULL != got_entry);
+ return pParent.getTarget().getGOT().addr() + got_entry->getOffset();
+}
+
+static
+PLTEntryBase& helper_PLT_init(Relocation& pReloc, X86_32Relocator& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ X86_32GNULDBackend& ld_backend = pParent.getTarget();
+ assert(NULL == pParent.getSymPLTMap().lookUp(*rsym));
+
+ PLTEntryBase* plt_entry = ld_backend.getPLT().create();
+ pParent.getSymPLTMap().record(*rsym, *plt_entry);
+
+ // initialize plt and the corresponding gotplt and dyn rel entry.
+ assert(NULL == pParent.getSymGOTPLTMap().lookUp(*rsym) &&
+ "PLT entry not exist, but GOTPLT entry exist!");
+ X86_32GOTEntry* gotplt_entry = ld_backend.getGOTPLT().create();
+ pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
+
+ // init the corresponding rel entry in .rel.plt
+ Relocation& rel_entry = *ld_backend.getRelPLT().create();
+ rel_entry.setType(llvm::ELF::R_386_JUMP_SLOT);
+ rel_entry.targetRef().assign(*gotplt_entry);
+ rel_entry.setSymInfo(rsym);
+ return *plt_entry;
+}
+
+static
+X86Relocator::Address helper_get_PLT_address(ResolveInfo& pSym, X86_32Relocator& pParent)
+{
+ PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(pSym);
+ assert(NULL != plt_entry);
+ return pParent.getTarget().getPLT().addr() + plt_entry->getOffset();
+}
+
+//===--------------------------------------------------------------------===//
+// X86_32 Relocation Functions and Tables
//===--------------------------------------------------------------------===//
DECL_X86_32_APPLY_RELOC_FUNCS
@@ -58,7 +180,8 @@
void X86Relocator::scanRelocation(Relocation& pReloc,
IRBuilder& pLinker,
Module& pModule,
- LDSection& pSection)
+ LDSection& pSection,
+ Input& pInput)
{
if (LinkerConfig::Object == config().codeGenType())
return;
@@ -67,7 +190,6 @@
assert(NULL != rsym &&
"ResolveInfo of relocation not set while scanRelocation");
- pReloc.updateAddend();
assert(NULL != pSection.getLink());
if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC))
return;
@@ -82,12 +204,12 @@
// check if we should issue undefined reference for the relocation target
// symbol
if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
- fatal(diag::undefined_reference) << rsym->name();
+ issueUndefRef(pReloc, pSection, pInput);
}
void X86Relocator::addCopyReloc(ResolveInfo& pSym, X86GNULDBackend& pTarget)
{
- Relocation& rel_entry = *pTarget.getRelDyn().consumeEntry();
+ Relocation& rel_entry = *pTarget.getRelDyn().create();
rel_entry.setType(pTarget.getCopyRelType());
assert(pSym.outSymbol()->hasFragRef());
rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef());
@@ -202,9 +324,9 @@
}
void X86_32Relocator::scanLocalReloc(Relocation& pReloc,
- IRBuilder& pBuilder,
- Module& pModule,
- LDSection& pSection)
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
@@ -212,13 +334,31 @@
switch(pReloc.type()){
case llvm::ELF::R_386_32:
+ // If buiding PIC object (shared library or PIC executable),
+ // a dynamic relocations with RELATIVE type to this location is needed.
+ // Reserve an entry in .rel.dyn
+ if (config().isCodeIndep()) {
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ getTarget().checkAndSetHasTextRel(*pSection.getLink());
+ // set up the dyn rel directly
+ helper_DynRel_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ llvm::ELF::R_386_RELATIVE,
+ *this);
+ }
+ return;
+
case llvm::ELF::R_386_16:
case llvm::ELF::R_386_8:
// If buiding PIC object (shared library or PIC executable),
// a dynamic relocations with RELATIVE type to this location is needed.
// Reserve an entry in .rel.dyn
if (config().isCodeIndep()) {
- getTarget().getRelDyn().reserveEntry();
+ // set up the dyn rel directly
+ helper_DynRel_init(rsym, *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(), pReloc.type(), *this);
// set Rel bit
rsym->setReserved(rsym->reserved() | ReserveRel);
getTarget().checkAndSetHasTextRel(*pSection.getLink());
@@ -236,28 +376,25 @@
case llvm::ELF::R_386_GOT32:
// Symbol needs GOT entry, reserve entry in .got
// return if we already create GOT for this symbol
- if (rsym->reserved() & (ReserveGOT | GOTRel))
+ if (rsym->reserved() & ReserveGOT)
return;
- // FIXME: check STT_GNU_IFUNC symbol
- getTarget().getGOT().reserve();
- // If the GOT is used in statically linked binaries,
- // the GOT entry is enough and no relocation is needed.
- if (config().isCodeStatic()) {
- rsym->setReserved(rsym->reserved() | ReserveGOT);
- return;
- }
+ // FIXME: check STT_GNU_IFUNC symbol
+
// If building shared object or the symbol is undefined, a dynamic
// relocation is needed to relocate this GOT entry. Reserve an
// entry in .rel.dyn
if (LinkerConfig::DynObj ==
config().codeGenType() || rsym->isUndef() || rsym->isDyn()) {
- getTarget().getRelDyn().reserveEntry();
- // set GOTRel bit
- rsym->setReserved(rsym->reserved() | GOTRel);
+ helper_GOT_init(pReloc, true, *this);
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
}
- // set GOT bit
+
+ // elsewhere if the GOT is used in statically linked binaries,
+ // the GOT entry is enough and no relocation is needed.
+ helper_GOT_init(pReloc, false, *this);
rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
@@ -268,13 +405,9 @@
case llvm::ELF::R_386_TLS_GD: {
// FIXME: no linker optimization for TLS relocation
- if (rsym->reserved() & GOTRel)
+ if (rsym->reserved() & ReserveGOT)
return;
- getTarget().getGOT().reserve(2);
- // reserve an rel entry
- getTarget().getRelDyn().reserveEntry();
- // set GOTRel bit
- rsym->setReserved(rsym->reserved() | GOTRel);
+
// define the section symbol for .tdata or .tbss
// the target symbol of the created dynamic relocation should be the
// section symbol of the section which this symbol defined. so we
@@ -282,19 +415,40 @@
ELFFileFormat* file_format = getTarget().getOutputFormat();
const LDSection* sym_sect =
&rsym->outSymbol()->fragRef()->frag()->getParent()->getSection();
+ LDSymbol* sect_sym = NULL;
if (&file_format->getTData() == sym_sect) {
- if (!getTarget().hasTDATASymbol())
- getTarget().setTDATASymbol(*pModule.getSectionSymbolSet().get(*sym_sect));
+ if (!getTarget().hasTDATASymbol()) {
+ sect_sym = pModule.getSectionSymbolSet().get(*sym_sect);
+ getTarget().setTDATASymbol(*sect_sym);
+ }
}
else if (&file_format->getTBSS() == sym_sect || rsym->isCommon()) {
- if (!getTarget().hasTBSSSymbol())
- getTarget().setTBSSSymbol(*pModule.getSectionSymbolSet().get(*sym_sect));
+ if (!getTarget().hasTBSSSymbol()) {
+ sect_sym = pModule.getSectionSymbolSet().get(*sym_sect);
+ getTarget().setTBSSSymbol(*sect_sym);
+ }
}
else
error(diag::invalid_tls) << rsym->name() << sym_sect->name();
+
+ // set up a pair of got entries and a dyn rel
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
+ X86_32GOTEntry* got_entry1 = getTarget().getGOT().create();
+ X86_32GOTEntry* got_entry2 = getTarget().getGOT().create();
+ getSymGOTMap().record(*rsym, *got_entry1, *got_entry2);
+ // set up value of got entries, the value of got_entry2 should be the
+ // symbol value, which has to be set during apply relocation
+ got_entry1->setValue(0x0);
+
+ // setup dyn rel for got_entry1
+ Relocation& rel_entry1 = helper_DynRel_init(rsym, *got_entry1, 0x0,
+ llvm::ELF::R_386_TLS_DTPMOD32, *this);
+ // for local tls symbol, add rel entry against the section symbol this
+ // symbol belong to (.tdata or .tbss)
+ rel_entry1.setSymInfo(sect_sym->resolveInfo());
return;
}
-
case llvm::ELF::R_386_TLS_LDM:
getTLSModuleID();
return;
@@ -302,46 +456,65 @@
case llvm::ELF::R_386_TLS_LDO_32:
return;
- case llvm::ELF::R_386_TLS_IE:
+ case llvm::ELF::R_386_TLS_IE: {
getTarget().setHasStaticTLS();
- // if buildint shared object, a RELATIVE dynamic relocation is needed
+
+ // if building shared object, a RELATIVE dynamic relocation is needed
if (LinkerConfig::DynObj == config().codeGenType()) {
- getTarget().getRelDyn().reserveEntry();
+ helper_DynRel_init(rsym, *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ llvm::ELF::R_386_RELATIVE, *this);
rsym->setReserved(rsym->reserved() | ReserveRel);
getTarget().checkAndSetHasTextRel(*pSection.getLink());
- } else {
+ }
+ else {
// for local sym, we can convert ie to le if not building shared object
convertTLSIEtoLE(pReloc, pSection);
return;
}
- if (rsym->reserved() & GOTRel)
- return;
- // reserve got and dyn relocation entries for tp-relative offset
- getTarget().getGOT().reserve();
- getTarget().getRelDyn().reserveEntry();
- // set GOTRel bit
- rsym->setReserved(rsym->reserved() | GOTRel);
- getTarget().getRelDyn().addSymbolToDynSym(*rsym->outSymbol());
- return;
- case llvm::ELF::R_386_TLS_GOTIE:
- getTarget().setHasStaticTLS();
- if (rsym->reserved() & GOTRel)
+ if (rsym->reserved() & ReserveGOT)
return;
- // reserve got and dyn relocation entries for tp-relative offset
- getTarget().getGOT().reserve();
- getTarget().getRelDyn().reserveEntry();
- // set GOTRel bit
- rsym->setReserved(rsym->reserved() | GOTRel);
+
+ // set up the got and the corresponding rel entry
+ X86_32GOTEntry* got_entry = getTarget().getGOT().create();
+ getSymGOTMap().record(*rsym, *got_entry);
+ got_entry->setValue(0x0);
+ helper_DynRel_init(rsym, *got_entry, 0x0, llvm::ELF::R_386_TLS_TPOFF,
+ *this);
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
+ // add symbol to dyn sym table
getTarget().getRelDyn().addSymbolToDynSym(*rsym->outSymbol());
return;
+ }
+
+ case llvm::ELF::R_386_TLS_GOTIE: {
+ getTarget().setHasStaticTLS();
+ if (rsym->reserved() & ReserveGOT)
+ return;
+ // set up the got and the corresponding dyn rel
+ X86_32GOTEntry* got_entry = getTarget().getGOT().create();
+ getSymGOTMap().record(*rsym, *got_entry);
+ got_entry->setValue(0x0);
+ helper_DynRel_init(rsym, *got_entry, 0x0, llvm::ELF::R_386_TLS_TPOFF,
+ *this);
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
+ getTarget().getRelDyn().addSymbolToDynSym(*rsym->outSymbol());
+ return;
+ }
case llvm::ELF::R_386_TLS_LE:
case llvm::ELF::R_386_TLS_LE_32:
getTarget().setHasStaticTLS();
// if buildint shared object, a dynamic relocation is needed
if (LinkerConfig::DynObj == config().codeGenType()) {
- getTarget().getRelDyn().reserveEntry();
+ helper_DynRel_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ llvm::ELF::R_386_TLS_TPOFF,
+ *this);
rsym->setReserved(rsym->reserved() | ReserveRel);
getTarget().checkAndSetHasTextRel(*pSection.getLink());
// the target symbol of the dynamic relocation is rsym, so we need to
@@ -359,9 +532,9 @@
}
void X86_32Relocator::scanGlobalReloc(Relocation& pReloc,
- IRBuilder& pBuilder,
- Module& pModule,
- LDSection& pSection)
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
@@ -375,29 +548,39 @@
if (getTarget().symbolNeedsPLT(*rsym)) {
// create plt for this symbol if it does not have one
if (!(rsym->reserved() & ReservePLT)){
- // Symbol needs PLT entry, we need to reserve a PLT entry
+ // Symbol needs PLT entry, we need a PLT entry
// and the corresponding GOT and dynamic relocation entry
- // in .got and .rel.plt. (GOT entry will be reserved simultaneously
- // when calling X86PLT->reserveEntry())
- getTarget().getPLT().reserveEntry();
- getTarget().getGOTPLT().reserve();
- getTarget().getRelPLT().reserveEntry();
+ // in .got and .rel.plt.
+ helper_PLT_init(pReloc, *this);
// set PLT bit
rsym->setReserved(rsym->reserved() | ReservePLT);
}
}
- if (getTarget().symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), true)) {
- // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
- getTarget().getRelDyn().reserveEntry();
+ if (getTarget().symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT),
+ true)) {
+ // symbol needs dynamic relocation entry, set up the dynrel entry
if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym, getTarget());
addCopyReloc(*cpy_sym.resolveInfo(), getTarget());
}
else {
- // set Rel bit
+ // set Rel bit and the dyn rel
rsym->setReserved(rsym->reserved() | ReserveRel);
- getTarget().checkAndSetHasTextRel(pSection);
+ getTarget().checkAndSetHasTextRel(*pSection.getLink());
+ if (llvm::ELF::R_386_32 == pReloc.type() &&
+ helper_use_relative_reloc(*rsym, *this))
+ helper_DynRel_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ llvm::ELF::R_386_RELATIVE,
+ *this);
+ else
+ helper_DynRel_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ pReloc.type(),
+ *this);
}
}
return;
@@ -422,17 +605,13 @@
// if symbol is defined in the ouput file and it's not
// preemptible, no need plt
if (rsym->isDefine() && !rsym->isDyn() &&
- !getTarget().isSymbolPreemptible(*rsym)) {
+ !getTarget().isSymbolPreemptible(*rsym))
return;
- }
- // Symbol needs PLT entry, we need to reserve a PLT entry
+ // Symbol needs PLT entry, we need a PLT entry
// and the corresponding GOT and dynamic relocation entry
- // in .got and .rel.plt. (GOT entry will be reserved simultaneously
- // when calling X86PLT->reserveEntry())
- getTarget().getPLT().reserveEntry();
- getTarget().getGOTPLT().reserve();
- getTarget().getRelPLT().reserveEntry();
+ // in .got and .rel.plt
+ helper_PLT_init(pReloc, *this);
// set PLT bit
rsym->setReserved(rsym->reserved() | ReservePLT);
return;
@@ -440,26 +619,16 @@
case llvm::ELF::R_386_GOT32:
// Symbol needs GOT entry, reserve entry in .got
// return if we already create GOT for this symbol
- if (rsym->reserved() & (ReserveGOT | GOTRel))
+ if (rsym->reserved() & ReserveGOT)
return;
- getTarget().getGOT().reserve();
-
- // If the GOT is used in statically linked binaries,
- // the GOT entry is enough and no relocation is needed.
- if (config().isCodeStatic()) {
- rsym->setReserved(rsym->reserved() | ReserveGOT);
- return;
- }
// If building shared object or the symbol is undefined, a dynamic
// relocation is needed to relocate this GOT entry. Reserve an
// entry in .rel.dyn
if (LinkerConfig::DynObj ==
- config().codeGenType() || rsym->isUndef() || rsym->isDyn()) {
- getTarget().getRelDyn().reserveEntry();
- // set GOTRel bit
- rsym->setReserved(rsym->reserved() | GOTRel);
- return;
- }
+ config().codeGenType() || rsym->isUndef() || rsym->isDyn())
+ helper_GOT_init(pReloc, true, *this);
+ else
+ helper_GOT_init(pReloc, false, *this);
// set GOT bit
rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
@@ -472,43 +641,65 @@
LinkerConfig::DynObj != config().codeGenType()) {
// create plt for this symbol if it does not have one
if (!(rsym->reserved() & ReservePLT)){
- // Symbol needs PLT entry, we need to reserve a PLT entry
+ // Symbol needs PLT entry, we need a PLT entry
// and the corresponding GOT and dynamic relocation entry
- // in .got and .rel.plt. (GOT entry will be reserved simultaneously
- // when calling X86PLT->reserveEntry())
- getTarget().getPLT().reserveEntry();
- getTarget().getGOTPLT().reserve();
- getTarget().getRelPLT().reserveEntry();
+ // in .got and .rel.plt.
// set PLT bit
+ helper_PLT_init(pReloc, *this);
rsym->setReserved(rsym->reserved() | ReservePLT);
}
}
- if (getTarget().symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), false)) {
- // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
- getTarget().getRelDyn().reserveEntry();
+ if (getTarget().symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT),
+ false)) {
+ // symbol needs dynamic relocation entry, setup an entry in .rel.dyn
if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
- LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym, getTarget());
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym,
+ getTarget());
addCopyReloc(*cpy_sym.resolveInfo(), getTarget());
}
else {
- // set Rel bit
+ // set Rel bit and the dyn rel
rsym->setReserved(rsym->reserved() | ReserveRel);
- getTarget().checkAndSetHasTextRel(pSection);
+ getTarget().checkAndSetHasTextRel(*pSection.getLink());
+ if (llvm::ELF::R_386_32 == pReloc.type() &&
+ helper_use_relative_reloc(*rsym, *this))
+ helper_DynRel_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ llvm::ELF::R_386_RELATIVE,
+ *this);
+ else
+ helper_DynRel_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ pReloc.type(),
+ *this);
}
}
return;
case llvm::ELF::R_386_TLS_GD: {
// FIXME: no linker optimization for TLS relocation
- if (rsym->reserved() & GOTRel)
+ if (rsym->reserved() & ReserveGOT)
return;
- // reserve two pairs of got entry and dynamic relocation
- getTarget().getGOT().reserve(2);
- getTarget().getRelDyn().reserveEntry(2);
+
+ // set up a pair of got entries and a pair of dyn rel
+ X86_32GOTEntry* got_entry1 = getTarget().getGOT().create();
+ X86_32GOTEntry* got_entry2 = getTarget().getGOT().create();
+ getSymGOTMap().record(*rsym, *got_entry1, *got_entry2);
+ got_entry1->setValue(0x0);
+ got_entry2->setValue(0x0);
+ // setup dyn rel for got entries against rsym
+ helper_DynRel_init(rsym, *got_entry1, 0x0,
+ llvm::ELF::R_386_TLS_DTPMOD32, *this);
+ helper_DynRel_init(rsym, *got_entry2, 0x0,
+ llvm::ELF::R_386_TLS_DTPOFF32, *this);
+
+ // add the rsym to dynamic symbol table
getTarget().getRelDyn().addSymbolToDynSym(*rsym->outSymbol());
- // set GOTRel bit
- rsym->setReserved(rsym->reserved() | GOTRel);
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
}
@@ -519,11 +710,13 @@
case llvm::ELF::R_386_TLS_LDO_32:
return;
- case llvm::ELF::R_386_TLS_IE:
+ case llvm::ELF::R_386_TLS_IE: {
getTarget().setHasStaticTLS();
// if buildint shared object, a RELATIVE dynamic relocation is needed
if (LinkerConfig::DynObj == config().codeGenType()) {
- getTarget().getRelDyn().reserveEntry();
+ helper_DynRel_init(rsym, *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ llvm::ELF::R_386_RELATIVE, *this);
rsym->setReserved(rsym->reserved() | ReserveRel);
getTarget().checkAndSetHasTextRel(*pSection.getLink());
} else {
@@ -533,34 +726,45 @@
return;
}
}
- if (rsym->reserved() & GOTRel)
+ if (rsym->reserved() & ReserveGOT)
return;
- // reserve got and dyn relocation entries for tp-relative offset
- getTarget().getGOT().reserve();
- getTarget().getRelDyn().reserveEntry();
- getTarget().getRelDyn().addSymbolToDynSym(*rsym->outSymbol());
- // set GOTRel bit
- rsym->setReserved(rsym->reserved() | GOTRel);
+ // set up the got and the corresponding rel entry
+ X86_32GOTEntry* got_entry = getTarget().getGOT().create();
+ getSymGOTMap().record(*rsym, *got_entry);
+ got_entry->setValue(0x0);
+ helper_DynRel_init(rsym, *got_entry, 0x0, llvm::ELF::R_386_TLS_TPOFF,
+ *this);
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
+ }
- case llvm::ELF::R_386_TLS_GOTIE:
+ case llvm::ELF::R_386_TLS_GOTIE: {
getTarget().setHasStaticTLS();
- if (rsym->reserved() & GOTRel)
+ if (rsym->reserved() & ReserveGOT)
return;
- // reserve got and dyn relocation entries for tp-relative offset
- getTarget().getGOT().reserve();
- getTarget().getRelDyn().reserveEntry();
+ // set up the got and the corresponding dyn rel
+ X86_32GOTEntry* got_entry = getTarget().getGOT().create();
+ getSymGOTMap().record(*rsym, *got_entry);
+ got_entry->setValue(0x0);
+ helper_DynRel_init(rsym, *got_entry, 0x0, llvm::ELF::R_386_TLS_TPOFF,
+ *this);
getTarget().getRelDyn().addSymbolToDynSym(*rsym->outSymbol());
- // set GOTRel bit
- rsym->setReserved(rsym->reserved() | GOTRel);
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
+ }
case llvm::ELF::R_386_TLS_LE:
case llvm::ELF::R_386_TLS_LE_32:
getTarget().setHasStaticTLS();
// if buildint shared object, a dynamic relocation is needed
if (LinkerConfig::DynObj == config().codeGenType()) {
- getTarget().getRelDyn().reserveEntry();
+ helper_DynRel_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ llvm::ELF::R_386_TLS_TPOFF,
+ *this);
getTarget().getRelDyn().addSymbolToDynSym(*rsym->outSymbol());
rsym->setReserved(rsym->reserved() | ReserveRel);
getTarget().checkAndSetHasTextRel(*pSection.getLink());
@@ -583,16 +787,11 @@
return *got_entry;
// Allocate 2 got entries and 1 dynamic reloc for R_386_TLS_LDM
- getTarget().getGOT().reserve(2);
- got_entry = getTarget().getGOT().consume();
- getTarget().getGOT().consume()->setValue(0x0);
+ got_entry = getTarget().getGOT().create();
+ getTarget().getGOT().create()->setValue(0x0);
- getTarget().getRelDyn().reserveEntry();
- Relocation* rel_entry = getTarget().getRelDyn().consumeEntry();
- rel_entry->setType(llvm::ELF::R_386_TLS_DTPMOD32);
- rel_entry->targetRef().assign(*got_entry, 0x0);
- rel_entry->setSymInfo(NULL);
-
+ helper_DynRel_init(NULL, *got_entry, 0x0, llvm::ELF::R_386_TLS_DTPMOD32,
+ *this);
return *got_entry;
}
@@ -611,10 +810,11 @@
off = 0;
FragmentRef* fragref = FragmentRef::Create(*pReloc.targetRef().frag(), off);
- // TODO: add symbols for R_386_TLS_OPT relocs
Relocation* reloc = Relocation::Create(X86_32Relocator::R_386_TLS_OPT,
*fragref,
0x0);
+ // FIXME: should we create a special symbol for the tls opt instead?
+ reloc->setSymInfo(pReloc.symInfo());
// 2. modify the opcodes to the appropriate ones
uint8_t* op = (reinterpret_cast<uint8_t*>(&reloc->target()));
@@ -647,154 +847,9 @@
pReloc.setType(llvm::ELF::R_386_TLS_LE);
}
-//===--------------------------------------------------------------------===//
-// Relocation helper function
-//===--------------------------------------------------------------------===//
-
-/// helper_DynRel - Get an relocation entry in .rel.dyn
-static
-Relocation& helper_DynRel(ResolveInfo* pSym,
- Fragment& pFrag,
- uint64_t pOffset,
- X86Relocator::Type pType,
- X86_32Relocator& pParent)
-{
- X86_32GNULDBackend& ld_backend = pParent.getTarget();
- Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
- rel_entry.setType(pType);
- rel_entry.targetRef().assign(pFrag, pOffset);
- if (pType == llvm::ELF::R_386_RELATIVE || NULL == pSym)
- rel_entry.setSymInfo(0);
- else
- rel_entry.setSymInfo(pSym);
-
- return rel_entry;
-}
-
-
-/// helper_use_relative_reloc - Check if symbol can use relocation
-/// R_386_RELATIVE
-static bool
-helper_use_relative_reloc(const ResolveInfo& pSym,
- const X86_32Relocator& pFactory)
-
-{
- // if symbol is dynamic or undefine or preemptible
- if (pSym.isDyn() ||
- pSym.isUndef() ||
- pFactory.getTarget().isSymbolPreemptible(pSym))
- return false;
- return true;
-}
-
-static
-X86_32GOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
- X86_32Relocator& pParent)
-{
- // rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
- X86_32GNULDBackend& ld_backend = pParent.getTarget();
-
- X86_32GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
- if (NULL != got_entry)
- return *got_entry;
-
- // not found
- got_entry = ld_backend.getGOT().consume();
- pParent.getSymGOTMap().record(*rsym, *got_entry);
-
- // If we first get this GOT entry, we should initialize it.
- if (rsym->reserved() & X86Relocator::ReserveGOT) {
- // No corresponding dynamic relocation, initialize to the symbol value.
- got_entry->setValue(pReloc.symValue());
- }
- else if (rsym->reserved() & X86Relocator::GOTRel) {
- // Initialize got_entry content and the corresponding dynamic relocation.
- if (helper_use_relative_reloc(*rsym, pParent)) {
- helper_DynRel(rsym, *got_entry, 0x0, llvm::ELF::R_386_RELATIVE, pParent);
- got_entry->setValue(pReloc.symValue());
- }
- else {
- helper_DynRel(rsym, *got_entry, 0x0, llvm::ELF::R_386_GLOB_DAT, pParent);
- got_entry->setValue(0);
- }
- }
- else {
- fatal(diag::reserve_entry_number_mismatch_got);
- }
- return *got_entry;
-}
-
-
-static
-X86Relocator::Address helper_GOT_ORG(X86_32Relocator& pParent)
-{
- return pParent.getTarget().getGOTPLT().addr();
-}
-
-
-static
-X86Relocator::Address helper_GOT(Relocation& pReloc, X86_32Relocator& pParent)
-{
- X86_32GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent);
- X86Relocator::Address got_addr = pParent.getTarget().getGOT().addr();
- return got_addr + got_entry.getOffset();
-}
-
-
-static
-PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc,
- X86_32Relocator& pParent)
-{
- // rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
- X86_32GNULDBackend& ld_backend = pParent.getTarget();
-
- PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(*rsym);
- if (NULL != plt_entry)
- return *plt_entry;
-
- // not found
- plt_entry = ld_backend.getPLT().consume();
- pParent.getSymPLTMap().record(*rsym, *plt_entry);
- // If we first get this PLT entry, we should initialize it.
- if (rsym->reserved() & X86Relocator::ReservePLT) {
- X86_32GOTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym);
- assert(NULL == gotplt_entry && "PLT entry not exist, but DynRel entry exist!");
- gotplt_entry = ld_backend.getGOTPLT().consume();
- pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
- // init the corresponding rel entry in .rel.plt
- Relocation& rel_entry = *ld_backend.getRelPLT().consumeEntry();
- rel_entry.setType(llvm::ELF::R_386_JUMP_SLOT);
- rel_entry.targetRef().assign(*gotplt_entry);
- rel_entry.setSymInfo(rsym);
- }
- else {
- fatal(diag::reserve_entry_number_mismatch_plt);
- }
-
- return *plt_entry;
-}
-
-
-static
-X86Relocator::Address helper_PLT_ORG(X86_32Relocator& pParent)
-{
- return pParent.getTarget().getPLT().addr();
-}
-
-
-static
-X86Relocator::Address helper_PLT(Relocation& pReloc, X86_32Relocator& pParent)
-{
- PLTEntryBase& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
- return helper_PLT_ORG(pParent) + plt_entry.getOffset();
-}
-
-
-//=========================================//
-// Each relocation function implementation //
-//=========================================//
+//================================================//
+// X86_32 Each relocation function implementation //
+//================================================//
// R_386_NONE
X86Relocator::Result none(Relocation& pReloc, X86_32Relocator& pParent)
@@ -811,13 +866,12 @@
Relocator::DWord A = pReloc.target() + pReloc.addend();
Relocator::DWord S = pReloc.symValue();
bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel(
- *rsym,
- (rsym->reserved() & X86Relocator::ReservePLT),
- true);
- FragmentRef &target_fragref = pReloc.targetRef();
- Fragment *target_frag = target_fragref.frag();
+ *rsym,
+ (rsym->reserved() & X86Relocator::ReservePLT),
+ true);
- LDSection& target_sect = target_frag->getParent()->getSection();
+
+ LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
// If the flag of target section is not ALLOC, we will not scan this relocation
// but perform static relocation. (e.g., applying .debug section)
if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
@@ -825,36 +879,18 @@
return X86Relocator::OK;
}
- // A local symbol may need REL Type dynamic relocation
- if (rsym->isLocal() && has_dyn_rel) {
- X86Relocator::Type pType = pReloc.type();
- if (llvm::ELF::R_386_32 == pType)
- pType = llvm::ELF::R_386_RELATIVE;
- helper_DynRel(rsym, *target_frag, target_fragref.offset(), pType, pParent);
- pReloc.target() = S + A;
- return X86Relocator::OK;
- }
-
// An external symbol may need PLT and dynamic relocation
if (!rsym->isLocal()) {
if (rsym->reserved() & X86Relocator::ReservePLT) {
- S = helper_PLT(pReloc, pParent);
+ S = helper_get_PLT_address(*rsym, pParent);
}
// If we generate a dynamic relocation (except R_386_RELATIVE)
// for a place, we should not perform static relocation on it
// in order to keep the addend store in the place correct.
- if (has_dyn_rel) {
- if (llvm::ELF::R_386_32 == pReloc.type() &&
- helper_use_relative_reloc(*rsym, pParent)) {
- helper_DynRel(rsym, *target_frag, target_fragref.offset(),
- llvm::ELF::R_386_RELATIVE, pParent);
- }
- else {
- helper_DynRel(rsym, *target_frag, target_fragref.offset(),
- pReloc.type(), pParent);
+ if (has_dyn_rel)
+ if (llvm::ELF::R_386_32 != pReloc.type() ||
+ (!helper_use_relative_reloc(*rsym, pParent)))
return X86Relocator::OK;
- }
- }
}
// perform static relocation
@@ -871,6 +907,10 @@
Relocator::DWord A = pReloc.target() + pReloc.addend();
Relocator::DWord S = pReloc.symValue();
Relocator::DWord P = pReloc.place();
+ bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel(
+ *rsym,
+ (rsym->reserved() & X86Relocator::ReservePLT),
+ true);
LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
// If the flag of target section is not ALLOC, we will not scan this relocation
@@ -883,23 +923,12 @@
// An external symbol may need PLT and dynamic relocation
if (!rsym->isLocal()) {
if (rsym->reserved() & X86Relocator::ReservePLT) {
- S = helper_PLT(pReloc, pParent);
- pReloc.target() = S + A - P;
+ S = helper_get_PLT_address(*rsym, pParent);
+ pReloc.target() = S + A - P;
}
- if (pParent.getTarget().symbolNeedsDynRel(
- *rsym,
- (rsym->reserved() & X86Relocator::ReservePLT),
- false)) {
- if (helper_use_relative_reloc(*rsym, pParent) ) {
- helper_DynRel(rsym, *pReloc.targetRef().frag(),
- pReloc.targetRef().offset(), llvm::ELF::R_386_RELATIVE, pParent);
- }
- else {
- helper_DynRel(rsym, *pReloc.targetRef().frag(),
- pReloc.targetRef().offset(), pReloc.type(), pParent);
- return X86Relocator::OK;
- }
- }
+ if (has_dyn_rel)
+ if (!helper_use_relative_reloc(*rsym, pParent))
+ return X86Relocator::OK;
}
// perform static relocation
@@ -931,11 +960,18 @@
// R_386_GOT32: GOT(S) + A - GOT_ORG
X86Relocator::Result got32(Relocation& pReloc, X86_32Relocator& pParent)
{
- if (!(pReloc.symInfo()->reserved()
- & (X86Relocator::ReserveGOT | X86Relocator::GOTRel))) {
+ ResolveInfo* rsym = pReloc.symInfo();
+ if (!(rsym->reserved() & (X86Relocator::ReserveGOT)))
return X86Relocator::BadReloc;
- }
- X86Relocator::Address GOT_S = helper_GOT(pReloc, pParent);
+
+ // set up got entry value if the got has no dyn rel or
+ // the dyn rel is RELATIVE
+ X86_32GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
+ assert(NULL != got_entry);
+ if (got_entry->getValue() == X86Relocator::SymVal)
+ got_entry->setValue(pReloc.symValue());
+
+ X86Relocator::Address GOT_S = helper_get_GOT_address(pReloc, pParent);
Relocator::DWord A = pReloc.target() + pReloc.addend();
X86Relocator::Address GOT_ORG = helper_GOT_ORG(pParent);
// Apply relocation.
@@ -949,7 +985,7 @@
// PLT_S depends on if there is a PLT entry.
X86Relocator::Address PLT_S;
if ((pReloc.symInfo()->reserved() & X86Relocator::ReservePLT))
- PLT_S = helper_PLT(pReloc, pParent);
+ PLT_S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
else
PLT_S = pReloc.symValue();
Relocator::DWord A = pReloc.target() + pReloc.addend();
@@ -964,50 +1000,19 @@
// global-dynamic
ResolveInfo* rsym = pReloc.symInfo();
// must reserve two pairs of got and dynamic relocation
- if (!(rsym->reserved() & X86Relocator::GOTRel)) {
- return X86Relocator::BadReloc;
- }
+ if (!(rsym->reserved() & X86Relocator::ReserveGOT))
+ return X86Relocator::BadReloc;
- X86_32GNULDBackend& ld_backend = pParent.getTarget();
ELFFileFormat* file_format = pParent.getTarget().getOutputFormat();
// setup corresponding got and dynamic relocatio entries:
// get first got entry, if there is already a got entry for rsym, then apply
// this relocation to the got entry directly. If not, setup the corresponding
// got and dyn relocation entries
- X86_32GOTEntry* got_entry1 = pParent.getSymGOTMap().lookUp(*rsym);
+ X86_32GOTEntry* got_entry1 = pParent.getSymGOTMap().lookUpFirstEntry(*rsym);
- if (NULL == got_entry1) {
- // get and init two got entries if not exist
- got_entry1 = ld_backend.getGOT().consume();
- pParent.getSymGOTMap().record(*rsym, *got_entry1);
- X86_32GOTEntry* got_entry2 = ld_backend.getGOT().consume();
- got_entry1->setValue(0x0);
- got_entry2->setValue(0x0);
- // setup dyn rel for get_entry1
- Relocation& rel_entry1 = helper_DynRel(rsym, *got_entry1, 0x0,
- llvm::ELF::R_386_TLS_DTPMOD32, pParent);
- if (rsym->isLocal()) {
- // for local symbol, set got_entry2 to symbol value
- got_entry2->setValue(pReloc.symValue());
-
- // for local tls symbol, add rel entry against the section symbol this
- // symbol belong to (.tdata or .tbss)
- const LDSection* sym_sect =
- &rsym->outSymbol()->fragRef()->frag()->getParent()->getSection();
- ResolveInfo* sect_sym = NULL;
- if (&file_format->getTData() == sym_sect)
- sect_sym = pParent.getTarget().getTDATASymbol().resolveInfo();
- else
- sect_sym = pParent.getTarget().getTBSSSymbol().resolveInfo();
- rel_entry1.setSymInfo(sect_sym);
- }
- else {
- // for non-local symbol, add a pair of rel entries against this symbol
- // for those two got entries
- helper_DynRel(rsym, *got_entry2, 0x0,
- llvm::ELF::R_386_TLS_DTPOFF32, pParent);
- }
- }
+ // set the got_entry2 value to symbol value
+ if (rsym->isLocal())
+ pParent.getSymGOTMap().lookUpSecondEntry(*rsym)->setValue(pReloc.symValue());
// perform relocation to the first got entry
Relocator::DWord A = pReloc.target() + pReloc.addend();
@@ -1051,31 +1056,13 @@
X86Relocator::Result tls_ie(Relocation& pReloc, X86_32Relocator& pParent)
{
ResolveInfo* rsym = pReloc.symInfo();
- if (!(rsym->reserved() & X86Relocator::GOTRel)) {
+ if (!(rsym->reserved() & X86Relocator::ReserveGOT)) {
return X86Relocator::BadReloc;
}
- if (rsym->reserved() & X86Relocator::ReserveRel) {
- // when building shared object, set up a RELATIVE dynamic relocation
- helper_DynRel(rsym, *pReloc.targetRef().frag(), pReloc.targetRef().offset(),
- llvm::ELF::R_386_RELATIVE, pParent);
- }
-
// set up the got and dynamic relocation entries if not exist
X86_32GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
- if (NULL == got_entry) {
- // set got entry
- X86_32GNULDBackend& ld_backend = pParent.getTarget();
- got_entry = ld_backend.getGOT().consume();
- pParent.getSymGOTMap().record(*rsym, *got_entry);
- got_entry->setValue(0x0);
- // set relocation entry
- Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
- rel_entry.setType(llvm::ELF::R_386_TLS_TPOFF);
- rel_entry.setSymInfo(rsym);
- rel_entry.targetRef().assign(*got_entry);
- }
-
+ assert(NULL != got_entry);
// perform relocation to the absolute address of got_entry
X86Relocator::Address GOT_S =
pParent.getTarget().getGOT().addr() + got_entry->getOffset();
@@ -1090,24 +1077,13 @@
X86Relocator::Result tls_gotie(Relocation& pReloc, X86_32Relocator& pParent)
{
ResolveInfo* rsym = pReloc.symInfo();
- if (!(rsym->reserved() & X86Relocator::GOTRel)) {
+ if (!(rsym->reserved() & X86Relocator::ReserveGOT)) {
return X86Relocator::BadReloc;
}
// set up the got and dynamic relocation entries if not exist
X86_32GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
- if (NULL == got_entry) {
- // set got entry
- X86_32GNULDBackend& ld_backend = pParent.getTarget();
- got_entry = ld_backend.getGOT().consume();
- pParent.getSymGOTMap().record(*rsym, *got_entry);
- got_entry->setValue(0x0);
- // set relocation entry
- Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
- rel_entry.setType(llvm::ELF::R_386_TLS_TPOFF);
- rel_entry.setSymInfo(rsym);
- rel_entry.targetRef().assign(*got_entry);
- }
+ assert(NULL != got_entry);
// All GOT offsets are relative to the end of the GOT.
X86Relocator::SWord GOT_S = got_entry->getOffset() -
@@ -1121,23 +1097,19 @@
// R_X86_TLS_LE
X86Relocator::Result tls_le(Relocation& pReloc, X86_32Relocator& pParent)
{
- ResolveInfo* rsym = pReloc.symInfo();
- if (pReloc.symInfo()->reserved() & X86Relocator::ReserveRel) {
- helper_DynRel(rsym,
- *pReloc.targetRef().frag(),
- pReloc.targetRef().offset(),
- llvm::ELF::R_386_TLS_TPOFF,
- pParent);
+ if (pReloc.symInfo()->reserved() & X86Relocator::ReserveRel)
return X86Relocator::OK;
- }
// perform static relocation
// get TLS segment
- ELFSegment* tls_seg = pParent.getTarget().elfSegmentTable().find(
- llvm::ELF::PT_TLS, llvm::ELF::PF_R, 0x0);
+ ELFSegmentFactory::const_iterator tls_seg =
+ pParent.getTarget().elfSegmentTable().find(llvm::ELF::PT_TLS,
+ llvm::ELF::PF_R,
+ 0x0);
+ assert(tls_seg != pParent.getTarget().elfSegmentTable().end());
Relocator::DWord A = pReloc.target() + pReloc.addend();
X86Relocator::Address S = pReloc.symValue();
- pReloc.target() = S + A - tls_seg->memsz();
+ pReloc.target() = S + A - (*tls_seg)->memsz();
return X86Relocator::OK;
}
@@ -1147,7 +1119,130 @@
}
//===--------------------------------------------------------------------===//
-// Relocation Functions and Tables
+// X86_64 Relocation helper function
+//===--------------------------------------------------------------------===//
+/// helper_DynRel - Get an relocation entry in .rela.dyn
+static
+Relocation& helper_DynRel_init(ResolveInfo* pSym,
+ Fragment& pFrag,
+ uint64_t pOffset,
+ X86Relocator::Type pType,
+ X86_64Relocator& pParent)
+{
+ X86_64GNULDBackend& ld_backend = pParent.getTarget();
+ Relocation& rel_entry = *ld_backend.getRelDyn().create();
+ rel_entry.setType(pType);
+ rel_entry.targetRef().assign(pFrag, pOffset);
+ if (pType == llvm::ELF::R_X86_64_RELATIVE || NULL == pSym)
+ rel_entry.setSymInfo(NULL);
+ else
+ rel_entry.setSymInfo(pSym);
+
+ return rel_entry;
+}
+
+
+/// helper_use_relative_reloc - Check if symbol can use relocation
+/// R_X86_64_RELATIVE
+static bool
+helper_use_relative_reloc(const ResolveInfo& pSym,
+ const X86_64Relocator& pFactory)
+
+{
+ // if symbol is dynamic or undefine or preemptible
+ if (pSym.isDyn() ||
+ pSym.isUndef() ||
+ pFactory.getTarget().isSymbolPreemptible(pSym))
+ return false;
+ return true;
+}
+
+static
+X86_64GOTEntry& helper_GOT_init(Relocation& pReloc,
+ bool pHasRel,
+ X86_64Relocator& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ X86_64GNULDBackend& ld_backend = pParent.getTarget();
+ assert(NULL == pParent.getSymGOTMap().lookUp(*rsym));
+
+ X86_64GOTEntry* got_entry = ld_backend.getGOT().create();
+ pParent.getSymGOTMap().record(*rsym, *got_entry);
+
+ // If we first get this GOT entry, we should initialize it.
+ if (!pHasRel) {
+ // No corresponding dynamic relocation, initialize to the symbol value.
+ got_entry->setValue(X86Relocator::SymVal);
+ }
+ else {
+ // Initialize got_entry content and the corresponding dynamic relocation.
+ if (helper_use_relative_reloc(*rsym, pParent)) {
+ Relocation& rel_entry = helper_DynRel_init(rsym, *got_entry, 0x0,
+ llvm::ELF::R_X86_64_RELATIVE, pParent);
+ rel_entry.setAddend(X86Relocator::SymVal);
+ pParent.getRelRelMap().record(pReloc, rel_entry);
+ }
+ else {
+ helper_DynRel_init(rsym, *got_entry, 0x0, llvm::ELF::R_X86_64_GLOB_DAT,
+ pParent);
+ }
+ got_entry->setValue(0);
+ }
+ return *got_entry;
+}
+
+static
+X86Relocator::Address helper_GOT_ORG(X86_64Relocator& pParent)
+{
+ return pParent.getTarget().getGOT().addr();
+}
+
+static
+X86Relocator::Address helper_get_GOT_address(Relocation& pReloc,
+ X86_64Relocator& pParent)
+{
+ X86_64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
+ assert(NULL != got_entry);
+ return got_entry->getOffset();
+}
+
+static
+X86Relocator::Address helper_get_PLT_address(ResolveInfo& pSym,
+ X86_64Relocator& pParent)
+{
+ PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(pSym);
+ assert(NULL != plt_entry);
+ return pParent.getTarget().getPLT().addr() + plt_entry->getOffset();
+}
+
+static
+PLTEntryBase& helper_PLT_init(Relocation& pReloc, X86_64Relocator& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ X86_64GNULDBackend& ld_backend = pParent.getTarget();
+ assert(NULL == pParent.getSymPLTMap().lookUp(*rsym));
+
+ PLTEntryBase* plt_entry = ld_backend.getPLT().create();
+ pParent.getSymPLTMap().record(*rsym, *plt_entry);
+
+ // initialize plt and the corresponding gotplt and dyn rel entry.
+ assert(NULL == pParent.getSymGOTPLTMap().lookUp(*rsym) &&
+ "PLT entry not exist, but DynRel entry exist!");
+ X86_64GOTEntry* gotplt_entry = ld_backend.getGOTPLT().create();
+ pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
+
+ // init the corresponding rel entry in .rel.plt
+ Relocation& rel_entry = *ld_backend.getRelPLT().create();
+ rel_entry.setType(llvm::ELF::R_X86_64_JUMP_SLOT);
+ rel_entry.targetRef().assign(*gotplt_entry);
+ rel_entry.setSymInfo(rsym);
+ return *plt_entry;
+}
+
+//===--------------------------------------------------------------------===//
+// X86_64 Relocation Functions and Tables
//===--------------------------------------------------------------------===//
DECL_X86_64_APPLY_RELOC_FUNCS
@@ -1210,6 +1305,22 @@
switch(pReloc.type()){
case llvm::ELF::R_X86_64_64:
+ // If buiding PIC object (shared library or PIC executable),
+ // a dynamic relocations with RELATIVE type to this location is needed.
+ // Reserve an entry in .rela.dyn
+ if (config().isCodeIndep()) {
+ Relocation& reloc = helper_DynRel_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ llvm::ELF::R_X86_64_RELATIVE,
+ *this);
+ getRelRelMap().record(pReloc, reloc);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ getTarget().checkAndSetHasTextRel(*pSection.getLink());
+ }
+ return;
+
case llvm::ELF::R_X86_64_32:
case llvm::ELF::R_X86_64_16:
case llvm::ELF::R_X86_64_8:
@@ -1218,7 +1329,12 @@
// a dynamic relocations with RELATIVE type to this location is needed.
// Reserve an entry in .rela.dyn
if (config().isCodeIndep()) {
- getTarget().getRelDyn().reserveEntry();
+ Relocation& reloc = helper_DynRel_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ pReloc.type(),
+ *this);
+ getRelRelMap().record(pReloc, reloc);
// set Rel bit
rsym->setReserved(rsym->reserved() | ReserveRel);
getTarget().checkAndSetHasTextRel(*pSection.getLink());
@@ -1233,27 +1349,17 @@
case llvm::ELF::R_X86_64_GOTPCREL:
// Symbol needs GOT entry, reserve entry in .got
// return if we already create GOT for this symbol
- if (rsym->reserved() & (ReserveGOT | GOTRel))
+ if (rsym->reserved() & ReserveGOT)
return;
- getTarget().getGOT().reserve();
- // If the GOT is used in statically linked binaries,
- // the GOT entry is enough and no relocation is needed.
- if (config().isCodeStatic()) {
- rsym->setReserved(rsym->reserved() | ReserveGOT);
- return;
- }
// If building shared object or the symbol is undefined, a dynamic
// relocation is needed to relocate this GOT entry. Reserve an
// entry in .rela.dyn
if (LinkerConfig::DynObj ==
- config().codeGenType() || rsym->isUndef() || rsym->isDyn()) {
- getTarget().getRelDyn().reserveEntry();
- // set GOTRel bit
- rsym->setReserved(rsym->reserved() | GOTRel);
- return;
- }
- // set GOT bit
+ config().codeGenType() || rsym->isUndef() || rsym->isDyn())
+ helper_GOT_init(pReloc, true, *this);
+ else
+ helper_GOT_init(pReloc, false, *this);
rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
@@ -1285,26 +1391,41 @@
if (!(rsym->reserved() & ReservePLT)){
// Symbol needs PLT entry, we need to reserve a PLT entry
// and the corresponding GOT and dynamic relocation entry
- // in .got and .rela.plt. (GOT entry will be reserved simultaneously
- // when calling X86PLT->reserveEntry())
- getTarget().getPLT().reserveEntry();
- getTarget().getGOTPLT().reserve();
- getTarget().getRelPLT().reserveEntry();
+ // in .got and .rela.plt.
+ helper_PLT_init(pReloc, *this);
// set PLT bit
rsym->setReserved(rsym->reserved() | ReservePLT);
}
}
- if (getTarget().symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), true)) {
- // symbol needs dynamic relocation entry, reserve an entry in .rela.dyn
- getTarget().getRelDyn().reserveEntry();
+ if (getTarget().symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT),
+ true)) {
+ // symbol needs dynamic relocation entry, set up the dynrel entry
if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym, getTarget());
addCopyReloc(*cpy_sym.resolveInfo(), getTarget());
}
else {
- // set Rel bit
+ // set Rel bit and the dyn rel
rsym->setReserved(rsym->reserved() | ReserveRel);
+ getTarget().checkAndSetHasTextRel(*pSection.getLink());
+ if (llvm::ELF::R_386_32 == pReloc.type() &&
+ helper_use_relative_reloc(*rsym, *this)) {
+ Relocation& reloc = helper_DynRel_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ llvm::ELF::R_X86_64_RELATIVE,
+ *this);
+ getRelRelMap().record(pReloc, reloc);
+ }
+ else {
+ Relocation& reloc = helper_DynRel_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ pReloc.type(),
+ *this);
+ getRelRelMap().record(pReloc, reloc);
+ }
getTarget().checkAndSetHasTextRel(*pSection.getLink());
}
}
@@ -1313,26 +1434,17 @@
case llvm::ELF::R_X86_64_GOTPCREL:
// Symbol needs GOT entry, reserve entry in .got
// return if we already create GOT for this symbol
- if (rsym->reserved() & (ReserveGOT | GOTRel))
+ if (rsym->reserved() & ReserveGOT)
return;
- getTarget().getGOT().reserve();
- // If the GOT is used in statically linked binaries,
- // the GOT entry is enough and no relocation is needed.
- if (config().isCodeStatic()) {
- rsym->setReserved(rsym->reserved() | ReserveGOT);
- return;
- }
// If building shared object or the symbol is undefined, a dynamic
// relocation is needed to relocate this GOT entry. Reserve an
// entry in .rela.dyn
if (LinkerConfig::DynObj ==
- config().codeGenType() || rsym->isUndef() || rsym->isDyn()) {
- getTarget().getRelDyn().reserveEntry();
- // set GOTRel bit
- rsym->setReserved(rsym->reserved() | GOTRel);
- return;
- }
+ config().codeGenType() || rsym->isUndef() || rsym->isDyn())
+ helper_GOT_init(pReloc, true, *this);
+ else
+ helper_GOT_init(pReloc, false, *this);
// set GOT bit
rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
@@ -1355,13 +1467,10 @@
return;
}
- // Symbol needs PLT entry, we need to reserve a PLT entry
+ // Symbol needs PLT entry, we need a PLT entry
// and the corresponding GOT and dynamic relocation entry
- // in .got and .rel.plt. (GOT entry will be reserved simultaneously
- // when calling X86PLT->reserveEntry())
- getTarget().getPLT().reserveEntry();
- getTarget().getGOTPLT().reserve();
- getTarget().getRelPLT().reserveEntry();
+ // in .got and .rel.plt.
+ helper_PLT_init(pReloc, *this);
// set PLT bit
rsym->setReserved(rsym->reserved() | ReservePLT);
return;
@@ -1373,13 +1482,10 @@
LinkerConfig::DynObj != config().codeGenType()) {
// create plt for this symbol if it does not have one
if (!(rsym->reserved() & ReservePLT)){
- // Symbol needs PLT entry, we need to reserve a PLT entry
+ // Symbol needs PLT entry, we need a PLT entry
// and the corresponding GOT and dynamic relocation entry
- // in .got and .rel.plt. (GOT entry will be reserved simultaneously
- // when calling X86PLT->reserveEntry())
- getTarget().getPLT().reserveEntry();
- getTarget().getGOTPLT().reserve();
- getTarget().getRelPLT().reserveEntry();
+ // in .got and .rel.plt.
+ helper_PLT_init(pReloc, *this);
// set PLT bit
rsym->setReserved(rsym->reserved() | ReservePLT);
}
@@ -1391,11 +1497,12 @@
// All other dynamic relocations may lead to run-time relocation
// overflow.
if (getTarget().isDynamicSymbol(*rsym) &&
- getTarget().symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), false) &&
- getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
- getTarget().getRelDyn().reserveEntry();
- LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym, getTarget());
- addCopyReloc(*cpy_sym.resolveInfo(), getTarget());
+ getTarget().symbolNeedsDynRel(*rsym,
+ (rsym->reserved() & ReservePLT),
+ false) &&
+ getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym, getTarget());
+ addCopyReloc(*cpy_sym.resolveInfo(), getTarget());
}
return;
@@ -1406,147 +1513,9 @@
} // end switch
}
-//===--------------------------------------------------------------------===//
-// Relocation helper function
-//===--------------------------------------------------------------------===//
-/// helper_DynRel - Get an relocation entry in .rela.dyn
-static
-Relocation& helper_DynRel(ResolveInfo* pSym,
- Fragment& pFrag,
- uint64_t pOffset,
- X86Relocator::Type pType,
- X86_64Relocator& pParent)
-{
- X86_64GNULDBackend& ld_backend = pParent.getTarget();
- Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
- rel_entry.setType(pType);
- rel_entry.targetRef().assign(pFrag, pOffset);
- if (pType == llvm::ELF::R_X86_64_RELATIVE || NULL == pSym)
- rel_entry.setSymInfo(0);
- else
- rel_entry.setSymInfo(pSym);
-
- return rel_entry;
-}
-
-
-/// helper_use_relative_reloc - Check if symbol can use relocation
-/// R_X86_64_RELATIVE
-static bool
-helper_use_relative_reloc(const ResolveInfo& pSym,
- const X86_64Relocator& pFactory)
-
-{
- // if symbol is dynamic or undefine or preemptible
- if (pSym.isDyn() ||
- pSym.isUndef() ||
- pFactory.getTarget().isSymbolPreemptible(pSym))
- return false;
- return true;
-}
-
-static
-X86_64GOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
- X86_64Relocator& pParent)
-{
- // rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
- X86_64GNULDBackend& ld_backend = pParent.getTarget();
-
- X86_64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
- if (NULL != got_entry)
- return *got_entry;
-
- // not found
- got_entry = ld_backend.getGOT().consume();
- pParent.getSymGOTMap().record(*rsym, *got_entry);
-
- // If we first get this GOT entry, we should initialize it.
- if (rsym->reserved() & X86Relocator::ReserveGOT) {
- // No corresponding dynamic relocation, initialize to the symbol value.
- got_entry->setValue(pReloc.symValue());
- }
- else if (rsym->reserved() & X86Relocator::GOTRel) {
- // Initialize got_entry content and the corresponding dynamic relocation.
- if (helper_use_relative_reloc(*rsym, pParent)) {
- Relocation& rel_entry = helper_DynRel(rsym, *got_entry, 0x0,
- llvm::ELF::R_X86_64_RELATIVE,
- pParent);
- rel_entry.setAddend(pReloc.symValue());
- }
- else {
- helper_DynRel(rsym, *got_entry, 0x0, llvm::ELF::R_X86_64_GLOB_DAT,
- pParent);
- }
- got_entry->setValue(0);
- }
- else {
- fatal(diag::reserve_entry_number_mismatch_got);
- }
- return *got_entry;
-}
-
-static
-X86Relocator::Address helper_GOT_ORG(X86_64Relocator& pParent)
-{
- return pParent.getTarget().getGOT().addr();
-}
-
-static
-X86Relocator::Address helper_GOT(Relocation& pReloc, X86_64Relocator& pParent)
-{
- X86_64GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent);
- return got_entry.getOffset();
-}
-
-static
-PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc,
- X86_64Relocator& pParent)
-{
- // rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
- X86_64GNULDBackend& ld_backend = pParent.getTarget();
-
- PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(*rsym);
- if (NULL != plt_entry)
- return *plt_entry;
-
- // not found
- plt_entry = ld_backend.getPLT().consume();
- pParent.getSymPLTMap().record(*rsym, *plt_entry);
- // If we first get this PLT entry, we should initialize it.
- if (rsym->reserved() & X86Relocator::ReservePLT) {
- X86_64GOTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym);
- assert(NULL == gotplt_entry && "PLT entry not exist, but DynRel entry exist!");
- gotplt_entry = ld_backend.getGOTPLT().consume();
- pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
- // init the corresponding rel entry in .rel.plt
- Relocation& rel_entry = *ld_backend.getRelPLT().consumeEntry();
- rel_entry.setType(llvm::ELF::R_X86_64_JUMP_SLOT);
- rel_entry.targetRef().assign(*gotplt_entry);
- rel_entry.setSymInfo(rsym);
- }
- else {
- fatal(diag::reserve_entry_number_mismatch_plt);
- }
-
- return *plt_entry;
-}
-
-static
-X86Relocator::Address helper_PLT_ORG(X86_64Relocator& pParent)
-{
- return pParent.getTarget().getPLT().addr();
-}
-
-static
-X86Relocator::Address helper_PLT(Relocation& pReloc, X86_64Relocator& pParent)
-{
- PLTEntryBase& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
- return helper_PLT_ORG(pParent) + plt_entry.getOffset();
-}
-
+// ===
//
+// ===
// R_X86_64_NONE
X86Relocator::Result none(Relocation& pReloc, X86_64Relocator& pParent)
{
@@ -1562,15 +1531,10 @@
ResolveInfo* rsym = pReloc.symInfo();
Relocator::DWord A = pReloc.target() + pReloc.addend();
Relocator::DWord S = pReloc.symValue();
- bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel(
- *rsym,
- (rsym->reserved() & X86Relocator::ReservePLT),
- true);
+ Relocation* dyn_rel = pParent.getRelRelMap().lookUp(pReloc);
+ bool has_dyn_rel = (NULL != dyn_rel);
- FragmentRef &target_fragref = pReloc.targetRef();
- Fragment *target_frag = target_fragref.frag();
-
- LDSection& target_sect = target_frag->getParent()->getSection();
+ LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
// If the flag of target section is not ALLOC, we will not scan this relocation
// but perform static relocation. (e.g., applying .debug section)
if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
@@ -1580,19 +1544,14 @@
// A local symbol may need RELA Type dynamic relocation
if (rsym->isLocal() && has_dyn_rel) {
- X86Relocator::Type pType = pReloc.type();
- if (llvm::ELF::R_X86_64_64 == pType)
- pType = llvm::ELF::R_X86_64_RELATIVE;
- Relocation& rel_entry = helper_DynRel(rsym, *target_frag,
- target_fragref.offset(), pType, pParent);
- rel_entry.setAddend(S + A);
+ dyn_rel->setAddend(S + A);
return X86Relocator::OK;
}
// An external symbol may need PLT and dynamic relocation
if (!rsym->isLocal()) {
if (rsym->reserved() & X86Relocator::ReservePLT) {
- S = helper_PLT(pReloc, pParent);
+ S = helper_get_PLT_address(*rsym, pParent);
}
// If we generate a dynamic relocation (except R_X86_64_RELATIVE)
// for a place, we should not perform static relocation on it
@@ -1600,14 +1559,10 @@
if (has_dyn_rel) {
if (llvm::ELF::R_X86_64_64 == pReloc.type() &&
helper_use_relative_reloc(*rsym, pParent)) {
- Relocation& rel_entry = helper_DynRel(rsym, *target_frag,
- target_fragref.offset(), llvm::ELF::R_X86_64_RELATIVE, pParent);
- rel_entry.setAddend(S + A);
+ dyn_rel->setAddend(S + A);
}
else {
- Relocation& rel_entry = helper_DynRel(rsym, *target_frag,
- target_fragref.offset(), pReloc.type(), pParent);
- rel_entry.setAddend(A);
+ dyn_rel->setAddend(A);
return X86Relocator::OK;
}
}
@@ -1624,13 +1579,9 @@
ResolveInfo* rsym = pReloc.symInfo();
Relocator::DWord A = pReloc.target() + pReloc.addend();
Relocator::DWord S = pReloc.symValue();
- bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel(
- *rsym,
- (rsym->reserved() & X86Relocator::ReservePLT),
- true);
// There should be no dynamic relocations for R_X86_64_32S.
- if (has_dyn_rel)
+ if (NULL != pParent.getRelRelMap().lookUp(pReloc))
return X86Relocator::BadReloc;
LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
@@ -1639,7 +1590,7 @@
// An external symbol may need PLT and dynamic relocation
if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag()) &&
!rsym->isLocal() && rsym->reserved() & X86Relocator::ReservePLT)
- S = helper_PLT(pReloc, pParent);
+ S = helper_get_PLT_address(*rsym, pParent);
#if notyet
// Check 32-bit signed overflow.
@@ -1656,11 +1607,22 @@
// R_X86_64_GOTPCREL: GOT(S) + GOT_ORG + A - P
X86Relocator::Result gotpcrel(Relocation& pReloc, X86_64Relocator& pParent)
{
- if (!(pReloc.symInfo()->reserved()
- & (X86Relocator::ReserveGOT | X86Relocator::GOTRel))) {
+ if (!(pReloc.symInfo()->reserved() & X86Relocator::ReserveGOT)) {
return X86Relocator::BadReloc;
}
- X86Relocator::Address GOT_S = helper_GOT(pReloc, pParent);
+
+ // set symbol value of the got entry if needed
+ X86_64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
+ if (X86Relocator::SymVal == got_entry->getValue())
+ got_entry->setValue(pReloc.symValue());
+
+ // setup relocation addend if needed
+ Relocation* dyn_rel = pParent.getRelRelMap().lookUp(pReloc);
+ if ((NULL != dyn_rel) && (X86Relocator::SymVal == dyn_rel->addend())) {
+ dyn_rel->setAddend(pReloc.symValue());
+ }
+
+ X86Relocator::Address GOT_S = helper_get_GOT_address(pReloc, pParent);
Relocator::DWord A = pReloc.target() + pReloc.addend();
X86Relocator::Address GOT_ORG = helper_GOT_ORG(pParent);
// Apply relocation.
@@ -1674,7 +1636,7 @@
// PLT_S depends on if there is a PLT entry.
X86Relocator::Address PLT_S;
if ((pReloc.symInfo()->reserved() & X86Relocator::ReservePLT))
- PLT_S = helper_PLT(pReloc, pParent);
+ PLT_S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
else
PLT_S = pReloc.symValue();
Relocator::DWord A = pReloc.target() + pReloc.addend();
@@ -1701,17 +1663,22 @@
return X86Relocator::OK;
}
+ // setup relocation addend if needed
+ Relocation* dyn_rel = pParent.getRelRelMap().lookUp(pReloc);
+ if ((NULL != dyn_rel) && (X86Relocator::SymVal == dyn_rel->addend())) {
+ dyn_rel->setAddend(S);
+ }
+
// An external symbol may need PLT and dynamic relocation
if (!rsym->isLocal()) {
if (rsym->reserved() & X86Relocator::ReservePLT) {
- S = helper_PLT(pReloc, pParent);
- pReloc.target() = S + A - P;
+ S = helper_get_PLT_address(*rsym, pParent);
}
if (pParent.getTarget().symbolNeedsDynRel(
*rsym,
(rsym->reserved() & X86Relocator::ReservePLT),
false)) {
- return X86Relocator::Overflow;
+ return X86Relocator::Overflow;
}
}
diff --git a/lib/Target/X86/X86Relocator.h b/lib/Target/X86/X86Relocator.h
index d6e97ed..da67464 100644
--- a/lib/Target/X86/X86Relocator.h
+++ b/lib/Target/X86/X86Relocator.h
@@ -15,7 +15,7 @@
#include <mcld/LD/Relocator.h>
#include <mcld/Target/GOT.h>
#include <mcld/Target/PLT.h>
-#include <mcld/Target/SymbolEntryMap.h>
+#include <mcld/Target/KeyEntryMap.h>
#include "X86LDBackend.h"
namespace mcld {
@@ -30,49 +30,41 @@
class X86Relocator : public Relocator
{
public:
- typedef SymbolEntryMap<PLTEntryBase> SymPLTMap;
+ typedef KeyEntryMap<ResolveInfo, PLTEntryBase> SymPLTMap;
/** \enum ReservedEntryType
* \brief The reserved entry type of reserved space in ResolveInfo.
*
* This is used for sacnRelocation to record what kinds of entries are
- * reserved for this resolved symbol
+ * reserved for this resolved symbol. In X86, there are three kinds of
+ * entries, GOT, PLT, and dynamic reloction.
*
- * In X86, there are three kinds of entries, GOT, PLT, and dynamic reloction.
- * GOT may needs a corresponding relocation to relocate itself, so we
- * separate GOT to two situations: GOT and GOTRel. Besides, for the same
- * symbol, there might be two kinds of entries reserved for different location.
- * For example, reference to the same symbol, one may use GOT and the other may
- * use dynamic relocation.
- *
- * bit: 3 2 1 0
- * | PLT | GOTRel | GOT | Rel |
+ * bit: 3 2 1 0
+ * | | PLT | GOT | Rel |
*
* value Name - Description
*
* 0000 None - no reserved entry
* 0001 ReserveRel - reserve an dynamic relocation entry
* 0010 ReserveGOT - reserve an GOT entry
- * 0011 GOTandRel - For different relocation, we've reserved GOT and
- * Rel for different location.
- * 0100 GOTRel - reserve an GOT entry and the corresponding Dyncamic
- * relocation entry which relocate this GOT entry
- * 0101 GOTRelandRel - For different relocation, we've reserved GOTRel
- * and relocation entry for different location.
- * 1000 ReservePLT - reserve an PLT entry and the corresponding GOT,
- * Dynamic relocation entries
- * 1001 PLTandRel - For different relocation, we've reserved PLT and
- * Rel for different location.
+ * 0100 ReservePLT - reserve an PLT entry and the corresponding GOT,
+ *
*/
enum ReservedEntryType {
None = 0,
ReserveRel = 1,
ReserveGOT = 2,
- GOTandRel = 3,
- GOTRel = 4,
- GOTRelandRel = 5,
- ReservePLT = 8,
- PLTandRel = 9
+ ReservePLT = 4,
+ };
+
+ /** \enum EntryValue
+ * \brief The value of the entries. The symbol value will be decided at after
+ * layout, so we mark the entry during scanRelocation and fill up the actual
+ * value when applying relocations.
+ */
+ enum EntryValue {
+ Default = 0,
+ SymVal = 1
};
public:
@@ -95,7 +87,8 @@
void scanRelocation(Relocation& pReloc,
IRBuilder& pBuilder,
Module& pModule,
- LDSection& pSection);
+ LDSection& pSection,
+ Input& pInput);
protected:
/// addCopyReloc - add a copy relocation into .rel.dyn for pSym
@@ -131,8 +124,8 @@
class X86_32Relocator : public X86Relocator
{
public:
- typedef SymbolEntryMap<X86_32GOTEntry> SymGOTMap;
- typedef SymbolEntryMap<X86_32GOTEntry> SymGOTPLTMap;
+ typedef KeyEntryMap<ResolveInfo, X86_32GOTEntry> SymGOTMap;
+ typedef KeyEntryMap<ResolveInfo, X86_32GOTEntry> SymGOTPLTMap;
enum {
R_386_TLS_OPT = 44 // mcld internal relocation type
@@ -189,8 +182,9 @@
class X86_64Relocator : public X86Relocator
{
public:
- typedef SymbolEntryMap<X86_64GOTEntry> SymGOTMap;
- typedef SymbolEntryMap<X86_64GOTEntry> SymGOTPLTMap;
+ typedef KeyEntryMap<ResolveInfo, X86_64GOTEntry> SymGOTMap;
+ typedef KeyEntryMap<ResolveInfo, X86_64GOTEntry> SymGOTPLTMap;
+ typedef KeyEntryMap<Relocation, Relocation> RelRelMap;
public:
X86_64Relocator(X86_64GNULDBackend& pParent, const LinkerConfig& pConfig);
@@ -213,6 +207,9 @@
const SymGOTPLTMap& getSymGOTPLTMap() const { return m_SymGOTPLTMap; }
SymGOTPLTMap& getSymGOTPLTMap() { return m_SymGOTPLTMap; }
+ const RelRelMap& getRelRelMap() const { return m_RelRelMap; }
+ RelRelMap& getRelRelMap() { return m_RelRelMap; }
+
private:
void scanLocalReloc(Relocation& pReloc,
IRBuilder& pBuilder,
@@ -228,6 +225,7 @@
X86_64GNULDBackend& m_Target;
SymGOTMap m_SymGOTMap;
SymGOTPLTMap m_SymGOTPLTMap;
+ RelRelMap m_RelRelMap;
};
} // namespace of mcld
diff --git a/lib/Target/X86/X86TargetMachine.cpp b/lib/Target/X86/X86TargetMachine.cpp
index b419fd1..82fea93 100644
--- a/lib/Target/X86/X86TargetMachine.cpp
+++ b/lib/Target/X86/X86TargetMachine.cpp
@@ -9,7 +9,6 @@
#include "X86TargetMachine.h"
#include "X86.h"
-#include <mcld/Target/TargetMachine.h>
#include <mcld/Support/TargetRegistry.h>
extern "C" void MCLDInitializeX86LDTarget() {
@@ -18,13 +17,15 @@
mcld::RegisterTargetMachine<mcld::X86TargetMachine> Y(mcld::TheX86_64Target);
}
-mcld::X86TargetMachine::X86TargetMachine(llvm::TargetMachine& pPM,
- const mcld::Target &pTarget,
- const std::string& pTriple)
- : mcld::MCLDTargetMachine(pPM, pTarget, pTriple) {
-}
+using namespace mcld;
-mcld::X86TargetMachine::~X86TargetMachine()
-{
+//===----------------------------------------------------------------------===//
+// X86TargetMachine
+//===----------------------------------------------------------------------===//
+X86TargetMachine::X86TargetMachine(llvm::TargetMachine& pPM,
+ const llvm::Target& pLLVMTarget,
+ const mcld::Target& pMCLDTarget,
+ const std::string& pTriple)
+ : MCLDTargetMachine(pPM, pLLVMTarget, pMCLDTarget, pTriple) {
}
diff --git a/lib/Target/X86/X86TargetMachine.h b/lib/Target/X86/X86TargetMachine.h
index 9034741..b9d78e1 100644
--- a/lib/Target/X86/X86TargetMachine.h
+++ b/lib/Target/X86/X86TargetMachine.h
@@ -9,18 +9,17 @@
#ifndef MCLD_X86_TARGET_MACHINE_H
#define MCLD_X86_TARGET_MACHINE_H
#include "X86.h"
-#include <mcld/Target/TargetMachine.h>
+#include <mcld/CodeGen/TargetMachine.h>
namespace mcld {
class X86TargetMachine : public MCLDTargetMachine
{
public:
- X86TargetMachine(llvm::TargetMachine &pTM,
- const mcld::Target &pTarget,
- const std::string &pTriple);
-
- virtual ~X86TargetMachine();
+ X86TargetMachine(llvm::TargetMachine& pTM,
+ const llvm::Target& pLLVMTarget,
+ const mcld::Target& pMCLDTarget,
+ const std::string& pTriple);
};
} // namespace of mcld
diff --git a/templates/header.h b/templates/header.h
new file mode 100644
index 0000000..2b9acf7
--- /dev/null
+++ b/templates/header.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 MCLD_${CLASS_NAME}_H
+#define MCLD_${CLASS_NAME}_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+/** \class ${class_name}
+ * \brief ${brief}
+ */
+class ${class_name}
+{
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/templates/headerTest.h b/templates/headerTest.h
new file mode 100644
index 0000000..d36bda1
--- /dev/null
+++ b/templates/headerTest.h
@@ -0,0 +1,40 @@
+//===- headerTest.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_${CLASS_NAME}_TEST_H
+#define MCLD_${CLASS_NAME}_TEST_H
+
+#include <gtest.h>
+
+namespace mcld {
+
+class ${class_name};
+
+namespace test {
+
+class ${class_name}Test : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ ${class_name}Test();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~${class_name}Test();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+};
+
+} // namespace of test
+} // namespace of mcld
+
+#endif
+
diff --git a/templates/impl.cpp b/templates/impl.cpp
new file mode 100644
index 0000000..fe468d8
--- /dev/null
+++ b/templates/impl.cpp
@@ -0,0 +1,16 @@
+//===- impl.cpp -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/${deployment}/${class_name}.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// ${class_name}
+//===----------------------------------------------------------------------===//
+
diff --git a/templates/implTest.cpp b/templates/implTest.cpp
new file mode 100644
index 0000000..fbfdf05
--- /dev/null
+++ b/templates/implTest.cpp
@@ -0,0 +1,44 @@
+//===- implTest.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/${deployment}/${class_name}.h>
+#include "${class_name}Test.h"
+
+using namespace mcld;
+using namespace mcld::test;
+
+
+// Constructor can do set-up work for all test here.
+${class_name}Test::${class_name}Test()
+{
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+${class_name}Test::~${class_name}Test()
+{
+}
+
+// SetUp() will be called immediately before each test.
+void ${class_name}Test::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void ${class_name}Test::TearDown()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// Testcases
+//===----------------------------------------------------------------------===//
+/**
+TEST_F( ${class_name}Test, name of the testcase for ${class_name} ) {
+ Write you exercise here
+}
+**/
+
diff --git a/tools/mcld/include/alone/Config/Config.h.in b/tools/mcld/include/alone/Config/Config.h.in
deleted file mode 100644
index 6618b08..0000000
--- a/tools/mcld/include/alone/Config/Config.h.in
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef ALONE_CONFIG_CONFIG_H
-#define ALONE_CONFIG_CONFIG_H
-
-#if defined(TARGET_BUILD)
- #define PROVIDE_@PROVIDE_ALONE_TARGET@_CODEGEN
- #define DEFAULT_@DEFAULT_ALONE_TARGET@_CODEGEN
-#else
- #define PROVIDE_ARM_CODEGEN
- #define PROVIDE_X86_CODEGEN
- #define PROVIDE_MIPS_CODEGEN
- #define DEFAULT_@DEFAULT_ALONE_TARGET@_CODEGEN
-#endif
-
-#define DEFAULT_ARM_TRIPLE_STRING "armv7-none-linux-gnueabi"
-#define DEFAULT_X86_TRIPLE_STRING "i686-unknown-linux"
-#define DEFAULT_MIPS_TRIPLE_STRING "mipsel-none-linux-gnueabi"
-#define DEFAULT_X86_64_TRIPLE_STRING "x86_64-unknown-linux"
-
-#define DEFAULT_TARGET_TRIPLE_STRING DEFAULT_@DEFAULT_ALONE_TARGET@_TRIPLE_STRING
-
-#endif // ALONE_CONFIG_CONFIG_H
diff --git a/tools/mcld/include/alone/Linker.h b/tools/mcld/include/alone/Linker.h
deleted file mode 100644
index 987b36a..0000000
--- a/tools/mcld/include/alone/Linker.h
+++ /dev/null
@@ -1,94 +0,0 @@
-//===- Linker.h -----------------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef ALONE_LINKER_H
-#define ALONE_LINKER_H
-
-#include <string>
-
-namespace mcld {
-
-class Module;
-class IRBuilder;
-class LinkerConfig;
-class Linker;
-class Input;
-class MemoryArea;
-
-namespace sys { namespace fs {
-
-class Path;
-
-} } // end namespace sys::fs
-
-} // end namespace mcld
-
-namespace alone {
-
-class LinkerConfig;
-
-class Linker {
-public:
- enum ErrorCode {
- kSuccess,
- kDoubleConfig,
- kDelegateLDInfo,
- kFindNameSpec,
- kOpenObjectFile,
- kOpenMemory,
- kNotConfig,
- kNotSetUpOutput,
- kOpenOutput,
- kReadSections,
- kReadSymbols,
- kAddAdditionalSymbols,
- kMaxErrorCode
- };
-
- static const char *GetErrorString(enum ErrorCode pErrCode);
-
-private:
- const mcld::LinkerConfig *mLDConfig;
- mcld::Module *mModule;
- mcld::Linker *mLinker;
- mcld::IRBuilder *mBuilder;
- std::string mSOName;
- std::string mOutputPath;
- int mOutputHandler;
-
-public:
- Linker();
-
- Linker(const LinkerConfig& pConfig);
-
- ~Linker();
-
- enum ErrorCode config(const LinkerConfig& pConfig);
-
- enum ErrorCode addNameSpec(const std::string &pNameSpec);
-
- enum ErrorCode addObject(const std::string &pObjectPath);
-
- enum ErrorCode addObject(void* pMemory, size_t pSize);
-
- enum ErrorCode addCode(void* pMemory, size_t pSize);
-
- enum ErrorCode setOutput(const std::string &pPath);
-
- enum ErrorCode setOutput(int pFileHandler);
-
- enum ErrorCode link();
-
-private:
- enum ErrorCode extractFiles(const LinkerConfig& pConfig);
-};
-
-} // end namespace alone
-
-#endif // ALONE_LINKER_H
diff --git a/tools/mcld/include/alone/Support/Initialization.h b/tools/mcld/include/alone/Support/Initialization.h
deleted file mode 100644
index 9af994e..0000000
--- a/tools/mcld/include/alone/Support/Initialization.h
+++ /dev/null
@@ -1,23 +0,0 @@
-//===- Initialization.h ---------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef ALONE_SUPPORT_INITIALIZATION_H
-#define ALONE_SUPPORT_INITIALIZATION_H
-
-namespace alone {
-
-namespace init {
-
-void Initialize();
-
-} // end namespace init
-
-} // end namespace alone
-
-#endif // ALONE_SUPPORT_INITIALIZATION_H
diff --git a/tools/mcld/include/alone/Support/LinkerConfig.h b/tools/mcld/include/alone/Support/LinkerConfig.h
deleted file mode 100644
index 8f36ec5..0000000
--- a/tools/mcld/include/alone/Support/LinkerConfig.h
+++ /dev/null
@@ -1,123 +0,0 @@
-//===- Linker.h -----------------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef ALONE_SUPPORT_LINKER_CONFIG_H
-#define ALONE_SUPPORT_LINKER_CONFIG_H
-
-#include <string>
-
-#include <mcld/LinkerConfig.h>
-#include <mcld/LinkerScript.h>
-#include <mcld/Support/TargetRegistry.h>
-#include <mcld/LD/DiagnosticLineInfo.h>
-#include <mcld/LD/DiagnosticPrinter.h>
-
-namespace alone {
-
-class LinkerConfig {
-private:
- //===--------------------------------------------------------------------===//
- // Available Configurations
- //===--------------------------------------------------------------------===//
- const std::string mTriple;
- std::string mSOName;
-
-private:
- //===--------------------------------------------------------------------===//
- // These are generated by LinkerConfig during initialize().
- //===--------------------------------------------------------------------===//
- const mcld::Target *mTarget;
- bool initializeTarget();
-
- mcld::LinkerConfig *mLDConfig;
- bool initializeLDInfo();
-
- mcld::LinkerScript *mLDScript;
- bool initializeLDScript();
-
- mcld::DiagnosticLineInfo *mDiagLineInfo;
- mcld::DiagnosticPrinter *mDiagPrinter;
- bool initializeDiagnostic();
-
-public:
- enum ZOptionEnum {
- kCombReloc = 1 << 0, ///< [on] -z combreloc, [off] -z nocombreloc
- kDefs = 1 << 1, ///< -z defs
- kExecStack = 1 << 2, ///< [on] -z execstack, [off] -z noexecstack
- kInitFirst = 1 << 3, ///< -z initfirst
- kInterPose = 1 << 4, ///< -z interpose
- kLoadFltr = 1 << 5, ///< -z loadfltr
- kMulDefs = 1 << 6, ///< -z muldefs
- kNoCopyReloc = 1 << 7, ///< -z nocopyreloc
- kNoDefaultLib = 1 << 8, ///< -z nodefaultlib
- kNoDelete = 1 << 9, ///< -z nodelete
- kNoDLOpen = 1 << 10, ///< -z nodlopen
- kNoDump = 1 << 11, ///< -z nodump
- kRelro = 1 << 12, ///< [on] -z relro, [off] -z norelro
- kLazy = 1 << 13, ///< [on] -z lazy, [off] -z now
- kOrigin = 1 << 14, ///< -z origin
- kZOptionMask = 0xFFFF
- };
-
-public:
- //===--------------------------------------------------------------------===//
- // Getters
- //===--------------------------------------------------------------------===//
- inline const std::string &getTriple() const
- { return mTriple; }
-
- inline const mcld::Target *getTarget() const
- { return mTarget; }
-
- inline mcld::LinkerConfig* getLDConfig()
- { return mLDConfig; }
-
- inline const mcld::LinkerConfig* getLDConfig() const
- { return mLDConfig; }
-
- inline mcld::LinkerScript* getLDScript()
- { return mLDScript; }
-
- inline const mcld::LinkerScript* getLDScript() const
- { return mLDScript; }
-
- bool isShared() const;
-
- inline std::string getSOName() const
- { return mSOName; }
-
- void setShared(bool pEnable = true);
-
- void setBsymbolic(bool pEnable = true);
-
- void setDefineCommon(bool pEnable = true);
-
- void setSOName(const std::string &pSOName);
-
- void setDyld(const std::string &pDyld);
-
- void setSysRoot(const std::string &pSysRoot);
-
- void setZOption(unsigned int pOptions);
-
- void addWrap(const std::string &pWrapSymbol);
-
- void addPortable(const std::string &pPortableSymbol);
-
- void addSearchDir(const std::string &pDir);
-
-public:
- LinkerConfig(const std::string& pTriple);
-
- virtual ~LinkerConfig();
-};
-
-} // end namespace alone
-
-#endif // ALONE_SUPPORT_LINKER_CONFIG_H
diff --git a/tools/mcld/include/alone/Support/Log.h b/tools/mcld/include/alone/Support/Log.h
deleted file mode 100644
index e3c80d1..0000000
--- a/tools/mcld/include/alone/Support/Log.h
+++ /dev/null
@@ -1,18 +0,0 @@
-//===- Log.h --------------------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef ALONE_SUPPORT_LOG_H
-#define ALONE_SUPPORT_LOG_H
-
-#include <cstdio>
-
-#define ALOGE(fmt, args...) \
-printf("%s:%s:%d: " fmt, __FILE__, __FUNCTION__, __LINE__, args)
-
-#endif // ALONE_SUPPORT_LOG_H
diff --git a/tools/mcld/include/alone/Support/TargetLinkerConfigs.h b/tools/mcld/include/alone/Support/TargetLinkerConfigs.h
deleted file mode 100644
index 3bb6b7b..0000000
--- a/tools/mcld/include/alone/Support/TargetLinkerConfigs.h
+++ /dev/null
@@ -1,89 +0,0 @@
-//===- TargetLinkerConfig.h -----------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef ALONE_SUPPORT_TARGET_LINKER_CONFIGS_H
-#define ALONE_SUPPORT_TARGET_LINKER_CONFIGS_H
-
-#include <string>
-
-#include "alone/Config/Config.h"
-#include "alone/Support/LinkerConfig.h"
-
-namespace alone {
-
-//===----------------------------------------------------------------------===//
-// ARM
-//===----------------------------------------------------------------------===//
-#if defined(PROVIDE_ARM_CODEGEN)
-class ARMLinkerConfig : public LinkerConfig {
-public:
- ARMLinkerConfig();
-};
-#endif // defined(PROVIDE_ARM_CODEGEN)
-
-//===----------------------------------------------------------------------===//
-// MIPS
-//===----------------------------------------------------------------------===//
-#if defined(PROVIDE_MIPS_CODEGEN)
-class MipsLinkerConfig : public LinkerConfig {
-public:
- MipsLinkerConfig();
-};
-#endif // defined(PROVIDE_MIPS_CODEGEN)
-
-//===----------------------------------------------------------------------===//
-// X86 and X86_64
-//===----------------------------------------------------------------------===//
-#if defined(PROVIDE_X86_CODEGEN)
-class X86FamilyLinkerConfigBase : public LinkerConfig {
-public:
- X86FamilyLinkerConfigBase(const std::string& pTriple);
-};
-
-class X86_32LinkerConfig : public X86FamilyLinkerConfigBase {
-public:
- X86_32LinkerConfig();
-};
-
-class X86_64LinkerConfig : public X86FamilyLinkerConfigBase {
-public:
- X86_64LinkerConfig();
-};
-#endif // defined(PROVIDE_X86_CODEGEN)
-
-//===----------------------------------------------------------------------===//
-// Default target
-//===----------------------------------------------------------------------===//
-class DefaultLinkerConfig : public
-#if defined (DEFAULT_ARM_CODEGEN)
- ARMLinkerConfig
-#elif defined (DEFAULT_MIPS_CODEGEN)
- MipsLinkerConfig
-#elif defined (DEFAULT_X86_CODEGEN)
- X86_32LinkerConfig
-#elif defined (DEFAULT_X86_64_CODEGEN)
- X86_64LinkerConfig
-#else
-# error "Unsupported Default Target!"
-#endif
-{ };
-
-#if !defined(TARGET_BUILD)
-//===----------------------------------------------------------------------===//
-// General target
-//===----------------------------------------------------------------------===//
-class GeneralLinkerConfig : public LinkerConfig {
-public:
- GeneralLinkerConfig(const std::string& pTriple);
-};
-#endif // !defined(TARGET_BUILD)
-
-} // end namespace alone
-
-#endif // ALONE_SUPPORT_LINKER_CONFIG_H
diff --git a/tools/mcld/lib/Core/Linker.cpp b/tools/mcld/lib/Core/Linker.cpp
deleted file mode 100644
index 99d658c..0000000
--- a/tools/mcld/lib/Core/Linker.cpp
+++ /dev/null
@@ -1,176 +0,0 @@
-//===- Linker.cpp ---------------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "alone/Linker.h"
-#include "alone/Support/LinkerConfig.h"
-#include "alone/Support/Log.h"
-
-#include <llvm/Support/ELF.h>
-
-#include <mcld/Module.h>
-#include <mcld/IRBuilder.h>
-#include <mcld/MC/MCLDInput.h>
-#include <mcld/Linker.h>
-#include <mcld/LD/LDSection.h>
-#include <mcld/LD/LDContext.h>
-#include <mcld/Support/Path.h>
-
-using namespace alone;
-
-const char* Linker::GetErrorString(enum Linker::ErrorCode pErrCode) {
- static const char* ErrorString[] = {
- /* kSuccess */
- "Successfully compiled.",
- /* kDoubleConfig */
- "Configure Linker twice.",
- /* kDelegateLDInfo */
- "Cannot get linker information",
- /* kFindNameSpec */
- "Cannot find -lnamespec",
- /* kOpenObjectFile */
- "Cannot open object file",
- /* kNotConfig */
- "Linker::config() is not called",
- /* kNotSetUpOutput */
- "Linker::setOutput() is not called before add input files",
- /* kOpenOutput */
- "Cannot open output file",
- /* kReadSections */
- "Cannot read sections",
- /* kReadSymbols */
- "Cannot read symbols",
- /* kAddAdditionalSymbols */
- "Cannot add standard and target symbols",
- /* kMaxErrorCode */
- "(Unknown error code)"
- };
-
- if (pErrCode > kMaxErrorCode) {
- pErrCode = kMaxErrorCode;
- }
-
- return ErrorString[ static_cast<size_t>(pErrCode) ];
-}
-
-//===----------------------------------------------------------------------===//
-// Linker
-//===----------------------------------------------------------------------===//
-Linker::Linker()
- : mLDConfig(NULL), mModule(NULL), mLinker(NULL), mBuilder(NULL),
- mOutputHandler(-1) {
-}
-
-Linker::Linker(const LinkerConfig& pConfig)
- : mLDConfig(NULL), mModule(NULL), mLinker(NULL), mBuilder(NULL),
- mOutputHandler(-1) {
-
- const std::string &triple = pConfig.getTriple();
-
- enum ErrorCode err = config(pConfig);
- if (kSuccess != err) {
- ALOGE("%s (%s)", GetErrorString(err), triple.c_str());
- return;
- }
-
- return;
-}
-
-Linker::~Linker() {
- delete mModule;
- delete mLinker;
- delete mBuilder;
-}
-
-enum Linker::ErrorCode Linker::extractFiles(const LinkerConfig& pConfig) {
- mLDConfig = pConfig.getLDConfig();
- if (mLDConfig == NULL) {
- return kDelegateLDInfo;
- }
- return kSuccess;
-}
-
-enum Linker::ErrorCode Linker::config(const LinkerConfig& pConfig) {
- if (mLDConfig != NULL) {
- return kDoubleConfig;
- }
-
- extractFiles(pConfig);
-
- mModule = new mcld::Module(mLDConfig->options().soname(),
- const_cast<mcld::LinkerScript&>(*pConfig.getLDScript()));
-
- mBuilder = new mcld::IRBuilder(*mModule, *mLDConfig);
-
- mLinker = new mcld::Linker();
-
- mLinker->emulate(const_cast<mcld::LinkerScript&>(*pConfig.getLDScript()),
- const_cast<mcld::LinkerConfig&>(*mLDConfig));
-
- return kSuccess;
-}
-
-enum Linker::ErrorCode Linker::addNameSpec(const std::string &pNameSpec) {
- mcld::Input* input = mBuilder->ReadInput(pNameSpec);
- if (NULL == input)
- return kFindNameSpec;
- return kSuccess;
-}
-
-/// addObject - Add a object file by the filename.
-enum Linker::ErrorCode Linker::addObject(const std::string &pObjectPath) {
- mcld::Input* input = mBuilder->ReadInput(pObjectPath, pObjectPath);
- if (NULL == input)
- return kOpenObjectFile;
- return kSuccess;
-}
-
-/// addObject - Add a piece of memory. The memory is of ELF format.
-enum Linker::ErrorCode Linker::addObject(void* pMemory, size_t pSize) {
- mcld::Input* input = mBuilder->ReadInput("NAN", pMemory, pSize);
- if (NULL == input)
- return kOpenMemory;
- return kSuccess;
-}
-
-enum Linker::ErrorCode Linker::addCode(void* pMemory, size_t pSize) {
- mcld::Input* input = mBuilder->CreateInput("NAN", "NAN", mcld::Input::Object);
- mcld::LDSection* sect = mBuilder->CreateELFHeader(*input, ".text",
- llvm::ELF::SHT_PROGBITS,
- llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
- 0x1);
- mcld::SectionData* data = mBuilder->CreateSectionData(*sect);
- mcld::Fragment* frag = mBuilder->CreateRegion(pMemory, pSize);
- mBuilder->AppendFragment(*frag, *data);
- return kSuccess;
-}
-
-enum Linker::ErrorCode Linker::setOutput(const std::string &pPath) {
- mOutputPath = pPath;
- return kSuccess;
-}
-
-enum Linker::ErrorCode Linker::setOutput(int pFileHandler) {
- mOutputHandler = pFileHandler;
- return kSuccess;
-}
-
-enum Linker::ErrorCode Linker::link() {
- mLinker->link(*mModule, *mBuilder);
- if (!mOutputPath.empty()) {
- mLinker->emit(mOutputPath);
- return kSuccess;
- }
-
- if (-1 != mOutputHandler) {
- mLinker->emit(mOutputHandler);
- return kSuccess;
- }
- return kNotSetUpOutput;
-}
-
diff --git a/tools/mcld/lib/Support/Initialization.cpp b/tools/mcld/lib/Support/Initialization.cpp
deleted file mode 100644
index 71bd57d..0000000
--- a/tools/mcld/lib/Support/Initialization.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-//===- Initialization.cpp -------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "alone/Support/Initialization.h"
-
-#include <cstdlib>
-
-#include <llvm/Support/ErrorHandling.h>
-#include <llvm/Support/TargetSelect.h>
-
-#include <mcld/Support/TargetSelect.h>
-#include <mcld/Support/TargetRegistry.h>
-
-#include "alone/Config/Config.h"
-#include "alone/Support/Log.h"
-
-namespace {
-
-void llvm_error_handler(void *pUserData, const std::string &pMessage) {
- ALOGE("%s", pMessage.c_str());
- ::exit(1);
-}
-
-} // end anonymous namespace
-
-void alone::init::Initialize() {
- static bool is_initialized = false;
-
- if (is_initialized) {
- return;
- }
-
- // Setup error handler for LLVM.
- llvm::remove_fatal_error_handler();
- llvm::install_fatal_error_handler(llvm_error_handler, NULL);
-
-#if defined(PROVIDE_ARM_CODEGEN)
- LLVMInitializeARMAsmPrinter();
-# if USE_DISASSEMBLER
- LLVMInitializeARMDisassembler();
-# endif
- LLVMInitializeARMTargetMC();
- LLVMInitializeARMTargetInfo();
- LLVMInitializeARMTarget();
- MCLDInitializeARMLDTargetInfo();
- MCLDInitializeARMLDTarget();
- MCLDInitializeARMLDBackend();
- MCLDInitializeARMDiagnosticLineInfo();
-#endif
-
-#if defined(PROVIDE_MIPS_CODEGEN)
- LLVMInitializeMipsAsmPrinter();
-# if USE_DISASSEMBLER
- LLVMInitializeMipsDisassembler();
-# endif
- LLVMInitializeMipsTargetMC();
- LLVMInitializeMipsTargetInfo();
- LLVMInitializeMipsTarget();
- MCLDInitializeMipsLDTargetInfo();
- MCLDInitializeMipsLDTarget();
- MCLDInitializeMipsLDBackend();
- MCLDInitializeMipsDiagnosticLineInfo();
-#endif
-
-#if defined(PROVIDE_X86_CODEGEN)
- LLVMInitializeX86AsmPrinter();
-# if USE_DISASSEMBLER
- LLVMInitializeX86Disassembler();
-# endif
- LLVMInitializeX86TargetMC();
- LLVMInitializeX86TargetInfo();
- LLVMInitializeX86Target();
- MCLDInitializeX86LDTargetInfo();
- MCLDInitializeX86LDTarget();
- MCLDInitializeX86LDBackend();
- MCLDInitializeX86DiagnosticLineInfo();
-#endif
-
- is_initialized = true;
-
- return;
-}
diff --git a/tools/mcld/lib/Support/LinkerConfig.cpp b/tools/mcld/lib/Support/LinkerConfig.cpp
deleted file mode 100644
index e968cc1..0000000
--- a/tools/mcld/lib/Support/LinkerConfig.cpp
+++ /dev/null
@@ -1,340 +0,0 @@
-//===- LinkerConfig.cpp ---------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "alone/Support/LinkerConfig.h"
-#include "alone/Support/Log.h"
-
-#include <llvm/Support/Signals.h>
-
-#include <mcld/MC/MCLDDirectory.h>
-#include <mcld/MC/ZOption.h>
-#include <mcld/LD/TextDiagnosticPrinter.h>
-#include <mcld/Support/Path.h>
-#include <mcld/Support/MsgHandling.h>
-#include <mcld/Support/raw_ostream.h>
-
-using namespace alone;
-
-LinkerConfig::LinkerConfig(const std::string &pTriple)
- : mTriple(pTriple), mSOName(), mTarget(NULL), mLDConfig(NULL),
- mLDScript(NULL), mDiagLineInfo(NULL), mDiagPrinter(NULL) {
-
- initializeTarget();
- initializeLDScript();
- initializeLDInfo();
- initializeDiagnostic();
-}
-
-LinkerConfig::~LinkerConfig() {
- delete mLDConfig;
-
- if (mDiagPrinter->getNumErrors() != 0) {
- // If here, the program failed ungracefully. Run the interrupt handlers to
- // ensure any other cleanups (e.g., files that registered by
- // RemoveFileOnSignal(...)) getting done before exit.
- llvm::sys::RunInterruptHandlers();
- }
- mDiagPrinter->finish();
-
- delete mLDScript;
- delete mDiagLineInfo;
- delete mDiagPrinter;
-}
-
-bool LinkerConfig::initializeTarget() {
- std::string error;
- mTarget = mcld::TargetRegistry::lookupTarget(mTriple, error);
- if (NULL != mTarget) {
- return true;
- } else {
- ALOGE("Cannot initialize mcld::Target for given triple '%s'! (%s)\n",
- mTriple.c_str(), error.c_str());
- return false;
- }
-}
-
-bool LinkerConfig::initializeLDInfo() {
- if (NULL != mLDConfig) {
- ALOGE("Cannot initialize mcld::MCLDInfo for given triple '%s!\n",
- mTriple.c_str());
- return false;
- }
-
- mLDConfig = new mcld::LinkerConfig(getTriple());
- mLDConfig->setCodeGenType(mcld::LinkerConfig::Exec);
-
- struct NameMap {
- const char* from;
- const char* to;
- };
-
- static const NameMap map[] =
- {
- {".text", ".text"},
- {".rodata", ".rodata"},
- {".data.rel.ro.local", ".data.rel.ro.local"},
- {".data.rel.ro", ".data.rel.ro"},
- {".data", ".data"},
- {".bss", ".bss"},
- {".tdata", ".tdata"},
- {".tbss", ".tbss"},
- {".init_array", ".init_array"},
- {".fini_array", ".fini_array"},
- // TODO: Support DT_INIT_ARRAY for all constructors?
- {".ctors", ".ctors"},
- {".dtors", ".dtors"},
- // FIXME: in GNU ld, if we are creating a shared object .sdata2 and .sbss2
- // sections would be handled differently.
- {".sdata2", ".sdata"},
- {".sbss2", ".sbss"},
- {".sdata", ".sdata"},
- {".sbss", ".sbss"},
- {".lrodata", ".lrodata"},
- {".ldata", ".ldata"},
- {".lbss", ".lbss"},
- {".gcc_except_table", ".gcc_except_table"},
- {".gnu.linkonce.d.rel.ro.local", ".data.rel.ro.local"},
- {".gnu.linkonce.d.rel.ro", ".data.rel.ro"},
- {".gnu.linkonce.r", ".rodata"},
- {".gnu.linkonce.d", ".data"},
- {".gnu.linkonce.b", ".bss"},
- {".gnu.linkonce.sb2", ".sbss"},
- {".gnu.linkonce.sb", ".sbss"},
- {".gnu.linkonce.s2", ".sdata"},
- {".gnu.linkonce.s", ".sdata"},
- {".gnu.linkonce.wi", ".debug_info"},
- {".gnu.linkonce.td", ".tdata"},
- {".gnu.linkonce.tb", ".tbss"},
- {".gnu.linkonce.t", ".text"},
- {".gnu.linkonce.lr", ".lrodata"},
- {".gnu.linkonce.lb", ".lbss"},
- {".gnu.linkonce.l", ".ldata"},
- };
-
- if (mLDConfig->codeGenType() != mcld::LinkerConfig::Object) {
- const unsigned int map_size = (sizeof(map) / sizeof(map[0]) );
- for (unsigned int i = 0; i < map_size; ++i) {
- bool exist = false;
- mLDScript->sectionMap().append(map[i].from,
- map[i].to,
- exist);
- }
- }
- return true;
-}
-
-bool LinkerConfig::initializeLDScript() {
- mLDScript = new mcld::LinkerScript();
- return true;
-}
-
-bool LinkerConfig::initializeDiagnostic() {
- // Set up MsgHandler.
- mDiagPrinter = new mcld::TextDiagnosticPrinter(mcld::errs(), *mLDConfig);
-
- mcld::InitializeDiagnosticEngine(*mLDConfig, mDiagPrinter);
-
- mDiagLineInfo = mTarget->createDiagnosticLineInfo(*mTarget, mTriple);
-
- mcld::getDiagnosticEngine().setLineInfo(*mDiagLineInfo);
- return true;
-}
-
-bool LinkerConfig::isShared() const {
- return (mcld::LinkerConfig::DynObj == mLDConfig->codeGenType());
-}
-
-void LinkerConfig::setShared(bool pEnable) {
- if (pEnable)
- mLDConfig->setCodeGenType(mcld::LinkerConfig::DynObj);
- else
- mLDConfig->setCodeGenType(mcld::LinkerConfig::Exec);
- return;
-}
-
-void LinkerConfig::setBsymbolic(bool pEnable) {
- mLDConfig->options().setBsymbolic(pEnable);
- return;
-}
-
-void LinkerConfig::setDefineCommon(bool pEnable) {
- mLDConfig->options().setDefineCommon(pEnable);
- return;
-}
-
-void LinkerConfig::setSOName(const std::string &pSOName) {
- mLDConfig->options().setSOName(pSOName);
- return;
-}
-
-void LinkerConfig::setDyld(const std::string &pDyld) {
- mLDConfig->options().setDyld(pDyld);
- return;
-}
-
-void LinkerConfig::setSysRoot(const std::string &pSysRoot) {
- mLDScript->setSysroot(mcld::sys::fs::Path(pSysRoot));
- return;
-}
-
-void LinkerConfig::setZOption(unsigned int pOptions) {
- mcld::ZOption option;
- if (pOptions & kCombReloc) {
- option.setKind(mcld::ZOption::CombReloc);
- mLDConfig->options().addZOption(option);
- }
- else {
- option.setKind(mcld::ZOption::NoCombReloc);
- mLDConfig->options().addZOption(option);
- }
-
- if (pOptions & kDefs) {
- option.setKind(mcld::ZOption::Defs);
- mLDConfig->options().addZOption(option);
- }
-
- if (pOptions & kExecStack) {
- option.setKind(mcld::ZOption::ExecStack);
- mLDConfig->options().addZOption(option);
- }
- else {
- option.setKind(mcld::ZOption::NoExecStack);
- mLDConfig->options().addZOption(option);
- }
-
- if (pOptions & kInitFirst) {
- option.setKind(mcld::ZOption::InitFirst);
- mLDConfig->options().addZOption(option);
- }
-
- if (pOptions & kInterPose) {
- option.setKind(mcld::ZOption::InterPose);
- mLDConfig->options().addZOption(option);
- }
-
- if (pOptions & kLoadFltr) {
- option.setKind(mcld::ZOption::LoadFltr);
- mLDConfig->options().addZOption(option);
- }
-
- if (pOptions & kMulDefs) {
- option.setKind(mcld::ZOption::MulDefs);
- mLDConfig->options().addZOption(option);
- }
-
- if (pOptions & kNoCopyReloc) {
- option.setKind(mcld::ZOption::NoCopyReloc);
- mLDConfig->options().addZOption(option);
- }
-
- if (pOptions & kNoDefaultLib) {
- option.setKind(mcld::ZOption::NoDefaultLib);
- mLDConfig->options().addZOption(option);
- }
-
- if (pOptions & kNoDelete) {
- option.setKind(mcld::ZOption::NoDelete);
- mLDConfig->options().addZOption(option);
- }
-
- if (pOptions & kNoDLOpen) {
- option.setKind(mcld::ZOption::NoDLOpen);
- mLDConfig->options().addZOption(option);
- }
-
- if (pOptions & kNoDump) {
- option.setKind(mcld::ZOption::NoDump);
- mLDConfig->options().addZOption(option);
- }
-
- if (pOptions & kRelro) {
- option.setKind(mcld::ZOption::Relro);
- mLDConfig->options().addZOption(option);
- }
- else {
- option.setKind(mcld::ZOption::NoRelro);
- mLDConfig->options().addZOption(option);
- }
-
- if (pOptions & kLazy) {
- option.setKind(mcld::ZOption::Lazy);
- mLDConfig->options().addZOption(option);
- }
- else {
- option.setKind(mcld::ZOption::Now);
- mLDConfig->options().addZOption(option);
- }
-
- if (pOptions & kOrigin) {
- option.setKind(mcld::ZOption::Origin);
- mLDConfig->options().addZOption(option);
- }
-}
-
-void LinkerConfig::addWrap(const std::string &pWrapSymbol) {
- bool exist = false;
-
- // Add wname -> __wrap_wname.
- mcld::StringEntry<llvm::StringRef>* to_wrap =
- mLDScript->renameMap().insert(pWrapSymbol, exist);
-
- std::string to_wrap_str = "__wrap_" + pWrapSymbol;
- to_wrap->setValue(to_wrap_str);
-
- if (exist) {
- mcld::warning(mcld::diag::rewrap) << pWrapSymbol << to_wrap_str;
- }
-
- // Add __real_wname -> wname.
- std::string from_real_str = "__real_" + pWrapSymbol;
- mcld::StringEntry<llvm::StringRef>* from_real =
- mLDScript->renameMap().insert(from_real_str, exist);
- from_real->setValue(pWrapSymbol);
-
- if (exist) {
- mcld::warning(mcld::diag::rewrap) << pWrapSymbol << from_real_str;
- }
-
- return;
-}
-
-void LinkerConfig::addPortable(const std::string &pPortableSymbol) {
- bool exist = false;
-
- // Add pname -> pname_portable.
- mcld::StringEntry<llvm::StringRef>* to_port =
- mLDScript->renameMap().insert(pPortableSymbol, exist);
-
- std::string to_port_str = pPortableSymbol + "_portable";
- to_port->setValue(to_port_str);
-
- if (exist) {
- mcld::warning(mcld::diag::rewrap) << pPortableSymbol << to_port_str;
-}
-
- // Add __real_pname -> pname.
- std::string from_real_str = "__real_" + pPortableSymbol;
- mcld::StringEntry<llvm::StringRef>* from_real =
- mLDScript->renameMap().insert(from_real_str, exist);
-
- from_real->setValue(pPortableSymbol);
-
- if (exist) {
- mcld::warning(mcld::diag::rewrap) << pPortableSymbol << from_real_str;
- }
-
- return;
-}
-
-void LinkerConfig::addSearchDir(const std::string &pDirPath) {
- // SearchDirs will remove the created MCLDDirectory.
- if (!mLDScript->directories().insert(pDirPath)) {
- mcld::warning(mcld::diag::warn_cannot_open_search_dir) << pDirPath;
- }
-}
diff --git a/tools/mcld/lib/Support/TargetLinkerConfigs.cpp b/tools/mcld/lib/Support/TargetLinkerConfigs.cpp
deleted file mode 100644
index d8722f6..0000000
--- a/tools/mcld/lib/Support/TargetLinkerConfigs.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-//===- TargetLinkerConfigs.cpp --------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "alone/Config/Config.h"
-#include "alone/Support/TargetLinkerConfigs.h"
-
-#include <mcld/TargetOptions.h>
-#include <mcld/MC/InputFactory.h>
-#include <mcld/Fragment/Relocation.h>
-
-using namespace alone;
-
-#ifdef TARGET_BUILD
-static const char* gDefaultDyld = "/system/bin/linker";
-static const char* gDefaultSysroot = "/system";
-#else
-static const char* gDefaultDyld = "/usr/lib/ld.so.1";
-static const char* gDefaultSysroot = "/";
-#endif
-
-//===----------------------------------------------------------------------===//
-// ARM
-//===----------------------------------------------------------------------===//
-#if defined(PROVIDE_ARM_CODEGEN)
-ARMLinkerConfig::ARMLinkerConfig() : LinkerConfig(DEFAULT_ARM_TRIPLE_STRING) {
-
- // set up target-dependent options
- getLDConfig()->targets().setEndian(mcld::TargetOptions::Little);
- getLDConfig()->targets().setBitClass(32);
-
- // set up target-dependent constraints of attributes
- getLDConfig()->attribute().constraint().enableWholeArchive();
- getLDConfig()->attribute().constraint().disableAsNeeded();
- getLDConfig()->attribute().constraint().setSharedSystem();
-
- // set up the predefined attributes
- getLDConfig()->attribute().predefined().unsetWholeArchive();
- getLDConfig()->attribute().predefined().setDynamic();
-
- // set up target dependent options
- if (getLDScript()->sysroot().empty()) {
- getLDScript()->setSysroot(gDefaultSysroot);
- }
-
- if (!getLDConfig()->options().hasDyld()) {
- getLDConfig()->options().setDyld(gDefaultDyld);
- }
-
- // set up section map
- if (getLDConfig()->codeGenType() != mcld::LinkerConfig::Object) {
- bool exist = false;
- getLDScript()->sectionMap().append(".ARM.exidx", ".ARM.exidx", exist);
- getLDScript()->sectionMap().append(".ARM.extab", ".ARM.extab", exist);
- getLDScript()->sectionMap().append(".ARM.attributes", ".ARM.attributes", exist);
- }
-
- // set up relocation factory
- mcld::Relocation::SetUp(*getLDConfig());
-}
-#endif // defined(PROVIDE_ARM_CODEGEN)
-
-//===----------------------------------------------------------------------===//
-// Mips
-//===----------------------------------------------------------------------===//
-#if defined(PROVIDE_MIPS_CODEGEN)
-MipsLinkerConfig::MipsLinkerConfig()
- : LinkerConfig(DEFAULT_MIPS_TRIPLE_STRING) {
-
- // set up target-dependent options
- getLDConfig()->targets().setEndian(mcld::TargetOptions::Little);
- getLDConfig()->targets().setBitClass(32);
-
- // set up target-dependent constraints of attibutes
- getLDConfig()->attribute().constraint().enableWholeArchive();
- getLDConfig()->attribute().constraint().disableAsNeeded();
- getLDConfig()->attribute().constraint().setSharedSystem();
-
- // set up the predefined attributes
- getLDConfig()->attribute().predefined().unsetWholeArchive();
- getLDConfig()->attribute().predefined().setDynamic();
-
- // set up target dependent options
- if (getLDScript()->sysroot().empty()) {
- getLDScript()->setSysroot(gDefaultSysroot);
- }
-
- if (!getLDConfig()->options().hasDyld()) {
- getLDConfig()->options().setDyld(gDefaultDyld);
- }
-
- // set up relocation factory
- mcld::Relocation::SetUp(*getLDConfig());
-}
-#endif // defined(PROVIDE_MIPS_CODEGEN)
-
-//===----------------------------------------------------------------------===//
-// X86 and X86_64
-//===----------------------------------------------------------------------===//
-#if defined(PROVIDE_X86_CODEGEN)
-X86FamilyLinkerConfigBase::X86FamilyLinkerConfigBase(const std::string& pTriple)
- : LinkerConfig(pTriple) {
- // set up target-dependent options
- getLDConfig()->targets().setEndian(mcld::TargetOptions::Little);
- getLDConfig()->targets().setBitClass(32);
-
- // set up target-dependent constraints of attibutes
- getLDConfig()->attribute().constraint().enableWholeArchive();
- getLDConfig()->attribute().constraint().disableAsNeeded();
- getLDConfig()->attribute().constraint().setSharedSystem();
-
- // set up the predefined attributes
- getLDConfig()->attribute().predefined().unsetWholeArchive();
- getLDConfig()->attribute().predefined().setDynamic();
-
- // set up target dependent options
- if (getLDScript()->sysroot().empty()) {
- getLDScript()->setSysroot(gDefaultSysroot);
- }
-
- if (!getLDConfig()->options().hasDyld()) {
- getLDConfig()->options().setDyld(gDefaultDyld);
- }
-
- // set up relocation factory
- mcld::Relocation::SetUp(*getLDConfig());
-}
-
-X86_32LinkerConfig::X86_32LinkerConfig()
- : X86FamilyLinkerConfigBase(DEFAULT_X86_TRIPLE_STRING) {
-}
-
-X86_64LinkerConfig::X86_64LinkerConfig()
- : X86FamilyLinkerConfigBase(DEFAULT_X86_64_TRIPLE_STRING) {
-}
-#endif // defined(PROVIDE_X86_CODEGEN)
-
-#if !defined(TARGET_BUILD)
-//===----------------------------------------------------------------------===//
-// General
-//===----------------------------------------------------------------------===//
-GeneralLinkerConfig::GeneralLinkerConfig(const std::string& pTriple)
- : LinkerConfig(pTriple) {
-
- // set up target-dependent options
- getLDConfig()->targets().setEndian(mcld::TargetOptions::Little);
- getLDConfig()->targets().setBitClass(32);
-
- // set up target-dependent constraints of attributes
- getLDConfig()->attribute().constraint().enableWholeArchive();
- getLDConfig()->attribute().constraint().disableAsNeeded();
- getLDConfig()->attribute().constraint().setSharedSystem();
-
- // set up the predefined attributes
- getLDConfig()->attribute().predefined().unsetWholeArchive();
- getLDConfig()->attribute().predefined().setDynamic();
-
- // set up section map
- if (llvm::Triple::arm == getLDConfig()->targets().triple().getArch() &&
- getLDConfig()->codeGenType() != mcld::LinkerConfig::Object) {
- bool exist = false;
- getLDScript()->sectionMap().append(".ARM.exidx", ".ARM.exidx", exist);
- getLDScript()->sectionMap().append(".ARM.extab", ".ARM.extab", exist);
- getLDScript()->sectionMap().append(".ARM.attributes", ".ARM.attributes", exist);
- }
-
- // set up relocation factory
- mcld::Relocation::SetUp(*getLDConfig());
-}
-#endif // defined(TARGET_BUILD)
diff --git a/tools/mcld/main.cpp b/tools/mcld/main.cpp
index 968c5e6..dcb8140 100644
--- a/tools/mcld/main.cpp
+++ b/tools/mcld/main.cpp
@@ -1,4 +1,4 @@
-//===- mcld.cpp -----------------------------------------------------------===//
+//===- llvm-mcld.cpp ------------------------------------------------------===//
//
// The MCLinker Project
//
@@ -6,367 +6,1552 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include <mcld/Module.h>
+#include <mcld/LinkerConfig.h>
+#include <mcld/LinkerScript.h>
+#include <mcld/CodeGen/TargetMachine.h>
+#include <mcld/Support/TargetSelect.h>
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/Support/CommandLine.h>
+#include <mcld/Support/Path.h>
+#include <mcld/Support/RealPath.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/FileHandle.h>
+#include <mcld/Support/FileSystem.h>
+#include <mcld/Support/raw_ostream.h>
+#include <mcld/Support/SystemUtils.h>
+#include <mcld/Support/ToolOutputFile.h>
+#include <mcld/LD/DiagnosticLineInfo.h>
+#include <mcld/LD/TextDiagnosticPrinter.h>
-#include <stdlib.h>
-#include <string>
-
-#include <llvm/ADT/SmallString.h>
+#include <llvm/PassManager.h>
+#include <llvm/Pass.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/DataLayout.h>
+#include <llvm/IR/LLVMContext.h>
+#include <llvm/IRReader/IRReader.h>
+#include <llvm/ADT/Triple.h>
+#include <llvm/ADT/StringSwitch.h>
+#include <llvm/MC/SubtargetFeature.h>
#include <llvm/Support/CommandLine.h>
-#include <llvm/Support/FileSystem.h>
-#include <llvm/Support/Path.h>
-#include <llvm/Support/raw_ostream.h>
-#include <llvm/Support/system_error.h>
+#include <llvm/Support/Debug.h>
+#include <llvm/Support/FormattedStream.h>
+#include <llvm/Support/Host.h>
+#include <llvm/Support/ManagedStatic.h>
+#include <llvm/Support/Signals.h>
+#include <llvm/Support/SourceMgr.h>
+#include <llvm/Support/TargetSelect.h>
+#include <llvm/Support/TargetRegistry.h>
+#include <llvm/Support/Process.h>
+#include <llvm/Target/TargetMachine.h>
-#include <mcld/Config/Config.h>
+#include <iostream>
-#include <alone/Config/Config.h>
-#include <alone/Support/LinkerConfig.h>
-#include <alone/Support/Initialization.h>
-#include <alone/Support/TargetLinkerConfigs.h>
-#include <alone/Linker.h>
+using namespace std;
-using namespace alone;
-
-//===----------------------------------------------------------------------===//
-// Compiler Options
-//===----------------------------------------------------------------------===//
-#ifdef TARGET_BUILD
-static const std::string OptTargetTriple(DEFAULT_TARGET_TRIPLE_STRING);
-#else
-static llvm::cl::opt<std::string>
-OptTargetTriple("mtriple",
- llvm::cl::desc("Specify the target triple (default: "
- DEFAULT_TARGET_TRIPLE_STRING ")"),
- llvm::cl::init(DEFAULT_TARGET_TRIPLE_STRING),
- llvm::cl::value_desc("triple"));
-
-static llvm::cl::alias OptTargetTripleC("C", llvm::cl::NotHidden,
- llvm::cl::desc("Alias for -mtriple"),
- llvm::cl::aliasopt(OptTargetTriple));
+#if defined(HAVE_UNISTD_H)
+# include <unistd.h>
#endif
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#include <io.h>
+#ifndef STDIN_FILENO
+# define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO 1
+#endif
+#ifndef STDERR_FILENO
+# define STDERR_FILENO 2
+#endif
+#endif
+
+using namespace llvm;
+
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+
+static cl::opt<bool>
+UnitTest("unittest", cl::desc("do unit test") );
+
+int unit_test( int argc, char* argv[] )
+{
+ testing::InitGoogleTest( &argc, argv );
+ return RUN_ALL_TESTS();
+}
+
+#endif
+
+// General options for llc. Other pass-specific options are specified
+// within the corresponding llc passes, and target-specific options
+// and back-end code generation options are specified with the target machine.
+//
+// Determine optimization level.
+static cl::opt<char>
+OptLevel("O",
+ cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
+ "(default = '-O2')"),
+ cl::Prefix,
+ cl::ZeroOrMore,
+ cl::init(' '));
+
+static cl::opt<std::string>
+TargetTriple("mtriple", cl::desc("Override target triple for module"));
+
+static cl::opt<std::string>
+MArch("march", cl::desc("Architecture to generate code for (see --version)"));
+
+static cl::opt<std::string>
+MCPU("mcpu",
+ cl::desc("Target a specific cpu type (-mcpu=help for details)"),
+ cl::value_desc("cpu-name"),
+ cl::init(""));
+
+static cl::list<std::string>
+MAttrs("mattr",
+ cl::CommaSeparated,
+ cl::desc("Target specific attributes (-mattr=help for details)"),
+ cl::value_desc("a1,+a2,-a3,..."));
+
+static cl::opt<llvm::CodeModel::Model>
+CMModel("code-model",
+ cl::desc("Choose code model"),
+ cl::init(CodeModel::Default),
+ cl::values(clEnumValN(CodeModel::Default, "default",
+ "Target default code model"),
+ clEnumValN(CodeModel::Small, "small",
+ "Small code model"),
+ clEnumValN(CodeModel::Kernel, "kernel",
+ "Kernel code model"),
+ clEnumValN(CodeModel::Medium, "medium",
+ "Medium code model"),
+ clEnumValN(CodeModel::Large, "large",
+ "Large code model"),
+ clEnumValEnd));
+
+cl::opt<bool> NoVerify("disable-verify", cl::Hidden,
+ cl::desc("Do not verify input module"));
+
+static cl::opt<bool>
+EnableFPMAD("enable-fp-mad",
+ cl::desc("Enable less precise MAD instructions to be generated"),
+ cl::init(false));
+
+static cl::opt<bool>
+DisableFPElim("disable-fp-elim",
+ cl::desc("Disable frame pointer elimination optimization"),
+ cl::init(false));
+
+static cl::opt<llvm::FPOpFusion::FPOpFusionMode>
+FuseFPOps("fuse-fp-ops",
+ cl::desc("Enable aggresive formation of fused FP ops"),
+ cl::init(FPOpFusion::Standard),
+ cl::values(
+ clEnumValN(FPOpFusion::Fast, "fast",
+ "Fuse FP ops whenever profitable"),
+ clEnumValN(FPOpFusion::Standard, "standard",
+ "Only fuse 'blessed' FP ops."),
+ clEnumValN(FPOpFusion::Strict, "strict",
+ "Only fuse FP ops when the result won't be effected."),
+ clEnumValEnd));
+
+static cl::opt<bool>
+EnableUnsafeFPMath("enable-unsafe-fp-math",
+ cl::desc("Enable optimizations that may decrease FP precision"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableNoInfsFPMath("enable-no-infs-fp-math",
+ cl::desc("Enable FP math optimizations that assume no +-Infs"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableNoNaNsFPMath("enable-no-nans-fp-math",
+ cl::desc("Enable FP math optimizations that assume no NaNs"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math",
+ cl::Hidden,
+ cl::desc("Force codegen to assume rounding mode can change dynamically"),
+ cl::init(false));
+
+static cl::opt<bool>
+GenerateSoftFloatCalls("soft-float",
+ cl::desc("Generate software floating point library calls"),
+ cl::init(false));
+
+static cl::opt<llvm::FloatABI::ABIType>
+FloatABIForCalls("float-abi",
+ cl::desc("Choose float ABI type"),
+ cl::init(FloatABI::Default),
+ cl::values(
+ clEnumValN(FloatABI::Default, "default",
+ "Target default float ABI type"),
+ clEnumValN(FloatABI::Soft, "soft",
+ "Soft float ABI (implied by -soft-float)"),
+ clEnumValN(FloatABI::Hard, "hard",
+ "Hard float ABI (uses FP registers)"),
+ clEnumValEnd));
+
+static cl::opt<bool>
+DontPlaceZerosInBSS("nozero-initialized-in-bss",
+ cl::desc("Don't place zero-initialized symbols into bss section"),
+ cl::init(false));
+
+// In debug builds, make this default to true.
+#ifdef NDEBUG
+#define EMIT_DEBUG false
+#else
+#define EMIT_DEBUG true
+#endif
+static cl::opt<bool>
+EmitJitDebugInfo("jit-emit-debug",
+ cl::desc("Emit debug information to debugger"),
+ cl::init(EMIT_DEBUG));
+#undef EMIT_DEBUG
+
+static cl::opt<bool>
+EmitJitDebugInfoToDisk("jit-emit-debug-to-disk",
+ cl::Hidden,
+ cl::desc("Emit debug info objfiles to disk"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableGuaranteedTailCallOpt("tailcallopt",
+ cl::desc("Turn fastcc calls into tail calls by (potentially) changing ABI."),
+ cl::init(false));
+
+static cl::opt<unsigned>
+OverrideStackAlignment("stack-alignment",
+ cl::desc("Override default stack alignment"),
+ cl::init(0));
+
+// --script is an alias, but cl::alias doesn't work correctly with cl::list.
+static cl::list<std::string>
+ArgLinkerScript("T",
+ cl::ZeroOrMore,
+ cl::desc("Linker script"),
+ cl::value_desc("file"));
+
+static cl::opt<std::string>
+TrapFuncName("trap-func", cl::Hidden,
+ cl::desc("Emit a call to trap function rather than a trap instruction"),
+ cl::init(""));
+
+static cl::opt<bool>
+SegmentedStacks("segmented-stacks",
+ cl::desc("Use segmented stacks if possible."),
+ cl::init(false));
+
//===----------------------------------------------------------------------===//
// Command Line Options
// There are four kinds of command line options:
-// 1. input, (may be a file, such as -m and /tmp/XXXX.o.)
-// 2. scripting options, (represent a subset of link scripting language, such
-// as --defsym.)
-// 3. and general options. (the rest of options)
+// 1. Bitcode option. Used to represent a bitcode.
+// 2. Attribute options. Attributes describes the input file after them. For
+// example, --as-needed affects the input file after this option. Attribute
+// options are not attributes. Attribute options are the options that is
+// used to define a legal attribute.
+// 3. Scripting options, Used to represent a subset of link scripting
+// language, such as --defsym.
+// 4. General options. (the rest of options)
+//===----------------------------------------------------------------------===//
+// Bitcode Options
+//===----------------------------------------------------------------------===//
+static cl::opt<mcld::sys::fs::Path, false, llvm::cl::parser<mcld::sys::fs::Path> >
+ArgBitcodeFilename("dB",
+ cl::desc("set default bitcode"),
+ cl::value_desc("bitcode"));
+
//===----------------------------------------------------------------------===//
// General Options
//===----------------------------------------------------------------------===//
-static llvm::cl::opt<std::string>
-OptOutputFilename("o",
- llvm::cl::desc("Output filename"),
- llvm::cl::value_desc("filename"));
+static cl::opt<mcld::sys::fs::Path, false, llvm::cl::parser<mcld::sys::fs::Path> >
+ArgOutputFilename("o",
+ cl::desc("Output filename"),
+ cl::value_desc("filename"));
-static llvm::cl::opt<std::string>
-OptSysRoot("sysroot", llvm::cl::desc("Use directory as the location of the "
- "sysroot, overriding the configure-time "
- "default."),
- llvm::cl::value_desc("directory"),
- llvm::cl::ValueRequired);
+static cl::alias
+AliasOutputFilename("output",
+ cl::desc("alias for -o"),
+ cl::aliasopt(ArgOutputFilename));
-static llvm::cl::list<std::string>
-OptSearchDirList("L",
- llvm::cl::ZeroOrMore,
- llvm::cl::desc("Add path searchdir to the list of paths that "
- "mcld will search for archive libraries and "
- "mcld control scripts."),
- llvm::cl::value_desc("searchdir"),
- llvm::cl::Prefix);
+static cl::opt<mcld::sys::fs::Path, false, llvm::cl::parser<mcld::sys::fs::Path> >
+ArgSysRoot("sysroot",
+ cl::desc("Use directory as the location of the sysroot, overriding the configure-time default."),
+ cl::value_desc("directory"),
+ cl::ValueRequired);
-static llvm::cl::opt<std::string>
-OptSOName("soname",
- llvm::cl::desc("Set internal name of shared library"),
- llvm::cl::value_desc("name"));
+static cl::list<std::string, bool, llvm::cl::SearchDirParser>
+ArgSearchDirList("L",
+ cl::ZeroOrMore,
+ cl::desc("Add path searchdir to the list of paths that ld will search for archive libraries and ld control scripts."),
+ cl::value_desc("searchdir"),
+ cl::Prefix);
+
+static cl::alias
+ArgSearchDirListAlias("library-path",
+ cl::desc("alias for -L"),
+ cl::aliasopt(ArgSearchDirList));
+
+static cl::opt<bool>
+ArgTrace("t",
+ cl::desc("Print the names of the input files as ld processes them."));
+
+static cl::alias
+ArgTraceAlias("trace",
+ cl::desc("alias for -t"),
+ cl::aliasopt(ArgTrace));
+
+static cl::opt<int>
+ArgVerbose("verbose",
+ cl::init(-1),
+ cl::desc("Display the version number for ld and list the linker emulations supported."));
+
+static cl::opt<bool>
+ArgVersion("V",
+ cl::init(false),
+ cl::desc("Display the version number for MCLinker."));
+
+static cl::opt<int>
+ArgMaxErrorNum("error-limit",
+ cl::init(-1),
+ cl::desc("limits the maximum number of erros."));
+
+static cl::opt<int>
+ArgMaxWarnNum("warning-limit",
+ cl::init(-1),
+ cl::desc("limits the maximum number of warnings."));
+
+static cl::opt<std::string>
+ArgEntry("e",
+ cl::desc("Use entry as the explicit symbol for beginning execution of your program."),
+ cl::value_desc("entry"),
+ cl::ValueRequired);
+
+static cl::alias
+ArgEntryAlias("entry",
+ cl::desc("alias for -e"),
+ cl::aliasopt(ArgEntry));
+
+static cl::opt<bool>
+ArgBsymbolic("Bsymbolic",
+ cl::desc("Bind references within the shared library."),
+ cl::init(false));
+
+static cl::opt<bool>
+ArgBgroup("Bgroup",
+ cl::desc("Info the dynamic linker to perform lookups only inside the group."),
+ cl::init(false));
+
+static cl::opt<std::string>
+ArgSOName("soname",
+ cl::desc("Set internal name of shared library"),
+ cl::value_desc("name"));
+
+static cl::opt<bool>
+ArgNoUndefined("no-undefined",
+ cl::desc("Do not allow unresolved references"),
+ cl::init(false));
+
+static cl::opt<bool>
+ArgAllowMulDefs("allow-multiple-definition",
+ cl::desc("Allow multiple definition"),
+ cl::init(false));
+
+static cl::opt<bool>
+ArgEhFrameHdr("eh-frame-hdr",
+ cl::ZeroOrMore,
+ cl::desc("Request creation of \".eh_frame_hdr\" section and ELF \"PT_GNU_EH_FRAME\" segment header."),
+ cl::init(false));
+
+static cl::list<mcld::ZOption, bool, llvm::cl::parser<mcld::ZOption> >
+ArgZOptionList("z",
+ cl::ZeroOrMore,
+ cl::desc("The -z options for GNU ld compatibility."),
+ cl::value_desc("keyword"),
+ cl::Prefix);
+
+cl::opt<mcld::CodeGenFileType>
+ArgFileType("filetype", cl::init(mcld::CGFT_EXEFile),
+ cl::desc("Choose a file type (not all types are supported by all targets):"),
+ cl::values(
+ clEnumValN(mcld::CGFT_ASMFile, "asm",
+ "Emit an assembly ('.s') file"),
+ clEnumValN(mcld::CGFT_OBJFile, "obj",
+ "Emit a relocatable object ('.o') file"),
+ clEnumValN(mcld::CGFT_DSOFile, "dso",
+ "Emit an dynamic shared object ('.so') file"),
+ clEnumValN(mcld::CGFT_EXEFile, "exe",
+ "Emit a executable ('.exe') file"),
+ clEnumValN(mcld::CGFT_NULLFile, "null",
+ "Emit nothing, for performance testing"),
+ clEnumValEnd));
+
+static cl::opt<bool>
+ArgShared("shared",
+ cl::desc("Create a shared library."),
+ cl::init(false));
+
+static cl::alias
+ArgSharedAlias("Bshareable",
+ cl::desc("alias for -shared"),
+ cl::aliasopt(ArgShared));
+
+static cl::opt<bool>
+ArgPIE("pie",
+ cl::desc("Emit a position-independent executable file"),
+ cl::init(false));
+
+static cl::opt<bool>
+ArgRelocatable("relocatable",
+ cl::desc("Generate relocatable output"),
+ cl::init(false));
+
+static cl::alias
+ArgRelocatableAlias("r",
+ cl::desc("alias for --relocatable"),
+ cl::aliasopt(ArgRelocatable));
+
+static cl::opt<Reloc::Model>
+ArgRelocModel("relocation-model",
+ cl::desc("Choose relocation model"),
+ cl::init(Reloc::Default),
+ cl::values(
+ clEnumValN(Reloc::Default, "default",
+ "Target default relocation model"),
+ clEnumValN(Reloc::Static, "static",
+ "Non-relocatable code"),
+ clEnumValN(Reloc::PIC_, "pic",
+ "Fully relocatable, position independent code"),
+ clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic",
+ "Relocatable external references, non-relocatable code"),
+ clEnumValEnd));
+
+static cl::opt<bool>
+ArgFPIC("fPIC",
+ cl::desc("Set relocation model to pic. The same as -relocation-model=pic."),
+ cl::init(false));
+
+static cl::opt<std::string>
+ArgDyld("dynamic-linker",
+ cl::ZeroOrMore,
+ cl::desc("Set the name of the dynamic linker."),
+ cl::value_desc("Program"));
+
+namespace color {
+enum Color {
+ Never,
+ Always,
+ Auto
+};
+} // namespace of color
+
+static cl::opt<color::Color>
+ArgColor("color",
+ cl::value_desc("WHEN"),
+ cl::desc("Surround the result strings with the marker"),
+ cl::init(color::Auto),
+ cl::values(
+ clEnumValN(color::Never, "never",
+ "do not surround result strings"),
+ clEnumValN(color::Always, "always",
+ "always surround result strings, even the output is a plain file"),
+ clEnumValN(color::Auto, "auto",
+ "surround result strings only if the output is a tty"),
+ clEnumValEnd));
+
+static cl::opt<bool>
+ArgDiscardLocals("discard-locals",
+ cl::desc("Delete all temporary local symbols."),
+ cl::init(false));
+
+static cl::alias
+ArgDiscardLocalsAlias("X",
+ cl::desc("alias for --discard-locals"),
+ cl::aliasopt(ArgDiscardLocals));
+
+static cl::opt<bool>
+ArgDiscardAll("discard-all",
+ cl::desc("Delete all local symbols."),
+ cl::init(false));
+
+static cl::alias
+ArgDiscardAllAlias("x",
+ cl::desc("alias for --discard-all"),
+ cl::aliasopt(ArgDiscardAll));
+
+static cl::opt<bool>
+ArgStripDebug("strip-debug",
+ cl::desc("Omit debugger symbol information from the output file."),
+ cl::init(false));
+
+static cl::alias
+ArgStripDebugAlias("S",
+ cl::desc("alias for --strip-debug"),
+ cl::aliasopt(ArgStripDebug));
+
+static cl::opt<bool>
+ArgStripAll("strip-all",
+ cl::desc("Omit all symbol information from the output file."),
+ cl::init(false));
+
+static cl::alias
+ArgStripAllAlias("s",
+ cl::desc("alias for --strip-all"),
+ cl::aliasopt(ArgStripAll));
+
+static cl::opt<bool>
+ArgNMagic("nmagic",
+ cl::desc("Do not page align data"),
+ cl::init(false));
+
+static cl::alias
+ArgNMagicAlias("n",
+ cl::desc("alias for --nmagic"),
+ cl::aliasopt(ArgNMagic));
+
+static cl::opt<bool>
+ArgOMagic("omagic",
+ cl::desc("Do not page align data, do not make text readonly"),
+ cl::init(false));
+
+static cl::alias
+ArgOMagicAlias("N",
+ cl::desc("alias for --omagic"),
+ cl::aliasopt(ArgOMagic));
-static llvm::cl::opt<bool>
-OptShared("shared",
- llvm::cl::desc("Create a shared library."),
- llvm::cl::init(false));
+static cl::opt<int>
+ArgGPSize("G",
+ cl::desc("Set the maximum size of objects to be optimized using GP"),
+ cl::init(8));
-static llvm::cl::opt<bool>
-OptBsymbolic("Bsymbolic",
- llvm::cl::desc("Bind references within the shared library."),
- llvm::cl::init(true));
+static bool ArgGenUnwindInfo;
-static llvm::cl::opt<std::string>
-OptDyld("dynamic-linker",
- llvm::cl::desc("Set the name of the dynamic linker."),
- llvm::cl::value_desc("Program"));
+static cl::opt<bool, true, cl::FalseParser>
+ArgNoGenUnwindInfoFlag("no-ld-generated-unwind-info",
+ cl::ZeroOrMore, cl::location(ArgGenUnwindInfo),
+ cl::desc("Don't create unwind info for linker generated"
+ " sections to save size"),
+ cl::init(false),
+ cl::ValueDisallowed);
+static cl::opt<bool, true>
+ArgGenUnwindInfoFlag("ld-generated-unwind-info",
+ cl::ZeroOrMore, cl::location(ArgGenUnwindInfo),
+ cl::desc("Request creation of unwind info for linker"
+ " generated code sections like PLT."),
+ cl::init(true),
+ cl::ValueDisallowed);
+/// @{
+/// @{
+/// @name FIXME: begin of unsupported options
+/// @}
+static cl::opt<bool>
+ArgGCSections("gc-sections",
+ cl::ZeroOrMore,
+ cl::desc("Enable garbage collection of unused input sections."),
+ cl::init(false));
-static llvm::cl::opt<bool>
-OptRelocatable("relocatable",
- llvm::cl::desc("Generate relocatable output"),
- llvm::cl::init(false));
+static cl::opt<bool>
+ArgNoGCSections("no-gc-sections",
+ cl::ZeroOrMore,
+ cl::desc("disable garbage collection of unused input sections."),
+ cl::init(false));
-static llvm::cl::alias
-OptRelocatableAlias("r",
- llvm::cl::desc("alias for --relocatable"),
- llvm::cl::aliasopt(OptRelocatable));
+namespace icf {
+enum Mode {
+ None,
+ All,
+ Safe
+};
+} // namespace of icf
-static llvm::cl::opt<bool>
-OptDefineCommon("d",
- llvm::cl::ZeroOrMore,
- llvm::cl::desc("Define common symbol"),
- llvm::cl::init(false));
+static cl::opt<icf::Mode>
+ArgICF("icf",
+ cl::ZeroOrMore,
+ cl::desc("Identical Code Folding"),
+ cl::init(icf::None),
+ cl::values(
+ clEnumValN(icf::None, "none",
+ "do not perform cold folding"),
+ clEnumValN(icf::All, "all",
+ "always preform cold folding"),
+ clEnumValN(icf::Safe, "safe",
+ "Folds ctors, dtors and functions whose pointers are definitely not taken."),
+ clEnumValEnd));
-static llvm::cl::alias
-OptDefineCommonAlias1("dc",
- llvm::cl::desc("alias for -d"),
- llvm::cl::aliasopt(OptDefineCommon));
+// FIXME: add this to target options?
+static cl::opt<bool>
+ArgFIXCA8("fix-cortex-a8",
+ cl::desc("Enable Cortex-A8 Thumb-2 branch erratum fix"),
+ cl::init(false));
-static llvm::cl::alias
-OptDefineCommonAlias2("dp",
- llvm::cl::desc("alias for -d"),
- llvm::cl::aliasopt(OptDefineCommon));
+static cl::opt<bool>
+ArgExportDynamic("export-dynamic",
+ cl::desc("Export all dynamic symbols"),
+ cl::init(false));
+static cl::alias
+ArgExportDynamicAlias("E",
+ cl::desc("alias for --export-dynamic"),
+ cl::aliasopt(ArgExportDynamic));
-//===----------------------------------------------------------------------===//
-// Inputs
-//===----------------------------------------------------------------------===//
-static llvm::cl::list<std::string>
-OptInputObjectFiles(llvm::cl::Positional,
- llvm::cl::desc("[input object files]"),
- llvm::cl::OneOrMore);
+static cl::opt<std::string>
+ArgEmulation("m",
+ cl::ZeroOrMore,
+ cl::desc("Set GNU linker emulation"),
+ cl::value_desc("emulation"),
+ cl::Prefix);
-static llvm::cl::list<std::string>
-OptNameSpecList("l",
- llvm::cl::ZeroOrMore,
- llvm::cl::desc("Add the archive or object file specified by "
- "namespec to the list of files to link."),
- llvm::cl::value_desc("namespec"),
- llvm::cl::Prefix);
+static cl::list<std::string, bool, llvm::cl::SearchDirParser>
+ArgRuntimePathLink("rpath-link",
+ cl::ZeroOrMore,
+ cl::desc("Add a directory to the link time library search path"),
+ cl::value_desc("dir"));
+
+static cl::list<std::string>
+ArgExcludeLIBS("exclude-libs",
+ cl::CommaSeparated,
+ cl::desc("Exclude libraries from automatic export"),
+ cl::value_desc("lib1,lib2,..."));
+
+static cl::opt<std::string>
+ArgBuildID("build-id",
+ cl::desc("Request creation of \".note.gnu.build-id\" ELF note section."),
+ cl::value_desc("style"),
+ cl::ValueOptional);
+
+static cl::opt<std::string>
+ArgForceUndefined("u",
+ cl::desc("Force symbol to be undefined in the output file"),
+ cl::value_desc("symbol"));
+
+static cl::alias
+ArgForceUndefinedAlias("undefined",
+ cl::desc("alias for -u"),
+ cl::aliasopt(ArgForceUndefined));
+
+static cl::opt<std::string>
+ArgVersionScript("version-script",
+ cl::desc("Version script."),
+ cl::value_desc("Version script"));
+
+static cl::opt<bool>
+ArgWarnCommon("warn-common",
+ cl::desc("warn common symbol"),
+ cl::init(false));
+
+static cl::opt<mcld::GeneralOptions::HashStyle>
+ArgHashStyle("hash-style", cl::init(mcld::GeneralOptions::SystemV),
+ cl::desc("Set the type of linker's hash table(s)."),
+ cl::values(
+ clEnumValN(mcld::GeneralOptions::SystemV, "sysv",
+ "classic ELF .hash section"),
+ clEnumValN(mcld::GeneralOptions::GNU, "gnu",
+ "new style GNU .gnu.hash section"),
+ clEnumValN(mcld::GeneralOptions::Both, "both",
+ "both the classic ELF and new style GNU hash tables"),
+ clEnumValEnd));
+
+static cl::opt<std::string>
+ArgFilter("F",
+ cl::desc("Filter for shared object symbol table"),
+ cl::value_desc("name"));
+
+static cl::alias
+ArgFilterAlias("filter",
+ cl::desc("alias for -F"),
+ cl::aliasopt(ArgFilterAlias));
+
+static cl::list<std::string>
+ArgAuxiliary("f",
+ cl::ZeroOrMore,
+ cl::desc("Auxiliary filter for shared object symbol table"),
+ cl::value_desc("name"));
+
+static cl::alias
+ArgAuxiliaryAlias("auxiliary",
+ cl::desc("alias for -f"),
+ cl::aliasopt(ArgAuxiliary));
+
+static cl::opt<bool>
+ArgUseGold("use-gold",
+ cl::desc("GCC/collect2 compatibility: uses ld.gold. Ignored"),
+ cl::init(false));
+
+static cl::opt<bool>
+ArgUseMCLD("use-mcld",
+ cl::desc("GCC/collect2 compatibility: uses ld.mcld. Ignored"),
+ cl::init(false));
+
+static cl::opt<bool>
+ArgUseLD("use-ld",
+ cl::desc("GCC/collect2 compatibility: uses ld.bfd. Ignored"),
+ cl::init(false));
+
+static cl::opt<bool>
+ArgEB("EB",
+ cl::desc("Link big-endian objects. This affects the default output format."),
+ cl::init(false));
+
+static cl::opt<bool>
+ArgEL("EL",
+ cl::desc("Link little-endian objects. This affects the default output format."),
+ cl::init(false));
+
+static cl::list<std::string>
+ArgPlugin("plugin",
+ cl::desc("Load a plugin library."),
+ cl::value_desc("plugin"));
+
+static cl::list<std::string>
+ArgPluginOpt("plugin-opt",
+ cl::desc(" Pass an option to the plugin."),
+ cl::value_desc("option"));
+
+static cl::opt<bool>
+ArgSVR4Compatibility("Qy",
+ cl::desc("This option is ignored for SVR4 compatibility"),
+ cl::init(false));
+
+static cl::list<std::string>
+ArgY("Y",
+ cl::desc("Add path to the default library search path"),
+ cl::value_desc("default-search-path"));
+
+static cl::opt<bool>
+ArgARMCompatibility("p",
+ cl::desc("Ignore for ARM backward compatibility"),
+ cl::init(false));
+
+/// @{
+/// @name FIXME: end of unsupported options
+/// @}
+
+static cl::opt<bool>
+ArgNoWarnMismatch("no-warn-mismatch",
+ cl::desc("Allow linking together mismatched input files."),
+ cl::init(false));
+
+static cl::opt<bool>
+ArgNoStdlib("nostdlib",
+ cl::desc("Only search lib dirs explicitly specified on cmdline"),
+ cl::init(false));
+
+static cl::list<std::string, bool, llvm::cl::SearchDirParser>
+ArgRuntimePath("rpath",
+ cl::ZeroOrMore,
+ cl::desc("Add a directory to the runtime library search path"),
+ cl::value_desc("dir"));
+
+static cl::alias
+ArgRuntimePathAlias("R",
+ cl::desc("alias for --rpath"),
+ cl::aliasopt(ArgRuntimePath), cl::Prefix);
+
+static cl::opt<bool>
+ArgEnableNewDTags("enable-new-dtags",
+ cl::desc("Enable use of DT_RUNPATH and DT_FLAGS"),
+ cl::init(false));
+
+static cl::opt<bool>
+ArgPrintMap("M",
+ cl::desc("Print a link map to the standard output."),
+ cl::init(false));
+
+static cl::alias
+ArgPrintMapAlias("print-map",
+ cl::desc("alias for -M"),
+ cl::aliasopt(ArgPrintMap));
+
+static bool ArgFatalWarnings;
+
+static cl::opt<bool, true, cl::FalseParser>
+ArgNoFatalWarnings("no-fatal-warnings",
+ cl::location(ArgFatalWarnings),
+ cl::desc("do not turn warnings into errors"),
+ cl::init(false),
+ cl::ValueDisallowed);
+
+static cl::opt<bool, true>
+ArgFatalWarningsFlag("fatal-warnings",
+ cl::location(ArgFatalWarnings),
+ cl::desc("turn all warnings into errors"),
+ cl::init(false),
+ cl::ValueDisallowed);
+
+static cl::opt<bool>
+ArgWarnSharedTextrel("warn-shared-textrel",
+ cl::desc("Warn if adding DT_TEXTREL in a shared object."),
+ cl::init(false));
+
+namespace format {
+enum Format {
+ Binary,
+ Unknown // decided by triple
+};
+} // namespace of format
+
+static cl::opt<format::Format>
+ArgFormat("b",
+ cl::value_desc("Format"),
+ cl::desc("set input format"),
+ cl::init(format::Unknown),
+ cl::values(
+ clEnumValN(format::Binary, "binary",
+ "read in binary machine code."),
+ clEnumValEnd));
+
+static cl::alias
+ArgFormatAlias("format",
+ cl::desc("alias for -b"),
+ cl::aliasopt(ArgFormat));
+
+static cl::opt<format::Format>
+ArgOFormat("oformat",
+ cl::value_desc("Format"),
+ cl::desc("set output format"),
+ cl::init(format::Unknown),
+ cl::values(
+ clEnumValN(format::Binary, "binary",
+ "generate binary machine code."),
+ clEnumValEnd));
+
+static cl::opt<bool>
+ArgDefineCommon("d",
+ cl::ZeroOrMore,
+ cl::desc("Define common symbol"),
+ cl::init(false));
+
+static cl::alias
+ArgDefineCommonAlias1("dc",
+ cl::ZeroOrMore,
+ cl::desc("alias for -d"),
+ cl::aliasopt(ArgDefineCommon));
+
+static cl::alias
+ArgDefineCommonAlias2("dp",
+ cl::ZeroOrMore,
+ cl::desc("alias for -d"),
+ cl::aliasopt(ArgDefineCommon));
//===----------------------------------------------------------------------===//
// Scripting Options
//===----------------------------------------------------------------------===//
-static llvm::cl::list<std::string>
-OptWrapList("wrap",
- llvm::cl::ZeroOrMore,
- llvm::cl::desc("Use a wrap function fo symbol."),
- llvm::cl::value_desc("symbol"));
+static cl::list<std::string>
+ArgWrapList("wrap",
+ cl::ZeroOrMore,
+ cl::desc("Use a wrap function fo symbol."),
+ cl::value_desc("symbol"));
-static llvm::cl::list<std::string>
-OptPortableList("portable",
- llvm::cl::ZeroOrMore,
- llvm::cl::desc("Use a portable function to symbol."),
- llvm::cl::value_desc("symbol"));
+static cl::list<std::string>
+ArgPortList("portable",
+ cl::ZeroOrMore,
+ cl::desc("Use a portable function fo symbol."),
+ cl::value_desc("symbol"));
+
+static cl::list<std::string>
+ArgAddressMapList("section-start",
+ cl::ZeroOrMore,
+ cl::desc("Locate a output section at the given absolute address"),
+ cl::value_desc("Set address of section"),
+ cl::Prefix);
+
+static cl::opt<unsigned long long>
+ArgBssSegAddr("Tbss",
+ cl::desc("Set the address of the bss segment"),
+ cl::init(-1U));
+
+static cl::opt<unsigned long long>
+ArgDataSegAddr("Tdata",
+ cl::desc("Set the address of the data segment"),
+ cl::init(-1U));
+
+static cl::opt<unsigned long long>
+ArgTextSegAddr("Ttext",
+ cl::desc("Set the address of the text segment"),
+ cl::init(-1U));
+
+static cl::alias
+ArgTextSegAddrAlias("Ttext-segment",
+ cl::desc("alias for -Ttext"),
+ cl::aliasopt(ArgTextSegAddr));
//===----------------------------------------------------------------------===//
-// Helper Functions
+// non-member functions
//===----------------------------------------------------------------------===//
-// Override "mcld -version"
-static void MCLDVersionPrinter() {
- llvm::raw_ostream &os = llvm::outs();
- os << "mcld (The MCLinker Project, http://mclinker.googlecode.com/):\n"
- << " version: " MCLD_VERSION "\n"
- << " Default target: " << DEFAULT_TARGET_TRIPLE_STRING << "\n";
+/// GetOutputStream - get the output stream.
+static mcld::ToolOutputFile *GetOutputStream(const char* pTargetName,
+ Triple::OSType pOSType,
+ mcld::CodeGenFileType pFileType,
+ const mcld::sys::fs::Path& pInputFilename,
+ mcld::sys::fs::Path& pOutputFilename)
+{
+ if (pOutputFilename.empty()) {
+ if (0 == pInputFilename.native().compare("-"))
+ pOutputFilename.assign("-");
+ else {
+ switch(pFileType) {
+ case mcld::CGFT_ASMFile: {
+ if (0 == pInputFilename.native().compare("-"))
+ pOutputFilename.assign("_out");
+ else
+ pOutputFilename.assign(pInputFilename.stem().native());
- os << "\n";
+ if (0 == strcmp(pTargetName, "c"))
+ pOutputFilename.native() += ".cbe.c";
+ else if (0 == strcmp(pTargetName, "cpp"))
+ pOutputFilename.native() += ".cpp";
+ else
+ pOutputFilename.native() += ".s";
+ }
+ break;
- os << "LLVM (http://llvm.org/):\n";
+ case mcld::CGFT_OBJFile: {
+ if (0 == pInputFilename.native().compare("-"))
+ pOutputFilename.assign("_out");
+ else
+ pOutputFilename.assign(pInputFilename.stem().native());
- return;
+ if (pOSType == Triple::Win32)
+ pOutputFilename.native() += ".obj";
+ else
+ pOutputFilename.native() += ".o";
+ }
+ break;
+
+ case mcld::CGFT_PARTIAL: {
+ if (Triple::Win32 == pOSType) {
+ if (0 == pInputFilename.native().compare("-"))
+ pOutputFilename.assign("_out");
+ else
+ pOutputFilename.assign(pInputFilename.stem().native());
+ pOutputFilename.native() += ".obj";
+ }
+ else
+ pOutputFilename.assign("a.out");
+ }
+ break;
+
+ case mcld::CGFT_DSOFile: {
+ if (Triple::Win32 == pOSType) {
+ if (0 == pInputFilename.native().compare("-"))
+ pOutputFilename.assign("_out");
+ else
+ pOutputFilename.assign(pInputFilename.stem().native());
+ pOutputFilename.native() += ".dll";
+ }
+ else
+ pOutputFilename.assign("a.out");
+ }
+ break;
+
+ case mcld::CGFT_EXEFile: {
+ if (Triple::Win32 == pOSType) {
+ if (0 == pInputFilename.native().compare("-"))
+ pOutputFilename.assign("_out");
+ else
+ pOutputFilename.assign(pInputFilename.stem().native());
+ pOutputFilename.native() += ".exe";
+ }
+ else
+ pOutputFilename.assign("a.out");
+ }
+ break;
+
+ case mcld::CGFT_NULLFile:
+ break;
+ default:
+ llvm::report_fatal_error("Unknown output file type.\n");
+ } // end of switch
+ } // end of ! pInputFilename == "-"
+ } // end of if empty pOutputFilename
+
+ mcld::FileHandle::Permission permission;
+ switch (pFileType) {
+ default: assert(0 && "Unknown file type");
+ case mcld::CGFT_ASMFile:
+ case mcld::CGFT_OBJFile:
+ case mcld::CGFT_PARTIAL:
+ permission = mcld::FileHandle::Permission(0x644);
+ break;
+ case mcld::CGFT_DSOFile:
+ case mcld::CGFT_EXEFile:
+ case mcld::CGFT_BINARY:
+ case mcld::CGFT_NULLFile:
+ permission = mcld::FileHandle::Permission(0x755);
+ break;
+ }
+
+ // Open the file.
+ mcld::ToolOutputFile* result_output =
+ new mcld::ToolOutputFile(pOutputFilename,
+ mcld::FileHandle::ReadWrite |
+ mcld::FileHandle::Create |
+ mcld::FileHandle::Truncate,
+ permission);
+
+ return result_output;
}
-#define DEFAULT_OUTPUT_PATH "a.out"
-static inline
-std::string DetermineOutputFilename(const std::string &pOutputPath) {
- if (!pOutputPath.empty()) {
- return pOutputPath;
+/// ParseProgName - Parse program name
+/// This function simplifies cross-compiling by reading triple from the program
+/// name. For example, if the program name is `arm-linux-eabi-ld.mcld', we can
+/// get the triple is arm-linux-eabi by the program name.
+static std::string ParseProgName(const char *progname)
+{
+ static const char *suffixes[] = {
+ "ld",
+ "ld.mcld",
+ };
+
+ std::string ProgName(mcld::sys::fs::Path(progname).stem().native());
+
+ for (size_t i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
+ if (ProgName == suffixes[i])
+ return std::string();
}
- // User does't specify the value to -o
- if (OptInputObjectFiles.size() > 1) {
- llvm::errs() << "Use " DEFAULT_OUTPUT_PATH " for output file!\n";
- return DEFAULT_OUTPUT_PATH;
+ StringRef ProgNameRef(ProgName);
+ StringRef Prefix;
+
+ for (size_t i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
+ if (!ProgNameRef.endswith(suffixes[i]))
+ continue;
+
+ StringRef::size_type LastComponent = ProgNameRef.rfind('-',
+ ProgNameRef.size() - strlen(suffixes[i]));
+ if (LastComponent == StringRef::npos)
+ continue;
+ StringRef Prefix = ProgNameRef.slice(0, LastComponent);
+ std::string IgnoredError;
+ if (!mcld::TargetRegistry::lookupTarget(Prefix, IgnoredError))
+ continue;
+ return Prefix.str();
}
-
- // There's only one input file
- const std::string &input_path = OptInputObjectFiles[0];
- llvm::SmallString<200> output_path(input_path);
-
- llvm::error_code err = llvm::sys::fs::make_absolute(output_path);
- if (llvm::errc::success != err) {
- llvm::errs() << "Failed to determine the absolute path of `" << input_path
- << "'! (detail: " << err.message() << ")\n";
- return "";
- }
-
- llvm::sys::path::remove_filename(output_path);
- llvm::sys::path::append(output_path, "a.out");
-
- return output_path.c_str();
+ return std::string();
}
-static inline
-bool ConfigLinker(Linker &pLinker, const std::string &pOutputFilename) {
- LinkerConfig* config = NULL;
+static Triple ParseEmulation(const std::string& pEmulation)
+{
+ Triple result = StringSwitch<Triple>(pEmulation)
+ .Case("armelf_linux_eabi", Triple("arm", "", "linux", "gnueabi"))
+ .Case("elf_i386", Triple("i386", "", "", "gnu"))
+ .Case("elf_x86_64", Triple("x86_64", "", "", "gnu"))
+ .Case("elf32_x86_64", Triple("x86_64", "", "", "gnux32"))
+ .Case("elf_i386_fbsd", Triple("i386", "", "freebsd", "gnu"))
+ .Case("elf_x86_64_fbsd", Triple("x86_64", "", "freebsd", "gnu"))
+ .Case("elf32ltsmip", Triple("mipsel", "", "", "gnu"))
+ .Default(Triple());
-#ifdef TARGET_BUILD
- config = new (std::nothrow) DefaultLinkerConfig();
-#else
- config = new (std::nothrow) GeneralLinkerConfig(OptTargetTriple);
+ if (result.getArch() == Triple::UnknownArch &&
+ result.getOS() == Triple::UnknownOS &&
+ result.getEnvironment() == Triple::UnknownEnvironment)
+ mcld::error(mcld::diag::err_invalid_emulation) << pEmulation << "\n";
+
+ return result;
+}
+
+static bool ShouldColorize()
+{
+ const char* term = getenv("TERM");
+ return term && (0 != strcmp(term, "dumb"));
+}
+
+static bool ProcessLinkerOptionsFromCommand(mcld::LinkerScript& pScript,
+ mcld::LinkerConfig& pConfig)
+{
+ // ----- Set up General Options ----- //
+ // set up colorize
+ switch (ArgColor) {
+ case color::Never:
+ pConfig.options().setColor(false);
+ break;
+ case color::Always:
+ pConfig.options().setColor(true);
+ break;
+ case color::Auto:
+ bool color_option = ShouldColorize() &&
+ llvm::sys::Process::FileDescriptorIsDisplayed(STDOUT_FILENO);
+ pConfig.options().setColor(color_option);
+ break;
+ }
+
+ mcld::outs().setColor(pConfig.options().color());
+ mcld::errs().setColor(pConfig.options().color());
+
+ // set up soname
+ pConfig.options().setSOName(ArgSOName);
+
+ // add all rpath entries
+ cl::list<std::string>::iterator rp;
+ cl::list<std::string>::iterator rpEnd = ArgRuntimePath.end();
+ for (rp = ArgRuntimePath.begin(); rp != rpEnd; ++rp) {
+ pConfig.options().getRpathList().push_back(*rp);
+ }
+
+ // add all linker scripts
+ cl::list<std::string>::iterator sp;
+ cl::list<std::string>::iterator spEnd = ArgLinkerScript.end();
+ for (sp = ArgLinkerScript.begin(); sp != spEnd; ++sp) {
+ pConfig.options().getScriptList().push_back(*sp);
+ }
+
+ pConfig.options().setGenUnwindInfo(ArgGenUnwindInfo);
+
+ // --fatal-warnings
+ // pConfig.options().setFatalWarnings(ArgFatalWarnings);
+
+ // -shared or -pie
+ if (true == ArgShared || true == ArgPIE) {
+ ArgFileType = mcld::CGFT_DSOFile;
+ }
+ else if (true == ArgRelocatable) {
+ ArgFileType = mcld::CGFT_PARTIAL;
+ }
+ else if (format::Binary == ArgOFormat) {
+ ArgFileType = mcld::CGFT_BINARY;
+ }
+
+ // -b [input-format], --format=[input-format]
+ if (format::Binary == ArgFormat)
+ pConfig.options().setBinaryInput();
+
+ // -V
+ if (ArgVersion) {
+ mcld::outs() << "MCLinker - "
+ << mcld::LinkerConfig::version()
+ << "\n";
+ }
+
+ // set up sysroot
+ if (!ArgSysRoot.empty()) {
+ if (exists(ArgSysRoot) && is_directory(ArgSysRoot))
+ pScript.setSysroot(ArgSysRoot);
+ }
+
+ // add all search directories
+ cl::list<std::string>::iterator sd;
+ cl::list<std::string>::iterator sdEnd = ArgSearchDirList.end();
+ for (sd=ArgSearchDirList.begin(); sd!=sdEnd; ++sd) {
+ if (!pScript.directories().insert(*sd)) {
+ // FIXME: need a warning function
+ errs() << "WARNING: can not open search directory `-L"
+ << *sd
+ << "'.\n";
+ }
+ }
+
+ pConfig.options().setPIE(ArgPIE);
+ pConfig.options().setTrace(ArgTrace);
+ pConfig.options().setVerbose(ArgVerbose);
+ pConfig.options().setMaxErrorNum(ArgMaxErrorNum);
+ pConfig.options().setMaxWarnNum(ArgMaxWarnNum);
+ pConfig.options().setBsymbolic(ArgBsymbolic);
+ pConfig.options().setBgroup(ArgBgroup);
+ pConfig.options().setDyld(ArgDyld);
+ pConfig.options().setNoUndefined(ArgNoUndefined);
+ pConfig.options().setMulDefs(ArgAllowMulDefs);
+ pConfig.options().setEhFrameHdr(ArgEhFrameHdr);
+ pConfig.options().setNMagic(ArgNMagic);
+ pConfig.options().setOMagic(ArgOMagic);
+ pConfig.options().setStripDebug(ArgStripDebug || ArgStripAll);
+ pConfig.options().setExportDynamic(ArgExportDynamic);
+ pConfig.options().setWarnSharedTextrel(ArgWarnSharedTextrel);
+ pConfig.options().setDefineCommon(ArgDefineCommon);
+ pConfig.options().setNewDTags(ArgEnableNewDTags);
+ pConfig.options().setHashStyle(ArgHashStyle);
+ pConfig.options().setNoStdlib(ArgNoStdlib);
+ pConfig.options().setPrintMap(ArgPrintMap);
+ pConfig.options().setGCSections(ArgGCSections);
+ pConfig.options().setGPSize(ArgGPSize);
+ if (ArgNoWarnMismatch)
+ pConfig.options().setWarnMismatch(false);
+ else
+ pConfig.options().setWarnMismatch(true);
+
+ if (ArgStripAll)
+ pConfig.options().setStripSymbols(mcld::GeneralOptions::StripAllSymbols);
+ else if (ArgDiscardAll)
+ pConfig.options().setStripSymbols(mcld::GeneralOptions::StripLocals);
+ else if (ArgDiscardLocals)
+ pConfig.options().setStripSymbols(mcld::GeneralOptions::StripTemporaries);
+ else
+ pConfig.options().setStripSymbols(mcld::GeneralOptions::KeepAllSymbols);
+
+ // set up entry point from -e
+ pScript.setEntry(ArgEntry);
+
+ // set up rename map, for --wrap
+ cl::list<std::string>::iterator wname;
+ cl::list<std::string>::iterator wnameEnd = ArgWrapList.end();
+ for (wname = ArgWrapList.begin(); wname != wnameEnd; ++wname) {
+ bool exist = false;
+
+ // add wname -> __wrap_wname
+ mcld::StringEntry<llvm::StringRef>* to_wrap =
+ pScript.renameMap().insert(*wname, exist);
+
+ std::string to_wrap_str = "__wrap_" + *wname;
+ to_wrap->setValue(to_wrap_str);
+
+ if (exist)
+ mcld::warning(mcld::diag::rewrap) << *wname << to_wrap_str;
+
+ // add __real_wname -> wname
+ std::string from_real_str = "__real_" + *wname;
+ mcld::StringEntry<llvm::StringRef>* from_real =
+ pScript.renameMap().insert(from_real_str, exist);
+ from_real->setValue(*wname);
+ if (exist)
+ mcld::warning(mcld::diag::rewrap) << *wname << from_real_str;
+ } // end of for
+
+ // set up rename map, for --portable
+ cl::list<std::string>::iterator pname;
+ cl::list<std::string>::iterator pnameEnd = ArgPortList.end();
+ for (pname = ArgPortList.begin(); pname != pnameEnd; ++pname) {
+ bool exist = false;
+
+ // add pname -> pname_portable
+ mcld::StringEntry<llvm::StringRef>* to_port =
+ pScript.renameMap().insert(*pname, exist);
+
+ std::string to_port_str = *pname + "_portable";
+ to_port->setValue(to_port_str);
+
+ if (exist)
+ mcld::warning(mcld::diag::rewrap) << *pname << to_port_str;
+
+ // add __real_pname -> pname
+ std::string from_real_str = "__real_" + *pname;
+ mcld::StringEntry<llvm::StringRef>* from_real =
+ pScript.renameMap().insert(from_real_str, exist);
+
+ from_real->setValue(*pname);
+ if (exist)
+ mcld::warning(mcld::diag::rewrap) << *pname << from_real_str;
+ } // end of for
+
+ // add -z options
+ cl::list<mcld::ZOption>::iterator zOpt;
+ cl::list<mcld::ZOption>::iterator zOptEnd = ArgZOptionList.end();
+ for (zOpt = ArgZOptionList.begin(); zOpt != zOptEnd; ++zOpt) {
+ pConfig.options().addZOption(*zOpt);
+ }
+
+ // set up icf mode
+ switch (ArgICF) {
+ case icf::None:
+ break;
+ case icf::All:
+ case icf::Safe:
+ default:
+ mcld::warning(mcld::diag::warn_unsupported_option) << ArgICF.ArgStr;
+ break;
+ }
+
+ if (ArgFIXCA8) {
+ mcld::warning(mcld::diag::warn_unsupported_option) << ArgFIXCA8.ArgStr;
+ }
+
+ // add address mappings
+ // -Ttext
+ if (-1U != ArgTextSegAddr) {
+ bool exist = false;
+ mcld::StringEntry<uint64_t>* text_mapping =
+ pScript.addressMap().insert(".text", exist);
+ text_mapping->setValue(ArgTextSegAddr);
+ }
+ // -Tdata
+ if (-1U != ArgDataSegAddr) {
+ bool exist = false;
+ mcld::StringEntry<uint64_t>* data_mapping =
+ pScript.addressMap().insert(".data", exist);
+ data_mapping->setValue(ArgDataSegAddr);
+ }
+ // -Tbss
+ if (-1U != ArgBssSegAddr) {
+ bool exist = false;
+ mcld::StringEntry<uint64_t>* bss_mapping =
+ pScript.addressMap().insert(".bss", exist);
+ bss_mapping->setValue(ArgBssSegAddr);
+ }
+ // --section-start SECTION=ADDRESS
+ for (cl::list<std::string>::iterator
+ it = ArgAddressMapList.begin(), ie = ArgAddressMapList.end();
+ it != ie; ++it) {
+ // FIXME: Add a cl::parser
+ size_t pos = (*it).find_last_of('=');
+ llvm::StringRef script(*it);
+ uint64_t address = 0x0;
+ script.substr(pos + 1).getAsInteger(0, address);
+ bool exist = false;
+ mcld::StringEntry<uint64_t>* addr_mapping =
+ pScript.addressMap().insert(script.substr(0, pos), exist);
+ addr_mapping->setValue(address);
+ }
+
+ // set up filter/aux filter for shared object
+ pConfig.options().setFilter(ArgFilter);
+
+ cl::list<std::string>::iterator aux;
+ cl::list<std::string>::iterator auxEnd = ArgAuxiliary.end();
+ for (aux = ArgAuxiliary.begin(); aux != auxEnd; ++aux)
+ pConfig.options().getAuxiliaryList().push_back(*aux);
+
+ return true;
+}
+
+int main(int argc, char* argv[])
+{
+ sys::PrintStackTraceOnErrorSignal();
+
+ LLVMContext &Context = getGlobalContext();
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ // Initialize targets first, so that --version shows registered targets.
+ InitializeAllTargets();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+ InitializeAllTargetMCs();
+ mcld::InitializeAllTargets();
+ mcld::InitializeAllLinkers();
+ mcld::InitializeAllEmulations();
+ mcld::InitializeAllDiagnostics();
+
+ cl::ParseCommandLineOptions(argc, argv, "MCLinker\n");
+
+#ifdef ENABLE_UNITTEST
+ if (UnitTest) {
+ return unit_test( argc, argv );
+ }
#endif
- if (config == NULL) {
- llvm::errs() << "Out of memory when create the linker configuration!\n";
- return false;
+
+ // Load the module to be compiled...
+ std::auto_ptr<llvm::Module> M;
+
+ // Load the module to be linked...
+ mcld::LinkerScript LDScript;
+ mcld::Module LDIRModule(LDScript);
+ mcld::LinkerConfig LDConfig;
+
+ // Process the linker input from the command line
+ if (!ProcessLinkerOptionsFromCommand(LDScript, LDConfig)) {
+ errs() << argv[0] << ": failed to process linker options from command line!\n";
+ return 1;
}
- // Setup the configuration accroding to the command line options.
+ if (ArgBitcodeFilename.empty() &&
+ (mcld::CGFT_DSOFile != ArgFileType &&
+ mcld::CGFT_EXEFile != ArgFileType &&
+ mcld::CGFT_PARTIAL != ArgFileType &&
+ mcld::CGFT_BINARY != ArgFileType)) {
+ // If the file is not given, forcefully read from stdin
+ if (ArgVerbose >= 0) {
+ errs() << "** The bitcode/llvm asm file is not given. Read from stdin.\n"
+ << "** Specify input bitcode/llvm asm file by\n\n"
+ << " llvm-mcld -dB [the bitcode/llvm asm]\n\n";
+ }
- // 1. Set up soname.
- if (!OptSOName.empty()) {
- config->setSOName(OptSOName);
+ ArgBitcodeFilename.assign("-");
+ }
+
+ if (!ArgBitcodeFilename.empty()) {
+ SMDiagnostic Err;
+ M.reset(ParseIRFile(ArgBitcodeFilename.native(), Err, Context));
+
+ if (M.get() == 0) {
+ Err.print(argv[0], errs());
+ errs() << "** Failed to to the given bitcode/llvm asm file '"
+ << ArgBitcodeFilename.native() << "'. **\n";
+ return 1;
+ }
+ }
+ else {
+ // If here, output must be dynamic shared object (mcld::CGFT_DSOFile) and
+ // executable file (mcld::CGFT_EXEFile).
+ M.reset(new Module("Empty Module", Context));
+ }
+ Module &mod = *M.get();
+
+ // If we are supposed to override the target triple, do so now.
+ Triple TheTriple;
+ if (!TargetTriple.empty()) {
+ // 1. Use the triple from command.
+ TheTriple.setTriple(TargetTriple);
+ mod.setTargetTriple(TargetTriple);
+ } else if (!mod.getTargetTriple().empty()) {
+ // 2. Use the triple in the input Module.
+ TheTriple.setTriple(mod.getTargetTriple());
} else {
- config->setSOName(pOutputFilename);
- }
-
- // 2. If given, set up sysroot.
- if (!OptSysRoot.empty()) {
- config->setSysRoot(OptSysRoot);
- }
-
- // 3. If given, set up dynamic linker path.
- if (!OptDyld.empty()) {
- config->setDyld(OptDyld);
- }
-
- // 4. If given, set up wrapped symbols.
- llvm::cl::list<std::string>::iterator wrap, wrap_end = OptWrapList.end();
- for (wrap = OptWrapList.begin(); wrap != wrap_end; ++wrap) {
- config->addWrap(*wrap);
- }
-
- // 5. If given, set up portable symbols.
- llvm::cl::list<std::string>::iterator portable, portable_end = OptPortableList.end();
- for (portable = OptPortableList.begin(); portable != portable_end; ++portable) {
- config->addPortable(*portable);
- }
-
- // 6. if given, set up search directories.
- llvm::cl::list<std::string>::iterator sdir, sdir_end = OptSearchDirList.end();
- for (sdir = OptSearchDirList.begin(); sdir != sdir_end; ++sdir) {
- config->addSearchDir(*sdir);
- }
-
- // 7. Set up output's type.
- config->setShared(OptShared);
-
- // 8. Set up -Bsymbolic.
- config->setBsymbolic(OptBsymbolic);
-
- // 9. Set up -d (define common symbols)
- config->setDefineCommon(OptDefineCommon);
-
- Linker::ErrorCode result = pLinker.config(*config);
- if (Linker::kSuccess != result) {
- llvm::errs() << "Failed to configure the linker! (detail: "
- << Linker::GetErrorString(result) << ")\n";
- return false;
- }
-
- return true;
-}
-
-static inline
-bool PrepareInputOutput(Linker &pLinker, const std::string &pOutputPath) {
- // ----- Set output ----- //
-
- // FIXME: Current MCLinker requires one to set up output before inputs. The
- // constraint will be relaxed in the furture.
- Linker::ErrorCode result = pLinker.setOutput(pOutputPath);
-
- if (Linker::kSuccess != result) {
- llvm::errs() << "Failed to open the output file! (detail: "
- << pOutputPath << ": "
- << Linker::GetErrorString(result) << ")\n";
- return false;
- }
-
- // ----- Set inputs ----- //
- llvm::cl::list<std::string>::iterator file_it = OptInputObjectFiles.begin();
- llvm::cl::list<std::string>::iterator lib_it = OptNameSpecList.begin();
-
- llvm::cl::list<std::string>::iterator file_begin = OptInputObjectFiles.begin();
- llvm::cl::list<std::string>::iterator lib_begin = OptNameSpecList.begin();
- llvm::cl::list<std::string>::iterator file_end = OptInputObjectFiles.end();
- llvm::cl::list<std::string>::iterator lib_end = OptNameSpecList.end();
-
- unsigned lib_pos = 0, file_pos = 0;
- while (true) {
- if (lib_it != lib_end) {
- lib_pos = OptNameSpecList.getPosition(lib_it - lib_begin);
+ std::string ProgNameTriple = ParseProgName(argv[0]);
+ if (!ProgNameTriple.empty()) {
+ // 3. Use the triple from the program name prefix.
+ TheTriple.setTriple(ProgNameTriple);
+ mod.setTargetTriple(ProgNameTriple);
} else {
- lib_pos = 0;
- }
-
- if (file_it != file_end) {
- file_pos = OptInputObjectFiles.getPosition(file_it - file_begin);
- } else {
- file_pos = 0;
- }
-
- if ((file_pos != 0) && ((lib_pos == 0) || (file_pos < lib_pos))) {
- result = pLinker.addObject(*file_it);
- if (Linker::kSuccess != result) {
- llvm::errs() << "Failed to open the input file! (detail: " << *file_it
- << ": " << Linker::GetErrorString(result) << ")\n";
- return false;
- }
- ++file_it;
- } else if ((lib_pos != 0) && ((file_pos == 0) || (lib_pos < file_pos))) {
- result = pLinker.addNameSpec(*lib_it);
- if (Linker::kSuccess != result) {
- llvm::errs() << "Failed to open the namespec! (detail: " << *lib_it
- << ": " << Linker::GetErrorString(result) << ")\n";
- return false;
- }
- ++lib_it;
- } else {
- break; // we're done with the list
+ // 4. Use the default target triple.
+ TheTriple.setTriple(mcld::sys::getDefaultTargetTriple());
}
}
- return true;
+ // If a specific emulation was requested, apply it now.
+ if (!ArgEmulation.empty()) {
+ Triple EmulationTriple = ParseEmulation(ArgEmulation);
+ if (EmulationTriple.getArch() != Triple::UnknownArch)
+ TheTriple.setArch(EmulationTriple.getArch());
+ if (EmulationTriple.getOS() != Triple::UnknownOS)
+ TheTriple.setOS(EmulationTriple.getOS());
+ if (EmulationTriple.getEnvironment() != Triple::UnknownEnvironment)
+ TheTriple.setEnvironment(EmulationTriple.getEnvironment());
+ }
+
+ // Get the target specific parser.
+ std::string error;
+ const llvm::Target *LLVMTarget = llvm::TargetRegistry::lookupTarget(MArch,
+ TheTriple,
+ error);
+ if (NULL == LLVMTarget) {
+ errs() << argv[0] << ": " << error;
+ return 1;
+ }
+
+ // Allocate target machine. First, check whether the user has explicitly
+ // specified an architecture to compile for. If so we have to look it up by
+ // name, because it might be a backend that has no mapping to a target triple.
+ const mcld::Target *MCLDTarget = mcld::TargetRegistry::lookupTarget(MArch,
+ TheTriple,
+ error);
+ if (NULL == MCLDTarget) {
+ errs() << argv[0] << ": " << error;
+ return 1;
+ }
+
+
+ LDConfig.targets().setTriple(TheTriple);
+
+ // Package up features to be passed to target/subtarget
+ std::string FeaturesStr;
+ if (MAttrs.size()) {
+ SubtargetFeatures Features;
+ for (unsigned i = 0; i != MAttrs.size(); ++i)
+ Features.AddFeature(MAttrs[i]);
+ FeaturesStr = Features.getString();
+ }
+
+ CodeGenOpt::Level OLvl = CodeGenOpt::Default;
+ switch (OptLevel) {
+ default:
+ errs() << argv[0] << ": invalid optimization level.\n";
+ return 1;
+ case ' ': break;
+ case '0': OLvl = CodeGenOpt::None; break;
+ case '1': OLvl = CodeGenOpt::Less; break;
+ case '2': OLvl = CodeGenOpt::Default; break;
+ case '3': OLvl = CodeGenOpt::Aggressive; break;
+ }
+
+ // set -fPIC
+ if (ArgFPIC)
+ ArgRelocModel = Reloc::PIC_;
+
+ TargetOptions Options;
+ Options.LessPreciseFPMADOption = EnableFPMAD;
+ Options.NoFramePointerElim = DisableFPElim;
+ Options.AllowFPOpFusion = FuseFPOps;
+ Options.UnsafeFPMath = EnableUnsafeFPMath;
+ Options.NoInfsFPMath = EnableNoInfsFPMath;
+ Options.NoNaNsFPMath = EnableNoNaNsFPMath;
+ Options.HonorSignDependentRoundingFPMathOption =
+ EnableHonorSignDependentRoundingFPMath;
+ Options.UseSoftFloat = GenerateSoftFloatCalls;
+ if (FloatABIForCalls != FloatABI::Default)
+ Options.FloatABIType = FloatABIForCalls;
+ Options.NoZerosInBSS = DontPlaceZerosInBSS;
+ Options.JITEmitDebugInfo = EmitJitDebugInfo;
+ Options.JITEmitDebugInfoToDisk = EmitJitDebugInfoToDisk;
+ Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt;
+ Options.StackAlignmentOverride = OverrideStackAlignment;
+ Options.TrapFuncName = TrapFuncName;
+ Options.EnableSegmentedStacks = SegmentedStacks;
+
+ OwningPtr<llvm::TargetMachine>
+ TM(LLVMTarget->createTargetMachine(TheTriple.getTriple(),
+ MCPU, FeaturesStr, Options,
+ ArgRelocModel, CMModel, OLvl));
+
+ std::auto_ptr<mcld::MCLDTargetMachine> target_machine(
+ MCLDTarget->createTargetMachine(TheTriple.getTriple(),
+ *LLVMTarget,
+ *TM.get()));
+
+ assert(target_machine.get() && "Could not allocate target machine!");
+ mcld::MCLDTargetMachine &TheTargetMachine = *target_machine.get();
+
+ LDConfig.targets().setTargetCPU(MCPU);
+ LDConfig.targets().setTargetFeatureString(FeaturesStr);
+
+ TheTargetMachine.getTM().setMCUseLoc(false);
+ TheTargetMachine.getTM().setMCUseCFI(false);
+
+ // FIXME: Move the initialization of LineInfo to mcld::Linker when we
+ // finish LineInfo's implementation.
+ OwningPtr<mcld::DiagnosticLineInfo>
+ diag_line_info(MCLDTarget->createDiagnosticLineInfo(*MCLDTarget,
+ TheTriple.getTriple()));
+
+ mcld::getDiagnosticEngine().setLineInfo(*diag_line_info.take());
+
+ // Figure out where we are going to send the output...
+ OwningPtr<mcld::ToolOutputFile>
+ Out(GetOutputStream(MCLDTarget->name(),
+ TheTriple.getOS(),
+ ArgFileType,
+ ArgBitcodeFilename,
+ ArgOutputFilename));
+ if (!Out) {
+ // FIXME: show some error message pls.
+ return 1;
+ }
+
+ // Build up all of the passes that we want to do to the module.
+ PassManager PM;
+
+ // Add the data layout from the target machine, if it exists, or the module.
+ if (const DataLayout *DL = TheTargetMachine.getTM().getDataLayout())
+ PM.add(new DataLayout(*DL));
+ else
+ PM.add(new DataLayout(&mod));
+
+ // Override default to generate verbose assembly.
+ TheTargetMachine.getTM().setAsmVerbosityDefault(true);
+
+ {
+ // Ask the target to add backend passes as necessary.
+ if(TheTargetMachine.addPassesToEmitFile(PM,
+ *Out,
+ ArgFileType,
+ OLvl,
+ LDIRModule,
+ LDConfig,
+ NoVerify)) {
+ errs() << argv[0] << ": target does not support generation of this"
+ << " file type!\n";
+ return 1;
+ }
+
+ // Before executing passes, print the final values of the LLVM options.
+ cl::PrintOptionValues();
+
+ PM.run(mod);
+ }
+
+ if (mcld::getDiagnosticEngine().getPrinter()->getNumErrors())
+ return 1;
+
+ // Declare success.
+ Out->keep();
+ return 0;
}
-
-static inline bool LinkFiles(Linker &pLinker) {
- Linker::ErrorCode result = pLinker.link();
- if (Linker::kSuccess != result) {
- llvm::errs() << "Failed to linking! (detail: "
- << Linker::GetErrorString(result) << "\n";
- return false;
- }
- return true;
-}
-
-int main(int argc, char** argv) {
- llvm::cl::SetVersionPrinter(MCLDVersionPrinter);
- llvm::cl::ParseCommandLineOptions(argc, argv);
- init::Initialize();
-
- std::string OutputFilename = DetermineOutputFilename(OptOutputFilename);
- if (OutputFilename.empty()) {
- return EXIT_FAILURE;
- }
-
- Linker linker;
- if (!ConfigLinker(linker, OutputFilename)) {
- return EXIT_FAILURE;
- }
-
- if (!PrepareInputOutput(linker, OutputFilename)) {
- return EXIT_FAILURE;
- }
-
- if (!LinkFiles(linker)) {
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
diff --git a/unittests/BinTreeTest.cpp b/unittests/BinTreeTest.cpp
index 5d2cd0a..e436752 100644
--- a/unittests/BinTreeTest.cpp
+++ b/unittests/BinTreeTest.cpp
@@ -124,47 +124,46 @@
TEST_F( BinTreeTest, DFSIterator_BasicTraversal)
{
- int a = 111;
+ int a = 111, b = 10, c = 9, d = 8, e = 7;
BinaryTree<int>::iterator pos = m_pTestee->root();
m_pTestee->join<InputTree::Inclusive>(pos,a);
pos.move<InputTree::Inclusive>();
- m_pTestee->join<InputTree::Positional>(pos,10);
- m_pTestee->join<InputTree::Inclusive>(pos,9);
+ m_pTestee->join<InputTree::Positional>(pos,b);
+ m_pTestee->join<InputTree::Inclusive>(pos,c);
pos.move<InputTree::Inclusive>();
- m_pTestee->join<InputTree::Positional>(pos,8);
- m_pTestee->join<InputTree::Inclusive>(pos,7);
+ m_pTestee->join<InputTree::Positional>(pos,d);
+ m_pTestee->join<InputTree::Inclusive>(pos,e);
BinaryTree<int>::dfs_iterator dfs_it = m_pTestee->dfs_begin();
BinaryTree<int>::dfs_iterator dfs_end = m_pTestee->dfs_end();
ASSERT_EQ(111, **dfs_it);
++dfs_it;
- ASSERT_EQ(9, **dfs_it);
+ EXPECT_EQ(9, **dfs_it);
++dfs_it;
- ASSERT_EQ(7, **dfs_it);
+ EXPECT_EQ(7, **dfs_it);
++dfs_it;
- ASSERT_EQ(8, **dfs_it);
+ EXPECT_EQ(8, **dfs_it);
++dfs_it;
- ASSERT_EQ(10, **dfs_it);
+ EXPECT_EQ(10, **dfs_it);
++dfs_it;
- ASSERT_TRUE( dfs_it == dfs_end);
- BinaryTree<int>::bfs_iterator bfs_it = m_pTestee->bfs_begin();
- BinaryTree<int>::bfs_iterator bfs_end = m_pTestee->bfs_end();
+ EXPECT_TRUE( dfs_it == dfs_end);
}
TEST_F( BinTreeTest, DFSIterator_RightMostTree)
{
+ int a = 0, b = 1, c = 2, d = 3, e = 4;
BinaryTree<int>::iterator pos = m_pTestee->root();
- m_pTestee->join<InputTree::Inclusive>(pos,0);
+ m_pTestee->join<InputTree::Inclusive>(pos,a);
pos.move<InputTree::Inclusive>();
- m_pTestee->join<InputTree::Positional>(pos,1);
+ m_pTestee->join<InputTree::Positional>(pos,b);
pos.move<InputTree::Positional>();
- m_pTestee->join<InputTree::Positional>(pos,2);
+ m_pTestee->join<InputTree::Positional>(pos,c);
pos.move<InputTree::Positional>();
- m_pTestee->join<InputTree::Positional>(pos,3);
+ m_pTestee->join<InputTree::Positional>(pos,d);
pos.move<InputTree::Positional>();
- m_pTestee->join<InputTree::Positional>(pos,4);
+ m_pTestee->join<InputTree::Positional>(pos,e);
BinaryTree<int>::dfs_iterator dfs_it = m_pTestee->dfs_begin();
BinaryTree<int>::dfs_iterator dfs_end = m_pTestee->dfs_end();
@@ -199,16 +198,16 @@
TEST_F( BinTreeTest, BFSIterator_BasicTraversal)
{
- int a = 111;
+ int a = 111, b = 10, c = 9, d = 8, e = 7;
BinaryTree<int>::iterator pos = m_pTestee->root();
m_pTestee->join<InputTree::Inclusive>(pos,a);
pos.move<InputTree::Inclusive>();
- m_pTestee->join<InputTree::Positional>(pos,10);
- m_pTestee->join<InputTree::Inclusive>(pos,9);
+ m_pTestee->join<InputTree::Positional>(pos,b);
+ m_pTestee->join<InputTree::Inclusive>(pos,c);
pos.move<InputTree::Inclusive>();
- m_pTestee->join<InputTree::Positional>(pos,8);
- m_pTestee->join<InputTree::Inclusive>(pos,7);
+ m_pTestee->join<InputTree::Positional>(pos,d);
+ m_pTestee->join<InputTree::Inclusive>(pos,e);
BinaryTree<int>::bfs_iterator bfs_it = m_pTestee->bfs_begin();
BinaryTree<int>::bfs_iterator bfs_end = m_pTestee->bfs_end();
@@ -230,16 +229,17 @@
TEST_F( BinTreeTest, BFSIterator_RightMostTree)
{
+ int a = 0, b = 1, c = 2, d = 3, e = 4;
BinaryTree<int>::iterator pos = m_pTestee->root();
- m_pTestee->join<InputTree::Inclusive>(pos,0);
+ m_pTestee->join<InputTree::Inclusive>(pos,a);
pos.move<InputTree::Inclusive>();
- m_pTestee->join<InputTree::Positional>(pos,1);
+ m_pTestee->join<InputTree::Positional>(pos,b);
pos.move<InputTree::Positional>();
- m_pTestee->join<InputTree::Positional>(pos,2);
+ m_pTestee->join<InputTree::Positional>(pos,c);
pos.move<InputTree::Positional>();
- m_pTestee->join<InputTree::Positional>(pos,3);
+ m_pTestee->join<InputTree::Positional>(pos,d);
pos.move<InputTree::Positional>();
- m_pTestee->join<InputTree::Positional>(pos,4);
+ m_pTestee->join<InputTree::Positional>(pos,e);
BinaryTree<int>::bfs_iterator bfs_it = m_pTestee->bfs_begin();
BinaryTree<int>::bfs_iterator bfs_end = m_pTestee->bfs_end();
@@ -274,17 +274,18 @@
TEST_F( BinTreeTest, TreeIterator)
{
+ int a = 0, b = 1, c = 2, d = 3, e = 4, f = 5;
BinaryTree<int>::iterator pos = m_pTestee->root();
- m_pTestee->join<InputTree::Inclusive>(pos,0);
+ m_pTestee->join<InputTree::Inclusive>(pos,a);
pos.move<InputTree::Inclusive>();
- m_pTestee->join<InputTree::Positional>(pos,1);
+ m_pTestee->join<InputTree::Positional>(pos,b);
pos.move<InputTree::Positional>();
- m_pTestee->join<InputTree::Inclusive>(pos,2);
- m_pTestee->join<InputTree::Positional>(pos,5);
+ m_pTestee->join<InputTree::Inclusive>(pos,c);
+ m_pTestee->join<InputTree::Positional>(pos,f);
pos.move<InputTree::Inclusive>();
- m_pTestee->join<InputTree::Positional>(pos,3);
+ m_pTestee->join<InputTree::Positional>(pos,d);
pos.move<InputTree::Positional>();
- m_pTestee->join<InputTree::Positional>(pos,4);
+ m_pTestee->join<InputTree::Positional>(pos,e);
BinaryTree<int>::iterator it = m_pTestee->begin();
BinaryTree<int>::iterator end = m_pTestee->end();
diff --git a/unittests/DirIteratorTest.cpp b/unittests/DirIteratorTest.cpp
index f319172..13472ac 100644
--- a/unittests/DirIteratorTest.cpp
+++ b/unittests/DirIteratorTest.cpp
@@ -6,9 +6,9 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/Support/Directory.h"
+#include <mcld/Support/Directory.h>
#include "DirIteratorTest.h"
-#include "errno.h"
+#include <errno.h>
using namespace mcld;
using namespace mcld::sys::fs;
diff --git a/unittests/ELFBinaryReaderTest.cpp b/unittests/ELFBinaryReaderTest.cpp
new file mode 100644
index 0000000..7792717
--- /dev/null
+++ b/unittests/ELFBinaryReaderTest.cpp
@@ -0,0 +1,64 @@
+//===- ELFBinaryReaderTest.cpp --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/ELFBinaryReader.h>
+#include <mcld/Module.h>
+#include <mcld/LinkerScript.h>
+#include <mcld/LinkerConfig.h>
+#include <mcld/IRBuilder.h>
+#include <mcld/GeneralOptions.h>
+#include <mcld/MC/Input.h>
+
+#include "ELFBinaryReaderTest.h"
+
+using namespace mcld;
+using namespace mcld::test;
+
+
+// Constructor can do set-up work for all test here.
+ELFBinaryReaderTest::ELFBinaryReaderTest()
+{
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+ELFBinaryReaderTest::~ELFBinaryReaderTest()
+{
+}
+
+// SetUp() will be called immediately before each test.
+void ELFBinaryReaderTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void ELFBinaryReaderTest::TearDown()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// Testcases
+//===----------------------------------------------------------------------===//
+TEST_F( ELFBinaryReaderTest, is_myformat) {
+ LinkerScript script;
+ Module module("test", script);
+ LinkerConfig config;
+ IRBuilder builder(module, config);
+ ELFBinaryReader *reader = new ELFBinaryReader(builder, config);
+
+ Input input("test.bin");
+
+ bool doContinue = false;
+ config.options().setBinaryInput();
+ ASSERT_TRUE(reader->isMyFormat(input, doContinue));
+
+ config.options().setBinaryInput(false);
+ ASSERT_FALSE(reader->isMyFormat(input, doContinue));
+
+ delete reader;
+}
+
diff --git a/unittests/ELFBinaryReaderTest.h b/unittests/ELFBinaryReaderTest.h
new file mode 100644
index 0000000..a9ea042
--- /dev/null
+++ b/unittests/ELFBinaryReaderTest.h
@@ -0,0 +1,39 @@
+//===- ELFBinaryReaderTest.h ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELFBINARYREADER_TEST_H
+#define MCLD_ELFBINARYREADER_TEST_H
+
+#include <gtest.h>
+
+namespace mcld {
+class ELFBinaryReader;
+
+namespace test {
+
+class ELFBinaryReaderTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ ELFBinaryReaderTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~ELFBinaryReaderTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+};
+
+} // namespace of test
+} // namespace of mcld
+
+#endif
+
diff --git a/unittests/ELFReaderTest.cpp b/unittests/ELFReaderTest.cpp
index ddbc6d5..1ff2a31 100644
--- a/unittests/ELFReaderTest.cpp
+++ b/unittests/ELFReaderTest.cpp
@@ -8,12 +8,14 @@
//===----------------------------------------------------------------------===//
#include <cstdio>
+#include <llvm/ADT/StringRef.h>
#include <llvm/Support/ELF.h>
#include <mcld/IRBuilder.h>
#include <mcld/TargetOptions.h>
#include <mcld/LD/ELFReader.h>
-#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/Input.h>
#include <mcld/Support/Path.h>
+#include <mcld/Support/MemoryArea.h>
#include <../lib/Target/X86/X86LDBackend.h>
#include <../lib/Target/X86/X86GNUInfo.h>
@@ -66,11 +68,10 @@
ASSERT_TRUE(m_pInput->hasMemArea());
size_t hdr_size = m_pELFReader->getELFHeaderSize();
- MemoryRegion* region = m_pInput->memArea()->request(m_pInput->fileOffset(),
- hdr_size);
- uint8_t* ELF_hdr = region->start();
+ llvm::StringRef region = m_pInput->memArea()->request(m_pInput->fileOffset(),
+ hdr_size);
+ const char* ELF_hdr = region.begin();
bool shdr_result = m_pELFReader->readSectionHeaders(*m_pInput, ELF_hdr);
- m_pInput->memArea()->release(region);
ASSERT_TRUE(shdr_result);
}
@@ -109,22 +110,18 @@
LDSection* strtab_shdr = symtab_shdr->getLink();
ASSERT_TRUE(NULL!=strtab_shdr);
- MemoryRegion* symtab_region = m_pInput->memArea()->request(
- m_pInput->fileOffset() + symtab_shdr->offset(),
- symtab_shdr->size());
+ llvm::StringRef symtab_region = m_pInput->memArea()->request(
+ m_pInput->fileOffset() + symtab_shdr->offset(), symtab_shdr->size());
- MemoryRegion* strtab_region = m_pInput->memArea()->request(
- m_pInput->fileOffset() + strtab_shdr->offset(),
- strtab_shdr->size());
- char* strtab = reinterpret_cast<char*>(strtab_region->start());
+ llvm::StringRef strtab_region = m_pInput->memArea()->request(
+ m_pInput->fileOffset() + strtab_shdr->offset(), strtab_shdr->size());
+ const char* strtab = strtab_region.begin();
bool result = m_pELFReader->readSymbols(*m_pInput, *m_pIRBuilder,
- *symtab_region, strtab);
+ symtab_region, strtab);
ASSERT_TRUE(result);
ASSERT_EQ("hello.c", std::string(m_pInput->context()->getSymbol(1)->name()));
ASSERT_EQ("puts", std::string(m_pInput->context()->getSymbol(10)->name()));
ASSERT_TRUE(NULL==m_pInput->context()->getSymbol(11));
- m_pInput->memArea()->release(symtab_region);
- m_pInput->memArea()->release(strtab_region);
// -- read relocations
MemoryArea* mem = m_pInput->memArea();
@@ -134,12 +131,11 @@
uint64_t offset = m_pInput->fileOffset() + (*rs)->offset();
uint64_t size = (*rs)->size();
- MemoryRegion* region = mem->request(offset, size);
+ llvm::StringRef region = mem->request(offset, size);
IRBuilder::CreateRelocData(**rs); /// create relocation data for the header
ASSERT_EQ(llvm::ELF::SHT_RELA, (*rs)->type());
- ASSERT_TRUE(m_pELFReader->readRela(*m_pInput, **rs, *region));
- mem->release(region);
+ ASSERT_TRUE(m_pELFReader->readRela(*m_pInput, **rs, region));
const RelocData::RelocationListType &rRelocs =
(*rs)->getRelocData()->getRelocationList();
@@ -158,7 +154,8 @@
}
TEST_F( ELFReaderTest, is_my_format ) {
- ASSERT_TRUE( m_pELFObjReader->isMyFormat(*m_pInput) );
+ bool doContinue;
+ ASSERT_TRUE( m_pELFObjReader->isMyFormat(*m_pInput, doContinue) );
}
diff --git a/unittests/ELFReaderTest.h b/unittests/ELFReaderTest.h
index 58ec470..abe99b1 100644
--- a/unittests/ELFReaderTest.h
+++ b/unittests/ELFReaderTest.h
@@ -19,7 +19,7 @@
#include <mcld/MC/InputBuilder.h>
namespace mcld {
- class ELFReader<64, true>;
+ template<> class ELFReader<64, true>;
} // namespace for mcld
namespace mcldtest
diff --git a/unittests/FragmentRefTest.cpp b/unittests/FragmentRefTest.cpp
index 599289d..881cdb8 100644
--- a/unittests/FragmentRefTest.cpp
+++ b/unittests/FragmentRefTest.cpp
@@ -14,6 +14,7 @@
#include <mcld/Support/FileHandle.h>
#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/Path.h>
+#include <llvm/ADT/StringRef.h>
using namespace mcld;
using namespace mcld::sys::fs;
@@ -48,18 +49,18 @@
MemoryAreaFactory* areaFactory = new MemoryAreaFactory(1);
MemoryArea* area = areaFactory->produce(path, FileHandle::ReadWrite);
- MemoryRegion* region = area->request(0, 4096);
- RegionFragment *frag = new RegionFragment(*region);
+ llvm::StringRef region = area->request(0, 4096);
+ RegionFragment *frag = new RegionFragment(region);
FragmentRef *ref = FragmentRef::Create(*frag, 0x0);
- ASSERT_EQ('H', region->getBuffer()[0]);
- ASSERT_TRUE(4096 == region->size());
- ASSERT_EQ('H', frag->getRegion().getBuffer()[0]);
+ ASSERT_EQ('H', region.data()[0]);
+ ASSERT_TRUE(4096 == region.size());
+ ASSERT_EQ('H', frag->getRegion().data()[0]);
ASSERT_TRUE(4096 == frag->getRegion().size());
ASSERT_EQ(frag, ref->frag());
- ASSERT_EQ('H', static_cast<RegionFragment*>(ref->frag())->getRegion().getBuffer()[0]);
+ ASSERT_EQ('H', static_cast<RegionFragment*>(ref->frag())->getRegion().data()[0]);
ASSERT_TRUE(4096 == static_cast<RegionFragment*>(ref->frag())->getRegion().size());
- ASSERT_EQ('H', ref->deref()[0]);
+ //ASSERT_EQ('H', ref->deref()[0]);
ASSERT_TRUE(RegionFragment::classof(frag));
diff --git a/unittests/GraphTest.cpp b/unittests/GraphTest.cpp
new file mode 100644
index 0000000..38fc0d4
--- /dev/null
+++ b/unittests/GraphTest.cpp
@@ -0,0 +1,340 @@
+//===- GraphTest.cpp ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "GraphTest.h"
+#include <mcld/ADT/GraphLite/Digraph.h>
+#include <mcld/ADT/GraphLite/ListDigraph.h>
+
+using namespace mcld;
+using namespace mcld::test;
+using namespace mcld::graph;
+
+// Constructor can do set-up work for all test here.
+GraphTest::GraphTest()
+{
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+GraphTest::~GraphTest()
+{
+}
+
+// SetUp() will be called immediately before each test.
+void GraphTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void GraphTest::TearDown()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// Testcases
+//===----------------------------------------------------------------------===//
+TEST_F(GraphTest, list_digraph_add_n_erase_nodes_1)
+{
+ ListDigraph graph;
+
+ ListDigraph::Node* u1 = graph.addNode();
+ ListDigraph::Node* u2 = graph.addNode();
+ ListDigraph::Node* u3 = graph.addNode();
+
+ ASSERT_TRUE(NULL == u1->first_in);
+ ASSERT_TRUE(NULL == u1->first_out);
+ ASSERT_TRUE(u2 == u1->prev);
+ ASSERT_TRUE(NULL == u1->next);
+
+ ASSERT_TRUE(NULL == u2->first_in);
+ ASSERT_TRUE(NULL == u2->first_out);
+ ASSERT_TRUE(u3 == u2->prev);
+ ASSERT_TRUE(u1 == u2->next);
+
+ ASSERT_TRUE(NULL == u3->first_in);
+ ASSERT_TRUE(NULL == u3->first_out);
+ ASSERT_TRUE(u2 == u3->next);
+ ASSERT_TRUE(NULL == u3->prev);
+
+ ListDigraph::Node* head = NULL;
+ graph.getHead(head);
+ ASSERT_TRUE(head == u3);
+
+ graph.erase(*u2);
+
+ ASSERT_TRUE(NULL == u1->first_in);
+ ASSERT_TRUE(NULL == u1->first_out);
+ ASSERT_TRUE(u3 == u1->prev);
+ ASSERT_TRUE(NULL == u1->next);
+
+ ASSERT_TRUE(NULL == u3->first_in);
+ ASSERT_TRUE(NULL == u3->first_out);
+ ASSERT_TRUE(u1 == u3->next);
+ ASSERT_TRUE(NULL == u3->prev);
+
+ ASSERT_TRUE(NULL == u2->first_in);
+ ASSERT_TRUE(NULL == u2->first_out);
+ ASSERT_TRUE(NULL == u2->prev);
+ ASSERT_TRUE(NULL == u2->next);
+
+ graph.getHead(head);
+ ASSERT_TRUE(head == u3);
+}
+
+TEST_F(GraphTest, list_digraph_add_n_erase_nodes_2)
+{
+ ListDigraph graph;
+
+ ListDigraph::Node* u1 = graph.addNode();
+ ListDigraph::Node* u2 = graph.addNode();
+ ListDigraph::Node* u3 = graph.addNode();
+
+ ASSERT_TRUE(NULL == u1->first_in);
+ ASSERT_TRUE(NULL == u1->first_out);
+ ASSERT_TRUE(u2 == u1->prev);
+ ASSERT_TRUE(NULL == u1->next);
+
+ ASSERT_TRUE(NULL == u2->first_in);
+ ASSERT_TRUE(NULL == u2->first_out);
+ ASSERT_TRUE(u3 == u2->prev);
+ ASSERT_TRUE(u1 == u2->next);
+
+ ASSERT_TRUE(NULL == u3->first_in);
+ ASSERT_TRUE(NULL == u3->first_out);
+ ASSERT_TRUE(u2 == u3->next);
+ ASSERT_TRUE(NULL == u3->prev);
+
+ ListDigraph::Node* head = NULL;
+ graph.getHead(head);
+ ASSERT_TRUE(head == u3);
+
+ graph.erase(*u1);
+
+ ASSERT_TRUE(NULL == u1->first_in);
+ ASSERT_TRUE(NULL == u1->first_out);
+ ASSERT_TRUE(NULL == u1->prev);
+ ASSERT_TRUE(NULL == u1->next);
+
+ ASSERT_TRUE(NULL == u2->first_in);
+ ASSERT_TRUE(NULL == u2->first_out);
+ ASSERT_TRUE(u3 == u2->prev);
+ ASSERT_TRUE(NULL == u2->next);
+
+ ASSERT_TRUE(NULL == u3->first_in);
+ ASSERT_TRUE(NULL == u3->first_out);
+ ASSERT_TRUE(u2 == u3->next);
+ ASSERT_TRUE(NULL == u3->prev);
+
+ graph.getHead(head);
+ ASSERT_TRUE(head == u3);
+}
+
+TEST_F(GraphTest, list_digraph_add_n_erase_nodes_3)
+{
+ ListDigraph graph;
+
+ ListDigraph::Node* u1 = graph.addNode();
+ ListDigraph::Node* u2 = graph.addNode();
+ ListDigraph::Node* u3 = graph.addNode();
+
+ ASSERT_TRUE(NULL == u1->first_in);
+ ASSERT_TRUE(NULL == u1->first_out);
+ ASSERT_TRUE(u2 == u1->prev);
+ ASSERT_TRUE(NULL == u1->next);
+
+ ASSERT_TRUE(NULL == u2->first_in);
+ ASSERT_TRUE(NULL == u2->first_out);
+ ASSERT_TRUE(u3 == u2->prev);
+ ASSERT_TRUE(u1 == u2->next);
+
+ ASSERT_TRUE(NULL == u3->first_in);
+ ASSERT_TRUE(NULL == u3->first_out);
+ ASSERT_TRUE(u2 == u3->next);
+ ASSERT_TRUE(NULL == u3->prev);
+
+ ListDigraph::Node* head = NULL;
+ graph.getHead(head);
+ ASSERT_TRUE(head == u3);
+
+ graph.erase(*u3);
+
+ ASSERT_TRUE(NULL == u3->first_in);
+ ASSERT_TRUE(NULL == u3->first_out);
+ ASSERT_TRUE(NULL == u3->prev);
+ ASSERT_TRUE(NULL == u3->next);
+
+ ASSERT_TRUE(NULL == u1->first_in);
+ ASSERT_TRUE(NULL == u1->first_out);
+ ASSERT_TRUE(u2 == u1->prev);
+ ASSERT_TRUE(NULL == u1->next);
+
+ ASSERT_TRUE(NULL == u2->first_in);
+ ASSERT_TRUE(NULL == u2->first_out);
+ ASSERT_TRUE(u1 == u2->next);
+ ASSERT_TRUE(NULL == u2->prev);
+
+ graph.getHead(head);
+ ASSERT_TRUE(head == u2);
+
+}
+
+TEST_F(GraphTest, list_digraph_add_arcs_1)
+{
+ ListDigraph graph;
+
+ ListDigraph::Node* u1 = graph.addNode();
+ ListDigraph::Node* u2 = graph.addNode();
+ ListDigraph::Node* u3 = graph.addNode();
+
+ ListDigraph::Arc* a1 = graph.addArc(*u1, *u2);
+ ListDigraph::Arc* a2 = graph.addArc(*u2, *u3);
+ ListDigraph::Arc* a3 = graph.addArc(*u3, *u1);
+
+ ASSERT_TRUE(u1 == a1->source && u2 == a1->target);
+ ASSERT_TRUE(u2 == a2->source && u3 == a2->target);
+ ASSERT_TRUE(u3 == a3->source && u1 == a3->target);
+
+ ASSERT_TRUE(u1->first_in == a3 && u1->first_out == a1);
+ ASSERT_TRUE(u2->first_in == a1 && u2->first_out == a2);
+ ASSERT_TRUE(u3->first_in == a2 && u3->first_out == a3);
+}
+
+TEST_F(GraphTest, list_digraph_add_arcs_2)
+{
+ ListDigraph graph;
+
+ ListDigraph::Node* u1 = graph.addNode();
+ ListDigraph::Node* u2 = graph.addNode();
+ ListDigraph::Node* u3 = graph.addNode();
+
+ ListDigraph::Arc* a1 = graph.addArc(*u1, *u1);
+ ListDigraph::Arc* a2 = graph.addArc(*u1, *u2);
+ ListDigraph::Arc* a3 = graph.addArc(*u1, *u3);
+
+ ASSERT_TRUE(u1 == a1->source && u1 == a1->target);
+ ASSERT_TRUE(u1 == a2->source && u2 == a2->target);
+ ASSERT_TRUE(u1 == a3->source && u3 == a3->target);
+
+ ASSERT_TRUE(u1->first_in == a1 && u1->first_out == a3);
+ ASSERT_TRUE(u2->first_in == a2 && u2->first_out == NULL);
+ ASSERT_TRUE(u3->first_in == a3 && u3->first_out == NULL);
+}
+
+TEST_F(GraphTest, list_digraph_add_n_erase_arcs_1)
+{
+ ListDigraph graph;
+
+ ListDigraph::Node* u1 = graph.addNode();
+ ListDigraph::Node* u2 = graph.addNode();
+ ListDigraph::Node* u3 = graph.addNode();
+
+ ListDigraph::Arc* a1 = graph.addArc(*u1, *u2);
+ ListDigraph::Arc* a2 = graph.addArc(*u2, *u3);
+ ListDigraph::Arc* a3 = graph.addArc(*u3, *u1);
+
+ graph.erase(*a2);
+
+ ASSERT_TRUE(u1 == a1->source && u2 == a1->target);
+ ASSERT_TRUE(u3 == a3->source && u1 == a3->target);
+
+ // remove from the fan-out list
+ ASSERT_TRUE(u2->first_in == a1 && u2->first_out == NULL);
+
+ // remove from the fan-in list
+ ASSERT_TRUE(u3->first_in == NULL && u3->first_out == a3);
+
+ // put into free list
+ ASSERT_TRUE(NULL == a2->next_in);
+}
+
+
+TEST_F(GraphTest, list_digraph_add_n_erase_arcs_2)
+{
+ ListDigraph graph;
+
+ ListDigraph::Node* u1 = graph.addNode();
+ ListDigraph::Node* u2 = graph.addNode();
+ ListDigraph::Node* u3 = graph.addNode();
+
+ ListDigraph::Arc* a1 = graph.addArc(*u1, *u2);
+ ListDigraph::Arc* a2 = graph.addArc(*u2, *u3);
+ ListDigraph::Arc* a3 = graph.addArc(*u3, *u1);
+
+ graph.erase(*a1);
+
+ ASSERT_TRUE(u2 == a2->source && u3 == a2->target);
+ ASSERT_TRUE(u3 == a3->source && u1 == a3->target);
+
+ // remove from the fan-out list
+ ASSERT_TRUE(u1->first_in == a3 && u1->first_out == NULL);
+
+ // remove from the fan-in list
+ ASSERT_TRUE(u2->first_in == NULL && u2->first_out == a2);
+
+ // put into free list
+ ASSERT_TRUE(NULL == a1->next_in);
+}
+
+TEST_F(GraphTest, list_digraph_add_n_erase_arcs_3)
+{
+ ListDigraph graph;
+
+ ListDigraph::Node* u1 = graph.addNode();
+ ListDigraph::Node* u2 = graph.addNode();
+ ListDigraph::Node* u3 = graph.addNode();
+
+ ListDigraph::Arc* a1 = graph.addArc(*u1, *u2);
+ ListDigraph::Arc* a2 = graph.addArc(*u2, *u3);
+ ListDigraph::Arc* a3 = graph.addArc(*u3, *u1);
+
+ graph.erase(*a3);
+
+ ASSERT_TRUE(u1 == a1->source && u2 == a1->target);
+ ASSERT_TRUE(u2 == a2->source && u3 == a2->target);
+
+ // remove from the fan-out list
+ ASSERT_TRUE(u1->first_in == NULL && u1->first_out == a1);
+
+ // remove from the fan-in list
+ ASSERT_TRUE(u3->first_in == a2 && u3->first_out == NULL);
+
+ // put into free list
+ ASSERT_TRUE(NULL == a3->next_in);
+}
+
+TEST_F(GraphTest, list_digraph_add_n_erase_arcs_4)
+{
+ ListDigraph graph;
+
+ ListDigraph::Node* u1 = graph.addNode();
+ ListDigraph::Node* u2 = graph.addNode();
+ ListDigraph::Node* u3 = graph.addNode();
+
+ ListDigraph::Arc* a1 = graph.addArc(*u1, *u1);
+ graph.addArc(*u1, *u2);
+ graph.addArc(*u1, *u3);
+
+ graph.erase(*u1);
+
+ ASSERT_TRUE(u2->first_in == NULL);
+ ASSERT_TRUE(u3->first_in == NULL);
+ ASSERT_TRUE(a1->next_in == NULL);
+
+}
+
+TEST_F(GraphTest, api_test)
+{
+ Digraph graph;
+
+ Digraph::Node node = graph.addNode();
+ graph.addNode();
+ graph.addNode();
+ graph.addNode();
+
+ ASSERT_EQ(4, graph.numOfNodes());
+ ASSERT_EQ(0, graph.numOfArcs());
+}
diff --git a/unittests/GraphTest.h b/unittests/GraphTest.h
new file mode 100644
index 0000000..a71276b
--- /dev/null
+++ b/unittests/GraphTest.h
@@ -0,0 +1,38 @@
+//===- GraphTest.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_GRAPH_TEST_H
+#define MCLD_GRAPH_TEST_H
+
+#include <gtest.h>
+
+
+namespace mcld {
+namespace test {
+
+class GraphTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ GraphTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~GraphTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+};
+
+} // namespace of test
+} // namespace of mcld
+
+#endif
+
diff --git a/unittests/HashTableTest.cpp b/unittests/HashTableTest.cpp
index 532c307..fe67e95 100644
--- a/unittests/HashTableTest.cpp
+++ b/unittests/HashTableTest.cpp
@@ -8,8 +8,8 @@
//===----------------------------------------------------------------------===//
#include "HashTableTest.h"
-#include "mcld/ADT/HashEntry.h"
-#include "mcld/ADT/HashTable.h"
+#include <mcld/ADT/HashEntry.h>
+#include <mcld/ADT/HashTable.h>
#include <cstdlib>
using namespace std;
diff --git a/unittests/LDSymbolTest.cpp b/unittests/LDSymbolTest.cpp
index c414fa0..e0e681d 100644
--- a/unittests/LDSymbolTest.cpp
+++ b/unittests/LDSymbolTest.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "mcld/LD/LDSymbol.h"
+#include <mcld/LD/LDSymbol.h>
#include "LDSymbolTest.h"
using namespace mcld;
diff --git a/unittests/LinearAllocatorTest.cpp b/unittests/LinearAllocatorTest.cpp
index fea135f..d38684a 100644
--- a/unittests/LinearAllocatorTest.cpp
+++ b/unittests/LinearAllocatorTest.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
#include "LinearAllocatorTest.h"
-#include "mcld/Support/Allocators.h"
+#include <mcld/Support/Allocators.h>
using namespace mcld;
using namespace mcldtest;
diff --git a/unittests/LinkerTest.cpp b/unittests/LinkerTest.cpp
index 16c6448..479bbb9 100644
--- a/unittests/LinkerTest.cpp
+++ b/unittests/LinkerTest.cpp
@@ -14,6 +14,7 @@
#include <mcld/IRBuilder.h>
#include <mcld/Linker.h>
#include <mcld/LinkerConfig.h>
+#include <mcld/LinkerScript.h>
#include <mcld/Support/Path.h>
@@ -63,7 +64,7 @@
// builder.CreateInput("./test.o");
if (linker.link(module, builder))
- linker.emit("./test.so");
+ linker.emit(module, "./test.so");
Finalize();
}
@@ -123,7 +124,7 @@
builder.ReadInput("crtend", crtend);
if (linker.link(module, builder)) {
- linker.emit("libplasma.so"); ///< -o libplasma.so
+ linker.emit(module, "libplasma.so"); ///< -o libplasma.so
}
Finalize();
@@ -181,7 +182,7 @@
builder1.ReadInput("crtend", crtend);
if (linker.link(module1, builder1)) {
- linker.emit("libplasma.once.so"); ///< -o libplasma.so
+ linker.emit(module1, "libplasma.once.so"); ///< -o libplasma.so
}
Finalize();
@@ -224,7 +225,7 @@
builder2.ReadInput("crtend", crtend);
if (linker.link(module2, builder2)) {
- linker.emit("libplasma.twice.so"); ///< -o libplasma.exe
+ linker.emit(module2, "libplasma.twice.so"); ///< -o libplasma.exe
}
Finalize();
@@ -278,7 +279,7 @@
builder1->ReadInput("crtend", crtend);
if (linker.link(module1, *builder1)) {
- linker.emit("libplasma.once.so"); ///< -o libplasma.so
+ linker.emit(module1, "libplasma.once.so"); ///< -o libplasma.so
}
// Can not delete builder until emit the output. Dynamic string table
@@ -326,7 +327,7 @@
builder2->ReadInput("crtend", crtend);
if (linker.link(module2, *builder2)) {
- linker.emit("libplasma.twice.so"); ///< -o libplasma.exe
+ linker.emit(module2, "libplasma.twice.so"); ///< -o libplasma.exe
}
delete builder2;
@@ -467,7 +468,7 @@
builder.AddRelocation(*rel_text, llvm::ELF::R_ARM_PLT32, *z1gv, 0x4);
if (linker.link(module, builder)) {
- linker.emit("libgotplt.so"); ///< -o libgotplt.so
+ linker.emit(module, "libgotplt.so"); ///< -o libgotplt.so
}
Finalize();
diff --git a/unittests/MCRegionFragmentTest.cpp b/unittests/MCRegionFragmentTest.cpp
index 842ddf9..7d6c3b9 100644
--- a/unittests/MCRegionFragmentTest.cpp
+++ b/unittests/MCRegionFragmentTest.cpp
@@ -9,9 +9,9 @@
#include "MCRegionFragmentTest.h"
-#include "mcld/MC/MCRegionFragment.h"
-#include "mcld/Support/MemoryAreaFactory.h"
-#include "mcld/Support/Path.h"
+#include <mcld/MC/MCRegionFragment.h>
+#include <mcld/Support/MemoryAreaFactory.h>
+#include <mcld/Support/Path.h>
using namespace mcld;
using namespace mcldtest;
diff --git a/unittests/MemoryAreaTest.cpp b/unittests/MemoryAreaTest.cpp
deleted file mode 100644
index 0499a0d..0000000
--- a/unittests/MemoryAreaTest.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-//===- MemoryAreaTest.cpp -------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/Support/FileHandle.h>
-#include <mcld/Support/FileSystem.h>
-#include <mcld/Support/MemoryArea.h>
-#include <mcld/Support/MemoryRegion.h>
-#include <mcld/Support/MemoryAreaFactory.h>
-#include <mcld/Support/Path.h>
-
-#include "MemoryAreaTest.h"
-#include <fcntl.h>
-#include <cstdio>
-
-using namespace mcld;
-using namespace mcld::sys::fs;
-using namespace mcldtest;
-
-
-// Constructor can do set-up work for all test here.
-MemoryAreaTest::MemoryAreaTest()
-{
-}
-
-// Destructor can do clean-up work that doesn't throw exceptions here.
-MemoryAreaTest::~MemoryAreaTest()
-{
-}
-
-// SetUp() will be called immediately before each test.
-void MemoryAreaTest::SetUp()
-{
-}
-
-// TearDown() will be called immediately after each test.
-void MemoryAreaTest::TearDown()
-{
-}
-
-//==========================================================================//
-// Testcases
-//
-TEST_F( MemoryAreaTest, read_by_malloc )
-{
- Path path(TOPDIR);
- path.append("unittests/test3.txt");
-
- MemoryAreaFactory *AreaFactory = new MemoryAreaFactory(1);
- MemoryArea* area = AreaFactory->produce(path, FileHandle::ReadOnly);
- MemoryRegion* region = area->request(3, 2);
- ASSERT_EQ('L', region->getBuffer()[0]);
- ASSERT_EQ('O', region->getBuffer()[1]);
- area->release(region);
- AreaFactory->destruct(area);
- //delete AreaFactory;;
-}
-
-TEST_F( MemoryAreaTest, write_by_malloc )
-{
- Path path(TOPDIR);
- path.append("unittests/test2.txt");
- MemoryAreaFactory *AreaFactory = new MemoryAreaFactory(1);
- MemoryArea* area = AreaFactory->produce(path, FileHandle::ReadOnly);
- ASSERT_TRUE(area->handler()->isOpened());
- ASSERT_TRUE(area->handler()->isGood());
- MemoryRegion* region = area->request(3, 4);
- region->getBuffer()[0] = 'L';
- region->getBuffer()[1] = 'i';
- region->getBuffer()[2] = 'n';
- region->getBuffer()[3] = 'k';
- area->release(region);
- area->clear();
- area->handler()->close();
-
- area->handler()->open(path, FileHandle::ReadOnly);
- ASSERT_TRUE(area->handler()->isOpened());
- ASSERT_TRUE(area->handler()->isGood());
- region = area->request(5, 2);
- ASSERT_EQ('n', region->getBuffer()[0]);
- ASSERT_EQ('k', region->getBuffer()[1]);
- area->release(region);
- AreaFactory->destruct(area);
- //delete AreaFactory;;
-}
-
-TEST_F( MemoryAreaTest, read_one_page )
-{
- Path path(TOPDIR) ;
- path.append("unittests/test3.txt") ;
- MemoryAreaFactory *AreaFactory = new MemoryAreaFactory(1) ;
- MemoryArea* area = AreaFactory->produce(path, FileHandle::ReadOnly) ;
- ASSERT_TRUE(area->handler()->isOpened()) ;
- ASSERT_TRUE(area->handler()->isGood()) ;
- MemoryRegion* region = area->request(0, 4096);
- ASSERT_EQ('H', region->getBuffer()[0]);
- ASSERT_EQ('E', region->getBuffer()[1]);
- area->release(region);
- AreaFactory->destruct(area);
- //delete AreaFactory; ;
-}
-
-TEST_F( MemoryAreaTest, write_one_page )
-{
- Path path(TOPDIR) ;
- path.append("unittests/test2.txt") ;
- MemoryAreaFactory *AreaFactory = new MemoryAreaFactory(1) ;
- MemoryArea* area = AreaFactory->produce(path, FileHandle::ReadWrite);
- ASSERT_TRUE(area->handler()->isOpened()) ;
- ASSERT_TRUE(area->handler()->isGood()) ;
- MemoryRegion* region = area->request(0, 4096) ;
- region->getBuffer()[4000] = 'K' ;
- region->getBuffer()[4001] = 'R' ;
- ASSERT_EQ('K', region->getBuffer()[4000]);
- ASSERT_EQ('R', region->getBuffer()[4001]);
- area->release(region);
- area->clear() ;
- area->handler()->close();
-
- area->handler()->open(path, FileHandle::ReadOnly);
- region = area->request(4000, 4);
- ASSERT_EQ('K', region->getBuffer()[0]);
- ASSERT_EQ('R', region->getBuffer()[1]);
- region->getBuffer()[0] = 'O' ;
- region->getBuffer()[1] = 'H' ;
- area->clear() ;
- AreaFactory->destruct(area);
- //delete AreaFactory; ;
-}
-
-TEST_F( MemoryAreaTest, write_sync )
-{
- Path path(TOPDIR) ;
- path.append("unittests/test2.txt") ;
- MemoryAreaFactory *AreaFactory = new MemoryAreaFactory(1) ;
- MemoryArea* area = AreaFactory->produce(path, FileHandle::ReadWrite) ;
- ASSERT_TRUE(area->handler()->isOpened()) ;
- ASSERT_TRUE(area->handler()->isGood()) ;
- MemoryRegion* region1 = area->request(0, 4096) ;
- MemoryRegion* region2 = area->request(512, 1024) ;
- region1->getBuffer()[1000] = 'L' ;
- region1->getBuffer()[1001] = 'L' ;
- region2->getBuffer()[488] = 'V' ;
- region2->getBuffer()[489] = 'M' ;
- area->release(region1);
- area->release(region2);
- area->clear();
- area->handler()->close();
- area->handler()->open(path, FileHandle::ReadWrite);
- region1 = area->request(0, 1024) ;
- EXPECT_EQ('V', region1->getBuffer()[1000]) ;
- EXPECT_EQ('M', region1->getBuffer()[1001]) ;
- region1->getBuffer()[1000] = '@' ;
- region1->getBuffer()[1001] = '@' ;
- area->release(region1);
- area->clear();
- AreaFactory->destruct(area);
- //delete AreaFactory; ;
-}
-
-
diff --git a/unittests/MemoryAreaTest.h b/unittests/MemoryAreaTest.h
deleted file mode 100644
index 86a5da0..0000000
--- a/unittests/MemoryAreaTest.h
+++ /dev/null
@@ -1,50 +0,0 @@
-//===- MemoryAreaTest.h ---------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MEMORYAREA_TEST_H
-#define MEMORYAREA_TEST_H
-
-#include <gtest.h>
-
-namespace mcld
-{
-class MemoryArea;
-
-} // namespace for mcld
-
-namespace mcldtest
-{
-
-/** \class MemoryAreaTest
- * \brief
- *
- * \see MemoryArea
- */
-class MemoryAreaTest : public ::testing::Test
-{
-public:
- // Constructor can do set-up work for all test here.
- MemoryAreaTest();
-
- // Destructor can do clean-up work that doesn't throw exceptions here.
- virtual ~MemoryAreaTest();
-
- // SetUp() will be called immediately before each test.
- virtual void SetUp();
-
- // TearDown() will be called immediately after each test.
- virtual void TearDown();
-
-protected:
- mcld::MemoryArea* m_pTestee;
-};
-
-} // namespace of mcldtest
-
-#endif
-
diff --git a/unittests/PathTest.cpp b/unittests/PathTest.cpp
index 1a73de2..73e62cc 100644
--- a/unittests/PathTest.cpp
+++ b/unittests/PathTest.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
#include "PathTest.h"
-#include "mcld/Support/FileSystem.h"
+#include <mcld/Support/FileSystem.h>
#include <string>
//
diff --git a/unittests/RTLinearAllocatorTest.cpp b/unittests/RTLinearAllocatorTest.cpp
index 7ed5dac..1e07f4a 100644
--- a/unittests/RTLinearAllocatorTest.cpp
+++ b/unittests/RTLinearAllocatorTest.cpp
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/Support/Allocators.h"
-#include <RTLinearAllocatorTest.h>
+#include <mcld/Support/Allocators.h>
+#include "RTLinearAllocatorTest.h"
using namespace mcld;
using namespace mcldtest;
diff --git a/unittests/StaticResolverTest.cpp b/unittests/StaticResolverTest.cpp
index bd40cd5..eb3accc 100644
--- a/unittests/StaticResolverTest.cpp
+++ b/unittests/StaticResolverTest.cpp
@@ -59,7 +59,7 @@
ASSERT_TRUE( mcld::ResolveInfo::define_flag == new_sym->info());
ASSERT_TRUE( mcld::ResolveInfo::define_flag == old_sym->info());
bool override = true;
- bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override, 0x0);
ASSERT_TRUE(result);
ASSERT_FALSE( override );
}
@@ -85,7 +85,7 @@
ASSERT_TRUE( mcld::ResolveInfo::Define == old_sym->desc());
bool override = false;
- bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override, 0x0);
ASSERT_TRUE(result);
ASSERT_FALSE( override );
ASSERT_TRUE(1 == old_sym->size());
@@ -112,7 +112,7 @@
ASSERT_TRUE( mcld::ResolveInfo::Define == old_sym->desc());
bool override = false;
- bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override, 0x0);
ASSERT_TRUE(result);
ASSERT_FALSE( override );
ASSERT_TRUE(1 == old_sym->size());
@@ -139,7 +139,7 @@
ASSERT_TRUE( mcld::ResolveInfo::Undefined == old_sym->desc());
bool override = false;
- bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override, 0x0);
ASSERT_TRUE(result);
ASSERT_FALSE( override );
ASSERT_TRUE(1 == old_sym->size());
@@ -161,7 +161,7 @@
ASSERT_TRUE( mcld::ResolveInfo::global_flag == new_sym->info());
ASSERT_TRUE( mcld::ResolveInfo::weak_flag == old_sym->info());
bool override = false;
- bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override, 0x0);
ASSERT_TRUE(result);
ASSERT_TRUE( override );
ASSERT_TRUE(0 == old_sym->size());
@@ -190,7 +190,7 @@
ASSERT_TRUE( mcld::ResolveInfo::Define == new_sym->desc());
bool override = false;
- bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override, 0x0);
ASSERT_TRUE(result);
ASSERT_FALSE( override );
ASSERT_TRUE(1 == old_sym->size());
@@ -212,7 +212,7 @@
ASSERT_TRUE( mcld::ResolveInfo::common_flag == new_sym->info());
ASSERT_TRUE( mcld::ResolveInfo::common_flag == old_sym->info());
bool override = true;
- bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override, 0x0);
ASSERT_TRUE(result);
ASSERT_FALSE( override );
ASSERT_TRUE(999 == old_sym->size());
@@ -237,7 +237,7 @@
ASSERT_TRUE( (ResolveInfo::weak_flag | ResolveInfo::common_flag) == old_sym->info());
bool override = false;
- bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override, 0x0);
ASSERT_TRUE(result);
ASSERT_TRUE( override );
ASSERT_TRUE(999 == old_sym->size());
@@ -261,7 +261,7 @@
ASSERT_TRUE( ResolveInfo::common_flag == old_sym->info());
bool override = false;
- bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override, 0x0);
ASSERT_TRUE(result);
ASSERT_TRUE( override );
ASSERT_TRUE(999 == old_sym->size());
diff --git a/unittests/SymbolTableTest.cpp b/unittests/SymbolTableTest.cpp
index 5b665f0..2dc5143 100644
--- a/unittests/SymbolTableTest.cpp
+++ b/unittests/SymbolTableTest.cpp
@@ -6,7 +6,7 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/LD/SymbolTable.h"
+#include <mcld/LD/SymbolTable.h>
#include "SymbolTableTest.h"
using namespace mcld;
diff --git a/unittests/TargetMachineTest.cpp b/unittests/TargetMachineTest.cpp
index 6258906..85950a9 100644
--- a/unittests/TargetMachineTest.cpp
+++ b/unittests/TargetMachineTest.cpp
@@ -6,7 +6,7 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include <TargetMachineTest.h>
+#include "TargetMachineTest.h"
using namespace mcld;
using namespace mcldTEST;