MCLinker upstream commit e764452.
Change-Id: I5c9ec467ec96a0143e1e67c59365f3b6303e7348
diff --git a/include/mcld/ADT/BinTree.h b/include/mcld/ADT/BinTree.h
index 5c1dc0a..da30a89 100644
--- a/include/mcld/ADT/BinTree.h
+++ b/include/mcld/ADT/BinTree.h
@@ -479,3 +479,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/ADT/Flags.h b/include/mcld/ADT/Flags.h
new file mode 100644
index 0000000..0091cea
--- /dev/null
+++ b/include/mcld/ADT/Flags.h
@@ -0,0 +1,106 @@
+//===- Flags.h ------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_FLAGS_H
+#define MCLD_FLAGS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+template<typename Enum>
+class Flags
+{
+public:
+ typedef Enum enum_type;
+
+public:
+ Flags(const Flags& pOther)
+ : m_Data(pOther.m_Data) {}
+
+ Flags(Enum pFlag)
+ : m_Data(pFlag) {}
+
+ Flags(int pFlag = 0x0)
+ : m_Data(pFlag) {}
+
+ operator int () const
+ { return m_Data; }
+
+ bool operator! () const
+ { return (m_Data == 0x0); }
+
+ Flags operator& (int pMask ) const
+ { return Flags(m_Data & pMask); }
+
+ Flags operator& (unsigned int pMask ) const
+ { return Flags(m_Data & pMask); }
+
+ Flags operator& (Enum pMask ) const
+ { return Flags(m_Data & pMask); }
+
+ Flags& operator&= (int pMask ) {
+ m_Data &= pMask;
+ return *this;
+ }
+
+ Flags& operator&= (unsigned int pMask ) {
+ m_Data &= pMask;
+ return *this;
+ }
+
+ Flags& operator=(Flags pOther) {
+ m_Data = pOther.m_Data;
+ return *this;
+ }
+
+ Flags operator^ (Flags pOther) const
+ { return Flags(m_Data^pOther.m_Data); }
+
+ Flags operator^ (Enum pOther) const
+ { return Flags(m_Data^pOther); }
+
+ Flags& operator^= (Flags pOther) {
+ m_Data ^= pOther.m_Data;
+ return *this;
+ }
+
+ Flags& operator^= (Enum pOther) {
+ m_Data ^= pOther;
+ return *this;
+ }
+
+ Flags operator| (Flags pOther) const
+ { return Flags(m_Data | pOther.m_Data); }
+
+ Flags operator| (Enum pOther ) const
+ { return Flags(m_Data | pOther); }
+
+ Flags& operator|= (Flags pOther) {
+ m_Data |= pOther.m_Data;
+ return *this;
+ }
+
+ Flags& operator|= (Enum pOther) {
+ m_Data |= pOther;
+ return *this;
+ }
+
+ Flags operator~ () const
+ { return Flags(~m_Data); }
+
+private:
+ int m_Data;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/HashBase.h b/include/mcld/ADT/HashBase.h
index 36d825b..76410ab 100644
--- a/include/mcld/ADT/HashBase.h
+++ b/include/mcld/ADT/HashBase.h
@@ -136,3 +136,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/ADT/HashBase.tcc b/include/mcld/ADT/HashBase.tcc
index 35b40e3..62d92b1 100644
--- a/include/mcld/ADT/HashBase.tcc
+++ b/include/mcld/ADT/HashBase.tcc
@@ -247,3 +247,4 @@
m_NumOfBuckets = pNewSize;
m_NumOfTombstones = 0;
}
+
diff --git a/include/mcld/ADT/HashEntry.h b/include/mcld/ADT/HashEntry.h
index bc15ecb..c034783 100644
--- a/include/mcld/ADT/HashEntry.h
+++ b/include/mcld/ADT/HashEntry.h
@@ -92,3 +92,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/ADT/HashEntry.tcc b/include/mcld/ADT/HashEntry.tcc
index f397f23..fdd886b 100644
--- a/include/mcld/ADT/HashEntry.tcc
+++ b/include/mcld/ADT/HashEntry.tcc
@@ -50,3 +50,4 @@
{
return new HashEntryTy(pKey);
}
+
diff --git a/include/mcld/ADT/HashIterator.h b/include/mcld/ADT/HashIterator.h
index 055d91c..e25df77 100644
--- a/include/mcld/ADT/HashIterator.h
+++ b/include/mcld/ADT/HashIterator.h
@@ -322,3 +322,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/ADT/HashTable.h b/include/mcld/ADT/HashTable.h
index 16d87f5..dfc2f5a 100644
--- a/include/mcld/ADT/HashTable.h
+++ b/include/mcld/ADT/HashTable.h
@@ -64,7 +64,7 @@
// ----- constructor ----- //
explicit HashTable(size_type pSize=3);
~HashTable();
-
+
EntryFactoryTy& getEntryFactory()
{ return m_EntryFactory; }
@@ -89,7 +89,7 @@
const_iterator find(const key_type& pKey) const;
size_type count(const key_type& pKey) const;
-
+
// ----- hash policy ----- //
float load_factor() const;
@@ -123,3 +123,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/ADT/HashTable.tcc b/include/mcld/ADT/HashTable.tcc
index 885d737..7439982 100644
--- a/include/mcld/ADT/HashTable.tcc
+++ b/include/mcld/ADT/HashTable.tcc
@@ -183,7 +183,7 @@
HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::begin()
{
if (BaseTy::empty())
- return iterator(this, 0);
+ return end();
unsigned int index = 0;
while (bucket_type::getTombstone() == BaseTy::m_Buckets[index].Entry ||
bucket_type::getEmptyBucket() == BaseTy::m_Buckets[index].Entry) {
@@ -208,7 +208,7 @@
HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::begin() const
{
if (BaseTy::empty())
- return const_iterator(this, 0);
+ return end();
unsigned int index = 0;
while (bucket_type::getTombstone() == BaseTy::m_Buckets[index].Entry ||
bucket_type::getEmptyBucket() == BaseTy::m_Buckets[index].Entry) {
@@ -265,3 +265,4 @@
{
return const_chain_iterator();
}
+
diff --git a/include/mcld/ADT/SizeTraits.h b/include/mcld/ADT/SizeTraits.h
index 7e67db9..666d8c0 100644
--- a/include/mcld/ADT/SizeTraits.h
+++ b/include/mcld/ADT/SizeTraits.h
@@ -18,11 +18,12 @@
{
template<size_t SIZE>
-struct SizeTraits;
+class SizeTraits;
template<>
class SizeTraits<32>
{
+public:
typedef uint32_t Address;
typedef uint32_t Offset;
typedef uint32_t Word;
@@ -32,6 +33,7 @@
template<>
class SizeTraits<64>
{
+public:
typedef uint64_t Address;
typedef uint64_t Offset;
typedef uint64_t Word;
@@ -96,6 +98,18 @@
((pData & 0x00000000000000FFULL) << 56));
}
+template <size_t SizeOfStr, typename FieldType>
+class StringSizerHelper
+{
+private:
+ char FIELD_TOO_SMALL[SizeOfStr <= FieldType(~0U) ? 1 : -1];
+public:
+ enum { Size = SizeOfStr };
+};
+
+#define STR_SIZE(str, fieldTy) StringSizerHelper<sizeof(str)-1, fieldTy>::Size
+
} // namespace of mcld
#endif
+
diff --git a/include/mcld/ADT/StringEntry.h b/include/mcld/ADT/StringEntry.h
new file mode 100644
index 0000000..09c8dfe
--- /dev/null
+++ b/include/mcld/ADT/StringEntry.h
@@ -0,0 +1,152 @@
+//===- StringEntry.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_STRING_ENTRY_H
+#define MCLD_STRING_ENTRY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/DataTypes.h>
+#include <cstdlib>
+#include <cstring>
+#include <cassert>
+
+namespace mcld
+{
+template<typename DataType>
+class StringEntryFactory;
+
+/** \class StringEntry
+ * \brief StringEntry is a pair of strings which is designed for high locality.
+ */
+template<typename DataType>
+class StringEntry
+{
+public:
+ typedef llvm::StringRef key_type;
+ typedef DataType value_type;
+
+public:
+ key_type key()
+ { return key_type(m_Key, m_KeyLen); }
+
+ const key_type key() const
+ { return key_type(m_Key, m_KeyLen); }
+
+ value_type& value()
+ { return m_Value; }
+
+ const value_type& value() const
+ { return m_Value; }
+
+ size_t getKeyLength() const
+ { return m_KeyLen; }
+
+ size_t getValueLength() const
+ { return m_Value.size(); }
+
+ void setValue(const DataType& pVal)
+ { m_Value = pVal; }
+
+ bool compare(const llvm::StringRef& pX)
+ { return (0 == key().compare(pX)); }
+
+ bool compare(const llvm::StringRef& pX) const
+ { return (0 == key().compare(pX)); }
+
+private:
+ StringEntry();
+ StringEntry(const key_type& pKey);
+ StringEntry(const StringEntry& pCopy);
+ ~StringEntry();
+
+private:
+ DataType m_Value;
+ uint16_t m_KeyLen;
+ char m_Key[0];
+
+ friend class StringEntryFactory<DataType>;
+};
+
+
+template<>
+class StringEntry<llvm::StringRef>
+{
+public:
+ typedef llvm::StringRef key_type;
+ typedef llvm::StringRef value_type;
+
+public:
+ key_type key()
+ { return key_type(m_Key, m_KeyLen); }
+
+ const key_type key() const
+ { return key_type(m_Key, m_KeyLen); }
+
+ value_type& value()
+ { return m_Value; }
+
+ const value_type& value() const
+ { return m_Value; }
+
+ size_t getKeyLength() const
+ { return m_KeyLen; }
+
+ size_t getValueLength() const
+ { return m_Value.size(); }
+
+ void setValue(const std::string& pVal)
+ { setValue(pVal.c_str()); }
+
+ void setValue(const char* pVal);
+
+ void setValue(llvm::StringRef& pVal);
+
+ bool compare(const llvm::StringRef& pX)
+ { return (0 == key().compare(pX)); }
+
+ bool compare(const llvm::StringRef& pX) const
+ { return (0 == key().compare(pX)); }
+
+private:
+ StringEntry();
+ StringEntry(const key_type& pKey);
+ StringEntry(const StringEntry& pCopy);
+ ~StringEntry();
+
+private:
+ llvm::StringRef m_Value;
+ uint16_t m_KeyLen;
+ char m_Key[0];
+
+ friend class StringEntryFactory<llvm::StringRef>;
+};
+
+template<typename DataType>
+class StringEntryFactory
+{
+public:
+ typedef StringEntry<DataType> entry_type;
+ typedef typename StringEntry<DataType>::key_type key_type;
+ typedef typename StringEntry<DataType>::value_type value_type;
+
+public:
+ StringEntryFactory();
+ ~StringEntryFactory();
+
+ StringEntry<DataType>* produce(const key_type& pKey);
+ void destroy(StringEntry<DataType>* pEntry);
+};
+
+#include "StringEntry.tcc"
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/StringEntry.tcc b/include/mcld/ADT/StringEntry.tcc
new file mode 100644
index 0000000..fa86f24
--- /dev/null
+++ b/include/mcld/ADT/StringEntry.tcc
@@ -0,0 +1,71 @@
+//===- StringEntry.tcc -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// StringEntry
+template<typename DataType>
+StringEntry<DataType>::StringEntry()
+ : m_KeyLen(0) {
+}
+
+template<typename DataType>
+StringEntry<DataType>::StringEntry(const StringEntry::key_type& pKey)
+ : m_KeyLen(pKey.size()) {
+}
+
+template<typename DataType>
+StringEntry<DataType>::StringEntry(const StringEntry<DataType>& pCopy)
+ : m_KeyLen(pCopy.m_KeyLen), m_Value(pCopy.m_Value) {
+ assert("Copy constructor of StringEntry should not be called!");
+}
+
+template<typename DataType>
+StringEntry<DataType>::~StringEntry()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// StringEntryFactory
+template<typename DataType>
+StringEntryFactory<DataType>::StringEntryFactory()
+{
+}
+
+template<typename DataType>
+StringEntryFactory<DataType>::~StringEntryFactory()
+{
+}
+
+template<typename DataType>
+StringEntry<DataType>*
+StringEntryFactory<DataType>::produce(const typename StringEntryFactory<DataType>::key_type& pKey)
+{
+ StringEntry<DataType>* result = static_cast<StringEntry<DataType>*>(
+ malloc(sizeof(StringEntry<DataType>) + pKey.size() + 1));
+
+ if (NULL == result)
+ return NULL;
+
+ size_t len = pKey.size();
+ new (result) StringEntry<DataType>();
+ std::memcpy(result->m_Key, pKey.data(), len);
+ result->m_Key[len] = '\0';
+ result->m_KeyLen = len;
+ return result;
+}
+
+template<typename DataType>
+void StringEntryFactory<DataType>::destroy(StringEntry<DataType>* pEntry)
+{
+ if (NULL != pEntry) {
+ pEntry->~StringEntry<DataType>();
+ free(pEntry);
+ }
+}
+
diff --git a/include/mcld/ADT/StringHash.h b/include/mcld/ADT/StringHash.h
index cf6276d..f100a49 100644
--- a/include/mcld/ADT/StringHash.h
+++ b/include/mcld/ADT/StringHash.h
@@ -78,7 +78,7 @@
for(unsigned int i = 0; i < pKey.size(); ++i) {
hash_val ^= ((hash_val << 5) + pKey[i] + (hash_val >> 2));
- }
+ }
return hash_val;
}
};
@@ -123,7 +123,7 @@
for (unsigned int i = 0; i < pKey.size(); ++i) {
hash_val = (hash_val << 4) + pKey[i];
if((x = hash_val & 0xF0000000L) != 0)
- hash_val ^= (x >> 24);
+ hash_val ^= (x >> 24);
hash_val &= ~x;
}
return hash_val;
@@ -140,7 +140,7 @@
{
const size_t seed = 131;
size_t hash_val = 0;
-
+
for(size_t i = 0; i < pKey.size(); ++i)
hash_val = (hash_val * seed) + pKey[i];
return hash_val;
@@ -248,13 +248,13 @@
size_t operator()(const llvm::StringRef& pKey) const
{
unsigned int hash_val = 0xAAAAAAAA;
-
- for(size_t i = 0; i < pKey.size(); ++i) {
+
+ for(size_t i = 0; i < pKey.size(); ++i) {
hash_val ^= ((i & 1) == 0)?
((hash_val << 7) ^ pKey[i] * (hash_val >> 3)):
(~((hash_val << 11) + (pKey[i] ^ (hash_val >> 5))));
}
-
+
return hash_val;
}
};
@@ -286,3 +286,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/ADT/TreeAllocator.h b/include/mcld/ADT/TreeAllocator.h
index fc95bf7..899896c 100644
--- a/include/mcld/ADT/TreeAllocator.h
+++ b/include/mcld/ADT/TreeAllocator.h
@@ -27,7 +27,7 @@
* NodeFactory provides delegation of memory. Sometimes, we have to merge two
* NodeFactories, and NodeFactory::delegate() can move the memory from one
* NodeFactories to another.
- *
+ *
* @see LinearAllocator
*/
template<typename DataType>
@@ -95,3 +95,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/ADT/TreeBase.h b/include/mcld/ADT/TreeBase.h
index e231148..4df8d0d 100644
--- a/include/mcld/ADT/TreeBase.h
+++ b/include/mcld/ADT/TreeBase.h
@@ -126,3 +126,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/ADT/TypeTraits.h b/include/mcld/ADT/TypeTraits.h
index c24c4ae..90b2224 100644
--- a/include/mcld/ADT/TypeTraits.h
+++ b/include/mcld/ADT/TypeTraits.h
@@ -68,3 +68,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/ADT/Uncopyable.h b/include/mcld/ADT/Uncopyable.h
index d98c939..7ddfbe3 100644
--- a/include/mcld/ADT/Uncopyable.h
+++ b/include/mcld/ADT/Uncopyable.h
@@ -33,3 +33,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/CodeGen/SectLinker.h b/include/mcld/CodeGen/SectLinker.h
index cbc7214..b31b968 100644
--- a/include/mcld/CodeGen/SectLinker.h
+++ b/include/mcld/CodeGen/SectLinker.h
@@ -11,9 +11,8 @@
//This class primarily handles common functionality used by all linkers.
//
//===----------------------------------------------------------------------===//
-
-#ifndef SECTION_LINKER_H
-#define SECTION_LINKER_H
+#ifndef MCLD_SECTION_LINKER_H
+#define MCLD_SECTION_LINKER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -23,84 +22,83 @@
namespace llvm
{
- class Module;
- class MachineFunction;
+class Module;
+class MachineFunction;
} // namespace of llvm
namespace mcld
{
- class MCLDFile;
- class MCLDDriver;
- class TargetLDBackend;
- class AttributeFactory;
- class SectLinkerOption;
+class MCLDInfo;
+class MCLDFile;
+class MCLDDriver;
+class TargetLDBackend;
+class AttributeFactory;
+class SectLinkerOption;
+class MemoryAreaFactory;
- /** \class SectLinker
- * \brief SectLinker provides a linking pass for standard compilation flow
- *
- * SectLinker is responded for
- * - provide an interface for target-specific SectLinekr
- * - set up environment for MCLDDriver
- * - control AsmPrinter, make sure AsmPrinter has already prepared
- * all MCSectionDatas for linking
- *
- * SectLinker resolves the absolue paths of input arguments.
- *
- * @see MachineFunctionPass MCLDDriver
- */
- class SectLinker : public llvm::MachineFunctionPass
- {
- protected:
- // Constructor. Although SectLinker has only two arguments,
- // TargetSectLinker should handle
- // - enabled attributes
- // - the default attribute
- // - the default link script
- // - the standard symbols
- SectLinker(SectLinkerOption &pOption,
- TargetLDBackend &pLDBackend);
+/** \class SectLinker
+* \brief SectLinker provides a linking pass for standard compilation flow
+*
+* SectLinker is responded for
+* - provide an interface for target-specific SectLinekr
+* - set up environment for MCLDDriver
+* - control AsmPrinter, make sure AsmPrinter has already prepared
+* all MCSectionDatas for linking
+*
+* SectLinker resolves the absolue paths of input arguments.
+*
+* @see MachineFunctionPass MCLDDriver
+*/
+class SectLinker : public llvm::MachineFunctionPass
+{
+protected:
+ // Constructor. Although SectLinker has only two arguments,
+ // TargetSectLinker should handle
+ // - enabled attributes
+ // - the default attribute
+ // - the default link script
+ // - the standard symbols
+ SectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend);
- public:
- virtual ~SectLinker();
+public:
+ virtual ~SectLinker();
- /// addTargetOptions - target SectLinker can hook this function to add
- /// target-specific inputs
- virtual void addTargetOptions(llvm::Module &pM,
- SectLinkerOption &pOption)
- { }
+ /// doInitialization - Read all parameters and set up the AsmPrinter.
+ /// If your pass overrides this, it must make sure to explicitly call
+ /// this implementation.
+ virtual bool doInitialization(llvm::Module &pM);
- /// doInitialization - Read all parameters and set up the AsmPrinter.
- /// If your pass overrides this, it must make sure to explicitly call
- /// this implementation.
- virtual bool doInitialization(llvm::Module &pM);
+ /// doFinalization - Shut down the AsmPrinter, and do really linking.
+ /// If you override this in your pass, you must make sure to call it
+ /// explicitly.
+ virtual bool doFinalization(llvm::Module &pM);
- /// doFinalization - Shut down the AsmPrinter, and do really linking.
- /// If you override this in your pass, you must make sure to call it
- /// explicitly.
- virtual bool doFinalization(llvm::Module &pM);
+ /// runOnMachineFunction
+ /// redirect to AsmPrinter
+ virtual bool runOnMachineFunction(llvm::MachineFunction& pMFn);
- /// runOnMachineFunction
- /// redirect to AsmPrinter
- virtual bool runOnMachineFunction(llvm::MachineFunction& pMFn);
+protected:
+ void initializeInputTree(const PositionDependentOptions &pOptions) const;
- protected:
- void initializeInputTree(const PositionDependentOptions &pOptions) const;
+ void initializeInputOutput(MCLDInfo& pLDInfo);
- AttributeFactory* attrFactory()
- { return m_pAttrFactory; }
+ MemoryAreaFactory* memAreaFactory()
+ { return m_pMemAreaFactory; }
- private:
- SectLinkerOption *m_pOption;
+private:
+ SectLinkerOption *m_pOption;
- protected:
- TargetLDBackend *m_pLDBackend;
- MCLDDriver *m_pLDDriver;
- AttributeFactory *m_pAttrFactory;
+protected:
+ TargetLDBackend *m_pLDBackend;
+ MCLDDriver *m_pLDDriver;
+ MemoryAreaFactory *m_pMemAreaFactory;
- private:
- static char m_ID;
- };
+private:
+ static char m_ID;
+};
} // namespace of MC Linker
#endif
+
diff --git a/include/mcld/CodeGen/SectLinkerOption.h b/include/mcld/CodeGen/SectLinkerOption.h
index b3e3327..78c8f53 100644
--- a/include/mcld/CodeGen/SectLinkerOption.h
+++ b/include/mcld/CodeGen/SectLinkerOption.h
@@ -12,8 +12,8 @@
#include <gtest.h>
#endif
-#include "mcld/MC/MCLDInfo.h"
-#include "mcld/Support/PositionDependentOption.h"
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/Support/PositionDependentOption.h>
#include <string>
diff --git a/include/mcld/Config/Config.h.in b/include/mcld/Config/Config.h.in
index 6d428c0..c0e7e0a 100644
--- a/include/mcld/Config/Config.h.in
+++ b/include/mcld/Config/Config.h.in
@@ -9,13 +9,8 @@
#ifndef MCLD_CONFIG_H
#define MCLD_CONFIG_H
-namespace mcld {
-namespace internal {
-
-static const char* version="@MCLD_VERSION@";
-
-} // namespace of internal
-} // namespace of mcld
+#define @MCLD_ON_PLATFORM@ 1
+#define MCLD_VERSION "@MCLD_VERSION@"
#endif
diff --git a/include/mcld/LD/ArchiveReader.h b/include/mcld/LD/ArchiveReader.h
index 14a27e2..7d0aa58 100644
--- a/include/mcld/LD/ArchiveReader.h
+++ b/include/mcld/LD/ArchiveReader.h
@@ -23,9 +23,26 @@
* \brief ArchiveReader provides an common interface for all archive readers.
*
* ArchiveReader also reads the target-independent parts of an archive file.
+ * There are some property on all the archive formats.
+ * 1. All archive elements star on an even boundary, new line padded;
+ * 2. All archive headers are char *;
+ * 3. All archive headers are the same size.
*/
+
class ArchiveReader : public LDReader
{
+protected:
+ struct ArchiveMemberHeader
+ {
+ char name[16];
+ char date[12];
+ char uid[6];
+ char gid[6];
+ char mode[8];
+ char size[10];
+ char finalMagic[2];
+ };
+
public:
ArchiveReader();
virtual ~ArchiveReader();
@@ -36,3 +53,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/BSDArchiveReader.h b/include/mcld/LD/BSDArchiveReader.h
index 26add69..a275621 100644
--- a/include/mcld/LD/BSDArchiveReader.h
+++ b/include/mcld/LD/BSDArchiveReader.h
@@ -36,3 +36,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/BranchIsland.h b/include/mcld/LD/BranchIsland.h
index 9f13692..8e5cf9c 100644
--- a/include/mcld/LD/BranchIsland.h
+++ b/include/mcld/LD/BranchIsland.h
@@ -27,3 +27,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/CIE.h b/include/mcld/LD/CIE.h
new file mode 100644
index 0000000..15e1d69
--- /dev/null
+++ b/include/mcld/LD/CIE.h
@@ -0,0 +1,44 @@
+//===- CIE.h --------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_COMMON_INFORMATION_ENTRY_H
+#define MCLD_COMMON_INFORMATION_ENTRY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/DataTypes.h>
+#include <mcld/MC/MCRegionFragment.h>
+
+namespace mcld
+{
+
+/** \class CIE
+ * \brief Common Information Entry.
+ * The CIE structure refers to LSB Core Spec 4.1, chap.10.6. Exception Frames.
+ */
+class CIE : public MCRegionFragment
+{
+public:
+ explicit CIE(MemoryRegion& pRegion, uint8_t pFDEEncode);
+ ~CIE();
+
+ // ----- observers ----- //
+ /// getFDEEncoding - get the FDE encoding from Augmentation Data if 'R'
+ /// is present in Augmentaion String
+ uint8_t getFDEEncode() const
+ { return m_FDEEncoding; }
+
+private:
+ uint8_t m_FDEEncoding;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/DWARFLineInfo.h b/include/mcld/LD/DWARFLineInfo.h
new file mode 100644
index 0000000..004d597
--- /dev/null
+++ b/include/mcld/LD/DWARFLineInfo.h
@@ -0,0 +1,31 @@
+//===- DWARFLineInfo.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_DWARF_LINE_INFO_H
+#define MCLD_DWARF_LINE_INFO_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/LD/DiagnosticLineInfo.h>
+
+namespace mcld
+{
+
+/** \class DWARFLineInfo
+ * \brief DWARFLineInfo provides the conversion from address to line of code
+ * by DWARF format.
+ */
+class DWARFLineInfo : public DiagnosticLineInfo
+{
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/DiagCommonKinds.inc b/include/mcld/LD/DiagCommonKinds.inc
new file mode 100644
index 0000000..25cbb8f
--- /dev/null
+++ b/include/mcld/LD/DiagCommonKinds.inc
@@ -0,0 +1,41 @@
+DIAG(err_cannot_open_input, DiagnosticEngine::Error, "can not open input file `%0': %1", "can not open input file `%0' : %1")
+DIAG(err_cannot_open_output_file, DiagnosticEngine::Fatal, "cannot open output file `%0': %1", "cannot open output file `%0': %1")
+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(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")
+DIAG(unrecognized_output_file, DiagnosticEngine::Unreachable, "unsupported output file format: `%0'", "unsupported output file format: `%0'")
+DIAG(unrecognized_output_sectoin, DiagnosticEngine::Unreachable, "Unable to emit section `%0'\nPlease report to `%1'", "Unable to emit section `%0'\nPlease report to `%1'")
+DIAG(duplicated_wrap, DiagnosticEngine::Warning, "wrapped symbol `%0' had been claimed", "wrapped symbol `%0' had been claimed")
+DIAG(rewrap, DiagnosticEngine::Warning, "There are duplicated --wrap `%0' on the command line\nsymbol `%1' had been claimed", "There are duplicated --wrap `%0' on the command line]\nsymbol `%1' had been claimed.")
+DIAG(err_cannot_read_symbol, DiagnosticEngine::Fatal, "can not read symbol[%0] in file %1", "can not read symbol[%0] in file %1")
+DIAG(err_cannot_read_section, DiagnosticEngine::Fatal, "can not read section `%0'.", "can not read section `%0'.")
+DIAG(err_cannot_read_target_section, DiagnosticEngine::Fatal, "can not read target-dependent section `%0'.", "can not read target-dependent section `%0'.")
+DIAG(err_cannot_read_relocated_section, DiagnosticEngine::Fatal, "can not read the section being relocated in file %0.\ninvalid sh_info: %1\nrelocation section: %2", "can not read the section being relocated in file %0.\ninvalid sh_info: %1\nrelocation section: %2")
+DIAG(err_unsupported_section, DiagnosticEngine::Fatal, "unsupported section `%0' (type %1)", "unsupported section `%0' (type %1)")
+DIAG(unreachable_invalid_section_idx, DiagnosticEngine::Unreachable, "section[%0] is invalid in file %1", "section[%0] is invalid in file %1")
+DIAG(err_unsupported_whole_archive, DiagnosticEngine::Error, "Target does not support --whole-archive", "Target does not support --whole-archive")
+DIAG(err_unsupported_as_needed, DiagnosticEngine::Error, "Target does not support --as-needed", "Target does not support --as-needed")
+DIAG(err_unsupported_add_needed, DiagnosticEngine::Error, "Target doest not support --add-needed", "Target does not support --add-needed")
+DIAG(err_unsupported_Bdynamic, DiagnosticEngine::Error, "Target does not support --Bdynamic", "Target does not support --Bdynamic")
+DIAG(err_enable_as_needed_on_static_system, DiagnosticEngine::Warning, "can not enable --as-needed on the target which does not support shared objects", "can not enable --as-needed on the target which does not support shared objects")
+DIAG(err_mix_static_as_needed, DiagnosticEngine::Warning, "cannot mix --static with --as-needed", "cannot mix --static with --as-needed")
+DIAG(err_cannot_change_file_size, DiagnosticEngine::Error, "cannot truncate file `%0' to size %1", "cannot truncate ffile `%0' to size %1")
+DIAG(err_cannot_open_file, DiagnosticEngine::Error, "cannot open file %0.\nError Code: %1", "cannot open file %0.\nError Code: %1")
+DIAG(err_cannot_close_file, DiagnosticEngine::Error, "cannot close file %0.\nError Code: %1", "cannot close file %0.\nError Code: %1")
+DIAG(err_cannot_get_file_status, DiagnosticEngine::Error, "cannot get file status.\nError Code: %0", "cannot get file status.\nError Code: %0")
+DIAG(err_cannot_read_file, DiagnosticEngine::Error, "cannot read file %0 from offset %1 to length %2.", "cannot read file %0 from offset %1 to length %2.")
+DIAG(err_cannot_read_small_file, DiagnosticEngine::Fatal, "file %0 is too small to read.\n file size is %1.\n read from %2.", "file %0 is too small to read.\n file size is %1.\n read from %2.")
+DIAG(err_cannot_mmap_file, DiagnosticEngine::Error, "cannot open memory mapped file %0 from offset %1 to length %2.", "cannot open memoory mpped file %0 from offset %1 to length %2.")
+DIAG(err_cannot_munmap_file, DiagnosticEngine::Error, "cannot remove the mapped memory of file %0.", "cannot remove the mapped memory of file %0.")
+DIAG(err_cannot_write_file, DiagnosticEngine::Error, "cannot write file %0 from offset %1 to length %2.", "cannot write file %0 from offset %1 to length %2.")
+DIAG(warn_illegal_input_section, DiagnosticEngine::Warning, "section `%0' should not appear in input file `%1': %2", "section `%0' should not appear in input file `%1': %2")
+DIAG(err_cannot_trace_file, DiagnosticEngine::Unreachable, "cannot identify the type (%0) of input file `%1'.\n %2", "cannot identify the type (%0) of input file `%1'.\n %2")
+DIAG(err_out_of_range_region, DiagnosticEngine::Unreachable, "requested memory region is out of range.", "requested memory region is out of range.")
+DIAG(debug_eh_unsupport, DiagnosticEngine::Debug, "unsupported eh_frame: %0", "unsupported eh_frame: %0")
+DIAG(note_ehframe, DiagnosticEngine::Note, "eh_frame: %0", "eh_frame: %0")
+DIAG(note_eh_cie, DiagnosticEngine::Note, "CIE length: %0, aug_string: %1, fde_encodeing: %2", "CIE length: %0, aug_string: %1, fde_encodeing: %2")
+DIAG(note_eh_fde, DiagnosticEngine::Note, "FDE length: %0, offset of PC Begin: %1", "FDE length: %0, offset of PC Begin: %1")
diff --git a/include/mcld/LD/DiagGOTPLT.inc b/include/mcld/LD/DiagGOTPLT.inc
new file mode 100644
index 0000000..f0d3d2c
--- /dev/null
+++ b/include/mcld/LD/DiagGOTPLT.inc
@@ -0,0 +1,3 @@
+DIAG(mips_got_symbol, DiagnosticEngine::Unreachable, "%0 is not a dynamic symbol, do not put it in global got", "%0 is not a dynamic symbol, do not put it in global got")
+DIAG(fail_allocate_memory, DiagnosticEngine::Fatal, "fial to allocate memory for %0", "fial to allocate memory for %0")
+DIAG(reserve_entry_number_mismatch, DiagnosticEngine::Unreachable, "The number of reserved entries for %0 is inconsist", "The number of reserved entries for %0 is inconsist")
diff --git a/include/mcld/LD/DiagLayouts.inc b/include/mcld/LD/DiagLayouts.inc
new file mode 100644
index 0000000..af6bc96
--- /dev/null
+++ b/include/mcld/LD/DiagLayouts.inc
@@ -0,0 +1,3 @@
+DIAG(warn_unsupported_exception, DiagnosticEngine::Warning, "Exception handling has not been fully supported yet.\nsection `%0'.", "Exception handling has not been fully supported yet.\nsection `%0'.")
+DIAG(warn_unsupported_symbolic_versioning, DiagnosticEngine::Warning, "Symbolic versioning has not been fully supported yet.\nsection `%0'.", "Symbolic versioning has not been fully supported yet.\nsection `%0'")
+DIAG(err_section_not_laid_out, DiagnosticEngine::Unreachable, "section %0 has not been laid out. Developers may use an output LDSection in Layout::getFragmentRef", "section %0 has not been laid out. Developers may use an output LDSection in Layout::getFragmentRef")
diff --git a/include/mcld/LD/DiagReaders.inc b/include/mcld/LD/DiagReaders.inc
new file mode 100644
index 0000000..8ba28c2
--- /dev/null
+++ b/include/mcld/LD/DiagReaders.inc
@@ -0,0 +1 @@
+DIAG(archive_magic_mismatch, DiagnosticEngine::Error, "magic number is mismatched in `%0'", "magic number is mismatched in `%0'")
diff --git a/include/mcld/LD/DiagRelocations.inc b/include/mcld/LD/DiagRelocations.inc
new file mode 100644
index 0000000..e115fd8
--- /dev/null
+++ b/include/mcld/LD/DiagRelocations.inc
@@ -0,0 +1,9 @@
+DIAG(undefined_reference, DiagnosticEngine::Fatal, "undefined reference to `%0'", "In %1:%2, variable %0 must be defined")
+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, "enexpected relocation type `%0' in object file", "unexpected relocation type `%0' in object file")
+DIAG(unsupported_relocation, DiagnosticEngine::Unreachable, "encounter unsupported relocation type `%0'\nPlease report to %1", "encounter unsupported relocation type `%0'\nPlease report to %1")
+DIAG(unknown_relocation, DiagnosticEngine::Fatal, "encounter unknown relocation type `%0' for symbol `%1'", "encounter unknown relocation type `%0' for symbol `%1'")
+DIAG(invalid_global_relocation, DiagnosticEngine::Unreachable, "relocation type `%0' is invalid for global symbol `%1'", "relocation type `%0' is invalid for global symbol `%1'")
+DIAG(result_overflow, DiagnosticEngine::Error, "applying relocation `%0' causes overflow on symbol `%1'","applying relocation `%0' causes overflow on symbol `%1'")
+DIAG(result_badreloc, DiagnosticEngine::Error, "applying relocation `%0' encounters unexpected opcode on symbol `%1'","applying relocation `%0' encounters unexpected opcode on symbol `%1'")
diff --git a/include/mcld/LD/DiagSymbolResolutions.inc b/include/mcld/LD/DiagSymbolResolutions.inc
new file mode 100644
index 0000000..786eb4b
--- /dev/null
+++ b/include/mcld/LD/DiagSymbolResolutions.inc
@@ -0,0 +1,10 @@
+DIAG(note_has_no_symtab, DiagnosticEngine::Note, "input file `%0' has no symbol table `%2'\n path of input file: %1", "input file `%0' has no symbol table `%2'\n path of input file: %1")
+DIAG(fatal_cannot_read_strtab, DiagnosticEngine::Fatal, "cannot read strtab for %2 in file `%0': %1", "cannot read strtab for %2 in file `%0': %1")
+DIAG(fail_sym_resolution, DiagnosticEngine::Unreachable, "Fails to resolve symbols [%0:%1]\nPlease reports to `%2'", "Fails to resolve symbols [%0:%1]\nPlease reports to `%2'")
+DIAG(mark_dynamic_defined, DiagnosticEngine::Ignore, "refer to dynamic symbol %0", "call a external function %0")
+DIAG(comm_refer_to_define, DiagnosticEngine::Ignore, "common symbol %0 is overridden by previous definition", "common symbol %0 is overridden by previous definition")
+DIAG(redefine_common, DiagnosticEngine::Ignore, "common symbol %0 is overridden by definition", "common symbol %0 is overriden by definition")
+DIAG(indirect_refer_to_common, DiagnosticEngine::Ignore, "indirect symbol %0 points to a common symbol", "indirect symbol %0 points to a common symbol")
+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)")
diff --git a/include/mcld/LD/Diagnostic.h b/include/mcld/LD/Diagnostic.h
new file mode 100644
index 0000000..5e7d436
--- /dev/null
+++ b/include/mcld/LD/Diagnostic.h
@@ -0,0 +1,97 @@
+//===- Diagnostic.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_DIAGNOSTIC_H
+#define MCLD_DIAGNOSTIC_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <string>
+#include <cassert>
+#include <mcld/LD/DiagnosticEngine.h>
+
+namespace mcld
+{
+
+/** \class Diagnostic
+ * \brief Diagnostic provides current status to DiagnosticPrinters.
+ */
+class Diagnostic
+{
+public:
+ Diagnostic(DiagnosticEngine& pEngine);
+
+ ~Diagnostic();
+
+ unsigned int getID() const
+ { return m_Engine.state().ID; }
+
+ unsigned int getNumArgs() const
+ { return m_Engine.state().numArgs; }
+
+ DiagnosticEngine::ArgumentKind getArgKind(unsigned int pIdx) const {
+ assert(pIdx < getNumArgs() && "Argument index is out of range!");
+ return (DiagnosticEngine::ArgumentKind)m_Engine.state().ArgumentKinds[pIdx];
+ }
+
+ const std::string &getArgStdStr(unsigned int pIdx) const {
+ assert(getArgKind(pIdx) == DiagnosticEngine::ak_std_string &&
+ "Invalid argument accessor!");
+ return m_Engine.state().ArgumentStrs[pIdx];
+ }
+
+ const char* getArgCStr(unsigned int pIdx) const {
+ assert(getArgKind(pIdx) == DiagnosticEngine::ak_c_string &&
+ "Invalid argument accessor!");
+ return reinterpret_cast<const char*>(m_Engine.state().ArgumentVals[pIdx]);
+ }
+
+ int getArgSInt(unsigned int pIdx) const {
+ assert(getArgKind(pIdx) == DiagnosticEngine::ak_sint &&
+ "Invalid argument accessor!");
+ return (int)m_Engine.state().ArgumentVals[pIdx];
+ }
+
+ unsigned int getArgUInt(unsigned int pIdx) const {
+ assert(getArgKind(pIdx) == DiagnosticEngine::ak_uint &&
+ "Invalid argument accessor!");
+ return (unsigned int)m_Engine.state().ArgumentVals[pIdx];
+ }
+
+ bool getArgBool(unsigned int pIdx) const {
+ assert(getArgKind(pIdx) == DiagnosticEngine::ak_bool &&
+ "Invalid argument accessor!");
+ return (bool)m_Engine.state().ArgumentVals[pIdx];
+ }
+
+ intptr_t getRawVals(unsigned int pIdx) const {
+ assert(getArgKind(pIdx) != DiagnosticEngine::ak_std_string &&
+ "Invalid argument accessor!");
+ return m_Engine.state().ArgumentVals[pIdx];
+ }
+
+ // format - format this diagnostic into string, subsituting the formal
+ // arguments. The result is appended at on the pOutStr.
+ void format(std::string& pOutStr) const;
+
+ // format - format the given formal string, subsituting the formal
+ // arguments. The result is appended at on the pOutStr.
+ void format(const char* pBegin, const char* pEnd, std::string& pOutStr) const;
+
+private:
+ const char* findMatch(char pVal, const char* pBegin, const char* pEnd ) const;
+
+private:
+ DiagnosticEngine& m_Engine;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/DiagnosticEngine.h b/include/mcld/LD/DiagnosticEngine.h
new file mode 100644
index 0000000..9c106e5
--- /dev/null
+++ b/include/mcld/LD/DiagnosticEngine.h
@@ -0,0 +1,150 @@
+//===- DiagnosticEngine.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_DIAGNOSTIC_ENGINE_H
+#define MCLD_DIAGNOSTIC_ENGINE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <string>
+#include <llvm/Support/DataTypes.h>
+#include <mcld/LD/DiagnosticInfos.h>
+
+namespace mcld {
+
+class Input;
+class MCLDInfo;
+class MsgHandler;
+class DiagnosticPrinter;
+class DiagnosticLineInfo;
+
+/** \class DiagnosticEngine
+ * \brief DiagnosticEngine is used to report problems and issues.
+ *
+ * DiagnosticEngine is used to report problems and issues. It creates the
+ * Diagnostics and passes them to the DiagnosticPrinter for reporting to the
+ * user.
+ *
+ * DiagnosticEngine is a complex class, it is responsible for
+ * - remember the argument string for MsgHandler
+ * - choice the severity of a message by options
+ */
+class DiagnosticEngine
+{
+public:
+ enum Severity {
+ Unreachable,
+ Fatal,
+ Error,
+ Warning,
+ Debug,
+ Note,
+ Ignore,
+ None
+ };
+
+ enum ArgumentKind {
+ ak_std_string, // std::string
+ ak_c_string, // const char *
+ ak_sint, // int
+ ak_uint, // unsigned int
+ ak_bool // bool
+ };
+
+public:
+ DiagnosticEngine(const MCLDInfo& pLDInfo,
+ DiagnosticLineInfo* pLineInfo = NULL,
+ DiagnosticPrinter* pPrinter = NULL,
+ bool pShouldOwnPrinter = true);
+
+ ~DiagnosticEngine();
+
+ // ----- printer functions ----- //
+ void setPrinter(DiagnosticPrinter& pPrinter, bool pShouldOwnPrinter = true);
+
+ DiagnosticPrinter* getPrinter()
+ { return m_pPrinter; }
+
+ const DiagnosticPrinter* getPrinter() const
+ { return m_pPrinter; }
+
+ DiagnosticPrinter* takePrinter() {
+ m_OwnPrinter = false;
+ return m_pPrinter;
+ }
+
+ bool ownPrinter() const
+ { return m_OwnPrinter; }
+
+ // ----- emission ----- //
+ // emit - process the message to printer
+ bool emit();
+
+ // report - issue the message to the printer
+ MsgHandler report(uint16_t pID, Severity pSeverity);
+
+private:
+ friend class MsgHandler;
+ friend class Diagnostic;
+
+ enum {
+ /// MaxArguments - The maximum number of arguments we can hold. We currently
+ /// only support up to 10 arguments (%0-%9).
+ MaxArguments = 10,
+ };
+
+ struct State
+ {
+ public:
+ State() : numArgs(0), ID(-1), severity(None), file(NULL) { }
+ ~State() { }
+
+ void reset() {
+ numArgs = 0;
+ ID = -1;
+ severity = None;
+ file = NULL;
+ }
+
+ public:
+ std::string ArgumentStrs[MaxArguments];
+ intptr_t ArgumentVals[MaxArguments];
+ uint8_t ArgumentKinds[MaxArguments];
+ int8_t numArgs;
+ uint16_t ID;
+ Severity severity;
+ Input* file;
+ };
+
+private:
+ State& state()
+ { return m_State; }
+
+ const State& state() const
+ { return m_State; }
+
+ DiagnosticInfos& infoMap()
+ { return m_InfoMap; }
+
+ const DiagnosticInfos& infoMap() const
+ { return m_InfoMap; }
+
+private:
+ const MCLDInfo& m_LDInfo;
+ DiagnosticLineInfo* m_pLineInfo;
+ DiagnosticPrinter* m_pPrinter;
+ DiagnosticInfos m_InfoMap;
+ bool m_OwnPrinter;
+
+ State m_State;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/DiagnosticInfos.h b/include/mcld/LD/DiagnosticInfos.h
new file mode 100644
index 0000000..66f7fc0
--- /dev/null
+++ b/include/mcld/LD/DiagnosticInfos.h
@@ -0,0 +1,56 @@
+//===- DiagnosticInfo.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_DIAGNOSTIC_INFORMATION_H
+#define MCLD_DIAGNOSTIC_INFORMATION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/StringRef.h>
+
+namespace mcld {
+
+namespace diag {
+ enum ID {
+#define DIAG(ENUM, CLASS, ADDRMSG, LINEMSG) ENUM,
+#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"
+#undef DIAG
+ NUM_OF_BUILDIN_DIAGNOSTIC_INFO
+ };
+} // namespace of diag
+
+class MCLDInfo;
+class DiagnosticEngine;
+
+/** \class DiagnosticInfos
+ * \brief DiagnosticInfos caches run-time information of DiagnosticInfo.
+ */
+class DiagnosticInfos
+{
+public:
+ DiagnosticInfos(const MCLDInfo& pLDInfo);
+
+ ~DiagnosticInfos();
+
+ llvm::StringRef getDescription(unsigned int pID, bool pLoC) const;
+
+ bool process(DiagnosticEngine& pEngine) const;
+
+private:
+ const MCLDInfo& m_LDInfo;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/DiagnosticLineInfo.h b/include/mcld/LD/DiagnosticLineInfo.h
new file mode 100644
index 0000000..30f0546
--- /dev/null
+++ b/include/mcld/LD/DiagnosticLineInfo.h
@@ -0,0 +1,29 @@
+//===- DiagnosticLineInfo.h -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_DIAGNOSTICLINEINFO_H
+#define MCLD_DIAGNOSTICLINEINFO_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+/** \class DiagnosticLineInfo
+ * \brief Map the address to the line of code.
+ */
+class DiagnosticLineInfo
+{
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/DiagnosticPrinter.h b/include/mcld/LD/DiagnosticPrinter.h
new file mode 100644
index 0000000..13911f5
--- /dev/null
+++ b/include/mcld/LD/DiagnosticPrinter.h
@@ -0,0 +1,59 @@
+//===- DiagnosticPrinter.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_DIAGNOSTIC_PRINTER_H
+#define MCLD_DIAGNOSTIC_PRINTER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/LD/DiagnosticEngine.h>
+#include <mcld/LD/Diagnostic.h>
+
+namespace mcld
+{
+
+/** \class DiagnosticPrinter
+ * \brief DiagnosticPrinter provides the interface to customize diagnostic
+ * messages and output.
+ */
+class DiagnosticPrinter
+{
+public:
+ DiagnosticPrinter();
+
+ virtual ~DiagnosticPrinter();
+
+ virtual void beginInput(const Input& pInput, const MCLDInfo& pLDInfo) {}
+
+ virtual void endInput() {}
+
+ virtual void finish() {}
+
+ virtual void clear()
+ { m_NumErrors = m_NumWarnings = 0; }
+
+ /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
+ /// capturing it to a log as needed.
+ virtual void handleDiagnostic(DiagnosticEngine::Severity pSeverity,
+ const Diagnostic& pInfo);
+
+ unsigned int getNumErrors() const
+ { return m_NumErrors; }
+
+ unsigned int getNumWarnings() const
+ { return m_NumWarnings; }
+
+protected:
+ unsigned int m_NumErrors;
+ unsigned int m_NumWarnings;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/DynObjFileFormat.h b/include/mcld/LD/DynObjFileFormat.h
index 6a25184..7b1626d 100644
--- a/include/mcld/LD/DynObjFileFormat.h
+++ b/include/mcld/LD/DynObjFileFormat.h
@@ -26,3 +26,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/DynObjReader.h b/include/mcld/LD/DynObjReader.h
index c3b4099..0900109 100644
--- a/include/mcld/LD/DynObjReader.h
+++ b/include/mcld/LD/DynObjReader.h
@@ -42,3 +42,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/DynObjWriter.h b/include/mcld/LD/DynObjWriter.h
index 08bb237..1c77bd4 100644
--- a/include/mcld/LD/DynObjWriter.h
+++ b/include/mcld/LD/DynObjWriter.h
@@ -38,3 +38,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/ELFDynObjFileFormat.h b/include/mcld/LD/ELFDynObjFileFormat.h
index 02d7103..9b77e91 100644
--- a/include/mcld/LD/ELFDynObjFileFormat.h
+++ b/include/mcld/LD/ELFDynObjFileFormat.h
@@ -35,3 +35,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/ELFDynObjReader.h b/include/mcld/LD/ELFDynObjReader.h
index 7fdcc23..72a3336 100644
--- a/include/mcld/LD/ELFDynObjReader.h
+++ b/include/mcld/LD/ELFDynObjReader.h
@@ -48,3 +48,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/ELFDynObjWriter.h b/include/mcld/LD/ELFDynObjWriter.h
index 7cfac05..dc0e37b 100644
--- a/include/mcld/LD/ELFDynObjWriter.h
+++ b/include/mcld/LD/ELFDynObjWriter.h
@@ -50,3 +50,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/ELFExecFileFormat.h b/include/mcld/LD/ELFExecFileFormat.h
index a6544fa..3c0d8bd 100644
--- a/include/mcld/LD/ELFExecFileFormat.h
+++ b/include/mcld/LD/ELFExecFileFormat.h
@@ -28,10 +28,10 @@
ELFExecFileFormat(GNULDBackend& pBackend) : ELFFileFormat(pBackend)
{}
- void initObjectType(MCLinker& pLinker)
- { /** TODO **/ }
+ void initObjectType(MCLinker& pLinker);
};
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/ELFExecWriter.h b/include/mcld/LD/ELFExecWriter.h
new file mode 100644
index 0000000..09709f7
--- /dev/null
+++ b/include/mcld/LD/ELFExecWriter.h
@@ -0,0 +1,53 @@
+//===- ELFDynObjWriter.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_EXECUTABLE_OBJECT_WRITER_H
+#define MCLD_ELF_EXECUTABLE_OBJECT_WRITER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/DenseMap.h>
+#include <llvm/Support/ELF.h>
+#include <mcld/LD/ExecWriter.h>
+#include <mcld/LD/ELFWriter.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/Support/MemoryArea.h>
+#include <vector>
+#include <utility>
+
+
+namespace mcld
+{
+
+class GNULDBackend;
+class MCLinker;
+
+/** \class ELFDynObjWriter
+ * \brief ELFDynObjWriter writes the dynamic sections.
+ */
+class ELFExecWriter : public ExecWriter, private ELFWriter
+{
+public:
+ typedef ELFWriter::FileOffset FileOffset;
+
+public:
+ ELFExecWriter(GNULDBackend& pBackend, MCLinker& pLinker);
+ ~ELFExecWriter();
+
+ llvm::error_code writeExecutable(Output& pOutput);
+
+private:
+ GNULDBackend& m_Backend;
+ MCLinker& m_Linker;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFFileFormat.h b/include/mcld/LD/ELFFileFormat.h
index 1706a66..f7a0c68 100644
--- a/include/mcld/LD/ELFFileFormat.h
+++ b/include/mcld/LD/ELFFileFormat.h
@@ -171,6 +171,9 @@
bool hasStabStr() const
{ return (NULL != f_pStabStr) && (0 != f_pStabStr->size()); }
+ bool hasStack() const
+ { return (NULL != f_pStack) && (0 != f_pStack->size()); }
+
// ----- access functions ----- //
/// @ref Special Sections, Ch. 4.17, System V ABI, 4th edition.
LDSection& getNULLSection() {
@@ -595,6 +598,15 @@
return *f_pStabStr;
}
+ LDSection& getStack() {
+ assert(NULL != f_pStack);
+ return *f_pStack;
+ }
+
+ const LDSection& getStack() const {
+ assert(NULL != f_pStack);
+ return *f_pStack;
+ }
protected:
GNULDBackend& f_Backend;
@@ -646,8 +658,12 @@
LDSection* f_pNoteABITag; // .note.ABI-tag
LDSection* f_pStab; // .stab
LDSection* f_pStabStr; // .stabstr
+
+ /// practical
+ LDSection* f_pStack; // .stack
};
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/ELFObjectReader.h b/include/mcld/LD/ELFObjectReader.h
index 635da85..ac11261 100644
--- a/include/mcld/LD/ELFObjectReader.h
+++ b/include/mcld/LD/ELFObjectReader.h
@@ -56,3 +56,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/ELFObjectWriter.h b/include/mcld/LD/ELFObjectWriter.h
index e534a58..a6b9a87 100644
--- a/include/mcld/LD/ELFObjectWriter.h
+++ b/include/mcld/LD/ELFObjectWriter.h
@@ -44,3 +44,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/ELFReader.h b/include/mcld/LD/ELFReader.h
index 3acbf25..d232cab 100644
--- a/include/mcld/LD/ELFReader.h
+++ b/include/mcld/LD/ELFReader.h
@@ -24,6 +24,7 @@
#include <mcld/LD/LDContext.h>
#include <mcld/Target/GNULDBackend.h>
#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
namespace mcld
{
@@ -101,6 +102,14 @@
MCLinker& pLinker,
LDSection& pSection,
const MemoryRegion& pRegion) const = 0;
+
+ bool readEhFrame(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSection) const;
+
+ /// readDynamic - read ELF .dynamic in input dynobj
+ virtual bool readDynamic(Input& pInput) const = 0;
+
protected:
/// LinkInfo - some section needs sh_link and sh_info, remember them.
struct LinkInfo {
@@ -214,6 +223,9 @@
MCLinker& pLinker,
LDSection& pSection,
const MemoryRegion& pRegion) const;
+
+ /// readDynamic - read ELF .dynamic in input dynobj
+ inline bool readDynamic(Input& pInput) const;
};
#include "ELFReader.tcc"
@@ -221,3 +233,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/ELFReader.tcc b/include/mcld/LD/ELFReader.tcc
index 862b971..61e8331 100644
--- a/include/mcld/LD/ELFReader.tcc
+++ b/include/mcld/LD/ELFReader.tcc
@@ -190,7 +190,8 @@
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::Group == info->section->kind() ||
+ LDFileFormat::Note == info->section->kind()) {
info->section->setLink(pInput.context()->getSection(info->sh_link));
continue;
}
@@ -254,8 +255,8 @@
{
// get number of symbols
size_t entsize = pRegion.size()/sizeof(llvm::ELF::Elf32_Sym);
- llvm::ELF::Elf32_Sym* symtab =
- reinterpret_cast<llvm::ELF::Elf32_Sym*>(pRegion.start());
+ const llvm::ELF::Elf32_Sym* symtab =
+ reinterpret_cast<const llvm::ELF::Elf32_Sym*>(pRegion.start());
uint32_t st_name = 0x0;
uint32_t st_value = 0x0;
@@ -292,9 +293,6 @@
st_shndx = llvm::ELF::SHN_UNDEF;
}
- // get ld_name
- llvm::StringRef ld_name(pStrTab + st_name);
-
// get ld_type
ResolveInfo::Type ld_type = static_cast<ResolveInfo::Type>(st_info & 0xF);
@@ -316,6 +314,19 @@
// get ld_vis
ResolveInfo::Visibility ld_vis = getSymVisibility(st_other);
+ // get ld_name
+ llvm::StringRef ld_name;
+ if (ResolveInfo::Section == ld_type) {
+ // Section symbol's st_name is the section index.
+ LDSection* section = pInput.context()->getSection(st_shndx);
+ assert(NULL != section && "get a invalid section");
+ ld_name = llvm::StringRef(section->name());
+ }
+ else {
+ ld_name = llvm::StringRef(pStrTab + st_name);
+ }
+
+
// push into MCLinker
LDSymbol* input_sym = NULL;
@@ -404,13 +415,13 @@
ResolveInfo::Visibility ld_vis = getSymVisibility(st_other);
ResolveInfo* result =
- pLDInfo.getStrSymPool().createSymbol(ld_name,
- pInput.type() == Input::DynObj,
- ld_type,
- ld_desc,
- ld_binding,
- st_size,
- ld_vis);
+ pLDInfo.getNamePool().createSymbol(ld_name,
+ (pInput.type() == Input::DynObj),
+ ld_type,
+ ld_desc,
+ ld_binding,
+ st_size,
+ ld_vis);
// release regions
pInput.memArea()->release(symbol_region);
pInput.memArea()->release(strtab_region);
@@ -426,8 +437,8 @@
{
// get the number of rela
size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf32_Rela);
- llvm::ELF::Elf32_Rela* relaTab =
- reinterpret_cast<llvm::ELF::Elf32_Rela*>(pRegion.start());
+ const llvm::ELF::Elf32_Rela* relaTab =
+ reinterpret_cast<const llvm::ELF::Elf32_Rela*>(pRegion.start());
for (size_t idx=0; idx < entsize; ++idx) {
uint32_t r_offset = 0x0;
@@ -447,13 +458,8 @@
uint8_t r_type = static_cast<unsigned char>(r_info);
uint32_t r_sym = (r_info >> 8);
LDSymbol* symbol = pInput.context()->getSymbol(r_sym);
- if (NULL == symbol) {
- llvm::report_fatal_error(llvm::Twine("invalid symbol index :") +
- llvm::Twine(r_sym) +
- llvm::Twine(" in file `") +
- pInput.path().native() +
- llvm::Twine("'.\n"));
- }
+ if (NULL == symbol)
+ fatal(diag::err_cannot_read_symbol) << r_sym << pInput.path();
ResolveInfo* resolve_info = symbol->resolveInfo();
@@ -461,16 +467,13 @@
pLinker.getLayout().getFragmentRef(*pSection.getLink(), r_offset);
if (NULL == frag_ref) {
- llvm::report_fatal_error(llvm::Twine("invalid sh_info: ") +
- llvm::Twine(pSection.getLink()->index()) +
- llvm::Twine(" of the relocation section `") +
- pSection.name() +
- llvm::Twine("' in file `") +
- pInput.path().native() +
- llvm::Twine(".\n"));
+ fatal(diag::err_cannot_read_relocated_section)
+ << pSection.name()
+ << pSection.getLink()->index()
+ << pInput.path();
}
- pLinker.addRelocation(r_type, *symbol, *resolve_info, *frag_ref, r_addend);
+ pLinker.addRelocation(r_type, *symbol, *resolve_info, *frag_ref, pSection, r_addend);
}
return true;
}
@@ -483,8 +486,8 @@
{
// get the number of rel
size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf32_Rel);
- llvm::ELF::Elf32_Rel* relTab =
- reinterpret_cast<llvm::ELF::Elf32_Rel*>(pRegion.start());
+ const llvm::ELF::Elf32_Rel* relTab =
+ reinterpret_cast<const llvm::ELF::Elf32_Rel*>(pRegion.start());
for (size_t idx=0; idx < entsize; ++idx) {
uint32_t r_offset = 0x0;
@@ -503,11 +506,7 @@
LDSymbol* symbol = pInput.context()->getSymbol(r_sym);
if (NULL == symbol) {
- llvm::report_fatal_error(llvm::Twine("invalid symbol index :") +
- llvm::Twine(r_sym) +
- llvm::Twine(" in file `") +
- pInput.path().native() +
- llvm::Twine("'.\n"));
+ fatal(diag::err_cannot_read_symbol) << r_sym << pInput.path();
}
ResolveInfo* resolve_info = symbol->resolveInfo();
@@ -516,16 +515,78 @@
pLinker.getLayout().getFragmentRef(*pSection.getLink(), r_offset);
if (NULL == frag_ref) {
- llvm::report_fatal_error(llvm::Twine("invalid sh_info: ") +
- llvm::Twine(pSection.getLink()->index()) +
- llvm::Twine(" of the relocation section `") +
- pSection.name() +
- llvm::Twine("' in file `") +
- pInput.path().native() +
- llvm::Twine(".\n"));
+ fatal(diag::err_cannot_read_relocated_section)
+ << pSection.name()
+ << pSection.getLink()->index()
+ << pInput.path();
}
- pLinker.addRelocation(r_type, *symbol, *resolve_info, *frag_ref);
+ pLinker.addRelocation(r_type, *symbol, *resolve_info, *frag_ref, pSection);
}
return true;
}
+
+/// readDynamic - read ELF .dynamic in input dynobj
+bool ELFReader<32, true>::readDynamic(Input& pInput) const
+{
+ assert(pInput.type() == Input::DynObj);
+ const LDSection* dynamic_sect = pInput.context()->getSection(".dynamic");
+ if (NULL == dynamic_sect) {
+ fatal(diag::err_cannot_read_section) << ".dynamic";
+ }
+ const LDSection* dynstr_sect = dynamic_sect->getLink();
+ if (NULL == dynstr_sect) {
+ fatal(diag::err_cannot_read_section) << ".dynstr";
+ }
+
+ MemoryRegion* dynamic_region =
+ pInput.memArea()->request(dynamic_sect->offset(), dynamic_sect->size());
+
+ MemoryRegion* dynstr_region =
+ pInput.memArea()->request(dynstr_sect->offset(), dynstr_sect->size());
+
+ assert(NULL != dynamic_region && NULL != dynstr_region);
+
+ const llvm::ELF::Elf32_Dyn* dynamic =
+ (llvm::ELF::Elf32_Dyn*) dynamic_region->start();
+ const char* dynstr = (const char*) dynstr_region->start();
+ bool hasSOName = false;
+ size_t numOfEntries = dynamic_sect->size() / sizeof(llvm::ELF::Elf32_Dyn);
+
+ for (size_t idx = 0; idx < numOfEntries; ++idx) {
+
+ llvm::ELF::Elf32_Sword d_tag = 0x0;
+ llvm::ELF::Elf32_Word d_val = 0x0;
+
+ if (llvm::sys::isLittleEndianHost()) {
+ d_tag = dynamic[idx].d_tag;
+ d_val = dynamic[idx].d_un.d_val;
+ } else {
+ d_tag = bswap32(dynamic[idx].d_tag);
+ d_val = bswap32(dynamic[idx].d_un.d_val);
+ }
+
+ switch (d_tag) {
+ case llvm::ELF::DT_SONAME:
+ assert(d_val < dynstr_sect->size());
+ pInput.setSOName(dynstr + d_val);
+ hasSOName = true;
+ break;
+ case llvm::ELF::DT_NEEDED:
+ // TODO:
+ break;
+ case llvm::ELF::DT_NULL:
+ default:
+ break;
+ }
+ }
+
+ // if there is no SONAME in .dynamic, then set it from input path
+ if (!hasSOName)
+ pInput.setSOName(pInput.path().native());
+
+ pInput.memArea()->release(dynamic_region);
+ pInput.memArea()->release(dynstr_region);
+ return true;
+}
+
diff --git a/include/mcld/LD/ELFSegment.h b/include/mcld/LD/ELFSegment.h
index 312f0a7..8b9ff98 100644
--- a/include/mcld/LD/ELFSegment.h
+++ b/include/mcld/LD/ELFSegment.h
@@ -36,7 +36,8 @@
uint64_t pPaddr = 0,
uint64_t pFilesz = 0,
uint64_t pMemsz = 0,
- uint64_t pAlign = 0);
+ uint64_t pAlign = 0,
+ uint64_t pMaxSectAlign = 0);
~ELFSegment();
/// ----- iterators ----- ///
@@ -52,34 +53,32 @@
const_sect_iterator sectEnd() const
{ return m_SectionList.end(); }
- const LDSection* getFirstSection()
+ LDSection* getFirstSection()
{
- if (0 == m_SectionList.size())
+ if (0 == numOfSections())
return NULL;
return m_SectionList[0];
}
- const LDSection* getLastSection()
+ LDSection* getLastSection()
{
- size_t size = m_SectionList.size();
- if (0 == size)
+ if (0 == numOfSections())
return NULL;
- return m_SectionList[size - 1];
+ return m_SectionList[numOfSections() - 1];
}
const LDSection* getFirstSection() const
{
- if (0 == m_SectionList.size())
+ if (0 == numOfSections())
return NULL;
return m_SectionList[0];
}
const LDSection* getLastSection() const
{
- size_t size = m_SectionList.size();
- if (0 == size)
+ if (0 == numOfSections())
return NULL;
- return m_SectionList[size - 1];
+ return m_SectionList[numOfSections() - 1];
}
/// ----- observers ----- ///
@@ -105,7 +104,7 @@
{ return m_Flag; }
uint64_t align() const
- { return m_Align; }
+ { return std::max(m_Align, m_MaxSectionAlign); }
size_t numOfSections() const
{ return m_SectionList.size(); }
@@ -142,21 +141,25 @@
void addSection(LDSection* pSection)
{
assert(NULL != pSection);
+ if (pSection->align() > m_MaxSectionAlign)
+ m_MaxSectionAlign = pSection->align();
m_SectionList.push_back(pSection);
}
private:
- uint32_t m_Type; // Type of segment
- uint32_t m_Flag; // Segment flags
- uint64_t m_Offset; // File offset where segment is located, in bytes
- uint64_t m_Vaddr; // Virtual address of beginning of segment
- uint64_t m_Paddr; // Physical address of beginning of segment (OS-specific)
- uint64_t m_Filesz; // Num. of bytes in file image of segment (may be zero)
- uint64_t m_Memsz; // Num. of bytes in mem image of segment (may be zero)
- uint64_t m_Align; // Segment alignment constraint
+ uint32_t m_Type; // Type of segment
+ uint32_t m_Flag; // Segment flags
+ uint64_t m_Offset; // File offset where segment is located, in bytes
+ uint64_t m_Vaddr; // Virtual address of the segment
+ uint64_t m_Paddr; // Physical address of the segment (OS-specific)
+ uint64_t m_Filesz; // # of bytes in file image of segment (may be 0)
+ 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;
};
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/ELFSegmentFactory.h b/include/mcld/LD/ELFSegmentFactory.h
index 7b5e305..5085a18 100644
--- a/include/mcld/LD/ELFSegmentFactory.h
+++ b/include/mcld/LD/ELFSegmentFactory.h
@@ -31,12 +31,16 @@
/// 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);
+ ELFSegment* produce(uint32_t pType, uint32_t pFlag = llvm::ELF::PF_R);
- /// destroy - destruct the ELF segment
- void destroy(ELFSegment*& pSegment);
+ ELFSegment*
+ find(uint32_t pType, uint32_t pFlagSet, uint32_t pFlagClear);
+
+ const ELFSegment*
+ find(uint32_t pType, uint32_t pFlagSet, uint32_t pFlagClear) const;
};
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/ELFWriter.h b/include/mcld/LD/ELFWriter.h
index 51834d1..34a6483 100644
--- a/include/mcld/LD/ELFWriter.h
+++ b/include/mcld/LD/ELFWriter.h
@@ -71,6 +71,12 @@
void emitELF64SectionHeader(Output& pOutput, MCLinker& pLinker) const;
+ void emitELF32ProgramHeader(Output& pOutput,
+ const GNULDBackend& pBackend) const;
+
+ void emitELF64ProgramHeader(Output& pOutput,
+ const GNULDBackend& pBackend) const;
+
// emitShStrTab - emit .shstrtab
void emitELF32ShStrTab(Output& pOutput, MCLinker& pLinker) const;
@@ -119,3 +125,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/EhFrame.h b/include/mcld/LD/EhFrame.h
new file mode 100644
index 0000000..2e0d2c5
--- /dev/null
+++ b/include/mcld/LD/EhFrame.h
@@ -0,0 +1,140 @@
+//===- EhFrame.h ----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_EXCEPTION_HANDLING_FRAME_H
+#define MCLD_EXCEPTION_HANDLING_FRAME_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <vector>
+
+#include <mcld/ADT/TypeTraits.h>
+#include <mcld/LD/CIE.h>
+#include <mcld/LD/FDE.h>
+#include <mcld/MC/MCRegionFragment.h>
+#include <mcld/Support/GCFactory.h>
+
+namespace mcld
+{
+/** \class EhFrame
+ * \brief EhFrame represents .eh_frame section
+ * EhFrame is responsible to parse the input eh_frame sections and create
+ * the corresponding CIE and FDE entries.
+ */
+
+class TargetLDBackend;
+
+class EhFrame
+{
+public:
+ typedef ConstTraits<unsigned char>::pointer ConstAddress;
+ typedef std::vector<CIE*> CIEListType;
+ typedef std::vector<FDE*> FDEListType;
+ typedef CIEListType::iterator cie_iterator;
+ typedef CIEListType::const_iterator const_cie_iterator;
+ typedef FDEListType::iterator fde_iterator;
+ typedef FDEListType::const_iterator const_fde_iterator;
+
+public:
+ EhFrame();
+ ~EhFrame();
+
+ /// readEhFrame - read an .eh_frame section and create the corresponding
+ /// CIEs and FDEs
+ /// @param pSD - the MCSectionData of this input eh_frame
+ /// @param pSection - the input eh_frame
+ /// @param pArea - the memory area which pSection is within.
+ /// @ return - size of this eh_frame section, 0 if we do not recognize
+ /// this eh_frame or this is an empty section
+ uint64_t readEhFrame(Layout& pLayout,
+ const TargetLDBackend& pBackend,
+ llvm::MCSectionData& pSD,
+ LDSection& pSection,
+ MemoryArea& pArea);
+
+ // ----- observers ----- //
+ cie_iterator cie_begin()
+ { return m_CIEs.begin(); }
+
+ const_cie_iterator cie_begin() const
+ { return m_CIEs.begin(); }
+
+ cie_iterator cie_end()
+ { return m_CIEs.end(); }
+
+ const_cie_iterator cie_end() const
+ { return m_CIEs.end(); }
+
+ fde_iterator fde_begin()
+ { return m_FDEs.begin(); }
+
+ const_fde_iterator fde_begin() const
+ { return m_FDEs.begin(); }
+
+ fde_iterator fde_end()
+ { return m_FDEs.end(); }
+
+ const_fde_iterator fde_end() const
+ { return m_FDEs.end(); }
+
+ /// getFDECount - the number of FDE entries
+ size_t getFDECount()
+ { return m_FDEs.size(); }
+
+ size_t getFDECount() const
+ { return m_FDEs.size(); }
+
+ /// canRecognizeAllEhFrame - return if we are able to parse all input
+ /// eh_frame sections
+ /// @return false - if there is any input .eh_frame section that
+ /// we are not able to recognize
+ bool canRecognizeAllEhFrame()
+ { return m_fCanRecognizeAll; }
+
+ bool canRecognizeAllEhFrame() const
+ { return m_fCanRecognizeAll; }
+
+private:
+ typedef std::vector<llvm::MCFragment*> FragListType;
+
+private:
+ /// addCIE - parse and create a CIE entry
+ /// @return false - cannot recognize this CIE
+ bool addCIE(MemoryRegion& pFrag,
+ const TargetLDBackend& pBackend,
+ FragListType& pFragList);
+
+ /// addFDE - parse and create an FDE entry
+ /// @return false - cannot recognize this FDE
+ bool addFDE(MemoryRegion& pFrag,
+ const TargetLDBackend& pBackend,
+ FragListType& pFragList);
+
+ /// readVal - read a 32 bit data from pAddr, swap it if needed
+ uint32_t readVal(ConstAddress pAddr, bool pIsTargetLittleEndian);
+
+ /// skipLEB128 - skip the first LEB128 encoded value from *pp, update *pp
+ /// to the next character.
+ /// @return - false if we ran off the end of the string.
+ /// @ref - GNU gold 1.11, ehframe.h, Eh_frame::skip_leb128.
+ bool skipLEB128(ConstAddress* pp, ConstAddress pend);
+
+ /// deleteFragments - release the MemoryRegion and delete MCFragments in pList
+ void deleteFragments(FragListType& pList, MemoryArea& pArea);
+
+private:
+ CIEListType m_CIEs;
+ FDEListType m_FDEs;
+
+ bool m_fCanRecognizeAll;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/EhFrameHdr.h b/include/mcld/LD/EhFrameHdr.h
new file mode 100644
index 0000000..70f915c
--- /dev/null
+++ b/include/mcld/LD/EhFrameHdr.h
@@ -0,0 +1,99 @@
+//===- EhFrameHdr.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_EHFRAMEHDR_H
+#define MCLD_EHFRAMEHDR_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/Support/Dwarf.h>
+#include <llvm/Support/DataTypes.h>
+#include <mcld/ADT/SizeTraits.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/MC/MCLDOutput.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/LD/EhFrame.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/CIE.h>
+#include <mcld/LD/FDE.h>
+#include <mcld/LD/Layout.h>
+
+namespace mcld
+{
+class EhFrame;
+class LDSection;
+class Output;
+class FDE;
+class MCLinker;
+
+/** \class EhFrameHdr
+ * \brief EhFrameHdr represents .eh_frame_hdr section.
+ */
+class EhFrameHdr
+{
+public:
+ EhFrameHdr(const EhFrame& pEhFrameData,
+ const LDSection& pEhFrameSect,
+ LDSection& pEhFrameHdrSect);
+
+ ~EhFrameHdr();
+
+ /// sizeOutput - base on the fde count to size output
+ void sizeOutput();
+
+ /// emitOutput - write out eh_frame_hdr
+ template<size_t size>
+ void emitOutput(Output& pOutput, MCLinker& pLinker);
+
+private:
+ /// getFDEPC - return the address of FDE's pc
+ /// @param pFDE - FDE
+ /// @param pOffset - the output offset of FDE
+ template<size_t size>
+ typename SizeTraits<size>::Address
+ getFDEPC(const FDE& pFDE,
+ typename SizeTraits<size>::Offset pOffset,
+ const MemoryRegion& pEhFrameRegion);
+
+ template<size_t size>
+ class BSTEntry
+ {
+ public:
+ typedef std::pair<typename SizeTraits<size>::Address,
+ typename SizeTraits<size>::Address> EntryType;
+ };
+
+ template<size_t size>
+ struct BSTEntryCompare
+ : public std::binary_function<const typename BSTEntry<size>::EntryType&,
+ const typename BSTEntry<size>::EntryType&,
+ bool>
+ {
+ bool operator()(const typename BSTEntry<size>::EntryType& X,
+ const typename BSTEntry<size>::EntryType& Y) const
+ { return X.first < Y.first; }
+ };
+
+private:
+ /// eh_frame data
+ const EhFrame& m_EhFrameData;
+
+ /// .eh_frame section
+ const LDSection& m_EhFrameSect;
+
+ /// .eh_frame_hdr section
+ LDSection& m_EhFrameHdrSect;
+};
+
+#include "EhFrameHdr.tcc"
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/EhFrameHdr.tcc b/include/mcld/LD/EhFrameHdr.tcc
new file mode 100644
index 0000000..3b7d8ee
--- /dev/null
+++ b/include/mcld/LD/EhFrameHdr.tcc
@@ -0,0 +1,163 @@
+//===- EhFrameHdr.tcc -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <vector>
+
+using namespace mcld;
+using namespace llvm::dwarf;
+
+/// emitOutput - write out eh_frame_hdr
+template<size_t size>
+void EhFrameHdr::emitOutput(Output& pOutput, MCLinker& pLinker)
+{
+ MemoryRegion* ehframe_region =
+ pOutput.memArea()->request(m_EhFrameSect.offset(), m_EhFrameSect.size());
+
+ MemoryRegion* ehframehdr_region =
+ pOutput.memArea()->request(m_EhFrameHdrSect.offset(),
+ m_EhFrameHdrSect.size());
+
+ uint8_t* data = (uint8_t*)ehframehdr_region->start();
+ // version
+ data[0] = 1;
+ // eh_frame_ptr_enc
+ data[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
+
+ // eh_frame_ptr
+ uint32_t* eh_frame_ptr = (uint32_t*)(data + 4);
+ *eh_frame_ptr = m_EhFrameSect.addr() - (m_EhFrameHdrSect.addr() + 4);
+
+ // fde_count
+ uint32_t* fde_count = (uint32_t*)(data + 8);
+ *fde_count = m_EhFrameData.getFDECount();
+
+ if (m_EhFrameData.getFDECount() != 0 &&
+ m_EhFrameData.canRecognizeAllEhFrame()) {
+ // fde_count_enc
+ data[2] = DW_EH_PE_udata4;
+ // table_enc
+ data[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
+
+ // prepare the binary search table
+ typedef std::vector<typename BSTEntry<size>::EntryType> SearchTableType;
+ SearchTableType search_table;
+ EhFrame::const_fde_iterator fde = m_EhFrameData.fde_begin(),
+ fde_end = m_EhFrameData.fde_end();
+ for(; fde != fde_end; ++fde) {
+ assert(*fde != NULL);
+ typename SizeTraits<size>::Offset offset;
+ typename SizeTraits<size>::Address fde_pc;
+ typename SizeTraits<size>::Address fde_addr;
+ offset = pLinker.getLayout().getOutputOffset(**fde);
+ fde_pc = getFDEPC<size>(**fde, offset, *ehframe_region);
+ fde_addr = m_EhFrameSect.addr() + offset;
+ search_table.push_back(std::make_pair(fde_pc, fde_addr));
+ }
+
+ std::sort(search_table.begin(), search_table.end(), BSTEntryCompare<size>());
+
+ // write out the binary search table
+ uint32_t* bst = (uint32_t*)(data + 12);
+ typename SearchTableType::const_iterator entry = search_table.begin(),
+ entry_end = search_table.end();
+ for (size_t id = 0; entry != entry_end; ++entry) {
+ bst[id++] = (*entry).first - m_EhFrameHdrSect.addr();
+ bst[id++] = (*entry).second - m_EhFrameHdrSect.addr();
+ }
+ } else {
+ // fde_count_enc
+ data[2] = DW_EH_PE_omit;
+ // table_enc
+ data[3] = DW_EH_PE_omit;
+ }
+
+ pOutput.memArea()->release(ehframe_region);
+ pOutput.memArea()->release(ehframehdr_region);
+}
+
+/// getFDEPC - return the address of FDE's pc
+/// @ref binutils gold: ehframe.cc:222
+template<size_t size>
+typename SizeTraits<size>::Address
+EhFrameHdr::getFDEPC(const FDE& pFDE,
+ typename SizeTraits<size>::Offset pOffset,
+ const MemoryRegion& pEhFrameRegion)
+{
+ uint8_t fde_encoding = pFDE.getCIE().getFDEEncode();
+ unsigned int eh_value = fde_encoding & 0x7;
+
+ // check the size to read in
+ if (eh_value == llvm::dwarf::DW_EH_PE_absptr) {
+ if (size == 32)
+ eh_value = DW_EH_PE_udata4;
+ else if (size == 64)
+ eh_value = DW_EH_PE_udata8;
+ }
+
+ size_t pc_size = 0x0;
+ switch (eh_value) {
+ case DW_EH_PE_udata2:
+ pc_size = 2;
+ break;
+ case DW_EH_PE_udata4:
+ pc_size = 4;
+ break;
+ case DW_EH_PE_udata8:
+ pc_size = 8;
+ break;
+ default:
+ // TODO
+ break;
+ }
+
+ typename SizeTraits<size>::Address pc = 0x0;
+ const uint8_t* offset = (const uint8_t*) pEhFrameRegion.start() +
+ pOffset +
+ pFDE.getPCBeginOffset();
+ std::memcpy(&pc, offset, pc_size);
+
+ // adjust the signed value
+ bool is_signed = (fde_encoding & llvm::dwarf::DW_EH_PE_signed) != 0x0;
+ switch (eh_value) {
+ case DW_EH_PE_udata2:
+ if (is_signed)
+ pc = (pc ^ 0x8000) - 0x8000;
+ break;
+ case DW_EH_PE_udata4:
+ if (is_signed && size > 32)
+ pc = (pc ^ 0x80000000) - 0x80000000;
+ break;
+ case DW_EH_PE_udata8:
+ break;
+ default:
+ // TODO
+ break;
+ }
+
+ // handle eh application
+ switch (fde_encoding & 0x70)
+ {
+ case DW_EH_PE_absptr:
+ break;
+ case DW_EH_PE_pcrel:
+ pc += m_EhFrameSect.addr() +
+ pOffset +
+ pFDE.getPCBeginOffset();
+ break;
+ case DW_EH_PE_datarel:
+ // TODO
+ break;
+ default:
+ // TODO
+ break;
+ }
+
+ return pc;
+}
+
diff --git a/include/mcld/LD/ExecWriter.h b/include/mcld/LD/ExecWriter.h
new file mode 100644
index 0000000..edce096
--- /dev/null
+++ b/include/mcld/LD/ExecWriter.h
@@ -0,0 +1,41 @@
+//===- ExecWriter.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_EXECUTABLE_OBJECT_WRITER_H
+#define MCLD_EXECUTABLE_OBJECT_WRITER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/MC/MCLDOutput.h>
+#include <mcld/LD/LDWriter.h>
+#include <llvm/Support/system_error.h>
+
+namespace mcld
+{
+
+/** \class ExecWriter
+ * \brief ExecWriter provides an common interface for different object
+ * formats.
+ */
+class ExecWriter : public LDWriter
+{
+protected:
+ // force to have a TargetLDBackend
+ ExecWriter(TargetLDBackend& pLDBackend)
+ { }
+
+public:
+ virtual ~ExecWriter() { }
+
+ virtual llvm::error_code writeExecutable(Output& pOutput) = 0;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/FDE.h b/include/mcld/LD/FDE.h
new file mode 100644
index 0000000..bd52e78
--- /dev/null
+++ b/include/mcld/LD/FDE.h
@@ -0,0 +1,53 @@
+//===- FDE.h --------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_FRAME_DESCRIPTION_ENTRY_H
+#define MCLD_FRAME_DESCRIPTION_ENTRY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/DataTypes.h>
+#include <mcld/LD/CIE.h>
+#include <mcld/MC/MCRegionFragment.h>
+
+namespace mcld
+{
+
+/** \class FDE
+ * \brief Frame Description Entry
+ * The FDE structure refers to LSB Core Spec 4.1, chap.10.6. Exception Frames.
+ */
+
+class FDE : public MCRegionFragment
+{
+public:
+ typedef uint32_t Offset;
+
+public:
+ FDE(MemoryRegion& pRegion, const CIE& pCIE, Offset pPCBeginOffset);
+ ~FDE();
+
+ /// ----- observers ------ ///
+ /// getCIE - the CIE corresponding to this FDE
+ const CIE& getCIE() const
+ { return m_CIE; }
+
+ /// getPCBeginOffset - the offset to the FDE of the PC Begin field
+ Offset getPCBeginOffset() const
+ { return m_PCBeginOffset; }
+
+private:
+ const CIE& m_CIE;
+ Offset m_PCBeginOffset;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/GNUArchiveReader.h b/include/mcld/LD/GNUArchiveReader.h
index 8beac2c..92c7e7a 100644
--- a/include/mcld/LD/GNUArchiveReader.h
+++ b/include/mcld/LD/GNUArchiveReader.h
@@ -13,8 +13,6 @@
#endif
#include "mcld/LD/ArchiveReader.h"
-#include "mcld/Support/Path.h"
-#include <llvm/ADT/OwningPtr.h>
#include <vector>
#include <string>
@@ -27,6 +25,7 @@
namespace mcld
{
+class MemoryArea;
class MCLDInfo;
class Input;
class InputTree;
@@ -37,13 +36,24 @@
class GNUArchiveReader : public ArchiveReader
{
private:
- struct ArchiveMemberHeader;
struct SymbolTableEntry;
+ enum Constant
+ {
+ /// The length of the magic strign at the end of an archive member header.
+ HeaderFinalMagicSize = 2,
+ /// The length of the magic string at the start of an archive.
+ ArchiveMagicSize = 8
+ };
+ /// The magic string at the start of an archive.
+ static const char ArchiveMagic[ArchiveMagicSize];
+ static const char ThinArchiveMagic[ArchiveMagicSize];
+ /// The Magic string expected at the end of an archive member header.
+ static const char HeaderFinalMagic[HeaderFinalMagicSize];
+
public:
- explicit GNUArchiveReader(MCLDInfo &pLDInfo, LDReader::Endian endian)
- : m_pLDInfo(pLDInfo),
- m_endian(endian)
+ explicit GNUArchiveReader(MCLDInfo &pLDInfo)
+ : m_pLDInfo(pLDInfo)
{ }
~GNUArchiveReader()
@@ -63,23 +73,23 @@
/// second, read extended file name which is used in thin archive
InputTree *setupNewArchive(Input &pInput, size_t off);
- /// parse the archive header, and return the member size
- size_t parseMemberHeader(llvm::OwningPtr<llvm::MemoryBuffer> &mapFile,
+ /// read the archive header, and return the member size
+ size_t readMemberHeader(MemoryArea &pArea,
off_t off,
std::string *p_Name,
off_t *nestedOff,
std::string &p_ExtendedName);
- void readSymbolTable(llvm::OwningPtr<llvm::MemoryBuffer> &mapFile,
+ void readSymbolTable(MemoryArea &pArea,
std::vector<SymbolTableEntry> &pSymbolTable,
off_t start,
size_t size);
private:
MCLDInfo &m_pLDInfo;
- LDReader::Endian m_endian;
};
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/Group.h b/include/mcld/LD/Group.h
index c5ce827..31c4a68 100644
--- a/include/mcld/LD/Group.h
+++ b/include/mcld/LD/Group.h
@@ -25,3 +25,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/InputSymbolTable.h b/include/mcld/LD/InputSymbolTable.h
deleted file mode 100644
index c1614dd..0000000
--- a/include/mcld/LD/InputSymbolTable.h
+++ /dev/null
@@ -1,45 +0,0 @@
-//===- InputSymbolTable.h -------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef INPUTSYMBOLTABLE_H
-#define INPUTSYMBOLTABLE_H
-#include <llvm/ADT/StringRef.h>
-#include "mcld/LD/SymbolTableIF.h"
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-
-namespace mcld
-{
-
-class LDSymbol;
-
-/** \class InputSymbolTable
- * \brief Input symbol table, for MCLDInput.
- *
- * \see
- */
-class InputSymbolTable : public SymbolTableIF
-{
- /* draft. */
- friend class SymbolTableFactory;
-private:
- InputSymbolTable(StrSymPool &pStrSymPool,
- size_t pNumOfSymbols,
- StringTable &pEntireStringTable,
- StringTable &pDynamicStringTable);
-private:
- virtual void doInsertSymbol(LDSymbol *);
- virtual void doMerge(const SymbolTableIF &);
-public:
- virtual ~InputSymbolTable();
-};
-
-} // namespace of mcld
-
-#endif
diff --git a/include/mcld/LD/LDContext.h b/include/mcld/LD/LDContext.h
index a9cc978..878ba8d 100644
--- a/include/mcld/LD/LDContext.h
+++ b/include/mcld/LD/LDContext.h
@@ -102,3 +102,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/LDFileFormat.h b/include/mcld/LD/LDFileFormat.h
index 511471a..a537fb1 100644
--- a/include/mcld/LD/LDFileFormat.h
+++ b/include/mcld/LD/LDFileFormat.h
@@ -35,7 +35,9 @@
Relocation,
Debug,
Target,
- Exception,
+ EhFrame,
+ EhFrameHdr,
+ GCCExceptTable,
Version,
Note,
MetaData,
@@ -110,3 +112,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/LDReader.h b/include/mcld/LD/LDReader.h
index cb1e454..4fde9f0 100644
--- a/include/mcld/LD/LDReader.h
+++ b/include/mcld/LD/LDReader.h
@@ -44,3 +44,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/LDSection.h b/include/mcld/LD/LDSection.h
index 460c479..4c793de 100644
--- a/include/mcld/LD/LDSection.h
+++ b/include/mcld/LD/LDSection.h
@@ -202,3 +202,4 @@
} // end namespace mcld
#endif
+
diff --git a/include/mcld/LD/LDSectionFactory.h b/include/mcld/LD/LDSectionFactory.h
index 8495924..49b11c7 100644
--- a/include/mcld/LD/LDSectionFactory.h
+++ b/include/mcld/LD/LDSectionFactory.h
@@ -55,3 +55,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/LDSymbol.h b/include/mcld/LD/LDSymbol.h
index eabd05b..45c0b75 100644
--- a/include/mcld/LD/LDSymbol.h
+++ b/include/mcld/LD/LDSymbol.h
@@ -95,7 +95,7 @@
ResolveInfo* resolveInfo()
{ return m_pResolveInfo; }
- const ResolveInfo* resolveInfo() const
+ const ResolveInfo* resolveInfo() const
{ return m_pResolveInfo; }
bool hasFragRef() const
@@ -109,7 +109,7 @@
void setValue(ValueType pValue)
{ m_Value = pValue; }
-
+
void setFragmentRef(MCFragmentRef* pFragmentRef);
void setResolveInfo(const ResolveInfo& pInfo);
@@ -125,3 +125,4 @@
} // namespace mcld
#endif
+
diff --git a/include/mcld/LD/LDWriter.h b/include/mcld/LD/LDWriter.h
index 415c5c1..78c2871 100644
--- a/include/mcld/LD/LDWriter.h
+++ b/include/mcld/LD/LDWriter.h
@@ -38,3 +38,4 @@
} //end namespace
#endif
+
diff --git a/include/mcld/LD/Layout.h b/include/mcld/LD/Layout.h
index ea0d971..2b36126 100644
--- a/include/mcld/LD/Layout.h
+++ b/include/mcld/LD/Layout.h
@@ -18,6 +18,7 @@
#include <mcld/MC/MCFragmentRef.h>
#include <mcld/Support/GCFactory.h>
#include <mcld/LD/LDSection.h>
+#include <mcld/MC/MCLDInfo.h>
#include <map>
namespace mcld
@@ -112,7 +113,7 @@
const LDSection* getOutputLDSection(const llvm::MCFragment& pFrag) const;
// ----- modifiers ----- //
- bool layout(Output& pOutput, const TargetLDBackend& pBackend);
+ bool layout(Output& pOutput, const TargetLDBackend& pBackend, const MCLDInfo& pInfo);
/// addInputRange
void addInputRange(const llvm::MCSectionData& pSD,
@@ -252,7 +253,8 @@
/// sortSectionOrder - perform sorting on m_SectionOrder to get final layout
/// ordering
void sortSectionOrder(const Output& pOutput,
- const TargetLDBackend& pBackend);
+ const TargetLDBackend& pBackend,
+ const MCLDInfo& pInfo);
private:
/// a vector to describe the order of sections
@@ -267,3 +269,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/MsgHandler.h b/include/mcld/LD/MsgHandler.h
new file mode 100644
index 0000000..d10f8a2
--- /dev/null
+++ b/include/mcld/LD/MsgHandler.h
@@ -0,0 +1,128 @@
+//===- MsgHandler.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MESSAGE_HANDLER_H
+#define MCLD_MESSAGE_HANDLER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <string>
+#include <llvm/ADT/StringRef.h>
+#include <llvm/ADT/Twine.h>
+#include <mcld/Support/Path.h>
+#include <mcld/LD/DiagnosticEngine.h>
+
+namespace mcld
+{
+
+/** \class MsgHandler
+ * \brief MsgHandler controls the timing to output message.
+ */
+class MsgHandler
+{
+public:
+ MsgHandler(DiagnosticEngine& pEngine);
+ ~MsgHandler();
+
+ bool emit();
+
+ void addString(llvm::StringRef pStr) const;
+
+ void addString(const std::string& pStr) const;
+
+ void addTaggedVal(intptr_t pValue, DiagnosticEngine::ArgumentKind pKind) const;
+
+private:
+ void flushCounts()
+ { m_Engine.state().numArgs = m_NumArgs; }
+
+private:
+ DiagnosticEngine& m_Engine;
+ mutable unsigned int m_NumArgs;
+};
+
+inline const MsgHandler &
+operator<<(const MsgHandler& pHandler, llvm::StringRef pStr)
+{
+ pHandler.addString(pStr);
+ return pHandler;
+}
+
+inline const MsgHandler &
+operator<<(const MsgHandler& pHandler, const std::string& pStr)
+{
+ pHandler.addString(pStr);
+ return pHandler;
+}
+
+inline const MsgHandler &
+operator<<(const MsgHandler& pHandler, const sys::fs::Path& pPath)
+{
+ pHandler.addString(pPath.native());
+ return pHandler;
+}
+
+inline const MsgHandler &
+operator<<(const MsgHandler& pHandler, const char* pStr)
+{
+ pHandler.addTaggedVal(reinterpret_cast<intptr_t>(pStr),
+ DiagnosticEngine::ak_c_string);
+ return pHandler;
+}
+
+inline const MsgHandler &
+operator<<(const MsgHandler& pHandler, int pValue)
+{
+ pHandler.addTaggedVal(pValue, DiagnosticEngine::ak_sint);
+ return pHandler;
+}
+
+inline const MsgHandler &
+operator<<(const MsgHandler& pHandler, unsigned int pValue)
+{
+ pHandler.addTaggedVal(pValue, DiagnosticEngine::ak_uint);
+ return pHandler;
+}
+
+inline const MsgHandler &
+operator<<(const MsgHandler& pHandler, long pValue)
+{
+ pHandler.addTaggedVal(pValue, DiagnosticEngine::ak_sint);
+ return pHandler;
+}
+
+inline const MsgHandler &
+operator<<(const MsgHandler& pHandler, unsigned long pValue)
+{
+ pHandler.addTaggedVal(pValue, DiagnosticEngine::ak_uint);
+ return pHandler;
+}
+
+inline const MsgHandler &
+operator<<(const MsgHandler& pHandler, bool pValue)
+{
+ pHandler.addTaggedVal(pValue, DiagnosticEngine::ak_bool);
+ return pHandler;
+}
+
+//===----------------------------------------------------------------------===//
+// Inline member functions
+inline MsgHandler
+DiagnosticEngine::report(uint16_t pID, DiagnosticEngine::Severity pSeverity)
+{
+ m_State.ID = pID;
+ m_State.severity = pSeverity;
+
+ MsgHandler result(*this);
+ return result;
+}
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/StrSymPool.h b/include/mcld/LD/NamePool.h
similarity index 89%
rename from include/mcld/LD/StrSymPool.h
rename to include/mcld/LD/NamePool.h
index 0550a4c..79d55b9 100644
--- a/include/mcld/LD/StrSymPool.h
+++ b/include/mcld/LD/NamePool.h
@@ -1,4 +1,4 @@
-//===- StrSymPool.h -------------------------------------------------------===//
+//===- NamePool.h ---------------------------------------------------------===//
//
// The MCLinker Project
//
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_STRING_SYMBOL_POOL_H
-#define MCLD_STRING_SYMBOL_POOL_H
+#ifndef MCLD_NAME_POOL_H
+#define MCLD_NAME_POOL_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -33,20 +33,20 @@
class StringTable;
class SymbolTableIF;
-/** \class StrSymPool
+/** \class NamePool
* \brief Store symbol and search symbol by name. Can help symbol resolution.
*
- * - MCLinker is responsed for creating StrSymPool.
+ * - MCLinker is responsed for creating NamePool.
*/
-class StrSymPool : private Uncopyable
+class NamePool : private Uncopyable
{
public:
typedef HashTable<ResolveInfo, StringHash<ELF>, ResolveInfoFactory> Table;
typedef size_t size_type;
public:
- StrSymPool(const Resolver& pResolver, size_type pSize = 3);
- ~StrSymPool();
+ NamePool(const Resolver& pResolver, size_type pSize = 3);
+ ~NamePool();
// ----- modifiers ----- //
/// createSymbol - create a symbol but do not insert into the pool.
@@ -57,7 +57,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.
@@ -100,7 +100,7 @@
size_type capacity() const;
private:
- Resolver* m_pResolver;
+ const Resolver* m_pResolver;
Table m_Table;
};
@@ -108,3 +108,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/ObjectReader.h b/include/mcld/LD/ObjectReader.h
index bd49d5e..9dbe9ac 100644
--- a/include/mcld/LD/ObjectReader.h
+++ b/include/mcld/LD/ObjectReader.h
@@ -66,3 +66,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/ObjectWriter.h b/include/mcld/LD/ObjectWriter.h
index d10bfdc..0c48723 100644
--- a/include/mcld/LD/ObjectWriter.h
+++ b/include/mcld/LD/ObjectWriter.h
@@ -36,3 +36,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/OutputSymbolTable.h b/include/mcld/LD/OutputSymbolTable.h
deleted file mode 100644
index 1494ab7..0000000
--- a/include/mcld/LD/OutputSymbolTable.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//===- OutputSymbolTable.h ------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef OUTPUTSYMBOLTABLE_H
-#define OUTPUTSYMBOLTABLE_H
-#include <llvm/ADT/StringRef.h>
-#include "mcld/LD/SymbolTableIF.h"
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-
-namespace mcld
-{
-
-class LDSymbol;
-
-/** \class OutputSymbolTable
- * \brief Output symbol table, for MCLDOutput.
- *
- * \see
- */
-class OutputSymbolTable : public SymbolTableIF
-{
- /* draft. */
- friend class SymbolTableFactory;
-private:
- OutputSymbolTable(StrSymPool &pStrSymPool,
- size_t pNumOfSymbols,
- StringTable &pEntireStringTable,
- StringTable &pDynamicStringTable);
-private:
- virtual void doInsertSymbol(LDSymbol *);
- virtual void doMerge(const SymbolTableIF &);
-};
-
-} // namespace of mcld
-
-#endif
diff --git a/include/mcld/LD/Relocation.h b/include/mcld/LD/Relocation.h
index 9f7a117..09ff6e4 100644
--- a/include/mcld/LD/Relocation.h
+++ b/include/mcld/LD/Relocation.h
@@ -112,3 +112,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/RelocationFactory.h b/include/mcld/LD/RelocationFactory.h
index 357c2d3..eed3eae 100644
--- a/include/mcld/LD/RelocationFactory.h
+++ b/include/mcld/LD/RelocationFactory.h
@@ -78,3 +78,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/ResolveInfo.h b/include/mcld/LD/ResolveInfo.h
index 70e4f27..7b3cb27 100644
--- a/include/mcld/LD/ResolveInfo.h
+++ b/include/mcld/LD/ResolveInfo.h
@@ -55,7 +55,8 @@
Section = 3,
File = 4,
CommonBlock = 5,
- ThreadLocal = 6,
+ ThreadLocal = 6,
+ IndirectFunc = 10,
LoProc = 13,
HiProc = 15
};
@@ -276,3 +277,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/ResolveInfoFactory.h b/include/mcld/LD/ResolveInfoFactory.h
index 13a26b6..fcadf48 100644
--- a/include/mcld/LD/ResolveInfoFactory.h
+++ b/include/mcld/LD/ResolveInfoFactory.h
@@ -34,3 +34,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/Resolver.h b/include/mcld/LD/Resolver.h
index 8596eeb..d506a2d 100644
--- a/include/mcld/LD/Resolver.h
+++ b/include/mcld/LD/Resolver.h
@@ -18,7 +18,7 @@
{
class ResolveInfo;
-class StrSymPool;
+class NamePool;
/** \class Resolver
* \brief Resolver binds a symbol reference from one file to a symbol
@@ -51,49 +51,32 @@
};
public:
- Resolver();
-
- Resolver(const Resolver& pCopy);
-
virtual ~Resolver();
/// shouldOverride - Can resolver override the symbol pOld by the symbol pNew?
/// @return the action should be taken.
/// @param pOld the symbol which may be overridden.
/// @param pNew the symbol which is used to replace pOld
- virtual unsigned int resolve(ResolveInfo & __restrict__ pOld,
- const ResolveInfo & __restrict__ pNew,
- bool &pOverride) = 0;
+ virtual bool resolve(ResolveInfo & __restrict__ pOld,
+ const ResolveInfo & __restrict__ pNew,
+ bool &pOverride) const = 0;
/// resolveAgain - Can override by derived classes.
/// @return the pointer to resolved ResolveInfo
/// @return is the symbol existent?
- virtual void resolveAgain(StrSymPool& pStrSymPool,
+ virtual void resolveAgain(NamePool& pNamePool,
unsigned int pAction,
ResolveInfo& __restrict__ pOld,
const ResolveInfo& __restrict__ pNew,
- Result& pResult) {
+ Result& pResult) const {
pResult.info = NULL;
pResult.existent = false;
pResult.overriden = false;
}
- const std::string& mesg() const
- { return m_Mesg; }
-
- void clearMesg();
-
- Resolver* clone() const {
- return doClone();
- }
-
-protected:
- std::string m_Mesg;
-
-private:
- virtual Resolver* doClone() const = 0;
};
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/SectionMap.h b/include/mcld/LD/SectionMap.h
index 77e7e21..06ae02e 100644
--- a/include/mcld/LD/SectionMap.h
+++ b/include/mcld/LD/SectionMap.h
@@ -31,7 +31,6 @@
struct Mapping {
std::string inputSubStr;
std::string outputStr;
- uint64_t offset;
};
typedef std::vector<struct Mapping> SectionMappingTy;
@@ -49,8 +48,7 @@
// add a mapping from input substr to output name and offset.
bool push_back(const std::string& pInput,
- const std::string& pOutput,
- const uint64_t pOffset = 0);
+ const std::string& pOutput);
// find - return the iterator to the mapping
iterator find(const std::string& pInput);
@@ -102,3 +100,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/SectionMerger.h b/include/mcld/LD/SectionMerger.h
index a1c2a10..40f1453 100644
--- a/include/mcld/LD/SectionMerger.h
+++ b/include/mcld/LD/SectionMerger.h
@@ -95,3 +95,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/StaticResolver.h b/include/mcld/LD/StaticResolver.h
index 6275c59..9fc6104 100644
--- a/include/mcld/LD/StaticResolver.h
+++ b/include/mcld/LD/StaticResolver.h
@@ -18,7 +18,7 @@
namespace mcld
{
-class StrSymPool;
+class NamePool;
/** \class StaticResolver
*/
@@ -75,7 +75,7 @@
w_D = ResolveInfo::weak_flag | ResolveInfo::regular_flag | ResolveInfo::define_flag,
d_D = ResolveInfo::global_flag | ResolveInfo::dynamic_flag | ResolveInfo::define_flag,
wd_D = ResolveInfo::weak_flag | ResolveInfo::dynamic_flag | ResolveInfo::define_flag,
- C = ResolveInfo::global_flag | ResolveInfo::regular_flag | ResolveInfo::common_flag,
+ C = ResolveInfo::global_flag | ResolveInfo::regular_flag | ResolveInfo::common_flag,
w_C = ResolveInfo::weak_flag | ResolveInfo::regular_flag | ResolveInfo::common_flag,
d_C = ResolveInfo::global_flag | ResolveInfo::dynamic_flag | ResolveInfo::common_flag,
wd_C = ResolveInfo::weak_flag | ResolveInfo::dynamic_flag | ResolveInfo::common_flag,
@@ -103,23 +103,15 @@
};
public:
- StaticResolver();
-
- StaticResolver(const StaticResolver& pCopy);
-
virtual ~StaticResolver();
/// shouldOverride - Can resolver override the symbol pOld by the symbol pNew?
- /// @return the action should be taken.
+ /// @return successfully resolved, return true; otherwise, return false.
/// @param pOld the symbol which may be overridden.
/// @param pNew the symbol which is used to replace pOld
- virtual unsigned int resolve(ResolveInfo & __restrict__ pOld,
- const ResolveInfo & __restrict__ pNew,
- bool &pOverride);
-
- StaticResolver* doClone() const {
- return new StaticResolver(*this);
- }
+ virtual bool resolve(ResolveInfo & __restrict__ pOld,
+ const ResolveInfo & __restrict__ pNew,
+ bool &pOverride) const;
private:
inline unsigned int getOrdinate(const ResolveInfo& pInfo) const {
@@ -142,3 +134,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/StringUnorderedMap.h b/include/mcld/LD/StringUnorderedMap.h
index 7453c9f..05788aa 100644
--- a/include/mcld/LD/StringUnorderedMap.h
+++ b/include/mcld/LD/StringUnorderedMap.h
@@ -222,3 +222,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/LD/SymbolTableFactory.h b/include/mcld/LD/SymbolTableFactory.h
deleted file mode 100644
index 6196603..0000000
--- a/include/mcld/LD/SymbolTableFactory.h
+++ /dev/null
@@ -1,72 +0,0 @@
-//===- SymbolTableFactory.h -----------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_SYMBOL_TABLE_FACTORY_H
-#define MCLD_SYMBOL_TABLE_FACTORY_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-#include "mcld/LD/InputSymbolTable.h"
-#include "mcld/LD/OutputSymbolTable.h"
-
-namespace mcld
-{
-
-class StringTable;
-class StrSymPool;
-
-/** \class SymbolTableFactory
- * \brief SymbolTableFactory manages SymbolTableIFs.
- *
- * SymbolTableFactory is responsed for construction and destruction of
- * SymbolTableIF. Since different MCLDFiles have different type of
- * SymbolTableIF, SymbolTableFactory separates the construction of
- * SymbolTableIF into createInputTable() and createOutputTable().
- *
- * @see SymbolTableIF InputSymbolTable OutputSymbolTable
- */
-class SymbolTableFactory
-{
-public:
- /// SymbolTableFactory - constructor
- // @param pNumOfSymbolTables is the most appropriate number of created
- // symbol tables.
- // @param pStorage the real storage of created symbols
- explicit SymbolTableFactory(size_t pNumOfSymbolTables,
- StrSymPool& pStrSymPool);
- /// ~SymbolTableFactory - destructor
- // destructor destroys all created symbol tables.
- ~SymbolTableFactory();
-
- /// createInputTable - create a symbol table for an input file
- // @param pEntireStringTable the string table of created Symbols.
- // @param pDynamicStringTable the string table of created Dynamic Symbols.
- // @param pReserve Created symbol table must reserve pReserve number of
- // storages of symbol for creating symbols.
- SymbolTableIF *createInputTable(StringTable &pEntireStringTable,
- StringTable &pDynamicStringTable,
- size_t pReserve=256);
-
- /// createOutputTable - create a symbol table for an output file
- // @param pEntireStringTable the string table of created Symbols.
- // @param pDynamicStringTable the string table of created Dynamic Symbols.
- // @param pReserve Created symbol table must reserve pReserve number of
- // storages of symbol for creating symbols.
- SymbolTableIF *createOutputTable(StringTable &pEntireStringTable,
- StringTable &pDynamicStringTable,
- size_t pReserve=256);
-private:
- StrSymPool &m_StrSymPool;
- GCFactory<InputSymbolTable, 0> m_InputFactory;
- GCFactory<OutputSymbolTable, 0> m_OutputFactory;
-
-};
-
-} // namespace of mcld
-
-#endif
diff --git a/include/mcld/LD/TextDiagnosticPrinter.h b/include/mcld/LD/TextDiagnosticPrinter.h
new file mode 100644
index 0000000..278c00f
--- /dev/null
+++ b/include/mcld/LD/TextDiagnosticPrinter.h
@@ -0,0 +1,50 @@
+//===- TextDiagnosticPrinter.h --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TEXT_DIAGNOSTIC_PRINTER_H
+#define MCLD_TEXT_DIAGNOSTIC_PRINTER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/LD/DiagnosticPrinter.h>
+#include <llvm/Support/raw_ostream.h>
+
+namespace mcld
+{
+
+class MCLDInfo;
+
+/** \class TextDiagnosticPrinter
+ * \brief The plain, text-based DiagnosticPrinter.
+ */
+class TextDiagnosticPrinter : public DiagnosticPrinter
+{
+public:
+ TextDiagnosticPrinter(llvm::raw_ostream& pOStream, const MCLDInfo& pLDInfo);
+
+ virtual ~TextDiagnosticPrinter();
+
+ /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
+ /// capturing it to a log as needed.
+ virtual void handleDiagnostic(DiagnosticEngine::Severity pSeverity,
+ const Diagnostic& pInfo);
+
+ virtual void beginInput(const Input& pInput, const MCLDInfo& pLDInfo);
+
+ virtual void endInput();
+
+private:
+ llvm::raw_ostream& m_OStream;
+ const MCLDInfo& m_LDInfo;
+ const Input* m_pInput;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/AttributeFactory.h b/include/mcld/MC/AttributeFactory.h
index eb4368b..0af1328 100644
--- a/include/mcld/MC/AttributeFactory.h
+++ b/include/mcld/MC/AttributeFactory.h
@@ -11,8 +11,8 @@
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
-#include "mcld/ADT/Uncopyable.h"
-#include "mcld/MC/MCLDAttribute.h"
+#include <mcld/ADT/Uncopyable.h>
+#include <mcld/MC/MCLDAttribute.h>
namespace mcld
{
diff --git a/include/mcld/MC/ContextFactory.h b/include/mcld/MC/ContextFactory.h
index 1ae0d45..dde2627 100644
--- a/include/mcld/MC/ContextFactory.h
+++ b/include/mcld/MC/ContextFactory.h
@@ -38,6 +38,7 @@
explicit ContextFactory(size_t pNum);
~ContextFactory();
+ LDContext* produce();
LDContext* produce(const sys::fs::Path& pPath);
};
diff --git a/include/mcld/MC/MCLDInputTree.h b/include/mcld/MC/InputTree.h
similarity index 76%
rename from include/mcld/MC/MCLDInputTree.h
rename to include/mcld/MC/InputTree.h
index 7d8050c..fa6ba8f 100644
--- a/include/mcld/MC/MCLDInputTree.h
+++ b/include/mcld/MC/InputTree.h
@@ -1,4 +1,4 @@
-//===- MCLDInputTree.h ----------------------------------------------------===//
+//===- InputTree.h --------------------------------------------------------===//
//
// The MCLinker Project
//
@@ -90,13 +90,23 @@
typedef BinaryTree<Input>::const_iterator const_iterator;
public:
- struct Connector {
- virtual ~Connector() {}
+ /** \class Mover
+ * \brief Mover provides the interface for moving iterator forward.
+ *
+ * Mover is a function object (functor). @ref Mover::move moves
+ * iterator forward in certain direction. @ref Mover::connect
+ * connects two nodes of the given iterators togather.
+ */
+ struct Mover {
+ virtual ~Mover() {}
virtual void connect(iterator& pFrom, const const_iterator& pTo) const = 0;
virtual void move(iterator& pNode) const = 0;
};
- struct Succeeder : public Connector {
+ /** \class Succeeder
+ * \brief class Succeeder moves the iterator afterward.
+ */
+ struct Succeeder : public Mover {
virtual void connect(iterator& pFrom, const const_iterator& pTo) const {
proxy::hook<Positional>(pFrom.m_pNode, pTo.m_pNode);
}
@@ -106,7 +116,10 @@
}
};
- struct Includer : public Connector {
+ /** \class Includer
+ * \brief class Includer moves the iterator downward.
+ */
+ struct Includer : public Mover {
virtual void connect(iterator& pFrom, const const_iterator& pTo) const {
proxy::hook<Inclusive>(pFrom.m_pNode, pTo.m_pNode);
}
@@ -130,38 +143,37 @@
// ----- modify ----- //
/// insert - create a leaf node and merge it in the tree.
// This version of join determines the direction at run time.
- // @param position the parent node
- // @param value the value being pushed.
- // @param pConnector the direction of the connecting edge of the parent node.
+ // @param pRoot position the parent node
+ // @param pMover the direction of the connecting edge of the parent node.
template<size_t DIRECT>
- InputTree& insert(iterator pPosition,
+ InputTree& insert(iterator pRoot,
const std::string& pNamespec,
const sys::fs::Path& pPath,
unsigned int pType = Input::Unknown);
template<size_t DIRECT>
- InputTree& enterGroup(iterator pPosition);
+ InputTree& enterGroup(iterator pRoot);
template<size_t DIRECT>
- InputTree& insert(iterator pPosition,
+ InputTree& insert(iterator pRoot,
const Input& pInput);
- InputTree& merge(iterator pPosition,
- const Connector& pConnector,
+ InputTree& merge(iterator pRoot,
+ const Mover& pMover,
InputTree& pTree);
- InputTree& insert(iterator pPosition,
- const Connector& pConnector,
+ InputTree& insert(iterator pRoot,
+ const Mover& pMover,
const std::string& pNamespec,
const sys::fs::Path& pPath,
unsigned int pType = Input::Unknown);
- InputTree& insert(iterator pPosition,
- const Connector& pConnector,
+ InputTree& insert(iterator pRoot,
+ const Mover& pMover,
const Input& pInput);
- InputTree& enterGroup(iterator pPosition,
- const Connector& pConnector);
+ InputTree& enterGroup(iterator pRoot,
+ const Mover& pMover);
// ----- observers ----- //
unsigned int numOfInputs() const
@@ -188,47 +200,47 @@
// template member functions
template<size_t DIRECT>
mcld::InputTree&
-mcld::InputTree::insert(mcld::InputTree::iterator pPosition,
+mcld::InputTree::insert(mcld::InputTree::iterator pRoot,
const std::string& pNamespec,
const mcld::sys::fs::Path& pPath,
unsigned int pType)
{
BinTreeTy::node_type* node = createNode();
node->data = m_FileFactory.produce(pNamespec, pPath, pType);
- if (pPosition.isRoot())
- proxy::hook<TreeIteratorBase::Leftward>(pPosition.m_pNode,
+ if (pRoot.isRoot())
+ proxy::hook<TreeIteratorBase::Leftward>(pRoot.m_pNode,
const_cast<const node_type*>(node));
else
- proxy::hook<DIRECT>(pPosition.m_pNode,
+ proxy::hook<DIRECT>(pRoot.m_pNode,
const_cast<const node_type*>(node));
return *this;
}
template<size_t DIRECT>
mcld::InputTree&
-mcld::InputTree::enterGroup(mcld::InputTree::iterator pPosition)
+mcld::InputTree::enterGroup(mcld::InputTree::iterator pRoot)
{
BinTreeTy::node_type* node = createNode();
- if (pPosition.isRoot())
- proxy::hook<TreeIteratorBase::Leftward>(pPosition.m_pNode,
+ if (pRoot.isRoot())
+ proxy::hook<TreeIteratorBase::Leftward>(pRoot.m_pNode,
const_cast<const node_type*>(node));
else
- proxy::hook<DIRECT>(pPosition.m_pNode,
+ proxy::hook<DIRECT>(pRoot.m_pNode,
const_cast<const node_type*>(node));
return *this;
}
template<size_t DIRECT>
-mcld::InputTree& mcld::InputTree::insert(mcld::InputTree::iterator pPosition,
+mcld::InputTree& mcld::InputTree::insert(mcld::InputTree::iterator pRoot,
const mcld::Input& pInput)
{
BinTreeTy::node_type* node = createNode();
node->data = const_cast<mcld::Input*>(&pInput);
- if (pPosition.isRoot())
- proxy::hook<TreeIteratorBase::Leftward>(pPosition.m_pNode,
+ if (pRoot.isRoot())
+ proxy::hook<TreeIteratorBase::Leftward>(pRoot.m_pNode,
const_cast<const node_type*>(node));
else
- proxy::hook<DIRECT>(pPosition.m_pNode,
+ proxy::hook<DIRECT>(pRoot.m_pNode,
const_cast<const node_type*>(node));
return *this;
}
diff --git a/include/mcld/MC/MCDataFragment.h b/include/mcld/MC/MCDataFragment.h
index 330c9be..63ae497 100644
--- a/include/mcld/MC/MCDataFragment.h
+++ b/include/mcld/MC/MCDataFragment.h
@@ -21,9 +21,6 @@
/** \class MCDataFragment
* \brief MCDataFragment for mcld
- *
- * \see
- * \author Diana Chen <diana.chen@mediatek.com>
*/
class MCDataFragment : public llvm::MCFragment
{
@@ -33,7 +30,7 @@
/// m_pFragment - llvm MCDataFragment for this MCDataFragment
llvm::MCDataFragment* m_pFragment;
-
+
/// m_Relocation - The list of relocations in this fragment
RelocationsType m_Relocations;
@@ -49,14 +46,14 @@
setLayoutOrder( pFragment.getLayoutOrder());
}
~MCDataFragment(){}
-
+
// ------ observers ------//
llvm::SmallString<32> &getContents() { return m_pFragment->getContents(); }
const llvm::SmallString<32> &getContents() const { return m_pFragment->getContents(); }
// relocation access
void addRelocation(Relocation &pReloc){ m_Relocations.push_back(&pReloc); }
-
+
RelocationsType &getRelocations() { return m_Relocations; }
const RelocationsType &getRelcoations() const { return m_Relocations; }
@@ -73,10 +70,10 @@
return pF->getKind() == llvm::MCFragment::FT_Data;
}
static bool classof(const MCDataFragment *) { return true; }
-
+
// overwrite parent method
- FragmentType getKind() const { return m_pFragment->getKind(); }
-
+ FragmentType getKind() const { return m_pFragment->getKind(); }
+
};
} // namespace of mcld
diff --git a/include/mcld/MC/MCInstFragment.h b/include/mcld/MC/MCInstFragment.h
index 8625c42..6dbbc85 100644
--- a/include/mcld/MC/MCInstFragment.h
+++ b/include/mcld/MC/MCInstFragment.h
@@ -23,9 +23,6 @@
/** \class MCInstFragment
* \brief MCInstFragment for mcld
- *
- * \see
- * \author Diana Chen <diana.chen@mediatek.com>
*/
class MCInstFragment : public llvm::MCFragment
{
@@ -35,10 +32,10 @@
/// m_pFragment - llvm MCInstFragment for this MCInstFragment
llvm::MCInstFragment* m_pFragment;
-
+
/// m_Relocation - The list of relocations in this fragment
RelocationsType m_Relocations;
-
+
public:
typedef RelocationsType::const_iterator const_relocation_iterator;
typedef RelocationsType::iterator relocation_iterator;
@@ -51,7 +48,7 @@
setLayoutOrder( pFragment.getLayoutOrder());
}
~MCInstFragment(){}
-
+
// ------ observers ------//
llvm::SmallVectorImpl<char> &getCode() { return m_pFragment->getCode(); }
const llvm::SmallVectorImpl<char> &getCode() const { return m_pFragment->getCode(); }
@@ -60,13 +57,13 @@
llvm::MCInst &getInst() { return m_pFragment->getInst(); }
const llvm::MCInst &getInst() const { return m_pFragment->getInst(); }
-
+
// ----- modifiers ------//
void setInst(llvm::MCInst pValue) { m_pFragment->setInst(pValue); }
// relocation access
void addRelocation(Relocation &pReloc){ m_Relocations.push_back(&pReloc); }
-
+
RelocationsType &getRelocations() { return m_Relocations; }
const RelocationsType &getRelcoations() const { return m_Relocations; }
@@ -83,9 +80,9 @@
return pF->getKind() == llvm::MCFragment::FT_Inst;
}
static bool classof(const MCInstFragment *) { return true; }
-
+
// overwrite parent method
- FragmentType getKind() const { return m_pFragment->getKind(); }
+ FragmentType getKind() const { return m_pFragment->getKind(); }
};
diff --git a/include/mcld/MC/MCLDAttribute.h b/include/mcld/MC/MCLDAttribute.h
index 829cf61..f7f9f97 100644
--- a/include/mcld/MC/MCLDAttribute.h
+++ b/include/mcld/MC/MCLDAttribute.h
@@ -161,7 +161,7 @@
bool isStaticSystem() const
{ return m_Static; }
- bool isLegal(const Attribute& pAttr, std::string& pErrMesg) const;
+ bool isLegal(const Attribute& pAttr) const;
};
/** \class AttributeProxy
diff --git a/include/mcld/MC/MCLDDriver.h b/include/mcld/MC/MCLDDriver.h
index b4a7288..ec8acf5 100644
--- a/include/mcld/MC/MCLDDriver.h
+++ b/include/mcld/MC/MCLDDriver.h
@@ -19,12 +19,14 @@
#endif
#include <mcld/LD/SectionMap.h>
+
namespace mcld
{
class MCLinker;
class MCLDInfo;
class TargetLDBackend;
+class MemoryAreaFactory;
//===----------------------------------------------------------------------===//
/// MCLDDriver - MCLDDriver prepares parameters for MCLinker.
@@ -35,6 +37,13 @@
MCLDDriver(MCLDInfo& pLDInfo, TargetLDBackend& pLDBackend);
~MCLDDriver();
+ /// initMCLinker - initialize MCLinker
+ /// Connect all components in MCLinker
+ bool initMCLinker();
+
+ /// initStdSections - initialize standard sections of the output file.
+ bool initStdSections();
+
/// normalize - normalize the input files
void normalize();
@@ -44,10 +53,6 @@
/// - check every Input has a correct Attribute
bool linkable() const;
- /// initMCLinker - initialize MCLinker
- /// Connect all components in MCLinker
- bool initMCLinker();
-
/// readSections - read all input section headers
bool readSections();
@@ -95,7 +100,7 @@
/// Create relocation section, asking TargetLDBackend to
/// read the relocation information into RelocationEntry
/// and push_back into the relocation section
- bool relocate();
+ bool relocation();
/// finalizeSymbolValue - finalize the symbol value
bool finalizeSymbolValue();
@@ -106,6 +111,18 @@
/// postProcessing - do modificatiion after all processes
bool postProcessing();
+ /// getLinker - get internal MCLinker object
+ MCLinker* getLinker()
+ { return m_pLinker; }
+
+ /// getLinker - get internal MCLinker object
+ const MCLinker* getLinker() const
+ { return m_pLinker; }
+
+ /// hasInitLinker - has Linker been initialized?
+ bool hasInitLinker() const
+ { return (NULL != m_pLinker); }
+
private:
MCLDInfo& m_LDInfo;
TargetLDBackend &m_LDBackend;
diff --git a/include/mcld/MC/MCLDFile.h b/include/mcld/MC/MCLDFile.h
index 30cac7e..f77fe82 100644
--- a/include/mcld/MC/MCLDFile.h
+++ b/include/mcld/MC/MCLDFile.h
@@ -50,7 +50,8 @@
DynObj,
CoreFile,
Script,
- Archive
+ Archive,
+ External
};
public:
diff --git a/include/mcld/MC/MCLDInfo.h b/include/mcld/MC/MCLDInfo.h
index 15e70ff..d76fff4 100644
--- a/include/mcld/MC/MCLDInfo.h
+++ b/include/mcld/MC/MCLDInfo.h
@@ -15,23 +15,24 @@
#include <llvm/ADT/Triple.h>
#include <mcld/Support/FileSystem.h>
-#include <mcld/Support/MemoryAreaFactory.h>
#include <mcld/MC/MCLDOutput.h>
#include <mcld/MC/MCLDOptions.h>
-#include <mcld/MC/MCLDInputTree.h>
+#include <mcld/MC/InputTree.h>
#include <mcld/MC/AttributeFactory.h>
#include <mcld/MC/ContextFactory.h>
-#include <mcld/LD/StrSymPool.h>
+#include <mcld/LD/NamePool.h>
#include <string>
#include <cassert>
namespace mcld
{
+class Resolver;
/** \class MCLDInfo
* \brief MCLDInfo is composed of argumments of MCLinker.
- * options() - the general options.
+ * options() - the general options
+ * scripts() - the script options
* inputs() - the tree of inputs
* bitcode() - the bitcode being linked
* output() - the output file
@@ -55,6 +56,12 @@
const GeneralOptions& options() const
{ return m_Options; }
+ ScriptOptions& scripts()
+ { return m_Scripts; }
+
+ const ScriptOptions& scripts() const
+ { return m_Scripts; }
+
void setBitcode(const Input& pInput);
Input& bitcode();
const Input& bitcode() const;
@@ -90,33 +97,25 @@
const ContextFactory& contextFactory() const
{ return *m_pCntxtFactory; }
- MemoryAreaFactory& memAreaFactory()
- { return *m_pMemAreaFactory; }
-
- const MemoryAreaFactory& memAreaFactory() const
- { return *m_pMemAreaFactory; }
-
const llvm::Triple& triple() const
{ return m_Triple; }
static const char* version();
- void setNamePool(StrSymPool& pPool)
- { m_pStrSymPool = &pPool; }
-
- StrSymPool& getStrSymPool() {
- assert(NULL != m_pStrSymPool);
- return *m_pStrSymPool;
+ NamePool& getNamePool() {
+ assert(NULL != m_pNamePool);
+ return *m_pNamePool;
}
- const StrSymPool& getStrSymPool() const {
- assert(NULL != m_pStrSymPool);
- return *m_pStrSymPool;
+ const NamePool& getNamePool() const {
+ assert(NULL != m_pNamePool);
+ return *m_pNamePool;
}
private:
// ----- General Options ----- //
GeneralOptions m_Options;
+ ScriptOptions m_Scripts;
InputTree *m_pInputTree;
Input* m_pBitcode;
Output* m_pOutput;
@@ -126,10 +125,10 @@
InputFactory *m_pInputFactory;
AttributeFactory *m_pAttrFactory;
ContextFactory *m_pCntxtFactory;
- MemoryAreaFactory *m_pMemAreaFactory;
// ----- string and symbols ----- //
- StrSymPool* m_pStrSymPool;
+ Resolver* m_pResolver;
+ NamePool* m_pNamePool;
};
} // namespace of mcld
diff --git a/include/mcld/MC/MCLDInput.h b/include/mcld/MC/MCLDInput.h
index 097b8f6..2f1198c 100644
--- a/include/mcld/MC/MCLDInput.h
+++ b/include/mcld/MC/MCLDInput.h
@@ -40,7 +40,8 @@
Object = MCLDFile::Object,
DynObj = MCLDFile::DynObj,
Archive = MCLDFile::Archive,
- Script = MCLDFile::Script
+ Script = MCLDFile::Script,
+ External = MCLDFile::External
};
private:
diff --git a/include/mcld/MC/MCLDOptions.h b/include/mcld/MC/MCLDOptions.h
index 06097aa..ad857cb 100644
--- a/include/mcld/MC/MCLDOptions.h
+++ b/include/mcld/MC/MCLDOptions.h
@@ -11,9 +11,14 @@
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
-#include "mcld/Support/RealPath.h"
-#include "mcld/MC/SearchDirs.h"
-#include "mcld/Support/FileSystem.h"
+#include <string>
+#include <llvm/ADT/StringRef.h>
+#include <mcld/ADT/StringEntry.h>
+#include <mcld/ADT/HashTable.h>
+#include <mcld/Support/RealPath.h>
+#include <mcld/Support/FileSystem.h>
+#include <mcld/MC/SearchDirs.h>
+#include <mcld/MC/ZOption.h>
namespace mcld
{
@@ -22,8 +27,25 @@
/** \class ScriptOptions
*
*/
-class ScriptOption
+class ScriptOptions
{
+public:
+ typedef HashTable<StringEntry<llvm::StringRef>,
+ StringHash<ELF>,
+ StringEntryFactory<llvm::StringRef> > SymbolRenameMap;
+
+public:
+ ScriptOptions();
+ ~ScriptOptions();
+
+ SymbolRenameMap& renameMap()
+ { return m_SymbolRenames; }
+
+ const SymbolRenameMap& renameMap() const
+ { return m_SymbolRenames; }
+
+private:
+ SymbolRenameMap m_SymbolRenames;
};
/** \class GeneralOptions
@@ -35,6 +57,9 @@
class GeneralOptions
{
public:
+ GeneralOptions();
+ ~GeneralOptions();
+
/// default link script
bool hasDefaultLDScript() const;
const char* defaultLDScript() const;
@@ -60,18 +85,24 @@
bool trace() const
{ return m_bTrace; }
- void setVerbose(bool pVerbose = true)
- { m_bVerbose = pVerbose; }
-
- bool verbose() const
- { return m_bVerbose; }
-
void setBsymbolic(bool pBsymbolic = false)
{ m_Bsymbolic = pBsymbolic; }
bool Bsymbolic() const
{ return m_Bsymbolic; }
+ void setPIE(bool pPIE = true)
+ { m_bPIE = pPIE; }
+
+ bool isPIE() const
+ { return m_bPIE; }
+
+ void setBgroup(bool pBgroup = false)
+ { m_Bgroup = pBgroup; }
+
+ bool Bgroup() const
+ { return m_Bgroup; }
+
bool hasEntry() const
{ return !m_Entry.empty(); }
@@ -81,15 +112,155 @@
const std::string& entry() const
{ return m_Entry; }
+ void setDyld(const std::string& pDyld)
+ { m_Dyld = pDyld; }
+
+ const std::string& dyld() const
+ { return m_Dyld; }
+
+ bool hasDyld() const
+ { return !m_Dyld.empty(); }
+
+ void setAllowShlibUndefined(bool pEnabled = true)
+ { m_bAllowShlibUndefined = pEnabled; }
+
+ bool isAllowShlibUndefined() const
+ { return m_bAllowShlibUndefined; }
+
+ void setVerbose(int8_t pVerbose = -1)
+ { m_Verbose = pVerbose; }
+
+ int8_t verbose() const
+ { return m_Verbose; }
+
+ void setMaxErrorNum(int16_t pNum)
+ { m_MaxErrorNum = pNum; }
+
+ int16_t maxErrorNum() const
+ { return m_MaxErrorNum; }
+
+ void setMaxWarnNum(int16_t pNum)
+ { m_MaxWarnNum = pNum; }
+
+ int16_t maxWarnNum() const
+ { return m_MaxWarnNum; }
+
+ void setColor(bool pEnabled = true)
+ { m_bColor = pEnabled; }
+
+ bool color() const
+ { return m_bColor; }
+
+ void setNoUndefined(bool pEnable = false)
+ { m_bNoUndefined = pEnable; }
+
+ void setMulDefs(bool pEnable = false)
+ { m_bMulDefs = pEnable; }
+
+ void setEhFrameHdr(bool pEnable = true)
+ { m_bCreateEhFrameHdr = pEnable; }
+
+ /// ----- the -z options ----- ///
+ void addZOption(const mcld::ZOption& pOption);
+
+ bool hasCombReloc() const
+ { return m_bCombReloc; }
+
+ bool isNoUndefined() const
+ { return m_bNoUndefined; }
+
+ bool hasStackSet() const
+ { return (Unknown != m_ExecStack); }
+
+ bool hasExecStack() const
+ { return (YES == m_ExecStack); }
+
+ bool hasInitFirst() const
+ { return m_bInitFirst; }
+
+ bool hasInterPose() const
+ { return m_bInterPose; }
+
+ bool hasLoadFltr() const
+ { return m_bLoadFltr; }
+
+ bool hasMulDefs() const
+ { return m_bMulDefs; }
+
+ bool hasNoCopyReloc() const
+ { return m_bNoCopyReloc; }
+
+ bool hasNoDefaultLib() const
+ { return m_bNoDefaultLib; }
+
+ bool hasNoDelete() const
+ { return m_bNoDelete; }
+
+ bool hasNoDLOpen() const
+ { return m_bNoDLOpen; }
+
+ bool hasNoDump() const
+ { return m_bNoDump; }
+
+ bool hasRelro() const
+ { return m_bRelro; }
+
+ bool hasNow() const
+ { return m_bNow; }
+
+ bool hasOrigin() const
+ { return m_bOrigin; }
+
+ uint64_t commPageSize() const
+ { return m_CommPageSize; }
+
+ uint64_t maxPageSize() const
+ { return m_MaxPageSize; }
+
+ bool hasEhFrameHdr() const
+ { return m_bCreateEhFrameHdr; }
+
+private:
+ enum status {
+ YES,
+ NO,
+ Unknown
+ };
+
private:
Input* m_pDefaultBitcode;
std::string m_DefaultLDScript;
sys::fs::RealPath m_Sysroot;
SearchDirs m_SearchDirs;
- bool m_bTrace;
- bool m_bVerbose;
- bool m_Bsymbolic;
std::string m_Entry;
+ std::string m_Dyld;
+ 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
+ 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
+ bool m_bNoDLOpen : 1; // nodlopen
+ bool m_bNoDump : 1; // nodump
+ bool m_bRelro : 1; // relro, norelro
+ bool m_bNow : 1; // lazy, now
+ bool m_bOrigin : 1; // origin
+ bool m_bTrace : 1; // --trace
+ bool m_Bsymbolic : 1; // --Bsymbolic
+ bool m_Bgroup : 1;
+ bool m_bPIE : 1;
+ bool m_bColor : 1; // --color[=true,false,auto]
+ bool m_bAllowShlibUndefined : 1; // --[no-]allow-shlib-undefined and
+ bool m_bCreateEhFrameHdr : 1; // --eh-frame-hdr
};
} // namespace of mcld
diff --git a/include/mcld/MC/MCLinker.h b/include/mcld/MC/MCLinker.h
index 8de7148..29e6a46 100644
--- a/include/mcld/MC/MCLinker.h
+++ b/include/mcld/MC/MCLinker.h
@@ -19,7 +19,6 @@
#include <llvm/ADT/ilist.h>
#include <llvm/MC/MCAssembler.h>
-#include <mcld/LD/StrSymPool.h>
#include <mcld/LD/StaticResolver.h>
#include <mcld/LD/LDSectionFactory.h>
#include <mcld/LD/LDFileFormat.h>
@@ -42,6 +41,8 @@
class LDSectionFactory;
class SectionMap;
class Output;
+class EhFrame;
+class EhFrameHdr;
/** \class MCLinker
* \brief MCLinker provides a pass to link object files.
@@ -64,9 +65,8 @@
public:
MCLinker(TargetLDBackend& pBackend,
MCLDInfo& pLDInfo,
- LDContext& pContext,
- SectionMap& pSectionMap,
- const Resolver& pResolver = StaticResolver());
+ SectionMap& pSectionMap);
+
~MCLinker();
// ----- about symbols ----- //
@@ -111,12 +111,6 @@
MCFragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility = ResolveInfo::Default);
- /// mergeSymbolTable - merge the symbol table and resolve symbols.
- /// Since in current design, MCLinker resolves symbols when reading symbol
- /// tables, this function do nothing.
- bool mergeSymbolTable(Input& pInput)
- { return true; }
-
bool finalizeSymbols();
// ----- sections ----- //
@@ -144,7 +138,13 @@
/// getOrCreateSectData - for reader to map and perform section merging immediately
llvm::MCSectionData& getOrCreateSectData(LDSection& pSection);
- // ----- relocations ----- //
+ // ----- eh_frame sections ----- //
+ /// addEhFrame - add an exception handling section
+ /// @param pSection - the input section
+ /// @param pArea - the memory area which pSection is within.
+ uint64_t addEhFrame(LDSection& pSection, MemoryArea& pArea);
+
+ // ----- relocations ----- //
/// addRelocation - add a relocation entry in MCLinker (only for object file)
/// @param pType - the type of the relocation
/// @param pResolveInfo - the symbol should be the symbol in the input file. MCLinker
@@ -155,6 +155,7 @@
const LDSymbol& pSym,
ResolveInfo& pResolveInfo,
MCFragmentRef& pFragmentRef,
+ const LDSection& pSection,
Relocation::Address pAddend = 0);
/// applyRelocations - apply all relocation enties.
@@ -165,6 +166,8 @@
void syncRelocationResult();
// ----- layout ----- //
+ void initSectionMap();
+
Layout& getLayout()
{ return m_Layout; }
@@ -182,10 +185,10 @@
// ----- capacity ----- //
MCLDInfo& getLDInfo()
- { return m_Info; }
+ { return m_LDInfo; }
const MCLDInfo& getLDInfo() const
- { return m_Info; }
+ { return m_LDInfo; }
private:
LDSymbol* defineSymbolForcefully(const llvm::StringRef& pName,
@@ -257,18 +260,15 @@
private:
TargetLDBackend& m_Backend;
- MCLDInfo& m_Info;
- LDContext& m_Output;
+ MCLDInfo& m_LDInfo;
SectionMap& m_SectionMap;
LDSymbolFactory m_LDSymbolFactory;
LDSectionFactory m_LDSectHdrFactory;
LDSectionDataFactory m_LDSectDataFactory;
- SectionMerger m_SectionMerger;
- StrSymPool m_StrSymPool;
+ SectionMerger* m_pSectionMerger;
Layout m_Layout;
RelocationListType m_RelocationList;
SymbolCategory m_OutputSymbols;
-
};
#include "MCLinker.tcc"
diff --git a/include/mcld/MC/MCLinker.tcc b/include/mcld/MC/MCLinker.tcc
index 19a83ec..d6c5744 100644
--- a/include/mcld/MC/MCLinker.tcc
+++ b/include/mcld/MC/MCLinker.tcc
@@ -18,10 +18,19 @@
MCFragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
- // These if/else should be optimized by compiler.
- // This function is defined for clarity.
+ llvm::StringRef symbol_name = pName;
+ if (!getLDInfo().scripts().renameMap().empty() &&
+ ResolveInfo::Undefined == pDesc) {
+ // If the renameMap is not empty, some symbols should be renamed.
+ // --wrap and --portable defines the symbol rename map.
+ ScriptOptions::SymbolRenameMap::iterator renameSym
+ = getLDInfo().scripts().renameMap().find(pName);
+ if (renameSym != getLDInfo().scripts().renameMap().end())
+ symbol_name = renameSym.getEntry()->value();
+ }
+
if (FROM == Input::DynObj)
- return addSymbolFromDynObj(pName,
+ return addSymbolFromDynObj(symbol_name,
pType,
pDesc,
pBinding,
@@ -31,7 +40,7 @@
pVisibility);
if (FROM == Input::Object)
- return addSymbolFromObject(pName,
+ return addSymbolFromObject(symbol_name,
pType,
pDesc,
pBinding,
diff --git a/include/mcld/MC/SearchDirs.h b/include/mcld/MC/SearchDirs.h
index 1a22cf4..e0cf169 100644
--- a/include/mcld/MC/SearchDirs.h
+++ b/include/mcld/MC/SearchDirs.h
@@ -47,8 +47,9 @@
SearchDirs();
~SearchDirs();
- /// find - give a namespec, return a real path of the shared object.
- sys::fs::Path* find(const std::string& pNamespec, mcld::Input::Type pType);
+ // find - give a namespec, return a real path of the shared object.
+ //
+ sys::fs::Path* find(const std::string& pNamespec, mcld::Input::Type pPreferType);
// ----- iterators ----- //
iterator begin()
diff --git a/include/mcld/MC/ZOption.h b/include/mcld/MC/ZOption.h
new file mode 100644
index 0000000..e451734
--- /dev/null
+++ b/include/mcld/MC/ZOption.h
@@ -0,0 +1,75 @@
+//===- ZOption.h ----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ZOPTION_H
+#define MCLD_ZOPTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/Support/DataTypes.h>
+
+namespace mcld
+{
+
+/** \class ZOption
+ * \brief The -z options for GNU ld compatibility.
+ */
+class ZOption
+{
+public:
+ enum Kind {
+ CombReloc,
+ NoCombReloc,
+ Defs,
+ ExecStack,
+ NoExecStack,
+ InitFirst,
+ InterPose,
+ LoadFltr,
+ MulDefs,
+ NoCopyReloc,
+ NoDefaultLib,
+ NoDelete,
+ NoDLOpen,
+ NoDump,
+ Relro,
+ NoRelro,
+ Lazy,
+ Now,
+ Origin,
+ CommPageSize,
+ MaxPageSize,
+ Unknown
+ };
+
+public:
+ ZOption();
+
+ ~ZOption();
+
+ Kind kind() const
+ { return m_Kind; }
+
+ uint64_t pageSize() const
+ { return m_PageSize; }
+
+ void setKind(Kind pKind)
+ { m_Kind = pKind; }
+
+ void setPageSize(uint64_t pPageSize)
+ { m_PageSize = pPageSize; }
+
+private:
+ Kind m_Kind;
+ uint64_t m_PageSize;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/Allocators.h b/include/mcld/Support/Allocators.h
index 426cbc3..de6edec 100644
--- a/include/mcld/Support/Allocators.h
+++ b/include/mcld/Support/Allocators.h
@@ -15,7 +15,6 @@
#include "mcld/ADT/Uncopyable.h"
#include "mcld/ADT/TypeTraits.h"
#include "mcld/LD/LDContext.h"
-
#include <cstddef>
#include <cstdlib>
@@ -438,3 +437,4 @@
} // namespace mcld
#endif
+
diff --git a/include/mcld/Support/CommandLine.h b/include/mcld/Support/CommandLine.h
index e52c4a3..6a90309 100644
--- a/include/mcld/Support/CommandLine.h
+++ b/include/mcld/Support/CommandLine.h
@@ -13,8 +13,9 @@
#endif
#include <llvm/ADT/StringRef.h>
#include <llvm/Support/CommandLine.h>
-#include "mcld/Support/FileSystem.h"
-#include "mcld/MC/MCLDDirectory.h"
+#include <mcld/Support/FileSystem.h>
+#include <mcld/MC/MCLDDirectory.h>
+#include <mcld/MC/ZOption.h>
//--------------------------------------------------
// parser<mcld::sys::fs::Path>
@@ -56,6 +57,23 @@
virtual void anchor();
};
+//--------------------------------------------------
+// parser<mcld::ZOption>
+//
+template<>
+class parser<mcld::ZOption> : public llvm::cl::basic_parser<mcld::ZOption>
+{
+public:
+ bool parse(Option &O, StringRef ArgName, StringRef Arg, mcld::ZOption &Val);
+
+ virtual const char *getValueName() const { return "z-option"; }
+ void printOptionDiff(const Option &O,
+ const mcld::ZOption &V,
+ OptVal Default,
+ size_t GlobalWidth) const;
+ virtual void anchor();
+};
+
} // namespace of cl
} // namespace of llvm
diff --git a/include/mcld/Support/Directory.h b/include/mcld/Support/Directory.h
index 117d51d..c52dce1 100644
--- a/include/mcld/Support/Directory.h
+++ b/include/mcld/Support/Directory.h
@@ -12,13 +12,12 @@
#include <gtest.h>
#endif
-#include <cstddef>
-
#include "mcld/ADT/TypeTraits.h"
#include "mcld/Support/FileSystem.h"
#include "mcld/Support/Path.h"
#include "mcld/Support/PathCache.h"
#include <llvm/Support/Allocator.h>
+#include <cstddef>
namespace mcld {
diff --git a/include/mcld/Support/FileHandle.h b/include/mcld/Support/FileHandle.h
new file mode 100644
index 0000000..f6881c3
--- /dev/null
+++ b/include/mcld/Support/FileHandle.h
@@ -0,0 +1,141 @@
+//===- FileHandle.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_H
+#define MCLD_FILE_HANDLE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Support/Path.h>
+#include <mcld/ADT/Flags.h>
+#include <errno.h>
+
+namespace mcld
+{
+
+/** \class FileHandle
+ * \brief FileHandle class provides an interface for reading from and writing
+ * to files.
+ *
+ * Operators of FileHandle should neither throw exceptions nor call expressive
+ * diagnostic output.
+ */
+class FileHandle
+{
+public:
+ enum IOState
+ {
+ GoodBit = 0, // no error
+ BadBit = 1L << 0, // error due to the inappropriate operation
+ EOFBit = 1L << 1, // reached End-Of-File
+ FailBit = 1L << 2, // internal logic fail
+ IOStateEnd = 1L << 16
+ };
+
+ enum OpenModeEnum
+ {
+ NotOpen = 0x00,
+ ReadOnly = 0x01,
+ WriteOnly = 0x02,
+ ReadWrite = ReadOnly | WriteOnly,
+ Append = 0x04,
+ Create = 0x08,
+ Truncate = 0x10,
+ Unknown = 0xFF
+ };
+
+ typedef Flags<OpenModeEnum> OpenMode;
+
+ enum PermissionEnum
+ {
+ ReadOwner = 0x0400,
+ WriteOwner = 0x0200,
+ ExeOwner = 0x0100,
+ ReadGroup = 0x0040,
+ WriteGroup = 0x0020,
+ ExeGroup = 0x0010,
+ ReadOther = 0x0004,
+ WriteOther = 0x0002,
+ ExeOther = 0x0001
+ };
+
+ typedef Flags<PermissionEnum> Permission;
+
+public:
+ FileHandle();
+
+ ~FileHandle();
+
+ bool open(const sys::fs::Path& pPath,
+ OpenMode pMode);
+
+ bool open(const sys::fs::Path& pPath,
+ OpenMode pMode,
+ Permission pPerm);
+
+ bool delegate(int pFD, OpenMode pMode = Unknown);
+
+ bool close();
+
+ void setState(IOState pState);
+
+ void cleanState(IOState pState = GoodBit);
+
+ // truncate - truncate the file up to the pSize.
+ bool truncate(size_t pSize);
+
+ bool read(void* pMemBuffer, size_t pStartOffset, size_t pLength);
+
+ bool write(const void* pMemBuffer, size_t pStartOffset, size_t pLength);
+
+ bool mmap(void*& pMemBuffer, size_t pStartOffset, size_t pLength);
+
+ bool munmap(void* pMemBuffer, size_t pLength);
+
+ // ----- observers ----- //
+ const sys::fs::Path& path() const
+ { return m_Path; }
+
+ size_t size() const
+ { return m_Size; }
+
+ int handler() const
+ { return m_Handler; }
+
+ uint16_t rdstate() const
+ { return m_State; }
+
+ bool isOpened() const;
+
+ bool isGood() const;
+
+ bool isBad() const;
+
+ bool isFailed() const;
+
+ bool isReadable() const;
+
+ bool isWritable() const;
+
+ bool isReadWrite() const;
+
+ int error() const
+ { return errno; }
+
+private:
+ sys::fs::Path m_Path;
+ int m_Handler;
+ unsigned int m_Size;
+ uint16_t m_State;
+ OpenMode m_OpenMode;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/FileSystem.h b/include/mcld/Support/FileSystem.h
index 28dc563..230fa9b 100644
--- a/include/mcld/Support/FileSystem.h
+++ b/include/mcld/Support/FileSystem.h
@@ -18,12 +18,14 @@
#endif
#include "mcld/Support/PathCache.h"
+#include <mcld/Config/Config.h>
#include <string>
#include <iosfwd>
#include <locale>
namespace mcld {
namespace sys {
+
namespace fs {
enum FileType
@@ -89,8 +91,6 @@
namespace detail
{
-typedef unsigned char* Address;
-typedef off_t Offset;
extern std::string static_library_extension;
extern std::string shared_library_extension;
extern std::string executable_extension;
@@ -106,9 +106,12 @@
void open_dir(Directory& pDir);
void close_dir(Directory& pDir);
void get_pwd(std::string& pPWD);
-size_t pread(int pFD, Address pBuf, size_t pCount, off_t pOffset);
-size_t pwrite(int pFD, const Address pBuf, size_t pCount, off_t pOffset);
-char *strerror(int pErrnum);
+
+int open(const Path& pPath, int pOFlag);
+int open(const Path& pPath, int pOFlag, int pPermission);
+ssize_t pread(int pFD, void* pBuf, size_t pCount, size_t pOffset);
+ssize_t pwrite(int pFD, const void* pBuf, size_t pCount, size_t pOffset);
+int ftruncate(int pFD, size_t pLength);
} // namespace of detail
} // namespace of fs
diff --git a/include/mcld/Support/GCFactory.h b/include/mcld/Support/GCFactory.h
index eb3f9db..6679f41 100644
--- a/include/mcld/Support/GCFactory.h
+++ b/include/mcld/Support/GCFactory.h
@@ -228,3 +228,4 @@
} // namespace of mcld
#endif
+
diff --git a/include/mcld/Support/HandleToArea.h b/include/mcld/Support/HandleToArea.h
new file mode 100644
index 0000000..3cced3d
--- /dev/null
+++ b/include/mcld/Support/HandleToArea.h
@@ -0,0 +1,119 @@
+//===- 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 StringHash<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/MemoryArea.h b/include/mcld/Support/MemoryArea.h
index 2c04aff..5f4a29e 100644
--- a/include/mcld/Support/MemoryArea.h
+++ b/include/mcld/Support/MemoryArea.h
@@ -12,22 +12,23 @@
#include <gtest.h>
#endif
-#include "mcld/ADT/Uncopyable.h"
-#include "mcld/Support/FileSystem.h"
-#include "mcld/Support/Path.h"
-#include <llvm/ADT/ilist.h>
-#include <llvm/ADT/ilist_node.h>
+#include <mcld/ADT/Uncopyable.h>
+#include <mcld/Support/Path.h>
+#include <mcld/Support/FileSystem.h>
+#include <mcld/Support/FileHandle.h>
+#include <mcld/Support/Space.h>
#include <fcntl.h>
#include <string>
#include <list>
+
#if defined(ENABLE_UNITTEST)
namespace mcldtest
{
class MemoryAreaTest;
} // namespace of mcldtest
-
#endif
+
namespace mcld
{
@@ -52,85 +53,10 @@
*/
class MemoryArea : private Uncopyable
{
-#if defined(ENABLE_UNITTEST)
-friend class mcldtest::MemoryAreaTest;
-#endif
-public:
- enum IOState
- {
- GoodBit = 0,
- BadBit = 1L << 0,
- EOFBit = 1L << 1,
- FailBit = 1L << 2,
- IOStateEnd = 1L << 16
- };
-
- enum AccessMode
- {
- ReadOnly = O_RDONLY,
- WriteOnly = O_WRONLY,
- ReadWrite = O_RDWR,
- AccessMask = O_ACCMODE
- };
-
-private:
- typedef sys::fs::detail::Address Address;
-
- friend class MemoryRegion;
- friend class RegionFactory;
- struct Space : public llvm::ilist_node<Space>
- {
- public:
- enum Type
- {
- ALLOCATED_ARRAY,
- MMAPED,
- UNALLOCATED
- };
-
- public:
- Space()
- : m_pParent(NULL),
- type(UNALLOCATED),
- file_offset(0),
- size(0),
- data(0),
- region_num(0)
- { }
-
- Space(MemoryArea* pParent, size_t pOffset, size_t pLength)
- : m_pParent(pParent),
- type(UNALLOCATED),
- file_offset(pOffset),
- size(pLength),
- data(0),
- region_num(0)
- { }
-
- ~Space()
- { }
-
- void sync()
- { m_pParent->write(*this); }
-
- private:
- MemoryArea* m_pParent;
-
- public:
- Type type;
- size_t file_offset;
- size_t size;
- sys::fs::detail::Address data;
- size_t region_num;
- };
-
- friend class Space;
- typedef llvm::iplist<Space> SpaceList;
-
public:
// constructor
- // @param pRegionFactory the factory to manage MemoryRegions
- MemoryArea(RegionFactory& pRegionFactory);
+ MemoryArea(RegionFactory& pRegionFactory,
+ FileHandle& pFileHandle);
// destructor
~MemoryArea();
@@ -145,113 +71,39 @@
// release a MemoryRegion does not cause
void release(MemoryRegion* pRegion);
- // clean - release all MemoryRegion and unmap all spaces.
- void clean();
+ // clear - release all memory regions.
+ void clear();
- // sync - sync all MemoryRegion
- void sync();
+ FileHandle* handler()
+ { return m_pFileHandle; }
- // map - open the file pPath and mapped it onto MemoryArea
- // @param flags see man 2 open
- void map(const sys::fs::Path& pPath, int flags);
-
- // map - open the file pPath and mapped it onto MemoryArea
- // @param flags see man 2 open
- // @param mode see man 2 open
- void map(const sys::fs::Path& pPath, int flags, int mode);
-
- // unmap - close the opened file and unmap the MemoryArea
- void unmap();
-
- // path - the path of the mapped file.
- const sys::fs::Path& path() const
- { return m_FilePath; }
-
- // size - the real size of the mapped file.
- size_t size() const
- { return m_FileSize; }
-
- // isMapped - check if MemoryArea is mapped to a file
- bool isMapped() const;
-
- // isGood - check if the state of the opened area is good for read/write
- // operations
- bool isGood() const;
-
- // isBad - check if an error causes the loss of integrity of the memory space
- bool isBad() const;
-
- // isFailed - check if an error related to the internal logic of the operation
- // itself occurs
- bool isFailed() const;
-
- // isEOF - check if we reach the end of the file
- bool isEOF() const;
-
- // isReadable - check if the memory area is readable
- bool isReadable() const;
-
- // isWriteable - check if the memory area is writable
- bool isWritable() const;
-
- // rdstate - get error state flags
- // Returns the current internal error state flags of the stream
- int rdstate() const;
-
- // setState - set error state flag
- void setState(IOState pState);
-
- // clear - set error state flag
- void clear(IOState pState = GoodBit);
+ const FileHandle* handler() const
+ { return m_pFileHandle; }
private:
- // readToBuffer - read data from the file behind this MemorySpace and store
- // those bytes in pBuf. Return the number of byte read or -1 on error.
- ssize_t readToBuffer(sys::fs::detail::Address pBuf,
- size_t pSize, size_t pOffset);
+ friend class MemoryAreaFactory;
+
+#if defined(ENABLE_UNITTEST)
+ friend class mcldtest::MemoryAreaTest;
+#endif
+
+ typedef llvm::iplist<Space> SpaceList;
private:
- // find - first fit search
+ // ----- special methods ----- //
+ // @param pRegionFactory The factory of regions.
+ // @param pUniverse A initial univeral space.
+ MemoryArea(RegionFactory& pRegionFactory, Space& pUniverse);
+
+ // ----- space list methods ----- //
Space* find(size_t pOffset, size_t pLength);
- // release a Space, but does not remove it from space list
- void release(Space* pSpace);
-
- // read - read data from mapped file into virtual memroy of pSpace. Return
- // false on error.
- bool read(Space& pSpace);
-
- // write - write back the virtual memory of pSpace into mapped file.
- void write(const Space& pSpace);
-
- // truncate - truncate the file size to length.
- void truncate(size_t pLength);
-
- // policy - decide whehter to use dynamic memory or memory mapped I/O
- Space::Type policy(off_t pOffset, size_t pLength);
-
- // the size of one page
- static const off_t PageSize = 4096;
-
- // page_boundary - Given a file size, return the size to read integral pages.
- // return the first page boundary after pFileOffset
- static off_t page_boundary(off_t pFileOffset)
- { return (pFileOffset + (PageSize - 1)) & ~ (PageSize - 1); }
-
- // Given a file offset, return the page offset.
- // return the first page boundary before pFileOffset
- static off_t page_offset(off_t pFileOffset)
- { return pFileOffset & ~ (PageSize - 1); }
+ const Space* find(size_t pOffset, size_t pLength) const;
private:
RegionFactory& m_RegionFactory;
- sys::fs::Path m_FilePath;
- int m_FileDescriptor;
- size_t m_FileSize;
- int m_AccessFlags;
- int m_State;
-
SpaceList m_SpaceList;
+ FileHandle* m_pFileHandle;
};
} // namespace of mcld
diff --git a/include/mcld/Support/MemoryAreaFactory.h b/include/mcld/Support/MemoryAreaFactory.h
index f9ffa6e..be86b8c 100644
--- a/include/mcld/Support/MemoryAreaFactory.h
+++ b/include/mcld/Support/MemoryAreaFactory.h
@@ -11,13 +11,11 @@
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
-
-#include "mcld/Support/UniqueGCFactory.h"
-#include "mcld/Support/MemoryArea.h"
-#include "mcld/Support/Path.h"
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
+#include <mcld/Support/GCFactory.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/Path.h>
+#include <mcld/Support/FileHandle.h>
+#include <mcld/Support/HandleToArea.h>
namespace mcld
{
@@ -40,21 +38,35 @@
* MemoryRegion is requested.
*
* @see MemoryRegion
- * @see UniqueGCFactoryBase
*/
-class MemoryAreaFactory : public UniqueGCFactoryBase<sys::fs::Path, MemoryArea, 0>
+class MemoryAreaFactory : public GCFactory<MemoryArea, 0>
{
public:
explicit MemoryAreaFactory(size_t pNum);
- ~MemoryAreaFactory();
- // produce - create a MemoryArea and open its file
- // If the file fails to be opened, the returned MemoryArea::isMapped()
- // should be false
- MemoryArea* produce(const sys::fs::Path& pPath, int pFlags);
- MemoryArea* produce(const sys::fs::Path& pPath, int pFlags, mode_t pMode);
+ virtual ~MemoryAreaFactory();
+
+ // produce - create a MemoryArea and open its file.
+ MemoryArea* produce(const sys::fs::Path& pPath,
+ FileHandle::OpenMode pMode);
+
+ // produce - create a MemoryArea and open its file.
+ MemoryArea* produce(const sys::fs::Path& pPath,
+ FileHandle::OpenMode pMode,
+ FileHandle::Permission pPerm);
+
+ void destruct(MemoryArea* pArea);
+
+protected:
+ // Create a MemoryArea with an universal space.
+ // The created MemoryArea is not moderated by m_HandleToArea.
+ MemoryArea* create(void* pMemBuffer, size_t pSize);
+
+ // Create a MemoryArea by the given file handler
+ MemoryArea* create(int pFD, FileHandle::OpenMode pMode);
private:
+ HandleToArea m_HandleToArea;
RegionFactory* m_pRegionFactory;
};
diff --git a/include/mcld/Support/MemoryRegion.h b/include/mcld/Support/MemoryRegion.h
index 49f5fda..caa929f 100644
--- a/include/mcld/Support/MemoryRegion.h
+++ b/include/mcld/Support/MemoryRegion.h
@@ -13,12 +13,9 @@
#endif
#include <mcld/ADT/Uncopyable.h>
-#include <mcld/ADT/SizeTraits.h>
-#include <mcld/ADT/TypeTraits.h>
#include <mcld/Support/FileSystem.h>
#include <mcld/Support/MemoryArea.h>
-#include <llvm/ADT/ilist.h>
-#include <llvm/ADT/StringRef.h>
+#include <mcld/Support/Space.h>
namespace mcld
{
@@ -42,24 +39,17 @@
friend class MemoryArea;
public:
-typedef NonConstTraits<mcld::sys::fs::detail::Address>::value_type Address;
-typedef ConstTraits<mcld::sys::fs::detail::Address>::value_type ConstAddress;
-typedef NonConstTraits<mcld::sys::fs::detail::Offset>::value_type Offset;
-typedef ConstTraits<mcld::sys::fs::detail::Offset>::value_type ConstOffset;
+ typedef Space::Address Address;
+ typedef Space::ConstAddress ConstAddress;
private:
- MemoryRegion(MemoryArea::Space* pParentSpace,
- const Address pVMAStart,
- size_t pSize);
+ MemoryRegion(Space& pParent, const Address pVMAStart, size_t pSize);
- // drift - leave parent space
- void drift();
+ Space* parent()
+ { return &m_Parent; }
- MemoryArea::Space* parent()
- { return m_pParentSpace; }
-
- const MemoryArea::Space* parent() const
- { return m_pParentSpace; }
+ const Space* parent() const
+ { return &m_Parent; }
public:
~MemoryRegion();
@@ -79,14 +69,14 @@
size_t size() const
{ return m_Length; }
- Address getBuffer(Offset pOffset = 0)
+ Address getBuffer(size_t pOffset = 0)
{ return m_VMAStart+pOffset; }
- ConstAddress getBuffer(Offset pOffset = 0) const
+ ConstAddress getBuffer(size_t pOffset = 0) const
{ return m_VMAStart+pOffset; }
private:
- MemoryArea::Space* m_pParentSpace;
+ Space& m_Parent;
Address m_VMAStart;
size_t m_Length;
};
diff --git a/include/mcld/Support/MsgHandling.h b/include/mcld/Support/MsgHandling.h
new file mode 100644
index 0000000..a42bb54
--- /dev/null
+++ b/include/mcld/Support/MsgHandling.h
@@ -0,0 +1,77 @@
+//===- MsgHandling.h ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MESSAGE_HANDLING_H
+#define MCLD_MESSAGE_HANDLING_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/LD/MsgHandler.h>
+
+namespace mcld
+{
+
+class MCLDInfo;
+class DiagnosticPrinter;
+class DiagnosticLineInfo;
+
+void InitializeDiagnosticEngine(const MCLDInfo& pLDInfo,
+ DiagnosticLineInfo* pLineInfo,
+ DiagnosticPrinter* pPrinter);
+
+DiagnosticEngine& getDiagnosticEngine();
+
+MsgHandler unreachable(unsigned int pID);
+MsgHandler fatal(unsigned int pID);
+MsgHandler error(unsigned int pID);
+MsgHandler warning(unsigned int pID);
+MsgHandler debug(unsigned int pID);
+MsgHandler note(unsigned int pID);
+MsgHandler ignore(unsigned int pID);
+
+} // namespace of mcld
+
+//===----------------------------------------------------------------------===//
+// Inline functions
+inline mcld::MsgHandler mcld::unreachable(unsigned int pID)
+{
+ return getDiagnosticEngine().report(pID, DiagnosticEngine::Unreachable);
+}
+
+inline mcld::MsgHandler mcld::fatal(unsigned int pID)
+{
+ return getDiagnosticEngine().report(pID, DiagnosticEngine::Fatal);
+}
+
+inline mcld::MsgHandler mcld::error(unsigned int pID)
+{
+ return getDiagnosticEngine().report(pID, DiagnosticEngine::Error);
+}
+
+inline mcld::MsgHandler mcld::warning(unsigned int pID)
+{
+ return getDiagnosticEngine().report(pID, DiagnosticEngine::Warning);
+}
+
+inline mcld::MsgHandler mcld::debug(unsigned int pID)
+{
+ return getDiagnosticEngine().report(pID, DiagnosticEngine::Debug);
+}
+
+inline mcld::MsgHandler mcld::note(unsigned int pID)
+{
+ return getDiagnosticEngine().report(pID, DiagnosticEngine::Note);
+}
+
+inline mcld::MsgHandler mcld::ignore(unsigned int pID)
+{
+ return getDiagnosticEngine().report(pID, DiagnosticEngine::Ignore);
+}
+
+#endif
+
diff --git a/include/mcld/Support/Path.h b/include/mcld/Support/Path.h
index f5ee56c..113ff25 100644
--- a/include/mcld/Support/Path.h
+++ b/include/mcld/Support/Path.h
@@ -10,7 +10,6 @@
// filesystem (v3), but modified to remove exception handling and the
// path class.
//===----------------------------------------------------------------------===//
-
#ifndef MCLD_PATH_H
#define MCLD_PATH_H
#ifdef ENABLE_UNITTEST
@@ -18,15 +17,17 @@
#endif
#include <llvm/Support/raw_ostream.h>
+#include <mcld/Config/Config.h>
+
+#include <iosfwd>
#include <functional>
#include <string>
-//#include "mcld/Support/Directory.h"
namespace mcld {
namespace sys {
namespace fs {
-#ifdef LLVM_ON_WIN32
+#if defined(MCLD_ON_WIN32)
const wchar_t separator = L'\\';
const wchar_t preferred_separator = L'\\';
#else
@@ -44,7 +45,7 @@
class Path
{
public:
-#ifdef LLVM_ON_WIN32
+#if defined(MCLD_ON_WIN32)
typedef wchar_t ValueType;
#else
typedef char ValueType;
diff --git a/include/mcld/Support/PositionDependentOption.h b/include/mcld/Support/PositionDependentOption.h
index b5d60e8..8dd969d 100644
--- a/include/mcld/Support/PositionDependentOption.h
+++ b/include/mcld/Support/PositionDependentOption.h
@@ -40,20 +40,26 @@
};
protected:
- PositionDependentOption(unsigned pPosition, Type pType)
+ PositionDependentOption(unsigned int pPosition, Type pType)
: m_Type(pType),
m_Position(pPosition) {}
public:
- inline const Type& type() const
+ Type type()
{ return m_Type; }
- inline unsigned position() const
+ Type type() const
+ { return m_Type; }
+
+ unsigned int position()
+ { return m_Position; }
+
+ unsigned int position() const
{ return m_Position; }
private:
Type m_Type;
- unsigned m_Position;
+ unsigned int m_Position;
};
typedef std::vector<PositionDependentOption*> PositionDependentOptions;
diff --git a/include/mcld/Support/RegionFactory.h b/include/mcld/Support/RegionFactory.h
index ba9a88d..8893500 100644
--- a/include/mcld/Support/RegionFactory.h
+++ b/include/mcld/Support/RegionFactory.h
@@ -11,10 +11,10 @@
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
-#include "mcld/Support/GCFactory.h"
-#include "mcld/Support/MemoryRegion.h"
-#include "mcld/Support/MemoryArea.h"
-#include "mcld/Support/FileSystem.h"
+#include <mcld/Support/GCFactory.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/FileSystem.h>
namespace mcld
{
@@ -35,9 +35,7 @@
~RegionFactory();
// ----- production ----- //
- MemoryRegion* produce(MemoryArea::Space* pSpace,
- const sys::fs::detail::Address pVMAStart,
- size_t pSize);
+ MemoryRegion* produce(Space& pSpace, void* pVMAStart, size_t pSize);
void destruct(MemoryRegion* pRegion);
};
diff --git a/include/mcld/Support/Space.h b/include/mcld/Support/Space.h
new file mode 100644
index 0000000..7ebedce
--- /dev/null
+++ b/include/mcld/Support/Space.h
@@ -0,0 +1,104 @@
+//===- 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 <llvm/ADT/ilist.h>
+#include <llvm/ADT/ilist_node.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 llvm::ilist_node<Space>
+{
+public:
+ enum Type
+ {
+ ALLOCATED_ARRAY,
+ MMAPED,
+ EXTERNAL,
+ UNALLOCATED
+ };
+
+ typedef NonConstTraits<uint8_t>::pointer Address;
+ typedef ConstTraits<uint8_t>::pointer ConstAddress;
+
+// llvm::iplist functions
+public:
+ // llvm::iplist needs default constructor to make a sentinel.
+ // Normal users should use @ref Space::createSpace function.
+ Space();
+
+ // llvm::iplist needs public destructor to delete the sentinel.
+ // Normal users should use @ref Space::releaseSpace function.
+ ~Space();
+
+ // This constructor is opened for the clients who want to control the
+ // details. In MCLinker, this constructor is used no where.
+ 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; }
+
+ static Space* createSpace(FileHandle& pHandler,
+ size_t pOffset, size_t pSize);
+
+ static void releaseSpace(Space* pSpace, FileHandle& pHandler);
+
+ static void syncSpace(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
new file mode 100644
index 0000000..bfc522b
--- /dev/null
+++ b/include/mcld/Support/SystemUtils.h
@@ -0,0 +1,33 @@
+//===- SystemUtils.h ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SYSTEM_UTILS_H
+#define MCLD_SYSTEM_UTILS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/DataTypes.h>
+#include <mcld/Config/Config.h>
+
+namespace mcld {
+namespace sys {
+
+typedef uint8_t* Address;
+typedef off_t Offset;
+
+/** \fn strerror
+ * \brief system error message
+ */
+char *strerror(int pErrnum);
+
+} // namespace of sys
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/TargetRegistry.h b/include/mcld/Support/TargetRegistry.h
index a9ad875..b31bed4 100644
--- a/include/mcld/Support/TargetRegistry.h
+++ b/include/mcld/Support/TargetRegistry.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef TARGET_REGISTRY_H
-#define TARGET_REGISTRY_H
+#ifndef MCLD_TARGET_REGISTRY_H
+#define MCLD_TARGET_REGISTRY_H
#include <llvm/Support/TargetRegistry.h>
#include <string>
#include <list>
@@ -28,6 +28,7 @@
class AttributeFactory;
class InputFactory;
class ContextFactory;
+class DiagnosticLineInfo;
//===----------------------------------------------------------------------===//
/// Target - mcld::Target is an object adapter of llvm::Target
@@ -48,30 +49,28 @@
typedef TargetLDBackend *(*TargetLDBackendCtorTy)(const llvm::Target&,
const std::string&);
-private:
- TargetMachineCtorTy TargetMachineCtorFn;
- SectLinkerCtorTy SectLinkerCtorFn;
- TargetLDBackendCtorTy TargetLDBackendCtorFn;
+ typedef DiagnosticLineInfo *(*DiagnosticLineInfoCtorTy)(const llvm::Target&,
+ const std::string&);
public:
Target();
- void setTarget(const llvm::Target& pTarget) {
- m_pT = &pTarget;
- }
+ void setTarget(const llvm::Target& pTarget)
+ { m_pT = &pTarget; }
mcld::LLVMTargetMachine *createTargetMachine(const std::string &pTriple,
const std::string &pCPU, const std::string &pFeatures,
const llvm::TargetOptions &Options,
llvm::Reloc::Model RM = llvm::Reloc::Default,
llvm::CodeModel::Model CM = llvm::CodeModel::Default,
- llvm::CodeGenOpt::Level OL = llvm::CodeGenOpt::Default) const {
+ llvm::CodeGenOpt::Level OL = llvm::CodeGenOpt::Default) const
+ {
if (TargetMachineCtorFn && m_pT) {
llvm::TargetMachine *tm = m_pT->createTargetMachine(pTriple, pCPU, pFeatures, Options, RM, CM, OL);
if (tm)
return TargetMachineCtorFn(*this, *tm, pTriple);
}
- return 0;
+ return NULL;
}
/// createSectLinker - create target-specific SectLinker
@@ -81,7 +80,7 @@
SectLinkerOption &pOption,
TargetLDBackend &pLDBackend) const {
if (!SectLinkerCtorFn)
- return 0;
+ return NULL;
return SectLinkerCtorFn(pTriple,
pOption,
pLDBackend);
@@ -90,17 +89,33 @@
/// createLDBackend - create target-specific LDBackend
///
/// @return created TargetLDBackend
- TargetLDBackend *createLDBackend(const llvm::Target& T, const std::string& Triple) const {
+ TargetLDBackend* createLDBackend(const std::string& Triple) const
+ {
if (!TargetLDBackendCtorFn)
- return 0;
- return TargetLDBackendCtorFn(T, Triple);
+ return NULL;
+ return TargetLDBackendCtorFn(*get(), Triple);
}
- const llvm::Target* get() const {
- return m_pT;
+ /// createDiagnosticLineInfo - create target-specific DiagnosticLineInfo
+ DiagnosticLineInfo* createDiagnosticLineInfo(const llvm::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;
+ SectLinkerCtorTy SectLinkerCtorFn;
+ TargetLDBackendCtorTy TargetLDBackendCtorFn;
+ DiagnosticLineInfoCtorTy DiagnosticLineInfoCtorFn;
+
+ // ----- adapted llvm::Target ----- //
const llvm::Target* m_pT;
};
@@ -139,7 +154,8 @@
///
/// @param T - The target being registered.
/// @param Fn - A function to construct a TargetMachine for the target.
- static void RegisterTargetMachine(mcld::Target &T, mcld::Target::TargetMachineCtorTy Fn) {
+ static void RegisterTargetMachine(mcld::Target &T, mcld::Target::TargetMachineCtorTy Fn)
+ {
// Ignore duplicate registration.
if (!T.TargetMachineCtorFn)
T.TargetMachineCtorFn = Fn;
@@ -150,7 +166,8 @@
///
/// @param T - the target being registered
/// @param Fn - A function to create SectLinker for the target
- static void RegisterSectLinker(mcld::Target &T, mcld::Target::SectLinkerCtorTy Fn) {
+ static void RegisterSectLinker(mcld::Target &T, mcld::Target::SectLinkerCtorTy Fn)
+ {
if (!T.SectLinkerCtorFn)
T.SectLinkerCtorFn = Fn;
}
@@ -160,11 +177,25 @@
///
/// @param T - The target being registered
/// @param Fn - A function to create TargetLDBackend for the target
- static void RegisterTargetLDBackend(mcld::Target &T, mcld::Target::TargetLDBackendCtorTy Fn) {
+ static void RegisterTargetLDBackend(mcld::Target &T, mcld::Target::TargetLDBackendCtorTy Fn)
+ {
if (!T.TargetLDBackendCtorFn)
T.TargetLDBackendCtorFn = Fn;
}
+ /// RegisterTargetDiagnosticLineInfo - Register a DiagnosticLineInfo
+ /// implementation for the given target.
+ ///
+ /// @param T - The target being registered
+ /// @param Fn - A function to create DiagnosticLineInfo for the target
+ static void
+ RegisterDiagnosticLineInfo(mcld::Target &T,
+ mcld::Target::DiagnosticLineInfoCtorTy Fn)
+ {
+ if (!T.DiagnosticLineInfoCtorFn)
+ T.DiagnosticLineInfoCtorFn = Fn;
+ }
+
/// lookupTarget - Lookup a target based on a llvm::Target.
///
/// @param T - The llvm::Target to find
diff --git a/include/mcld/Support/TargetSelect.h b/include/mcld/Support/TargetSelect.h
index e040ae2..0788d1d 100644
--- a/include/mcld/Support/TargetSelect.h
+++ b/include/mcld/Support/TargetSelect.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef TARGETSELECT_H
-#define TARGETSELECT_H
+#ifndef MCLD_TARGET_SELECT_H
+#define MCLD_TARGET_SELECT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -32,6 +32,11 @@
// Declare all of the available target-specific linker
#define LLVM_LINKER(TargetName) void LLVMInitialize##TargetName##LDBackend();
#include "mcld/Config/Linkers.def"
+
+ // Declare all of the available target-specific diagnostic line infomation
+#define LLVM_LINKER(TargetName) void LLVMInitialize##TargetName##DiagnosticLineInfo();
+#include "mcld/Config/Linkers.def"
+
} // extern "C"
namespace mcld
@@ -56,6 +61,9 @@
#define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##LDTarget();
#include "mcld/Config/Targets.def"
+
+#define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##LDBackend();
+#include "mcld/Config/Targets.def"
}
/// InitializeAllLinkers - The main program should call this function if it
@@ -66,8 +74,13 @@
inline void InitializeAllLinkers() {
#define LLVM_LINKER(TargetName) LLVMInitialize##TargetName##SectLinker();
#include "mcld/Config/Linkers.def"
+ }
-#define LLVM_LINKER(TargetName) LLVMInitialize##TargetName##LDBackend();
+ /// InitializeMsgHandler - The main program should call this function if it
+ /// wants to print linker-specific messages. To make them available via the
+ /// TargetRegistry.
+ inline void InitializeAllDiagnostics() {
+#define LLVM_LINKER(TargetName) LLVMInitialize##TargetName##DiagnosticLineInfo();
#include "mcld/Config/Linkers.def"
}
diff --git a/include/mcld/Support/raw_ostream.h b/include/mcld/Support/raw_ostream.h
new file mode 100644
index 0000000..61706de
--- /dev/null
+++ b/include/mcld/Support/raw_ostream.h
@@ -0,0 +1,81 @@
+//===- raw_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_OSTREAM_H
+#define MCLD_RAW_OSTREAM_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <string>
+#include <llvm/Support/raw_ostream.h>
+#include <mcld/MC/MCLDInfo.h>
+
+namespace mcld
+{
+
+class raw_fd_ostream : public llvm::raw_fd_ostream
+{
+public:
+ /// raw_fd_ostream - Open the specified file for writing. If an error occurs,
+ /// information about the error is put into ErrorInfo, and the stream should
+ /// be immediately destroyed; the string will be empty if no error occurred.
+ /// This allows optional flags to control how the file will be opened.
+ ///
+ /// As a special case, if Filename is "-", then the stream will use
+ /// STDOUT_FILENO instead of opening a file. Note that it will still consider
+ /// itself to own the file descriptor. In particular, it will close the
+ /// file descriptor when it is done (this is necessary to detect
+ /// output errors).
+ raw_fd_ostream(const char *pFilename,
+ std::string &pErrorInfo,
+ unsigned int pFlags = 0,
+ const MCLDInfo* pLDInfo = NULL);
+
+ /// raw_fd_ostream ctor - FD is the file descriptor that this writes to. If
+ /// ShouldClose is true, this closes the file when the stream is destroyed.
+ raw_fd_ostream(int pFD, bool pShouldClose,
+ bool pUnbuffered=false,
+ const MCLDInfo* pLDInfo = NULL);
+
+ virtual ~raw_fd_ostream();
+
+ void setLDInfo(const MCLDInfo& pLDInfo);
+
+
+ llvm::raw_ostream &changeColor(enum llvm::raw_ostream::Colors pColors,
+ bool pBold=false,
+ bool pBackground=false);
+
+ llvm::raw_ostream &resetColor();
+
+ // FIXME: migrate to newer LLVM
+ // llvm::raw_ostream &reverseColor();
+
+ bool is_displayed() const;
+
+private:
+ const MCLDInfo* m_pLDInfo;
+
+};
+
+/// InitializeOStreams - This initialize mcld::outs() and mcld::errs().
+/// Call it before you use mcld::outs() and mcld::errs().
+void InitializeOStreams(const MCLDInfo& pLDInfo);
+
+/// outs() - This returns a reference to a raw_ostream for standard output.
+/// Use it like: outs() << "foo" << "bar";
+mcld::raw_fd_ostream &outs();
+
+/// errs() - This returns a reference to a raw_ostream for standard error.
+/// Use it like: errs() << "foo" << "bar";
+mcld::raw_fd_ostream &errs();
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/AndroidSectLinker.h b/include/mcld/Target/AndroidSectLinker.h
deleted file mode 100644
index dd68ff2..0000000
--- a/include/mcld/Target/AndroidSectLinker.h
+++ /dev/null
@@ -1,42 +0,0 @@
-//===- AndroidSectLinker.h ------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// AndroidSectLinker is a customized linker pass for Android platform.
-// This pass set up default parameters for Android.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef ANDROID_SECTLINKER_H
-#define ANDROID_SECTLINKER_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-#include <mcld/CodeGen/SectLinker.h>
-
-namespace mcld
-{
-
-class AndroidSectLinker : public SectLinker
-{
-public:
- AndroidSectLinker(SectLinkerOption &pOption,
- mcld::TargetLDBackend &pLDBackend);
-
- virtual ~AndroidSectLinker();
-
- // addTargetInputs - add Android-specific linker options
- virtual void addTargetOptions(llvm::Module &pM,
- SectLinkerOption &pOption);
-
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/Target/ELFSectLinker.h b/include/mcld/Target/ELFSectLinker.h
new file mode 100644
index 0000000..04234a8
--- /dev/null
+++ b/include/mcld/Target/ELFSectLinker.h
@@ -0,0 +1,36 @@
+//===- ELFSectLinker.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// ELFSectLinker is a customized linker pass for ELF platform.
+// This pass set up default parameters for ELF.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_SECTION_LINKER_H
+#define MCLD_ELF_SECTION_LINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/CodeGen/SectLinker.h>
+
+namespace mcld
+{
+
+class ELFSectLinker : public SectLinker
+{
+public:
+ ELFSectLinker(SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend);
+
+ virtual ~ELFSectLinker();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/GNULDBackend.h b/include/mcld/Target/GNULDBackend.h
index 7f51448..196420a 100644
--- a/include/mcld/Target/GNULDBackend.h
+++ b/include/mcld/Target/GNULDBackend.h
@@ -15,18 +15,20 @@
#include <llvm/Support/ELF.h>
#include <mcld/ADT/HashTable.h>
#include <mcld/ADT/HashEntry.h>
+#include <mcld/LD/EhFrameHdr.h>
+#include <mcld/LD/ELFDynObjFileFormat.h>
#include <mcld/LD/ELFDynObjReader.h>
#include <mcld/LD/ELFDynObjWriter.h>
+#include <mcld/LD/ELFExecFileFormat.h>
+#include <mcld/LD/ELFExecWriter.h>
#include <mcld/LD/ELFObjectReader.h>
#include <mcld/LD/ELFObjectWriter.h>
-#include <mcld/LD/ELFDynObjFileFormat.h>
-#include <mcld/LD/ELFExecFileFormat.h>
#include <mcld/LD/ELFSegment.h>
+#include <mcld/LD/ELFSegmentFactory.h>
#include <mcld/LD/GNUArchiveReader.h>
#include <mcld/Support/GCFactory.h>
#include <mcld/Target/ELFDynamic.h>
#include <mcld/Target/TargetLDBackend.h>
-#include <mcld/LD/ELFSegmentFactory.h>
namespace mcld
{
@@ -56,85 +58,81 @@
*/
class GNULDBackend : public TargetLDBackend
{
- // These dynamic section tags are GNU extension.
- enum {
- DT_RELACOUNT = 0x6ffffff9,
- DT_RELCOUNT = 0x6ffffffa,
- DT_FLAGS_1 = 0x6ffffffb,
- DT_VERDEF = 0x6ffffffc,
- DT_VERDEFNUM = 0x6ffffffd,
- DT_VERNEED = 0x6ffffffe,
- DT_VERNEEDNUM = 0x6fffffff
- };
-
-protected:
- // Based on Kind in LDFileFormat to define basic section orders for ELF, and
- // refer gold linker to add more enumerations to handle Regular and BSS kind
- enum SectionOrder {
- SHO_INTERP = 1, // .interp
- SHO_RO_NOTE, // .note.ABI-tag, .note.gnu.build-id
- SHO_NAMEPOOL, // *.hash, .dynsym, .dynstr
- SHO_RELOCATION, // .rel.*, .rela.*
- SHO_REL_PLT, // .rel.plt should come after other .rel.*
- SHO_INIT, // .init
- SHO_PLT, // .plt
- SHO_TEXT, // .text
- SHO_FINI, // .fini
- SHO_RO, // .rodata
- SHO_EHFRAME, // .eh_frame_hdr, .eh_frame
- SHO_TLS_DATA, // .tdata
- SHO_TLS_BSS, // .tbss
- SHO_RELRO_LOCAL, // .data.rel.ro.local
- SHO_RELRO, // .data.rel.ro,
- SHO_RELRO_LAST, // for x86 to adjust .got if needed
- SHO_NON_RELRO_FIRST, // for x86 to adjust .got.plt if needed
- SHO_DATA, // .data
- SHO_LARGE_DATA, // .ldata
- SHO_RW_NOTE, //
- SHO_SMALL_DATA, // .sdata
- SHO_SMALL_BSS, // .sbss
- SHO_BSS, // .bss
- SHO_LARGE_BSS, // .lbss
- SHO_UNDEFINED = ~(0U) // default order
- };
-
protected:
GNULDBackend();
public:
virtual ~GNULDBackend();
+ // ----- readers/writers ----- //
bool initArchiveReader(MCLinker& pLinker, MCLDInfo& pInfo);
bool initObjectReader(MCLinker& pLinker);
bool initDynObjReader(MCLinker& pLinker);
bool initObjectWriter(MCLinker& pLinker);
bool initDynObjWriter(MCLinker& pLinker);
-
- bool initExecSections(MCLinker& pMCLinker);
- bool initDynObjSections(MCLinker& pMCLinker);
-
- bool initStandardSymbols(MCLinker& pLinker);
+ bool initExecWriter(MCLinker& pLinker);
GNUArchiveReader *getArchiveReader();
- GNUArchiveReader *getArchiveReader() const;
+ const GNUArchiveReader *getArchiveReader() const;
ELFObjectReader *getObjectReader();
- ELFObjectReader *getObjectReader() const;
+ const ELFObjectReader *getObjectReader() const;
ELFDynObjReader *getDynObjReader();
- ELFDynObjReader *getDynObjReader() const;
+ const ELFDynObjReader *getDynObjReader() const;
ELFObjectWriter *getObjectWriter();
- ELFObjectWriter *getObjectWriter() const;
+ const ELFObjectWriter *getObjectWriter() const;
ELFDynObjWriter *getDynObjWriter();
- ELFDynObjWriter *getDynObjWriter() const;
+ const ELFDynObjWriter *getDynObjWriter() const;
+
+ ELFExecWriter *getExecWriter();
+ const ELFExecWriter *getExecWriter() const;
+
+ // ----- output sections ----- //
+ /// initExecSections - initialize sections of the output executable file.
+ bool initExecSections(MCLinker& pMCLinker);
+
+ /// initDynObjSections - initialize sections of the output shared object.
+ bool initDynObjSections(MCLinker& pMCLinker);
+
+ /// getOutputFormat - get the sections of the output file.
+ ELFFileFormat* getOutputFormat(const Output& pOutput);
+ const ELFFileFormat* getOutputFormat(const Output& pOutput) const;
ELFDynObjFileFormat* getDynObjFileFormat();
- ELFDynObjFileFormat* getDynObjFileFormat() const;
+ const ELFDynObjFileFormat* getDynObjFileFormat() const;
ELFExecFileFormat* getExecFileFormat();
- ELFExecFileFormat* getExecFileFormat() const;
+ const ELFExecFileFormat* getExecFileFormat() const;
+
+ // ----- target symbols ----- //
+ /// initStandardSymbols - initialize standard symbols.
+ /// Some section symbols is undefined in input object, and linkers must set
+ /// up its value. Take __init_array_begin for example. This symbol is an
+ /// undefined symbol in input objects. MCLinker must finalize its value
+ /// to the begin of the .init_array section, then relocation enties to
+ /// __init_array_begin can be applied without emission of "undefined
+ /// reference to `__init_array_begin'".
+ bool initStandardSymbols(MCLinker& pLinker, const Output& pOutput);
+
+ /// finalizeSymbol - Linker checks pSymbol.reserved() if it's not zero,
+ /// then it will ask backend to finalize the symbol value.
+ /// @return ture - if backend set the symbol value sucessfully
+ /// @return false - if backend do not recognize the symbol
+ bool finalizeSymbols(MCLinker& pLinker, const Output& pOutput) {
+ return (finalizeStandardSymbols(pLinker, pOutput) &&
+ finalizeTargetSymbols(pLinker, pOutput));
+ }
+
+ /// finalizeStandardSymbols - set the value of standard symbols
+ virtual bool finalizeStandardSymbols(MCLinker& pLinker,
+ const Output& pOutput);
+
+ /// finalizeTargetSymbols - set the value of target symbols
+ virtual bool finalizeTargetSymbols(MCLinker& pLinker,
+ const Output& pOutput) = 0;
size_t sectionStartOffset() const;
@@ -158,6 +156,21 @@
virtual const char* entry() const
{ return "_start"; }
+ /// dyld - the name of the default dynamic linker
+ /// target may override this function if needed.
+ /// @ref gnu ld, bfd/elf32-i386.c:521
+ virtual const char* dyld() const
+ { return "/usr/lib/libc.so.1"; }
+
+ /// defaultTextSegmentAddr - target should specify its own default start address
+ /// of the text segment. esp. for exec.
+ virtual uint64_t defaultTextSegmentAddr() const
+ { return 0x0; }
+
+ /// segmentStartAddr - this function returns the start address of the segment
+ uint64_t segmentStartAddr(const Output& pOutput,
+ const MCLDInfo& pInfo) const;
+
/// sizeNamePools - compute the size of regular name pools
/// In ELF executable files, regular name pools are .symtab, .strtab.,
/// .dynsym, .dynstr, and .hash
@@ -169,6 +182,7 @@
virtual uint64_t emitSectionData(const Output& pOutput,
const LDSection& pSection,
const MCLDInfo& pInfo,
+ const Layout& pLayout,
MemoryRegion& pRegion) const = 0;
/// emitRegNamePools - emit regular name pools - .symtab, .strtab
@@ -183,6 +197,13 @@
const Layout& pLayout,
const MCLDInfo& pLDInfo);
+ /// 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(const Output& pOutput, const MCLDInfo& pLDInfo);
+
+ /// emitInterp - emit the .interp
+ virtual void emitInterp(Output& pOutput, const MCLDInfo& pLDInfo);
+
/// getSectionOrder - compute the layout order of the section
/// Layout calls this function to get the default order of the pSectHdr.
/// If the pSectHdr.type() is LDFileFormat::Target, then getSectionOrder()
@@ -193,7 +214,8 @@
///
/// @see getTargetSectionOrder
virtual unsigned int getSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const;
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const;
/// getTargetSectionOrder - compute the layout order of target section
/// If the target favors certain order for the given gSectHdr, please
@@ -202,37 +224,107 @@
/// By default, this function returns the maximun order, and pSectHdr
/// will be the last section to be laid out.
virtual unsigned int
- getTargetSectionOrder(const Output& pOutput, const LDSection& pSectHdr) const
+ getTargetSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const
{ return (unsigned int)-1; }
- /// emitProgramHdrs - emit ELF program headers
- /// if the target favors other ways to emit program header, please override
- /// this function
- virtual void emitProgramHdrs(Output& pOutput);
-
/// numOfSegments - return the number of segments
/// if the target favors other ways to emit program header, please override
/// this function
virtual unsigned int numOfSegments() const
{ return m_ELFSegmentTable.size(); }
- /// pagesize - the page size of the target machine, we set it to 4K here.
- /// If target favors tht different size of page, please override this function
- virtual unsigned int pagesize() const
- { return 0x1000; }
+ /// 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; }
+
+ /// commonPageSize - the common page size of the target machine, and we set it
+ /// to 4K here. If target favors the different size, please override this
+ /// function
+ virtual uint64_t commonPageSize(const MCLDInfo& pInfo) const;
+
+ /// abiPageSize - the abi page size of the target machine, and we set it to 4K
+ /// here. If target favors the different size, please override this function
+ virtual uint64_t abiPageSize(const MCLDInfo& pInfo) const;
/// getSymbolIdx - get the symbol index of ouput symbol table
size_t getSymbolIdx(LDSymbol* pSymbol) const;
+ /// isDefaultExecStack - target should specify whether the stack is default
+ /// executable. If target favors another choice, please override this function
+ virtual bool isDefaultExecStack() const
+ { return true; }
+
+ /// allocateCommonSymbols - allocate common symbols in the corresponding
+ /// sections.
+ /// Different concrete target backend may overlap this function.
+ virtual bool allocateCommonSymbols(const MCLDInfo& pLDInfo, MCLinker& pLinker) const;
+
+ /// isSymbolPreemtible - whether the symbol can be preemted by other
+ /// link unit
+ /// @ref Google gold linker, symtab.h:551
+ bool isSymbolPreemptible(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const;
+
+protected:
+ uint64_t getSymbolSize(const LDSymbol& pSymbol) const;
+
+ uint64_t getSymbolInfo(const LDSymbol& pSymbol) const;
+
+ uint64_t getSymbolValue(const LDSymbol& pSymbol) const;
+
+ uint64_t getSymbolShndx(const LDSymbol& pSymbol, const Layout& pLayout) const;
+
+ /// getHashBucketCount - calculate hash bucket count.
+ /// @ref Google gold linker, dynobj.cc:791
+ static unsigned getHashBucketCount(unsigned pNumOfSymbols, bool pIsGNUStyle);
+
+ /// isDynamicSymbol
+ /// @ref Google gold linker: symtab.cc:311
+ static bool isDynamicSymbol(const LDSymbol& pSymbol, const Output& pOutput);
+
+ /// isOutputPIC - return whether the output is position-independent
+ bool isOutputPIC(const Output& pOutput, const MCLDInfo& pInfo) const;
+
+ /// isStaticLink - return whether we're doing static link
+ bool isStaticLink(const Output& pOutput, const MCLDInfo& pInfo) const;
+
+public:
+ /// symbolNeedsPLT - return whether the symbol needs a PLT entry
+ /// @ref Google gold linker, symtab.h:596
+ bool symbolNeedsPLT(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const;
+
+ /// symbolNeedsDynRel - return whether the symbol needs a dynamic relocation
+ /// @ref Google gold linker, symtab.h:645
+ bool symbolNeedsDynRel(const ResolveInfo& pSym,
+ bool pSymHasPLT,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput,
+ bool isAbsReloc) const;
+
+ /// symbolNeedsCopyReloc - return whether the symbol needs a copy relocation
+ bool symbolNeedsCopyReloc(const Layout& pLayout,
+ const Relocation& pReloc,
+ const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const;
+
private:
/// createProgramHdrs - base on output sections to create the program headers
- void createProgramHdrs(LDContext& pContext);
+ void createProgramHdrs(Output& pOutput,
+ const MCLDInfo& pInfo);
- /// writeELF32ProgramHdrs - write out the ELF32 program headers
- void writeELF32ProgramHdrs(Output& pOutput);
-
- /// writeELF64ProgramHdrs - write out the ELF64 program headers
- void writeELF64ProgramHdrs(Output& pOutput);
+ /// setupProgramHdrs - set up the attributes of segments
+ /// (i.e., offset, addresses, file/mem size, flag, and alignment)
+ void setupProgramHdrs(const Output& pOutput, const MCLDInfo& pInfo);
/// getSegmentFlag - give a section flag and return the corresponding segment
/// flag
@@ -246,6 +338,11 @@
return flag;
}
+ /// createGNUStackInfo - create an output GNU stack section or segment if needed
+ void createGNUStackInfo(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
/// preLayout - Backend can do any needed modification before layout
void preLayout(const Output& pOutput,
const MCLDInfo& pInfo,
@@ -256,16 +353,6 @@
const MCLDInfo& pInfo,
MCLinker& pLinker);
-protected:
- uint64_t getSymbolSize(const LDSymbol& pSymbol) const;
-
- uint64_t getSymbolInfo(const LDSymbol& pSymbol) const;
-
- uint64_t getSymbolValue(const LDSymbol& pSymbol) const;
-
- uint64_t getSymbolShndx(const LDSymbol& pSymbol, const Layout& pLayout) const;
-
-private:
/// preLayout - Backend can do any needed modification before layout
virtual void doPreLayout(const Output& pOutput,
const MCLDInfo& pInfo,
@@ -276,6 +363,11 @@
const MCLDInfo& pInfo,
MCLinker& pLinker) = 0;
+ /// postProcessing - Backend can do any needed modification in the final stage
+ void postProcessing(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
/// dynamic - the dynamic section of the target machine.
virtual ELFDynamic& dynamic() = 0;
@@ -283,37 +375,81 @@
virtual const ELFDynamic& dynamic() const = 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 = ~(0U) // default order
+ };
+
+ typedef HashEntry<LDSymbol*, size_t, SymCompare> HashEntryType;
+ typedef HashTable<HashEntryType, PtrHash, EntryFactory<HashEntryType> > HashTableType;
+
+protected:
// ----- readers and writers ----- //
GNUArchiveReader* m_pArchiveReader;
ELFObjectReader* m_pObjectReader;
ELFDynObjReader* m_pDynObjReader;
ELFObjectWriter* m_pObjectWriter;
ELFDynObjWriter* m_pDynObjWriter;
+ ELFExecWriter* m_pExecWriter;
// ----- file formats ----- //
ELFDynObjFileFormat* m_pDynObjFileFormat;
ELFExecFileFormat* m_pExecFileFormat;
- // ----- ELF segment factory ----- //
+ // ELF segment factory
ELFSegmentFactory m_ELFSegmentTable;
- // ----- ELF special sections ----- //
-
-protected:
- /// getHashBucketCount - calculate hash bucket count.
- /// @ref Google gold linker, dynobj.cc:791
- static unsigned getHashBucketCount(unsigned pNumOfSymbols, bool pIsGNUStyle);
-
- /// isDynamicSymbol
- /// @ref Google gold linker: symtab.cc:311
- static bool isDynamicSymbol(const LDSymbol& pSymbol, const Output& pOutput);
-
-protected:
- typedef HashEntry<LDSymbol*, size_t, SymCompare> HashEntryType;
- typedef HashTable<HashEntryType, PtrHash, EntryFactory<HashEntryType> > HashTableType;
-
- /// m_pSymIndexMap - Map the LDSymbol to its index in the output symbol table
+ // map the LDSymbol to its index in the output symbol table
HashTableType* m_pSymIndexMap;
+
+ // section .eh_frame_hdr
+ EhFrameHdr* m_pEhFrameHdr;
+
+ // ----- standard symbols ----- //
+ // section symbols
+ LDSymbol* f_pPreInitArrayStart;
+ LDSymbol* f_pPreInitArrayEnd;
+ LDSymbol* f_pInitArrayStart;
+ LDSymbol* f_pInitArrayEnd;
+ LDSymbol* f_pFiniArrayStart;
+ LDSymbol* f_pFiniArrayEnd;
+ LDSymbol* f_pStack;
+
+ // segment symbols
+ LDSymbol* f_pExecutableStart;
+ LDSymbol* f_pEText;
+ LDSymbol* f_p_EText;
+ LDSymbol* f_p__EText;
+ LDSymbol* f_pEData;
+ LDSymbol* f_p_EData;
+ LDSymbol* f_pBSSStart;
+ LDSymbol* f_pEnd;
+ LDSymbol* f_p_End;
};
} // namespace of mcld
diff --git a/include/mcld/Target/OutputRelocSection.h b/include/mcld/Target/OutputRelocSection.h
index c0cb5ca..fe83f2a 100644
--- a/include/mcld/Target/OutputRelocSection.h
+++ b/include/mcld/Target/OutputRelocSection.h
@@ -1,4 +1,4 @@
-//===- OutputRelocSection.h --------------------------------------------------===//
+//===- OutputRelocSection.h -----------------------------------------------===//
//
// The MCLinker Project
//
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef OUTPUTRELOCSECTION_H
-#define OUTPUTRELOCSECTION_H
+#ifndef MCLD_OUTPUT_RELOCATION_SECTION_H
+#define MCLD_OUTPUT_RELOCATION_SECTION_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -28,15 +28,10 @@
class OutputRelocSection
{
public:
- typedef llvm::DenseMap<const ResolveInfo*, Relocation*> SymRelMapType;
- typedef SymRelMapType::iterator SymRelMapIterator;
-
- typedef llvm::MCSectionData::iterator MCFragmentIterator;
-
-public:
OutputRelocSection(LDSection& pSection,
llvm::MCSectionData& pSectionData,
unsigned int pEntrySize);
+
~OutputRelocSection();
void reserveEntry(RelocationFactory& pRelFactory, size_t pNum=1);
@@ -46,6 +41,13 @@
bool& pExist);
private:
+ typedef llvm::DenseMap<const ResolveInfo*, Relocation*> SymRelMapType;
+
+ typedef SymRelMapType::iterator SymRelMapIterator;
+
+ typedef llvm::MCSectionData::iterator MCFragmentIterator;
+
+private:
/// m_pSection - LDSection of this Section
LDSection* m_pSection;
@@ -56,7 +58,7 @@
unsigned int m_EntryBytes;
/// m_isVisit - First time visit the function getEntry() or not
- bool m_isVisit ;
+ bool m_isVisit;
/// m_ValidEntryIterator - point to the first valid entry
MCFragmentIterator m_ValidEntryIterator;
diff --git a/include/mcld/Target/TargetLDBackend.h b/include/mcld/Target/TargetLDBackend.h
index 781b86f..205e1f2 100644
--- a/include/mcld/Target/TargetLDBackend.h
+++ b/include/mcld/Target/TargetLDBackend.h
@@ -11,6 +11,7 @@
#include <llvm/Support/DataTypes.h>
#include <mcld/MC/MCLDOutput.h>
+#include <mcld/LD/EhFrame.h>
namespace mcld {
@@ -23,6 +24,7 @@
class DynObjReader;
class ObjectWriter;
class DynObjWriter;
+class ExecWriter;
class LDContext;
class SectionMap;
class Output;
@@ -50,9 +52,9 @@
virtual bool initTargetSectionMap(SectionMap& pSectionMap) { return true;}
virtual void initTargetSegments(MCLinker& pLinker) { }
virtual void initTargetSections(MCLinker& pLinker) { }
- virtual void initTargetSymbols(MCLinker& pLinker) { }
+ virtual void initTargetSymbols(MCLinker& pLinker, const Output& pOutput) { }
virtual void initTargetRelocation(MCLinker& pLinker) { }
- virtual bool initStandardSymbols(MCLinker& pLinker) = 0;
+ virtual bool initStandardSymbols(MCLinker& pLinker, const Output& pOutput) = 0;
virtual bool initRelocFactory(const MCLinker& pLinker) = 0;
virtual RelocationFactory* getRelocFactory() = 0;
@@ -68,7 +70,8 @@
const LDSymbol& pInputSym,
MCLinker& pLinker,
const MCLDInfo& pLDInfo,
- const Output& pOutput) = 0;
+ const Output& pOutput,
+ const LDSection& pSection) = 0;
// ----- format dependent ----- //
virtual bool initArchiveReader(MCLinker&, MCLDInfo&) = 0;
@@ -76,6 +79,7 @@
virtual bool initDynObjReader(MCLinker&) = 0;
virtual bool initObjectWriter(MCLinker&) = 0;
virtual bool initDynObjWriter(MCLinker&) = 0;
+ virtual bool initExecWriter(MCLinker&) = 0;
virtual bool initExecSections(MCLinker&) = 0;
virtual bool initDynObjSections(MCLinker&) = 0;
@@ -85,6 +89,7 @@
virtual DynObjReader *getDynObjReader() = 0;
virtual ObjectWriter *getObjectWriter() = 0;
virtual DynObjWriter *getDynObjWriter() = 0;
+ virtual ExecWriter *getExecWriter() = 0;
virtual LDFileFormat* getDynObjFileFormat() = 0;
virtual LDFileFormat* getExecFileFormat() = 0;
@@ -99,21 +104,30 @@
const MCLDInfo& pInfo,
MCLinker& pLinker) = 0;
+ /// postProcessing - Backend can do any needed modification in the final stage
+ virtual void postProcessing(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker) = 0;
+
/// Is the target machine little endian? **/
virtual bool isLittleEndian() const = 0;
/// bit class. the bit length of the target machine, 32 or 64 **/
virtual unsigned int bitclass() const = 0;
- /// the page size of the target machine
- virtual unsigned int pagesize() const = 0;
+ /// the common page size of the target machine
+ virtual uint64_t commonPageSize(const MCLDInfo& pInfo) const = 0;
+
+ /// the abi page size of the target machine
+ virtual uint64_t abiPageSize(const MCLDInfo& pInfo) const = 0;
/// section start offset in the output file
virtual size_t sectionStartOffset() const = 0;
/// computeSectionOrder - compute the layout order of the given section
virtual unsigned int getSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const = 0;
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const = 0;
/// sizeNamePools - compute the size of regular name pools
/// In ELF executable files, regular name pools are .symtab, .strtab.,
@@ -127,7 +141,7 @@
/// then it will ask backend to finalize the symbol value.
/// @return ture - if backend set the symbol value sucessfully
/// @return false - if backend do not recognize the symbol
- virtual bool finalizeSymbol(LDSymbol& pSymbol) const = 0;
+ virtual bool finalizeSymbols(MCLinker& pLinker, const Output& pOutput) = 0;
/// allocateCommonSymbols - allocate common symbols in the corresponding
/// sections.
@@ -139,6 +153,22 @@
LDSection& pInputSectHdr)
{ return true; }
+ /// dyld - the name of the default dynamic linker
+ virtual const char* dyld() const = 0;
+
+ /// 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(const Output& pOutput, const MCLDInfo& pLDInfo) = 0;
+
+public:
+ EhFrame* getEhFrame();
+
+ const EhFrame* getEhFrame() const;
+
+private:
+ /// m_pEhFrame - section .eh_frame
+ EhFrame* m_pEhFrame;
+
};
} // End mcld namespace
diff --git a/include/mcld/Target/TargetMachine.h b/include/mcld/Target/TargetMachine.h
index 438edfd..02df7fd 100644
--- a/include/mcld/Target/TargetMachine.h
+++ b/include/mcld/Target/TargetMachine.h
@@ -36,7 +36,6 @@
enum CodeGenFileType {
CGFT_ASMFile,
CGFT_OBJFile,
- CGFT_ARCFile,
CGFT_DSOFile,
CGFT_EXEFile,
CGFT_NULLFile
diff --git a/lib/ADT/StringEntry.cpp b/lib/ADT/StringEntry.cpp
new file mode 100644
index 0000000..c853f83
--- /dev/null
+++ b/lib/ADT/StringEntry.cpp
@@ -0,0 +1,48 @@
+//===- StringEntry.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/ADT/StringEntry.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// StringEntry<llvm::StringRef>
+StringEntry<llvm::StringRef>::StringEntry()
+{
+}
+
+StringEntry<llvm::StringRef>::StringEntry(const StringEntry::key_type& pKey)
+{
+}
+
+StringEntry<llvm::StringRef>::StringEntry(const StringEntry<llvm::StringRef>& pCopy)
+{
+ assert("Copy constructor of StringEntry should not be called!");
+}
+
+StringEntry<llvm::StringRef>::~StringEntry()
+{
+ if (!m_Value.empty())
+ free(const_cast<char*>(m_Value.data()));
+}
+
+void StringEntry<llvm::StringRef>::setValue(llvm::StringRef& pVal)
+{
+ char* data = (char*)malloc(pVal.size()+1);
+ strcpy(data, pVal.data());
+ m_Value = llvm::StringRef(data, pVal.size());
+}
+
+void StringEntry<llvm::StringRef>::setValue(const char* pVal)
+{
+ size_t length = strlen(pVal);
+ char* data = (char*)malloc(length+1);
+ strcpy(data, pVal);
+ m_Value = llvm::StringRef(data, length);
+}
+
diff --git a/lib/CodeGen/LLVMTargetMachine.cpp b/lib/CodeGen/LLVMTargetMachine.cpp
index 13efa96..e24596c 100644
--- a/lib/CodeGen/LLVMTargetMachine.cpp
+++ b/lib/CodeGen/LLVMTargetMachine.cpp
@@ -231,10 +231,6 @@
pPM.add(createGCInfoDeleter()); // not in addPassesToMC
break;
}
- case CGFT_ARCFile: {
- assert(0 && "Output to archive file has not been supported yet!");
- break;
- }
case CGFT_EXEFile: {
if (pLinkerOpt == NULL)
return true;
@@ -378,7 +374,7 @@
return true;
pPM.add(printer);
#endif
- TargetLDBackend* ldBackend = getTarget().createLDBackend(*getTarget().get(), m_Triple);
+ TargetLDBackend* ldBackend = getTarget().createLDBackend(m_Triple);
if (0 == ldBackend)
return true;
@@ -410,3 +406,4 @@
pPM.add(funcPass);
return false;
}
+
diff --git a/lib/CodeGen/SectLinker.cpp b/lib/CodeGen/SectLinker.cpp
index 95e9e4f..4f32c4f 100644
--- a/lib/CodeGen/SectLinker.cpp
+++ b/lib/CodeGen/SectLinker.cpp
@@ -10,19 +10,20 @@
// This file implements the SectLinker class.
//
//===----------------------------------------------------------------------===//
-
-#include <mcld/ADT/BinTree.h>
+#include <mcld/Support/FileHandle.h>
+#include <mcld/MC/InputTree.h>
+#include <mcld/MC/MCLDDriver.h>
+#include <mcld/Support/FileSystem.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/FileHandle.h>
+#include <mcld/Support/raw_ostream.h>
+#include <mcld/Support/MemoryAreaFactory.h>
+#include <mcld/Support/DerivedPositionDependentOptions.h>
+#include <mcld/Target/TargetLDBackend.h>
#include <mcld/CodeGen/SectLinker.h>
#include <mcld/CodeGen/SectLinkerOption.h>
-#include <mcld/MC/MCLDInputTree.h>
-#include <mcld/MC/MCLDDriver.h>
-#include <mcld/Support/DerivedPositionDependentOptions.h>
-#include <mcld/Support/FileSystem.h>
-#include <mcld/Target/TargetLDBackend.h>
#include <llvm/Module.h>
-#include <llvm/Support/ErrorHandling.h>
-#include <llvm/Support/raw_ostream.h>
#include <algorithm>
#include <stack>
@@ -44,11 +45,16 @@
: MachineFunctionPass(m_ID),
m_pOption(&pOption),
m_pLDBackend(&pLDBackend),
- m_pLDDriver(NULL) { }
+ m_pLDDriver(NULL),
+ m_pMemAreaFactory(NULL)
+{
+ m_pMemAreaFactory = new MemoryAreaFactory(32);
+}
SectLinker::~SectLinker()
{
delete m_pLDDriver;
+
// FIXME: current implementation can not change the order of delete.
//
// Instance of TargetLDBackend was created outside and is not managed by
@@ -57,36 +63,19 @@
// objects it used during the processing, we destroy the object of
// TargetLDBackend here.
delete m_pLDBackend;
+
+ delete m_pMemAreaFactory;
}
bool SectLinker::doInitialization(Module &pM)
{
MCLDInfo &info = m_pOption->info();
- // setup the output
- info.output().setContext(info.contextFactory().produce(info.output().path()));
-
- int mode = (Output::Object == info.output().type())? 0544 : 0755;
- info.output().setMemArea(
- info.memAreaFactory().produce(info.output().path(),
- O_RDWR | O_CREAT | O_TRUNC,
- mode));
-
- // make sure output is openend successfully.
- if (!info.output().hasMemArea())
- report_fatal_error("output is not given on the command line\n");
-
- if (!info.output().memArea()->isGood())
- report_fatal_error("can not open output file :"+info.output().path().native());
-
- // let the target override the target-specific parameters
- addTargetOptions(pM, *m_pOption);
-
// ----- convert position dependent options into tree of input files ----- //
PositionDependentOptions &PosDepOpts = m_pOption->pos_dep_options();
std::stable_sort(PosDepOpts.begin(), PosDepOpts.end(), CompareOption);
initializeInputTree(PosDepOpts);
-
+ initializeInputOutput(info);
// Now, all input arguments are prepared well, send it into MCLDDriver
m_pLDDriver = new MCLDDriver(info, *m_pLDBackend);
@@ -97,42 +86,45 @@
{
const MCLDInfo &info = m_pOption->info();
- // 3. - initialize output's standard segments and sections
+ // 2. - initialize MCLinker
if (!m_pLDDriver->initMCLinker())
return true;
+ // 3. - initialize output's standard sections
+ if (!m_pLDDriver->initStdSections())
+ return true;
+
// 4. - normalize the input tree
m_pLDDriver->normalize();
- if (info.options().verbose()) {
- outs() << "MCLinker (LLVM Sub-project) - ";
- outs() << MCLDInfo::version();
- outs() << "\n";
- }
-
if (info.options().trace()) {
static int counter = 0;
- outs() << "** name\ttype\tpath\tsize (" << info.inputs().size() << ")\n";
+ mcld::outs() << "** name\ttype\tpath\tsize (" << info.inputs().size() << ")\n";
InputTree::const_dfs_iterator input, inEnd = info.inputs().dfs_end();
for (input=info.inputs().dfs_begin(); input!=inEnd; ++input) {
- outs() << counter++ << " * " << (*input)->name();
+ mcld::outs() << counter++ << " * " << (*input)->name();
switch((*input)->type()) {
case Input::Archive:
- outs() << "\tarchive\t(";
+ mcld::outs() << "\tarchive\t(";
break;
case Input::Object:
- outs() << "\tobject\t(";
+ mcld::outs() << "\tobject\t(";
break;
case Input::DynObj:
- outs() << "\tshared\t(";
+ mcld::outs() << "\tshared\t(";
break;
case Input::Script:
- outs() << "\tscript\t(";
+ mcld::outs() << "\tscript\t(";
+ break;
+ case Input::External:
+ mcld::outs() << "\textern\t(";
break;
default:
- report_fatal_error("** Trace a unsupported file. It must be an internal bug!");
+ unreachable(diag::err_cannot_trace_file) << (*input)->type()
+ << (*input)->name()
+ << (*input)->path();
}
- outs() << (*input)->path().c_str() << ")\n";
+ mcld::outs() << (*input)->path() << ")\n";
}
}
@@ -147,8 +139,7 @@
return true;
// 7. - read all symbol tables of input files and resolve them
- if (!m_pLDDriver->readSymbolTables() ||
- !m_pLDDriver->mergeSymbolTables())
+ if (!m_pLDDriver->readSymbolTables())
return true;
// 7.a - add standard symbols and target-dependent symbols
@@ -173,7 +164,7 @@
m_pLDDriver->finalizeSymbolValue();
// 12. - apply relocations
- m_pLDDriver->relocate();
+ m_pLDDriver->relocation();
// 13. - write out output
m_pLDDriver->emitOutput();
@@ -189,86 +180,188 @@
return false;
}
+void SectLinker::initializeInputOutput(MCLDInfo &pLDInfo)
+{
+ // ----- initialize output file ----- //
+ FileHandle::Permission perm;
+ if (Output::Object == pLDInfo.output().type())
+ perm = 0544;
+ else
+ perm = 0755;
+
+ MemoryArea* out_area = memAreaFactory()->produce(pLDInfo.output().path(),
+ FileHandle::ReadWrite,
+ perm);
+
+ if (!out_area->handler()->isGood()) {
+ // make sure output is openend successfully.
+ fatal(diag::err_cannot_open_output_file) << pLDInfo.output().name()
+ << pLDInfo.output().path();
+ }
+
+ pLDInfo.output().setMemArea(out_area);
+ pLDInfo.output().setContext(pLDInfo.contextFactory().produce());
+
+ // ----- initialize input files ----- //
+ InputTree::dfs_iterator input, inEnd = pLDInfo.inputs().dfs_end();
+ for (input = pLDInfo.inputs().dfs_begin(); input!=inEnd; ++input) {
+ // already got type - for example, bitcode
+ if ((*input)->type() == Input::Script ||
+ (*input)->type() == Input::Object ||
+ (*input)->type() == Input::DynObj ||
+ (*input)->type() == Input::Archive)
+ continue;
+
+ MemoryArea *input_memory =
+ memAreaFactory()->produce((*input)->path(), FileHandle::ReadOnly);
+
+ if (input_memory->handler()->isGood()) {
+ (*input)->setMemArea(input_memory);
+ }
+ else {
+ error(diag::err_cannot_open_input) << (*input)->name() << (*input)->path();
+ return;
+ }
+
+ LDContext *input_context =
+ pLDInfo.contextFactory().produce((*input)->path());
+
+ (*input)->setContext(input_context);
+ }
+}
+
void SectLinker::initializeInputTree(const PositionDependentOptions &pPosDepOptions) const
{
if (pPosDepOptions.empty())
- return;
+ fatal(diag::err_no_inputs);
MCLDInfo &info = m_pOption->info();
- PositionDependentOptions::const_iterator cur_char = pPosDepOptions.begin();
+ PositionDependentOptions::const_iterator option = pPosDepOptions.begin();
if (1 == pPosDepOptions.size() &&
- ((*cur_char)->type() != PositionDependentOption::INPUT_FILE &&
- (*cur_char)->type() != PositionDependentOption::NAMESPEC))
- return;
+ ((*option)->type() != PositionDependentOption::INPUT_FILE &&
+ (*option)->type() != PositionDependentOption::NAMESPEC) &&
+ (*option)->type() != PositionDependentOption::BITCODE) {
+ // if we only have one positional options, and the option is
+ // not an input file, then emit error message.
+ fatal(diag::err_no_inputs);
+ }
- InputTree::Connector *prev_ward = &InputTree::Downward;
+ // ----- Input tree insertion algorithm ----- //
+ // The type of the previsou node indicates the direction of the current
+ // insertion.
+ //
+ // root : the parent node who being inserted.
+ // mover : the direcion of current movement.
+ //
+ // for each positional options:
+ // insert the options in current root.
+ // calculate the next movement
+ // Initialization
+ InputTree::Mover *move = &InputTree::Downward;
+ InputTree::iterator root = info.inputs().root();
+ PositionDependentOptions::const_iterator optionEnd = pPosDepOptions.end();
std::stack<InputTree::iterator> returnStack;
- InputTree::iterator cur_node = info.inputs().root();
- PositionDependentOptions::const_iterator charEnd = pPosDepOptions.end();
- while (cur_char != charEnd ) {
- switch ((*cur_char)->type()) {
- case PositionDependentOption::BITCODE: {
- // threat bitcode as a script in this version.
- const BitcodeOption *bitcode_option =
- static_cast<const BitcodeOption*>(*cur_char);
- info.inputs().insert(cur_node,
- *prev_ward,
- bitcode_option->path()->native(),
- *(bitcode_option->path()),
- Input::Script);
- info.setBitcode(**cur_node);
- prev_ward->move(cur_node);
- prev_ward = &InputTree::Afterward;
- break;
- }
- case PositionDependentOption::INPUT_FILE: {
- const InputFileOption *input_file_option =
- static_cast<const InputFileOption*>(*cur_char);
- info.inputs().insert(cur_node,
- *prev_ward,
- input_file_option->path()->native(),
- *(input_file_option->path()));
- prev_ward->move(cur_node);
- prev_ward = &InputTree::Afterward;
- break;
- }
+ while (option != optionEnd ) {
+
+ switch ((*option)->type()) {
+ /** bitcode **/
+ case PositionDependentOption::BITCODE: {
+
+ const BitcodeOption *bitcode_option =
+ static_cast<const BitcodeOption*>(*option);
+
+ // threat bitcode as an external IR in this version.
+ info.inputs().insert(root, *move,
+ bitcode_option->path()->native(),
+ *(bitcode_option->path()),
+ Input::External);
+
+ info.setBitcode(**root);
+
+ // move root on the new created node.
+ move->move(root);
+
+ // the next file is appended after bitcode file.
+ move = &InputTree::Afterward;
+ break;
+ }
+
+ /** input object file **/
+ case PositionDependentOption::INPUT_FILE: {
+ const InputFileOption *input_file_option =
+ static_cast<const InputFileOption*>(*option);
+
+ info.inputs().insert(root, *move,
+ input_file_option->path()->native(),
+ *(input_file_option->path()));
+
+ // move root on the new created node.
+ move->move(root);
+
+ // the next file is appended after object file.
+ move = &InputTree::Afterward;
+ break;
+ }
+
+ /** -lnamespec **/
case PositionDependentOption::NAMESPEC: {
- sys::fs::Path* path = 0;
+ sys::fs::Path* path = NULL;
const NamespecOption *namespec_option =
- static_cast<const NamespecOption*>(*cur_char);
- if (info.attrFactory().last().isStatic()) {
+ static_cast<const NamespecOption*>(*option);
+
+ // find out the real path of the namespec.
+ if (info.attrFactory().constraint().isSharedSystem()) {
+ // In the system with shared object support, we can find both archive
+ // and shared object.
+
+ if (info.attrFactory().last().isStatic()) {
+ // with --static, we must search an archive.
+ path = info.options().directories().find(namespec_option->namespec(),
+ Input::Archive);
+ }
+ else {
+ // otherwise, with --Bdynamic, we can find either an archive or a
+ // shared object.
+ path = info.options().directories().find(namespec_option->namespec(),
+ Input::DynObj);
+ }
+ }
+ else {
+ // In the system without shared object support, we only look for an
+ // archive.
path = info.options().directories().find(namespec_option->namespec(),
Input::Archive);
}
- else {
- path = info.options().directories().find(namespec_option->namespec(),
- Input::DynObj);
- }
- if (0 == path) {
- llvm::report_fatal_error(std::string("Can't find namespec: ")+
- namespec_option->namespec());
- }
- info.inputs().insert(cur_node,
- *prev_ward,
+ if (NULL == path)
+ fatal(diag::err_cannot_find_namespec) << namespec_option->namespec();
+
+ info.inputs().insert(root, *move,
namespec_option->namespec(),
*path);
- prev_ward->move(cur_node);
- prev_ward = &InputTree::Afterward;
+
+ // iterate root on the new created node.
+ move->move(root);
+
+ // the file after a namespec must be appended afterward.
+ move = &InputTree::Afterward;
break;
}
+
+ /** start group **/
case PositionDependentOption::START_GROUP:
- info.inputs().enterGroup(cur_node, *prev_ward);
- prev_ward->move(cur_node);
- returnStack.push(cur_node);
- prev_ward = &InputTree::Downward;
+ info.inputs().enterGroup(root, *move);
+ move->move(root);
+ returnStack.push(root);
+ move = &InputTree::Downward;
break;
+ /** end group **/
case PositionDependentOption::END_GROUP:
- cur_node = returnStack.top();
+ root = returnStack.top();
returnStack.pop();
- prev_ward = &InputTree::Afterward;
+ move = &InputTree::Afterward;
break;
case PositionDependentOption::WHOLE_ARCHIVE:
info.attrFactory().last().setWholeArchive();
@@ -295,10 +388,11 @@
info.attrFactory().last().setDynamic();
break;
default:
- report_fatal_error("can not find the type of input file");
- }
- ++cur_char;
- }
+ fatal(diag::err_cannot_identify_option) << (*option)->position()
+ << (uint32_t)(*option)->type();
+ } // end of switch
+ ++option;
+ } // end of while
if (!returnStack.empty()) {
report_fatal_error("no matched --start-group and --end-group");
diff --git a/lib/LD/BSDArchiveReader.cpp b/lib/LD/BSDArchiveReader.cpp
index 1264824..079153b 100644
--- a/lib/LD/BSDArchiveReader.cpp
+++ b/lib/LD/BSDArchiveReader.cpp
@@ -6,9 +6,9 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/MC/MCLDInput.h"
-#include "mcld/MC/MCLDInputTree.h"
-#include "mcld/LD/BSDArchiveReader.h"
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/InputTree.h>
+#include <mcld/LD/BSDArchiveReader.h>
using namespace mcld;
diff --git a/lib/LD/CIE.cpp b/lib/LD/CIE.cpp
new file mode 100644
index 0000000..c2f4317
--- /dev/null
+++ b/lib/LD/CIE.cpp
@@ -0,0 +1,23 @@
+//===- CIE.cpp ------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/EhFrame.h>
+#include <mcld/LD/CIE.h>
+
+using namespace mcld;
+
+//==========================
+// CIE
+
+CIE::CIE(MemoryRegion& pRegion, uint8_t pFDEEncode)
+ : MCRegionFragment(pRegion), m_FDEEncoding(pFDEEncode) {
+}
+
+CIE::~CIE()
+{
+}
diff --git a/lib/LD/DWARFLineInfo.cpp b/lib/LD/DWARFLineInfo.cpp
new file mode 100644
index 0000000..63c588d
--- /dev/null
+++ b/lib/LD/DWARFLineInfo.cpp
@@ -0,0 +1,15 @@
+//===- DWARFLineInfo.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/DWARFLineInfo.h>
+
+using namespace mcld;
+
+//==========================
+// DWARFLineInfo
+
diff --git a/lib/LD/Diagnostic.cpp b/lib/LD/Diagnostic.cpp
new file mode 100644
index 0000000..5175ebd
--- /dev/null
+++ b/lib/LD/Diagnostic.cpp
@@ -0,0 +1,173 @@
+//===- Diagnostic.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/Diagnostic.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/ADT/Twine.h>
+#include <ctype.h>
+#include <algorithm>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// Diagnostic
+Diagnostic::Diagnostic(DiagnosticEngine& pEngine)
+ : m_Engine(pEngine) {
+}
+
+Diagnostic::~Diagnostic()
+{
+}
+
+// format - format this diagnostic into string, subsituting the formal
+// arguments. The result is appended at on the pOutStr.
+void Diagnostic::format(std::string& pOutStr) const
+{
+ // we've not implemented DWARF LOC messages yet. So, keep pIsLoC false
+ llvm::StringRef desc = m_Engine.infoMap().getDescription(getID(), false);
+
+ format(desc.begin(), desc.end(), pOutStr);
+}
+
+const char* Diagnostic::findMatch(char pVal,
+ const char* pBegin, const char* pEnd ) const
+{
+ unsigned int depth = 0;
+ for (; pBegin != pEnd; ++pBegin) {
+ if (0 == depth && *pBegin == pVal)
+ return pBegin;
+ if (0 != depth && *pBegin == '}')
+ --depth;
+
+ if ('%' == *pBegin) {
+ ++pBegin;
+ if (pBegin == pEnd)
+ break;
+
+ if (!isdigit(*pBegin) && !ispunct(*pBegin)) {
+ ++pBegin;
+ while (pBegin != pEnd && !isdigit(*pBegin) && *pBegin != '{')
+ ++pBegin;
+
+ if (pBegin == pEnd)
+ break;
+ if ('{' == *pBegin)
+ ++depth;
+ }
+ }
+ } // end of for
+ return pEnd;
+}
+
+// format - format the given formal string, subsituting the formal
+// arguments. The result is appended at on the pOutStr.
+void Diagnostic::format(const char* pBegin, const char* pEnd,
+ std::string& pOutStr) const
+{
+ const char* cur_char = pBegin;
+ while (cur_char != pEnd) {
+ if ('%' != *cur_char) {
+ const char* new_end = std::find(cur_char, pEnd, '%');
+ pOutStr.append(cur_char, new_end);
+ cur_char = new_end;
+ continue;
+ }
+ else if (ispunct(cur_char[1])) {
+ pOutStr.push_back(cur_char[1]); // %% -> %.
+ cur_char += 2;
+ continue;
+ }
+
+ // skip the %.
+ ++cur_char;
+
+ const char* modifier = NULL, *argument = NULL;
+ size_t modifier_len = 0, argument_len = 0;
+
+ // we get a modifier
+ if (!isdigit(*cur_char)) {
+ modifier = cur_char;
+ while (*cur_char == '-' || (*cur_char >= 'a' && *cur_char <= 'z'))
+ ++cur_char;
+ modifier_len = cur_char - modifier;
+
+ // we get an argument
+ if ('{' == *cur_char) {
+ ++cur_char; // skip '{'
+ argument = cur_char;
+ cur_char = findMatch('}', cur_char, pEnd);
+
+ if (cur_char == pEnd) {
+ // DIAG's format error
+ llvm::report_fatal_error(llvm::Twine("Mismatched {} in the diagnostic: ") +
+ llvm::Twine(getID()));
+ }
+
+ argument_len = cur_char - argument;
+ ++cur_char; // skip '}'
+ }
+ }
+ if (!isdigit(*cur_char)) {
+ llvm::report_fatal_error(llvm::Twine("In diagnostic: ") +
+ llvm::Twine(getID()) + llvm::Twine(": ") +
+ llvm::Twine(pBegin) +
+ llvm::Twine("\nNo given arugment number:\n"));
+ }
+
+ unsigned int arg_no = *cur_char - '0';
+ ++cur_char; // skip argument number
+
+ DiagnosticEngine::ArgumentKind kind = getArgKind(arg_no);
+ switch (kind) {
+ case DiagnosticEngine::ak_std_string: {
+ if (0 != modifier_len) {
+ llvm::report_fatal_error(llvm::Twine("In diagnostic: ") +
+ llvm::Twine(getID()) +
+ llvm::Twine(": ") + llvm::Twine(pBegin) +
+ llvm::Twine("\nNo modifiers for strings yet\n"));
+ }
+ const std::string& str = getArgStdStr(arg_no);
+ pOutStr.append(str.begin(), str.end());
+ break;
+ }
+ case DiagnosticEngine::ak_c_string: {
+ if (0 != modifier_len) {
+ llvm::report_fatal_error(llvm::Twine("In diagnostic: ") +
+ llvm::Twine(getID()) +
+ llvm::Twine(": ") + llvm::Twine(pBegin) +
+ llvm::Twine("\nNo modifiers for strings yet\n"));
+ }
+ const char* str = getArgCStr(arg_no);
+ if (NULL == str)
+ str = "(null)";
+ pOutStr.append(str);
+ break;
+ }
+ case DiagnosticEngine::ak_sint: {
+ int val = getArgSInt(arg_no);
+ llvm::raw_string_ostream(pOutStr) << val;
+ break;
+ }
+ case DiagnosticEngine::ak_uint: {
+ unsigned int val = getArgUInt(arg_no);
+ llvm::raw_string_ostream(pOutStr) << val;
+ break;
+ }
+ case DiagnosticEngine::ak_bool: {
+ bool val = getArgBool(arg_no);
+ if (val)
+ pOutStr.append("true");
+ else
+ pOutStr.append("false");
+ break;
+ }
+ } // end of switch
+ } // end of while
+}
+
diff --git a/lib/LD/DiagnosticEngine.cpp b/lib/LD/DiagnosticEngine.cpp
new file mode 100644
index 0000000..11dbe1b
--- /dev/null
+++ b/lib/LD/DiagnosticEngine.cpp
@@ -0,0 +1,58 @@
+//===- DiagnosticEngine.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/DiagnosticEngine.h>
+#include <mcld/LD/DiagnosticPrinter.h>
+#include <mcld/LD/DiagnosticLineInfo.h>
+#include <mcld/MC/MCLDInfo.h>
+
+using namespace mcld;
+
+//==========================
+// DiagnosticEngine
+DiagnosticEngine::DiagnosticEngine(const MCLDInfo& pLDInfo,
+ DiagnosticLineInfo* pLineInfo,
+ DiagnosticPrinter* pPrinter,
+ bool pShouldOwnPrinter)
+ : m_LDInfo(pLDInfo),
+ m_pLineInfo(pLineInfo),
+ m_pPrinter(pPrinter),
+ m_InfoMap(pLDInfo),
+ m_OwnPrinter(pShouldOwnPrinter) {
+ if (NULL == m_pPrinter) {
+ m_pPrinter = new DiagnosticPrinter(); // Dumb printer
+ m_OwnPrinter = true;
+ }
+}
+
+DiagnosticEngine::~DiagnosticEngine()
+{
+ if (m_OwnPrinter && m_pPrinter != NULL)
+ delete m_pPrinter;
+
+ if (NULL != m_pLineInfo)
+ delete m_pLineInfo;
+}
+
+void DiagnosticEngine::setPrinter(DiagnosticPrinter& pPrinter,
+ bool pShouldOwnPrinter)
+{
+ if (m_OwnPrinter && m_pPrinter != NULL)
+ delete m_pPrinter;
+ m_pPrinter = &pPrinter;
+ m_OwnPrinter = pShouldOwnPrinter;
+}
+
+// emit - process current diagnostic.
+bool DiagnosticEngine::emit()
+{
+ bool emitted = m_InfoMap.process(*this);
+ m_State.reset();
+ return emitted;
+}
+
diff --git a/lib/LD/DiagnosticInfos.cpp b/lib/LD/DiagnosticInfos.cpp
new file mode 100644
index 0000000..b9a6fa9
--- /dev/null
+++ b/lib/LD/DiagnosticInfos.cpp
@@ -0,0 +1,149 @@
+//===- DiagnosticInfo.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/DataTypes.h>
+
+#include <mcld/ADT/SizeTraits.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/LD/Diagnostic.h>
+#include <mcld/LD/DiagnosticInfos.h>
+#include <mcld/LD/DiagnosticPrinter.h>
+
+using namespace mcld;
+
+namespace {
+
+struct DiagStaticInfo
+{
+public:
+ uint16_t ID;
+ DiagnosticEngine::Severity Severity;
+ uint16_t DescriptionLen;
+ const char* DescriptionStr;
+
+public:
+ llvm::StringRef getDescription() const
+ { return llvm::StringRef(DescriptionStr, DescriptionLen); }
+
+ bool operator<(const DiagStaticInfo& pRHS) const
+ { return (ID < pRHS.ID); }
+};
+
+} // namespace anonymous
+
+static const DiagStaticInfo DiagCommonInfo[] = {
+#define DIAG(ENUM, CLASS, ADDRDESC, LOCDESC) \
+ { diag::ENUM, CLASS, STR_SIZE(ADDRDESC, uint16_t), ADDRDESC },
+#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"
+#undef DIAG
+ { 0, DiagnosticEngine::None, 0, 0}
+};
+
+static const unsigned int DiagCommonInfoSize =
+ sizeof(DiagCommonInfo)/sizeof(DiagCommonInfo[0])-1;
+
+static const DiagStaticInfo DiagLoCInfo[] = {
+#define DIAG(ENUM, CLASS, ADDRDESC, LOCDESC) \
+ { diag::ENUM, CLASS, STR_SIZE(LOCDESC, uint16_t), LOCDESC },
+#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"
+#undef DIAG
+ { 0, DiagnosticEngine::None, 0, 0}
+};
+
+static const unsigned int DiagLoCInfoSize =
+ sizeof(DiagLoCInfo)/sizeof(DiagLoCInfo[0])-1;
+
+
+static const DiagStaticInfo* getDiagInfo(unsigned int pID, bool pInLoC = false)
+{
+ const DiagStaticInfo* static_info = (pInLoC)?DiagLoCInfo:DiagCommonInfo;
+ unsigned int info_size = (pInLoC)?DiagLoCInfoSize:DiagCommonInfoSize;
+
+ DiagStaticInfo key = { static_cast<uint16_t>(pID), DiagnosticEngine::None, 0, 0 };
+ const DiagStaticInfo *result = std::lower_bound(static_info, static_info + info_size, key);
+
+ if (result == (static_info + info_size) || result->ID != pID)
+ return NULL;
+
+ return result;
+}
+
+//===----------------------------------------------------------------------===//
+// DiagnosticInfos
+DiagnosticInfos::DiagnosticInfos(const MCLDInfo& pLDInfo)
+ : m_LDInfo(pLDInfo) {
+}
+
+DiagnosticInfos::~DiagnosticInfos()
+{
+}
+
+llvm::StringRef DiagnosticInfos::getDescription(unsigned int pID, bool pInLoC) const
+{
+ return getDiagInfo(pID, pInLoC)->getDescription();
+}
+
+bool DiagnosticInfos::process(DiagnosticEngine& pEngine) const
+{
+ Diagnostic info(pEngine);
+
+ unsigned int ID = info.getID();
+
+ // we are not implement LineInfo, so keep pIsLoC false.
+ const DiagStaticInfo* static_info = getDiagInfo(ID);
+
+ DiagnosticEngine::Severity severity = static_info->Severity;
+
+ switch (ID) {
+ case diag::multiple_definitions: {
+ if (m_LDInfo.options().hasMulDefs()) {
+ severity = DiagnosticEngine::Ignore;
+ }
+ break;
+ }
+ case diag::undefined_reference: {
+ // 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_LDInfo.output().type()) {
+ case Output::Object:
+ if (m_LDInfo.options().isNoUndefined())
+ severity = DiagnosticEngine::Error;
+ else
+ severity = DiagnosticEngine::Ignore;
+ break;
+ case Output::DynObj:
+ if (m_LDInfo.options().isNoUndefined() || !m_LDInfo.options().isAllowShlibUndefined())
+ severity = DiagnosticEngine::Error;
+ else
+ severity = DiagnosticEngine::Ignore;
+ break;
+ case Output::Exec:
+ severity = DiagnosticEngine::Error;
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ } // end of switch
+
+ // finally, report it.
+ pEngine.getPrinter()->handleDiagnostic(severity, info);
+ return true;
+}
+
diff --git a/lib/LD/DiagnosticLineInfo.cpp b/lib/LD/DiagnosticLineInfo.cpp
new file mode 100644
index 0000000..d3c9190
--- /dev/null
+++ b/lib/LD/DiagnosticLineInfo.cpp
@@ -0,0 +1,15 @@
+//===- DiagnosticLineInfo.cpp ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/DiagnosticLineInfo.h>
+
+using namespace mcld;
+
+//==========================
+// DiagnosticLineInfo
+
diff --git a/lib/LD/DiagnosticPrinter.cpp b/lib/LD/DiagnosticPrinter.cpp
new file mode 100644
index 0000000..7bbf473
--- /dev/null
+++ b/lib/LD/DiagnosticPrinter.cpp
@@ -0,0 +1,34 @@
+//===- DiagnosticPrinter.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/DiagnosticPrinter.h>
+
+using namespace mcld;
+
+//==========================
+// DiagnosticPrinter
+DiagnosticPrinter::DiagnosticPrinter()
+ : m_NumErrors(0), m_NumWarnings(0) {
+}
+
+DiagnosticPrinter::~DiagnosticPrinter()
+{
+ clear();
+}
+
+/// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
+/// capturing it to a log as needed.
+void DiagnosticPrinter::handleDiagnostic(DiagnosticEngine::Severity pSeverity,
+ const Diagnostic& pInfo)
+{
+ if (pSeverity == DiagnosticEngine::Warning)
+ ++m_NumWarnings;
+ else if (pSeverity <= DiagnosticEngine::Error)
+ ++m_NumErrors;
+}
+
diff --git a/lib/LD/ELFDynObjFileFormat.cpp b/lib/LD/ELFDynObjFileFormat.cpp
index 77034eb..30183cc 100644
--- a/lib/LD/ELFDynObjFileFormat.cpp
+++ b/lib/LD/ELFDynObjFileFormat.cpp
@@ -6,11 +6,11 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include <llvm/Support/ELF.h>
#include <mcld/LD/ELFDynObjFileFormat.h>
#include <mcld/LD/LDFileFormat.h>
#include <mcld/LD/LDSection.h>
#include <mcld/MC/MCLinker.h>
-#include <llvm/Support/ELF.h>
#include <mcld/Target/GNULDBackend.h>
using namespace mcld;
@@ -77,5 +77,10 @@
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
f_Backend.bitclass() / 8);
+ f_pEhFrameHdr = &pLinker.getOrCreateOutputSectHdr(".eh_frame_hdr",
+ LDFileFormat::EhFrameHdr,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x4);
}
diff --git a/lib/LD/ELFDynObjReader.cpp b/lib/LD/ELFDynObjReader.cpp
index 12e6d7c..de36104 100644
--- a/lib/LD/ELFDynObjReader.cpp
+++ b/lib/LD/ELFDynObjReader.cpp
@@ -69,9 +69,13 @@
MemoryRegion* region = pInput.memArea()->request(0, hdr_size);
uint8_t* ELF_hdr = region->start();
- bool result = m_pELFReader->readSectionHeaders(pInput, m_Linker, ELF_hdr);
+ bool shdr_result = m_pELFReader->readSectionHeaders(pInput, m_Linker, ELF_hdr);
pInput.memArea()->release(region);
- return result;
+
+ // read .dynamic to get the correct SONAME
+ bool dyn_result = m_pELFReader->readDynamic(pInput);
+
+ return (shdr_result && dyn_result);
}
/// readSymbols
@@ -80,9 +84,20 @@
assert(pInput.hasMemArea());
LDSection* symtab_shdr = pInput.context()->getSection(".dynsym");
+ if (NULL == symtab_shdr) {
+ note(diag::note_has_no_symtab) << pInput.name()
+ << pInput.path()
+ << ".dynsym";
+ return true;
+ }
+
LDSection* strtab_shdr = symtab_shdr->getLink();
- if (NULL == symtab_shdr || NULL == strtab_shdr)
+ if (NULL == strtab_shdr) {
+ fatal(diag::fatal_cannot_read_strtab) << pInput.name()
+ << pInput.path()
+ << ".dynsym";
return false;
+ }
MemoryRegion* symtab_region = pInput.memArea()->request(symtab_shdr->offset(),
symtab_shdr->size());
diff --git a/lib/LD/ELFDynObjWriter.cpp b/lib/LD/ELFDynObjWriter.cpp
index 21cd8e4..cabc9e9 100644
--- a/lib/LD/ELFDynObjWriter.cpp
+++ b/lib/LD/ELFDynObjWriter.cpp
@@ -58,7 +58,10 @@
switch(sect->kind()) {
case LDFileFormat::Regular:
case LDFileFormat::Relocation:
- case LDFileFormat::Target: {
+ case LDFileFormat::Target:
+ case LDFileFormat::Debug:
+ case LDFileFormat::GCCExceptTable:
+ case LDFileFormat::EhFrame: {
region = pOutput.memArea()->request(sect->offset(), sect->size());
if (NULL == region) {
llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section[") +
@@ -72,11 +75,10 @@
case LDFileFormat::Null:
case LDFileFormat::NamePool:
case LDFileFormat::BSS:
- case LDFileFormat::Debug:
case LDFileFormat::Note:
case LDFileFormat::MetaData:
- case LDFileFormat::Exception:
case LDFileFormat::Version:
+ case LDFileFormat::EhFrameHdr:
// ignore these sections
continue;
default: {
@@ -91,7 +93,12 @@
// write out sections with data
switch(sect->kind()) {
- case LDFileFormat::Regular: {
+ case LDFileFormat::Regular:
+ case LDFileFormat::Debug:
+ case LDFileFormat::GCCExceptTable:
+ case LDFileFormat::EhFrame: {
+ // FIXME: if optimization of exception handling sections is enabled,
+ // then we should emit these sections by the other way.
emitSectionData(m_Linker.getLayout(), *sect, *region);
break;
}
@@ -99,11 +106,16 @@
emitRelocation(m_Linker.getLayout(), pOutput, *sect, *region);
break;
case LDFileFormat::Target:
- target().emitSectionData(pOutput, *sect, m_Linker.getLDInfo(), *region);
+ target().emitSectionData(pOutput,
+ *sect,
+ m_Linker.getLDInfo(),
+ m_Linker.getLayout(),
+ *region);
break;
default:
continue;
}
+
} // end of for loop
if (32 == target().bitclass()) {
@@ -116,6 +128,8 @@
target(),
pOutput);
+ emitELF32ProgramHeader(pOutput, target());
+
emitELF32SectionHeader(pOutput, m_Linker);
}
else if (64 == target().bitclass()) {
@@ -128,11 +142,13 @@
target(),
pOutput);
+ emitELF64ProgramHeader(pOutput, target());
+
emitELF64SectionHeader(pOutput, m_Linker);
}
else
return make_error_code(errc::not_supported);
-
+ pOutput.memArea()->clear();
return llvm::make_error_code(llvm::errc::success);
}
diff --git a/lib/LD/ELFExecFileFormat.cpp b/lib/LD/ELFExecFileFormat.cpp
index f10d764..8ae0de0 100644
--- a/lib/LD/ELFExecFileFormat.cpp
+++ b/lib/LD/ELFExecFileFormat.cpp
@@ -6,8 +6,81 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include <llvm/Support/ELF.h>
#include <mcld/LD/ELFExecFileFormat.h>
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/LD/LDSection.h>
#include <mcld/MC/MCLinker.h>
+#include <mcld/Target/GNULDBackend.h>
using namespace mcld;
+void ELFExecFileFormat::initObjectType(MCLinker& pLinker)
+{
+ // FIXME: make sure ELF executable files has these sections.
+ f_pDynSymTab = &pLinker.getOrCreateOutputSectHdr(".dynsym",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_DYNSYM,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pDynStrTab = &pLinker.getOrCreateOutputSectHdr(".dynstr",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_STRTAB,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ f_pInterp = &pLinker.getOrCreateOutputSectHdr(".interp",
+ LDFileFormat::Note,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ f_pHashTab = &pLinker.getOrCreateOutputSectHdr(".hash",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_HASH,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pDynamic = &pLinker.getOrCreateOutputSectHdr(".dynamic",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_DYNAMIC,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ f_Backend.bitclass() / 8);
+ f_pRelaDyn = &pLinker.getOrCreateOutputSectHdr(".rela.dyn",
+ LDFileFormat::Relocation,
+ llvm::ELF::SHT_RELA,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pRelaPlt = &pLinker.getOrCreateOutputSectHdr(".rela.plt",
+ LDFileFormat::Relocation,
+ llvm::ELF::SHT_RELA,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pRelDyn = &pLinker.getOrCreateOutputSectHdr(".rel.dyn",
+ LDFileFormat::Relocation,
+ llvm::ELF::SHT_REL,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pRelPlt = &pLinker.getOrCreateOutputSectHdr(".rel.plt",
+ LDFileFormat::Relocation,
+ llvm::ELF::SHT_REL,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pGOT = &pLinker.getOrCreateOutputSectHdr(".got",
+ LDFileFormat::Target,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ f_Backend.bitclass() / 8);
+ f_pPLT = &pLinker.getOrCreateOutputSectHdr(".plt",
+ LDFileFormat::Target,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
+ f_Backend.bitclass() / 8);
+ f_pGOTPLT = &pLinker.getOrCreateOutputSectHdr(".got.plt",
+ LDFileFormat::Target,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ f_Backend.bitclass() / 8);
+ f_pEhFrameHdr = &pLinker.getOrCreateOutputSectHdr(".eh_frame_hdr",
+ LDFileFormat::EhFrameHdr,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x4);
+}
diff --git a/lib/LD/ELFExecWriter.cpp b/lib/LD/ELFExecWriter.cpp
new file mode 100644
index 0000000..7438180
--- /dev/null
+++ b/lib/LD/ELFExecWriter.cpp
@@ -0,0 +1,157 @@
+//===- ELFExecWriter.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/ELFExecWriter.h>
+#include <mcld/LD/LDSymbol.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/MCLDOutput.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLinker.h>
+#include <llvm/Support/ELF.h>
+#include <vector>
+
+using namespace llvm;
+using namespace mcld;
+
+
+//==========================
+// ELFExecWriter
+ELFExecWriter::ELFExecWriter(GNULDBackend& pBackend, MCLinker& pLinker)
+ : ExecWriter(pBackend),
+ ELFWriter(pBackend),
+ m_Backend(pBackend),
+ m_Linker(pLinker) {
+
+}
+
+ELFExecWriter::~ELFExecWriter()
+{
+}
+
+llvm::error_code ELFExecWriter::writeExecutable(Output& pOutput)
+{
+ // write out the interpreter section: .interp
+ target().emitInterp(pOutput, m_Linker.getLDInfo());
+
+ // Write out name pool sections: .dynsym, .dynstr, .hash
+ target().emitDynNamePools(pOutput,
+ m_Linker.getOutputSymbols(),
+ m_Linker.getLayout(),
+ m_Linker.getLDInfo());
+
+ // Write out name pool sections: .symtab, .strtab
+ target().emitRegNamePools(pOutput,
+ m_Linker.getOutputSymbols(),
+ m_Linker.getLayout(),
+ m_Linker.getLDInfo());
+
+ // Write out regular ELF sections
+ unsigned int secIdx = 0;
+ unsigned int secEnd = pOutput.context()->numOfSections();
+ for (secIdx = 0; secIdx < secEnd; ++secIdx) {
+ LDSection* sect = pOutput.context()->getSection(secIdx);
+ MemoryRegion* region = NULL;
+ // request output region
+ switch(sect->kind()) {
+ case LDFileFormat::Regular:
+ case LDFileFormat::Relocation:
+ case LDFileFormat::Target:
+ case LDFileFormat::Debug:
+ case LDFileFormat::GCCExceptTable:
+ case LDFileFormat::EhFrame: {
+ region = pOutput.memArea()->request(sect->offset(), sect->size());
+ if (NULL == region) {
+ llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section[") +
+ llvm::Twine(secIdx) +
+ llvm::Twine("] - `") +
+ sect->name() +
+ llvm::Twine("'.\n"));
+ }
+ break;
+ }
+ case LDFileFormat::Null:
+ case LDFileFormat::NamePool:
+ case LDFileFormat::BSS:
+ case LDFileFormat::Note:
+ case LDFileFormat::MetaData:
+ case LDFileFormat::Version:
+ case LDFileFormat::EhFrameHdr:
+ // ignore these sections
+ continue;
+ default: {
+ llvm::errs() << "WARNING: unsupported section kind: "
+ << sect->kind()
+ << " of section "
+ << sect->name()
+ << ".\n";
+ continue;
+ }
+ }
+
+ // write out sections with data
+ switch(sect->kind()) {
+ case LDFileFormat::Regular:
+ case LDFileFormat::Debug:
+ case LDFileFormat::GCCExceptTable:
+ case LDFileFormat::EhFrame: {
+ // FIXME: if optimization of exception handling sections is enabled,
+ // then we should emit these sections by the other way.
+ emitSectionData(m_Linker.getLayout(), *sect, *region);
+ break;
+ }
+ case LDFileFormat::Relocation:
+ emitRelocation(m_Linker.getLayout(), pOutput, *sect, *region);
+ break;
+ case LDFileFormat::Target:
+ target().emitSectionData(pOutput,
+ *sect,
+ m_Linker.getLDInfo(),
+ m_Linker.getLayout(),
+ *region);
+ break;
+ default:
+ continue;
+ }
+ } // end of for loop
+
+ if (32 == target().bitclass()) {
+ // Write out ELF header
+ // Write out section header table
+ emitELF32ShStrTab(pOutput, m_Linker);
+
+ writeELF32Header(m_Linker.getLDInfo(),
+ m_Linker.getLayout(),
+ target(),
+ pOutput);
+
+ emitELF32ProgramHeader(pOutput, target());
+
+ emitELF32SectionHeader(pOutput, m_Linker);
+ }
+ else if (64 == target().bitclass()) {
+ // Write out ELF header
+ // Write out section header table
+ emitELF64ShStrTab(pOutput, m_Linker);
+
+ writeELF64Header(m_Linker.getLDInfo(),
+ m_Linker.getLayout(),
+ target(),
+ pOutput);
+
+ emitELF64ProgramHeader(pOutput, target());
+
+ emitELF64SectionHeader(pOutput, m_Linker);
+ }
+ else
+ return make_error_code(errc::not_supported);
+
+ pOutput.memArea()->clear();
+ return llvm::make_error_code(llvm::errc::success);
+}
+
diff --git a/lib/LD/ELFFileFormat.cpp b/lib/LD/ELFFileFormat.cpp
index 9394e44..f1c39cb 100644
--- a/lib/LD/ELFFileFormat.cpp
+++ b/lib/LD/ELFFileFormat.cpp
@@ -57,7 +57,8 @@
f_pJCR(NULL),
f_pNoteABITag(NULL),
f_pStab(NULL),
- f_pStabStr(NULL) {
+ f_pStabStr(NULL),
+ f_pStack(NULL) {
}
@@ -186,7 +187,7 @@
f_pDataRelRo = &pLinker.getOrCreateOutputSectHdr(".data.rel.ro",
LDFileFormat::Regular,
llvm::ELF::SHT_PROGBITS,
- llvm::ELF::SHF_ALLOC,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
0x1);
f_pDtors = &pLinker.getOrCreateOutputSectHdr(".dtors",
LDFileFormat::Regular,
@@ -194,20 +195,15 @@
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
0x1);
f_pEhFrame = &pLinker.getOrCreateOutputSectHdr(".eh_frame",
- LDFileFormat::Exception,
+ LDFileFormat::EhFrame,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC,
- 0x1);
- f_pEhFrameHdr = &pLinker.getOrCreateOutputSectHdr(".eh_frame_hdr",
- LDFileFormat::Exception,
- llvm::ELF::SHT_PROGBITS,
- llvm::ELF::SHF_ALLOC,
- 0x1);
+ 0x4);
f_pGCCExceptTable = &pLinker.getOrCreateOutputSectHdr(".gcc_except_table",
- LDFileFormat::Exception,
+ LDFileFormat::GCCExceptTable,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC,
- 0x1);
+ 0x4);
f_pGNUVersion = &pLinker.getOrCreateOutputSectHdr(".gnu.version",
LDFileFormat::Version,
llvm::ELF::SHT_GNU_versym,
diff --git a/lib/LD/ELFObjectReader.cpp b/lib/LD/ELFObjectReader.cpp
index abc3d30..1ea81e2 100644
--- a/lib/LD/ELFObjectReader.cpp
+++ b/lib/LD/ELFObjectReader.cpp
@@ -8,13 +8,13 @@
//===----------------------------------------------------------------------===//
#include <llvm/Support/ELF.h>
#include <llvm/ADT/Twine.h>
-#include <llvm/Support/ErrorHandling.h>
#include <mcld/LD/ELFObjectReader.h>
#include <mcld/LD/ELFReader.h>
#include <mcld/MC/MCLDInput.h>
#include <mcld/MC/MCLinker.h>
#include <mcld/MC/MCRegionFragment.h>
#include <mcld/Target/GNULDBackend.h>
+#include <mcld/Support/MsgHandling.h>
#include <string>
#include <cassert>
@@ -99,7 +99,14 @@
(*section)->getInfo());
bool exist = false;
- signatures().insert(signature->name(), exist);
+ if (0 == std::strlen(signature->name()) &&
+ ResolveInfo::Section == signature->type()) {
+ // if the signature is a section symbol in input object, we use the
+ // section name as group signature.
+ signatures().insert((*section)->name(), exist);
+ } else {
+ signatures().insert(signature->name(), exist);
+ }
if (exist) {
// if this is not the first time we see this group signature, then
@@ -132,28 +139,32 @@
break;
}
/** normal sections **/
- // FIXME: support Debug, Exception and Version Kinds
- case LDFileFormat::Debug:
- case LDFileFormat::Exception:
+ // FIXME: support Version Kinds
case LDFileFormat::Version:
/** Fall through **/
case LDFileFormat::Regular:
case LDFileFormat::Note:
+ case LDFileFormat::Debug:
case LDFileFormat::MetaData: {
if (!m_pELFReader->readRegularSection(pInput, m_Linker, **section))
- llvm::report_fatal_error(
- llvm::Twine("can not read regular section `") +
- (*section)->name() +
- llvm::Twine("'.\n"));
+ fatal(diag::err_cannot_read_section) << (*section)->name();
+ break;
+ }
+ case LDFileFormat::EhFrame: {
+ if (!m_pELFReader->readEhFrame(pInput, m_Linker, **section))
+ fatal(diag::err_cannot_read_section) <<(*section)->name();
+ break;
+ }
+ case LDFileFormat::GCCExceptTable: {
+ //if (!m_pELFReader->readExceptionSection(pInput, m_Linker, **section))
+ if (!m_pELFReader->readRegularSection(pInput, m_Linker, **section))
+ fatal(diag::err_cannot_read_section) << (*section)->name();
break;
}
/** target dependent sections **/
case LDFileFormat::Target: {
if (!m_pELFReader->readTargetSection(pInput, m_Linker, **section))
- llvm::report_fatal_error(
- llvm::Twine("can not read target dependentsection `") +
- (*section)->name() +
- llvm::Twine("'.\n"));
+ fatal(diag::err_cannot_read_target_section) << (*section)->name();
break;
}
/** BSS sections **/
@@ -179,7 +190,14 @@
case LDFileFormat::Null:
case LDFileFormat::NamePool:
continue;
-
+ // warning
+ case LDFileFormat::EhFrameHdr:
+ default: {
+ warning(diag::warn_illegal_input_section) << (*section)->name()
+ << pInput.name()
+ << pInput.path();
+ break;
+ }
}
} // end of for all sections
@@ -192,9 +210,20 @@
assert(pInput.hasMemArea());
LDSection* symtab_shdr = pInput.context()->getSection(".symtab");
+ if (NULL == symtab_shdr) {
+ note(diag::note_has_no_symtab) << pInput.name()
+ << pInput.path()
+ << ".symtab";
+ return true;
+ }
+
LDSection* strtab_shdr = symtab_shdr->getLink();
- if (NULL == symtab_shdr || NULL == strtab_shdr)
+ if (NULL == strtab_shdr) {
+ fatal(diag::fatal_cannot_read_strtab) << pInput.name()
+ << pInput.path()
+ << ".symtab";
return false;
+ }
MemoryRegion* symtab_region = pInput.memArea()->request(symtab_shdr->offset(),
symtab_shdr->size());
diff --git a/lib/LD/ELFReader.cpp b/lib/LD/ELFReader.cpp
index 1fd2a13..6aacc08 100644
--- a/lib/LD/ELFReader.cpp
+++ b/lib/LD/ELFReader.cpp
@@ -7,15 +7,16 @@
//
//===----------------------------------------------------------------------===//
-#include <llvm/Support/ELF.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ELF.h>
#include <llvm/Support/Host.h>
#include <mcld/MC/MCLinker.h>
-#include <mcld/Support/MemoryArea.h>
-#include <mcld/Support/MemoryRegion.h>
#include <mcld/LD/ELFReader.h>
#include <mcld/Target/GNULDBackend.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
#include <cstring>
using namespace mcld;
@@ -28,16 +29,22 @@
{
// name rules
llvm::StringRef name(pName);
- if (llvm::StringRef::npos != name.find(".debug"))
+ if (name.startswith(".debug") ||
+ name.startswith(".zdebug") ||
+ name.startswith(".gnu.linkonce.wi.") ||
+ name.startswith(".line") ||
+ name.startswith(".stab"))
return LDFileFormat::Debug;
if (name.startswith(".comment"))
return LDFileFormat::MetaData;
if (name.startswith(".interp") || name.startswith(".dynamic"))
return LDFileFormat::Note;
- if (name.startswith(".eh_frame") ||
- name.startswith(".eh_frame_hdr") ||
- name.startswith(".gcc_except_table"))
- return LDFileFormat::Exception;
+ if (name.startswith(".eh_frame"))
+ return LDFileFormat::EhFrame;
+ if (name.startswith(".eh_frame_hdr"))
+ return LDFileFormat::EhFrameHdr;
+ if (name.startswith(".gcc_except_table"))
+ return LDFileFormat::GCCExceptTable;
// type rules
switch(pType) {
@@ -74,8 +81,7 @@
(pType >= llvm::ELF::SHT_LOOS && pType <= llvm::ELF::SHT_HIOS) ||
(pType >= llvm::ELF::SHT_LOUSER && pType <= llvm::ELF::SHT_HIUSER))
return LDFileFormat::Target;
- llvm::report_fatal_error(llvm::Twine("unsupported ELF section type: ") +
- llvm::Twine(pType) + llvm::Twine(".\n"));
+ fatal(diag::err_unsupported_section) << pName << pType;
}
return LDFileFormat::MetaData;
}
@@ -141,13 +147,9 @@
LDSection* sect_hdr = pInput.context()->getSection(pShndx);
- if (NULL == sect_hdr) {
- llvm::report_fatal_error(llvm::Twine("section[") +
- llvm::Twine(pShndx) +
- llvm::Twine("] is invalid in file `") +
- pInput.path().native() +
- llvm::Twine("'.\n"));
- }
+ if (NULL == sect_hdr)
+ unreachable(diag::unreachable_invalid_section_idx) << pShndx
+ << pInput.path().native();
MCFragmentRef* result = pLinker.getLayout().getFragmentRef(*sect_hdr, pOffset);
return result;
@@ -186,3 +188,17 @@
return 0x0;
}
+bool ELFReaderIF::readEhFrame(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr) const
+{
+ LDSection& out_sect = pLinker.getOrCreateOutputSectHdr(pInputSectHdr.name(),
+ pInputSectHdr.kind(),
+ pInputSectHdr.type(),
+ pInputSectHdr.flag());
+
+ size_t size = pLinker.addEhFrame(pInputSectHdr, *pInput.memArea());
+
+ out_sect.setSize(out_sect.size() + size);
+ return true;
+}
diff --git a/lib/LD/ELFSegment.cpp b/lib/LD/ELFSegment.cpp
index a08641b..dbefbc5 100644
--- a/lib/LD/ELFSegment.cpp
+++ b/lib/LD/ELFSegment.cpp
@@ -19,7 +19,8 @@
uint64_t pPaddr,
uint64_t pFilesz,
uint64_t pMemsz,
- uint64_t pAlign)
+ uint64_t pAlign,
+ uint64_t pMaxSectAlign)
: m_Type(pType),
m_Flag(pFlag),
m_Offset(pOffset),
@@ -27,7 +28,8 @@
m_Paddr(pPaddr),
m_Filesz(pFilesz),
m_Memsz(pMemsz),
- m_Align(pAlign) {
+ m_Align(pAlign),
+ m_MaxSectionAlign(pMaxSectAlign) {
}
ELFSegment::~ELFSegment()
diff --git a/lib/LD/ELFSegmentFactory.cpp b/lib/LD/ELFSegmentFactory.cpp
index d8ad3cc..af0f588 100644
--- a/lib/LD/ELFSegmentFactory.cpp
+++ b/lib/LD/ELFSegmentFactory.cpp
@@ -25,16 +25,40 @@
/// 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)
+ELFSegment* ELFSegmentFactory::produce(uint32_t pType, uint32_t pFlag)
{
ELFSegment* segment = allocate();
- new (segment) ELFSegment(pType);
+ new (segment) ELFSegment(pType, pFlag);
return segment;
}
-/// destroy - destruct the ELF segment
-void ELFSegmentFactory::destroy(ELFSegment*& pSegment)
+ELFSegment*
+ELFSegmentFactory::find(uint32_t pType, uint32_t pFlagSet, uint32_t pFlagClear)
{
- deallocate(pSegment);
+ iterator segment, segEnd = end();
+ for (segment = begin(); segment != segEnd; ++segment) {
+ if ((*segment).type() == pType &&
+ ((*segment).flag() & pFlagSet) == pFlagSet &&
+ ((*segment).flag() & pFlagClear) == 0x0) {
+ return &(*segment);
+ }
+ }
+ return NULL;
+}
+
+const ELFSegment*
+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);
+ }
+ }
+ return NULL;
}
diff --git a/lib/LD/ELFWriter.cpp b/lib/LD/ELFWriter.cpp
index a94fd5c..2f2d898 100644
--- a/lib/LD/ELFWriter.cpp
+++ b/lib/LD/ELFWriter.cpp
@@ -18,6 +18,8 @@
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/LDSection.h>
#include <mcld/LD/Layout.h>
+#include <mcld/LD/ELFSegment.h>
+#include <mcld/LD/ELFSegmentFactory.h>
#include <mcld/Target/GNULDBackend.h>
#include <cstdlib>
#include <cstring>
@@ -146,7 +148,7 @@
&& (pOutput.type() != Output::Object)
&& (pOutput.type() != Output::DynObj));
- const LDSymbol* entry_symbol = pLDInfo.getStrSymPool().findSymbol(entry_name);
+ const LDSymbol* entry_symbol = pLDInfo.getNamePool().findSymbol(entry_name);
// found the symbol
if (NULL != entry_symbol) {
@@ -244,6 +246,70 @@
}
}
+
+/// emitELF32ProgramHeader - emit Elf32_Phdr
+void ELFWriter::emitELF32ProgramHeader(Output& pOutput,
+ const GNULDBackend& pBackend) const
+{
+ assert(pOutput.hasMemArea());
+
+ uint64_t start_offset, phdr_size;
+
+ start_offset = sizeof(Elf32_Ehdr);
+ phdr_size = sizeof(Elf32_Phdr);
+ // Program header must start directly after ELF header
+ MemoryRegion *region = pOutput.memArea()->request(start_offset,
+ pBackend.numOfSegments() * phdr_size);
+
+ Elf32_Phdr* phdr = (Elf32_Phdr*)region->start();
+
+ // Iterate the elf segment table in GNULDBackend
+ size_t index = 0;
+ ELFSegmentFactory::const_iterator seg = pBackend.elfSegmentTable().begin(),
+ segEnd = pBackend.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();
+ }
+}
+
+/// emitELF64ProgramHeader - emit ElfR64Phdr
+void ELFWriter::emitELF64ProgramHeader(Output& pOutput,
+ const GNULDBackend& pBackend) const
+{
+ assert(pOutput.hasMemArea());
+
+ uint64_t start_offset, phdr_size;
+
+ start_offset = sizeof(Elf64_Ehdr);
+ phdr_size = sizeof(Elf64_Phdr);
+ // Program header must start directly after ELF header
+ MemoryRegion *region = pOutput.memArea()->request(start_offset,
+ pBackend.numOfSegments() * phdr_size);
+ Elf64_Phdr* phdr = (Elf64_Phdr*)region->start();
+
+ // Iterate the elf segment table in GNULDBackend
+ size_t index = 0;
+ ELFSegmentFactory::const_iterator seg = pBackend.elfSegmentTable().begin(),
+ segEnd = pBackend.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();
+ }
+}
+
/// emitELF32ShStrTab - emit section string table
void ELFWriter::emitELF32ShStrTab(Output& pOutput, MCLinker& pLinker) const
{
diff --git a/lib/LD/EhFrame.cpp b/lib/LD/EhFrame.cpp
new file mode 100644
index 0000000..76af403
--- /dev/null
+++ b/lib/LD/EhFrame.cpp
@@ -0,0 +1,373 @@
+//===- EhFrame.cpp --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/EhFrame.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Target/TargetLDBackend.h>
+#include <llvm/Support/Dwarf.h>
+#include <llvm/Support/Host.h>
+
+using namespace mcld;
+
+//==========================
+// EhFrame
+EhFrame::EhFrame()
+ : m_fCanRecognizeAll(true) {
+}
+
+EhFrame::~EhFrame()
+{
+}
+
+uint64_t EhFrame::readEhFrame(Layout& pLayout,
+ const TargetLDBackend& pBackend,
+ llvm::MCSectionData& pSD,
+ LDSection& pSection,
+ MemoryArea& pArea)
+{
+ MemoryRegion* region = pArea.request(pSection.offset(),
+ pSection.size());
+ // an empty .eh_frame
+ if (NULL == region) {
+ note(diag::note_ehframe) << "an empty eh_frame";
+ return 0;
+ }
+
+ ConstAddress eh_start = region->start();
+ ConstAddress eh_end = region->end();
+ ConstAddress p = eh_start;
+
+ // read the Length filed
+ uint32_t len = readVal(p, pBackend.isLittleEndian());
+
+ // This CIE is a terminator if the Length field is 0, return 0 to handled it
+ // as an ordinary input.
+ if (0 == len) {
+ note(diag::note_ehframe) << "a terminator";
+ pArea.release(region);
+ return 0;
+ }
+
+ if (0xffffffff == len) {
+ debug(diag::debug_eh_unsupport) << "64-bit eh_frame";
+ pArea.release(region);
+ m_fCanRecognizeAll = false;
+ return 0;
+ }
+
+ // record the order of the CIE and FDE fragments
+ FragListType frag_list;
+
+ while (p < eh_end) {
+
+ if (eh_end - p < 4) {
+ debug(diag::debug_eh_unsupport) << "CIE or FDE size smaller than 4";
+ m_fCanRecognizeAll = false;
+ break;
+ }
+ // read the Length field
+ len = readVal(p, pBackend.isLittleEndian());
+ p += 4;
+
+ // the zero length entry should be the end of the section
+ if (0 == len) {
+ if (p < eh_end) {
+ debug(diag::debug_eh_unsupport) << "Non-end entry with zero length";
+ m_fCanRecognizeAll = false;
+ }
+ break;
+ }
+ if (0xffffffff == len) {
+ debug(diag::debug_eh_unsupport) << "64-bit eh_frame";
+ m_fCanRecognizeAll = false;
+ break;
+ }
+
+ if (eh_end - p < 4) {
+ debug(diag::debug_eh_unsupport) <<
+ "CIE:ID field / FDE: CIE Pointer field";
+ m_fCanRecognizeAll = false;
+ break;
+ }
+
+ // compute the section offset of this entry
+ uint32_t ent_offset = static_cast<uint32_t>(p - eh_start - 4);
+
+ // get the MemoryRegion for this entry
+ MemoryRegion* ent_region = pArea.request(pSection.offset() + ent_offset,
+ len + 4);
+
+ // create and add a CIE or FDE entry
+ uint32_t id = readVal(p, pBackend.isLittleEndian());
+ // CIE
+ if (0 == id) {
+ if (!addCIE(*ent_region, pBackend, frag_list)) {
+ m_fCanRecognizeAll = false;
+ pArea.release(ent_region);
+ break;
+ }
+ }
+
+ // FDE
+ else {
+ if (!addFDE(*ent_region, pBackend, frag_list)) {
+ m_fCanRecognizeAll = false;
+ pArea.release(ent_region);
+ break;
+ }
+ }
+ p += len;
+ }
+
+ if (!m_fCanRecognizeAll) {
+ pArea.release(region);
+ deleteFragments(frag_list, pArea);
+ return 0;
+ }
+
+ // append all CIE and FDE fragments to Layout after we successfully read
+ // this eh_frame
+ size_t section_size = 0;
+ for (FragListType::iterator it = frag_list.begin();
+ it != frag_list.end(); ++it)
+ section_size += pLayout.appendFragment(**it, pSD, pSection.align());
+
+ pArea.release(region);
+ return section_size;
+}
+
+bool EhFrame::addCIE(MemoryRegion& pRegion,
+ const TargetLDBackend& pBackend,
+ FragListType& pFragList)
+{
+ ConstAddress cie_start = pRegion.start();
+ ConstAddress cie_end = pRegion.end();
+ ConstAddress p = cie_start;
+
+ // skip the Length (4 byte) and CIE ID (4 byte) fields
+ p += 8;
+
+ // the version should be 1
+ if (1 != *p) {
+ debug(diag::debug_eh_unsupport) << "CIE version";
+ return false;
+ }
+ ++p;
+
+ // get the Augumentation String
+ ConstAddress aug_str = p;
+ ConstAddress aug_str_end = static_cast<ConstAddress>(
+ memchr(p, '\0', cie_end - p));
+
+ // skip the Augumentation String field
+ p = aug_str_end + 1;
+
+ // skip the Code Alignment Factor
+ if (!skipLEB128(&p, cie_end)) {
+ debug(diag::debug_eh_unsupport) << "unrecognized Code Alignment Factor";
+ return false;
+ }
+ // skip the Data Alignment Factor
+ if (!skipLEB128(&p, cie_end)) {
+ debug(diag::debug_eh_unsupport) << "unrecognized Data Alignment Factor";
+ return false;
+ }
+ // skip the Return Address Register
+ if (cie_end - p < 1) {
+ debug(diag::debug_eh_unsupport) << "unrecognized Return Address Register";
+ return false;
+ }
+ ++p;
+
+ // the Augmentation String start with 'eh' is a CIE from gcc before 3.0,
+ // in LSB Core Spec 3.0RC1. We do not support it.
+ if (aug_str[0] == 'e' && aug_str[1] == 'h') {
+ debug(diag::debug_eh_unsupport) << "augmentation string `eh`";
+ return false;
+ }
+
+ // parse the Augmentation String to get the FDE encodeing if 'z' existed
+ std::string aug_str_data;
+ uint8_t fde_encoding = llvm::dwarf::DW_EH_PE_absptr;
+ if (*aug_str == 'z') {
+
+ aug_str_data += *aug_str;
+ ++aug_str;
+
+ // skip the Augumentation Data Length
+ if (!skipLEB128(&p, cie_end)) {
+ debug(diag::debug_eh_unsupport) <<
+ "unrecognized Augmentation Data Length";
+ return false;
+ }
+
+ while (aug_str != aug_str_end) {
+ switch (*aug_str) {
+ default:
+ debug(diag::debug_eh_unsupport) << "augmentation string";
+ return false;
+
+ // LDSA encoding (1 byte)
+ case 'L':
+ if (cie_end - p < 1) {
+ debug(diag::debug_eh_unsupport) << "augmentation string `L`";
+ return false;
+ }
+ ++p;
+ break;
+
+ // Two arguments, the first one represents the encoding of the second
+ // argument (1 byte). The second one is the address of personality
+ // routine.
+ case 'P': {
+ // the first argument
+ if (cie_end - p < 1) {
+ debug(diag::debug_eh_unsupport) << "augmentation string `P`";
+ return false;
+ }
+ uint8_t per_encode = *p;
+ ++p;
+ // get the length of the second argument
+ uint32_t per_length = 0;
+ if (0x60 == (per_encode & 0x60)) {
+ debug(diag::debug_eh_unsupport) << "augmentation string `P`";
+ return false;
+ }
+ switch (per_encode & 7) {
+ default:
+ debug(diag::debug_eh_unsupport) << "augmentation string `P`";
+ return false;
+ case llvm::dwarf::DW_EH_PE_udata2:
+ per_length = 2;
+ break;
+ case llvm::dwarf::DW_EH_PE_udata4:
+ per_length = 4;
+ break;
+ case llvm::dwarf::DW_EH_PE_udata8:
+ per_length = 8;
+ break;
+ case llvm::dwarf::DW_EH_PE_absptr:
+ per_length = pBackend.bitclass() / 8;
+ break;
+ }
+ // skip the alignment
+ if (llvm::dwarf::DW_EH_PE_aligned == (per_encode & 0xf0)) {
+ uint32_t per_align = p - cie_end;
+ per_align += per_length - 1;
+ per_align &= ~(per_length -1);
+ if (static_cast<uint32_t>(cie_end - p) < per_align) {
+ debug(diag::debug_eh_unsupport) << "augmentation string `P`";
+ return false;
+ }
+ p += per_align;
+ }
+ // skip the second argument
+ if (static_cast<uint32_t>(cie_end - p) < per_length) {
+ debug(diag::debug_eh_unsupport) << "augmentation string `P`";
+ return false;
+ }
+ p += per_length;
+ }
+ break;
+
+ // FDE encoding (1 byte)
+ case 'R':
+ if (cie_end - p < 1) {
+ debug(diag::debug_eh_unsupport) << "augmentation string `R`";
+ return false;
+ }
+ fde_encoding = *p;
+ switch (fde_encoding & 7) {
+ case llvm::dwarf::DW_EH_PE_udata2:
+ case llvm::dwarf::DW_EH_PE_udata4:
+ case llvm::dwarf::DW_EH_PE_udata8:
+ case llvm::dwarf::DW_EH_PE_absptr:
+ break;
+ default:
+ debug(diag::debug_eh_unsupport) << "FDE encoding";
+ return false;
+ }
+ ++p;
+ break;
+ } // end switch
+ aug_str_data += *aug_str;
+ ++aug_str;
+ } // end while
+ }
+
+ note(diag::note_eh_cie) << pRegion.size()
+ << aug_str_data
+ << (fde_encoding & 7);
+
+ // create and push back the CIE entry
+ CIE* entry = new CIE(pRegion, fde_encoding);
+ m_CIEs.push_back(entry);
+ pFragList.push_back(static_cast<llvm::MCFragment*>(entry));
+ return true;
+}
+
+bool EhFrame::addFDE(MemoryRegion& pRegion,
+ const TargetLDBackend& pBackend,
+ FragListType& pFragList)
+{
+ ConstAddress fde_start = pRegion.start();
+ ConstAddress fde_end = pRegion.end();
+ ConstAddress p = fde_start;
+
+ // skip the Length (4 byte) and CIE Pointer (4 byte) fields
+ p += 8;
+
+ // get the entry offset of the PC Begin
+ if (fde_end - p < 1) {
+ debug(diag::debug_eh_unsupport) << "FDE PC Begin";
+ return false;
+ }
+ FDE::Offset pc_offset = static_cast<FDE::Offset>(p - fde_start);
+
+ note(diag::note_eh_fde) << pRegion.size() << pc_offset;
+ // create and push back the FDE entry
+ FDE* entry = new FDE(pRegion, **(m_CIEs.end() -1), pc_offset);
+ m_FDEs.push_back(entry);
+ pFragList.push_back(static_cast<llvm::MCFragment*>(entry));
+ return true;
+}
+
+uint32_t EhFrame::readVal(ConstAddress pAddr, bool pIsTargetLittleEndian)
+{
+ const uint32_t* p = reinterpret_cast<const uint32_t*>(pAddr);
+ uint32_t val = *p;
+
+ // byte swapping if the host and target have different endian
+ if (llvm::sys::isLittleEndianHost() != pIsTargetLittleEndian)
+ val = bswap32(val);
+ return val;
+}
+
+bool EhFrame::skipLEB128(ConstAddress* pp, ConstAddress pend)
+{
+ for (ConstAddress p = *pp; p < pend; ++p) {
+ if (0 == (*p & 0x80)) {
+ *pp = p + 1;
+ return true;
+ }
+ }
+ return false;
+}
+
+void EhFrame::deleteFragments(FragListType& pList, MemoryArea& pArea)
+{
+ MCRegionFragment* frag = NULL;
+ for (FragListType::iterator it = pList.begin(); it != pList.end(); ++it) {
+ frag = static_cast<MCRegionFragment*>(*it);
+ pArea.release(&(frag->getRegion()));
+ delete *it;
+ }
+ pList.clear();
+}
+
diff --git a/lib/LD/EhFrameHdr.cpp b/lib/LD/EhFrameHdr.cpp
new file mode 100644
index 0000000..8806af4
--- /dev/null
+++ b/lib/LD/EhFrameHdr.cpp
@@ -0,0 +1,49 @@
+//===- EhFrameHdr.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/EhFrameHdr.h>
+
+using namespace mcld;
+
+//==========================
+// EhFrameHdr
+EhFrameHdr::EhFrameHdr(const EhFrame& pEhFrameData,
+ const LDSection& pEhFrameSect,
+ LDSection& pEhFrameHdrSect)
+ : m_EhFrameData(pEhFrameData),
+ m_EhFrameSect(pEhFrameSect),
+ m_EhFrameHdrSect(pEhFrameHdrSect)
+{
+}
+
+EhFrameHdr::~EhFrameHdr()
+{
+}
+
+/// @ref lsb core generic 4.1
+/// .eh_frame_hdr section format
+/// uint8_t : version
+/// uint8_t : eh_frame_ptr_enc
+/// uint8_t : fde_count_enc
+/// uint8_t : table_enc
+/// uint32_t : eh_frame_ptr
+/// uint32_t : fde_count
+/// __________________________ when fde_count > 0
+/// <uint32_t, uint32_t>+ : binary search table
+
+/// sizeOutput - base on the fde count to size output
+void EhFrameHdr::sizeOutput()
+{
+ size_t size = 12;
+ if (m_EhFrameData.canRecognizeAllEhFrame()) {
+ size_t fde_count = m_EhFrameData.getFDECount();
+ size += 8 * fde_count;
+ }
+ m_EhFrameHdrSect.setSize(size);
+}
+
diff --git a/lib/LD/ExecWriter.cpp b/lib/LD/ExecWriter.cpp
new file mode 100644
index 0000000..d66cd17
--- /dev/null
+++ b/lib/LD/ExecWriter.cpp
@@ -0,0 +1,16 @@
+//===- ExecWriter.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/ExecWriter.h"
+#include "mcld/Target/TargetLDBackend.h"
+#include "mcld/MC/MCLDInput.h"
+
+using namespace mcld;
+
+//==========================
+// ExecWriter
diff --git a/lib/LD/FDE.cpp b/lib/LD/FDE.cpp
new file mode 100644
index 0000000..b70f7e1
--- /dev/null
+++ b/lib/LD/FDE.cpp
@@ -0,0 +1,24 @@
+//===- FDE.cpp ------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/EhFrame.h>
+#include <mcld/LD/FDE.h>
+
+using namespace mcld;
+
+//==========================
+// FDE
+
+FDE::FDE(MemoryRegion& pRegion, const CIE& pCIE, Offset pPCBeginOffset)
+ : MCRegionFragment(pRegion), m_CIE(pCIE), m_PCBeginOffset(pPCBeginOffset) {
+}
+
+FDE::~FDE()
+{
+}
+
diff --git a/lib/LD/GNUArchiveReader.cpp b/lib/LD/GNUArchiveReader.cpp
index 3fa00b8..0a64752 100644
--- a/lib/LD/GNUArchiveReader.cpp
+++ b/lib/LD/GNUArchiveReader.cpp
@@ -6,42 +6,35 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/MC/MCLDInfo.h"
-#include "mcld/MC/MCLDInput.h"
-#include "mcld/MC/MCLDInputTree.h"
-#include "mcld/LD/GNUArchiveReader.h"
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/InputTree.h>
+#include <mcld/LD/GNUArchiveReader.h>
+#include <mcld/Support/FileSystem.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MemoryAreaFactory.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/ADT/SizeTraits.h>
-#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/system_error.h>
+#include <llvm/Support/Host.h>
#include <sstream>
#include <string>
#include <vector>
#include <cstdlib>
-using namespace std;
using namespace mcld;
-typedef size_t sectionSizeTy;
typedef uint32_t elfWord;
-/// Archive Header, Magic number, etc..
-const unsigned archiveMagicSize = 8;
-const char archiveMagic[archiveMagicSize] = { '!', '<', 'a', 'r', 'c', 'h', '>', '\n' };
-const char thinArchiveMagic[archiveMagicSize] = { '!', '<', 't', 'h', 'i', 'n', '>', '\n' };
-const char archiveFinalMagic[2] = { '`', '\n' };
+/// Archive Header, Magic number
+const char GNUArchiveReader::ArchiveMagic[ArchiveMagicSize] = { '!', '<', 'a', 'r', 'c', 'h', '>', '\n' };
+const char GNUArchiveReader::ThinArchiveMagic[ArchiveMagicSize] = { '!', '<', 't', 'h', 'i', 'n', '>', '\n' };
+const char GNUArchiveReader::HeaderFinalMagic[HeaderFinalMagicSize] = { '`', '\n' };
-struct GNUArchiveReader::ArchiveMemberHeader
-{
- char name[16];
- char date[12];
- char uid[6];
- char gid[6];
- char mode[8];
- char size[10];
- char finalMagic[2];
-};
struct GNUArchiveReader::SymbolTableEntry
{
@@ -49,13 +42,6 @@
std::string name;
};
-inline void endian_swap(unsigned int& x)
-{
- x = (x>>24) |
- ((x<<8) & 0x00FF0000) |
- ((x>>8) & 0x0000FF00) |
- (x<<24);
-}
/// convert string to size_t
@@ -73,22 +59,25 @@
/// Public API
bool GNUArchiveReader::isMyFormat(Input &pInput) const
{
- llvm::OwningPtr<llvm::MemoryBuffer> mapFile;
- llvm::MemoryBuffer::getFile(pInput.path().c_str(), mapFile);
- const char* pFile = mapFile->getBufferStart();
+ assert(pInput.hasMemArea());
+
+ MemoryRegion *region = pInput.memArea()->request(0, ArchiveMagicSize);
+ if (!region)
+ llvm::report_fatal_error("can't request MemoryRegion for archive magic");
+
+ const char *p_buffer = reinterpret_cast<char *> (region->getBuffer());
/// check archive format.
- if(mapFile->getBufferSize() <= archiveMagicSize)
+ if (memcmp(p_buffer, ArchiveMagic, ArchiveMagicSize) != 0
+ && memcmp(p_buffer, ThinArchiveMagic, ArchiveMagicSize) != 0) {
return false;
- bool isThinArchive = memcmp(pFile, thinArchiveMagic, archiveMagicSize) == 0;
- if(!isThinArchive && memcmp(pFile, archiveMagic, archiveMagicSize) != 0)
- return false;
+ }
return true;
}
LDReader::Endian GNUArchiveReader::endian(Input& pFile) const
{
- return m_endian;
+ return LDReader::BigEndian;
}
InputTree *GNUArchiveReader::readArchive(Input &pInput)
@@ -103,62 +92,59 @@
InputTree *GNUArchiveReader::setupNewArchive(Input &pInput,
size_t off)
{
- llvm::OwningPtr<llvm::MemoryBuffer> mapFile;
- if(llvm::MemoryBuffer::getFile(pInput.path().c_str(), mapFile))
- {
- assert(0 && "GNUArchiveReader:can't map a file to MemoryBuffer\n");
- return NULL;
- }
+ assert(pInput.hasMemArea());
+ MemoryRegion *region = pInput.memArea()->request(off, ArchiveMagicSize);
+
+ if (!region)
+ llvm::report_fatal_error("can't request MemoryRegion for archive magic");
+
+ const char *pFile = reinterpret_cast<char *> (region->getBuffer());
+
+ /// check archive format.
+ bool isThinArchive;
+ isThinArchive = memcmp(pFile, ThinArchiveMagic, ArchiveMagicSize) == 0;
+ if(!isThinArchive && memcmp(pFile, ArchiveMagic, ArchiveMagicSize) != 0)
+ llvm::report_fatal_error("Fail : archive magic number is not matched");
InputTree *resultTree = new InputTree(m_pLDInfo.inputFactory());
std::vector<SymbolTableEntry> symbolTable;
std::string archiveMemberName;
std::string extendedName;
- bool isThinArchive;
- const char *pFile = mapFile->getBufferStart();
- /// check archive format.
- if(mapFile->getBufferSize() <= archiveMagicSize)
- return NULL;
- else
- {
- isThinArchive = memcmp(pFile, thinArchiveMagic, archiveMagicSize) == 0;
- if(!isThinArchive && memcmp(pFile, archiveMagic, archiveMagicSize) != 0)
- return NULL;
- }
-
- off += archiveMagicSize ;
- size_t symbolTableSize = parseMemberHeader(mapFile, off, &archiveMemberName,
+ off += ArchiveMagicSize ;
+ size_t symbolTableSize = readMemberHeader(*pInput.memArea(), off, &archiveMemberName,
NULL, extendedName);
/// read archive symbol table
if(archiveMemberName.empty())
{
- readSymbolTable(mapFile, symbolTable,
- off+sizeof(GNUArchiveReader::ArchiveMemberHeader), symbolTableSize);
- off = off + sizeof(GNUArchiveReader::ArchiveMemberHeader) + symbolTableSize;
+ readSymbolTable(*pInput.memArea(), symbolTable,
+ off+sizeof(ArchiveMemberHeader), symbolTableSize);
+ off = off + sizeof(ArchiveMemberHeader) + symbolTableSize;
}
else
{
- assert(0 && "fatal error : need symbol table\n");
+ llvm::report_fatal_error("fatal error : need symbol table\n");
return NULL;
}
if((off&1) != 0)
++off;
- size_t extendedSize = parseMemberHeader(mapFile, off, &archiveMemberName,
+ size_t extendedSize = readMemberHeader(*pInput.memArea(), off, &archiveMemberName,
NULL, extendedName);
/// read long Name table if exist
if(archiveMemberName == "/")
{
- off += sizeof(GNUArchiveReader::ArchiveMemberHeader);
- pFile += off;
- extendedName.assign(pFile,extendedSize);
+ off += sizeof(ArchiveMemberHeader);
+ MemoryRegion *extended_name_region = pInput.memArea()->request(off, extendedSize);
+ pFile = reinterpret_cast<char *>(extended_name_region->getBuffer());
+ extendedName.assign(pFile, extendedSize);
+
}
/// traverse all the archive members
InputTree::iterator node = resultTree->root();
- set<string> haveSeen;
+ std::set<std::string> haveSeen;
for(unsigned i=0 ; i<symbolTable.size() ; ++i)
{
/// We shall get each member at this archive.
@@ -166,7 +152,7 @@
/// the original InputTree, resultTree.
off_t nestedOff = 0;
- parseMemberHeader(mapFile, symbolTable[i].fileOffset, &archiveMemberName,
+ readMemberHeader(*pInput.memArea(), symbolTable[i].fileOffset, &archiveMemberName,
&nestedOff, extendedName);
if(haveSeen.find(archiveMemberName)==haveSeen.end())
@@ -191,8 +177,13 @@
continue;
}
-
- /// create the real path
+
+ /// TODO:(Duo)
+ /// adjust the relative pathname
+ /// For example
+ /// thin archive pathname : "/usr/lib/thin.a"
+ /// Member name : "member.a"
+ /// pathname after adjust : "/usr/lib/member.a"
sys::fs::RealPath realPath(archiveMemberName);
if(nestedOff > 0)
{
@@ -237,20 +228,20 @@
/// "filename.o/ " - regular file with short name
/// "/5566 " - name at offset 5566 at long name table
-size_t GNUArchiveReader::parseMemberHeader(llvm::OwningPtr<llvm::MemoryBuffer> &mapFile,
+size_t GNUArchiveReader::readMemberHeader(MemoryArea &pArea,
off_t off,
std::string *p_Name,
off_t *p_NestedOff,
std::string &p_ExtendedName)
{
- const char *pFile = mapFile->getBufferStart();
- pFile += off;
+ MemoryRegion *region = pArea.request(off, sizeof(ArchiveMemberHeader));
+ const char *pFile = reinterpret_cast<char *>(region->getBuffer());
const ArchiveMemberHeader *header = reinterpret_cast<const ArchiveMemberHeader *>(pFile);
/// check magic number of member header
- if(memcmp(header->finalMagic, archiveFinalMagic, sizeof archiveFinalMagic))
+ if(memcmp(header->finalMagic, HeaderFinalMagic, sizeof HeaderFinalMagic))
{
- assert(0 && "archive member header magic number false");
+ llvm::report_fatal_error("archive member header magic number false");
return 0;
}
@@ -259,7 +250,7 @@
size_t memberSize = stringToType<size_t>(sizeString);
if(memberSize == 0)
{
- assert(0 && "member Size Error");
+ llvm::report_fatal_error("member Size Error");
return 0;
}
@@ -270,7 +261,7 @@
size_t nameLen = ((nameEnd == NULL) ? 0 : (nameEnd - header->name));
if((nameLen <= 0) || (nameLen >= sizeof(header->name)))
{
- assert(0 && "header name format error\n");
+ llvm::report_fatal_error("header name format error\n");
return 0;
}
p_Name->assign(header->name, nameLen);
@@ -302,7 +293,7 @@
|| extendedNameOff < 0
|| static_cast<size_t>(extendedNameOff) >= p_ExtendedName.size())
{
- assert(0 && "extended name");
+ llvm::report_fatal_error("extended name");
return 0;
}
@@ -311,7 +302,7 @@
if(nameEnd[-1] != '/'
|| static_cast<size_t>(nameEnd-name) > p_ExtendedName.size())
{
- assert(0 && "p_ExtendedName substring is not end with / \n");
+ llvm::report_fatal_error("p_ExtendedName substring is not end with / \n");
return 0;
}
p_Name->assign(name, nameEnd-name-1);
@@ -322,35 +313,40 @@
return memberSize;
}
-void GNUArchiveReader::readSymbolTable(llvm::OwningPtr<llvm::MemoryBuffer> &mapFile,
+void GNUArchiveReader::readSymbolTable(MemoryArea &pArea,
std::vector<SymbolTableEntry> &pSymbolTable,
off_t start,
size_t size)
{
- const char *startPtr = mapFile->getBufferStart() + start;
- const elfWord *p_Word = reinterpret_cast<const elfWord *>(startPtr);
+ MemoryRegion *region = pArea.request(start, size);
+ const char *pFile = reinterpret_cast<char *>(region->getBuffer());
+ const elfWord *p_Word = reinterpret_cast<const elfWord *>(pFile);
unsigned int symbolNum = *p_Word;
/// Portable Issue on Sparc platform
/// Intel, ARM and Mips are littel-endian , Sparc is little-endian after verion 9
/// symbolNum in symbol table is always big-endian
- if(m_endian == LDReader::LittleEndian)
- endian_swap(symbolNum);
+ if(llvm::sys::isLittleEndianHost())
+ symbolNum = bswap32(symbolNum);
++p_Word;
const char *p_Name = reinterpret_cast<const char *>(p_Word + symbolNum);
- pSymbolTable.resize(symbolNum);
for(unsigned int i=0 ; i<symbolNum ; ++i)
{
- /// assign member offset
+ SymbolTableEntry entry;
+ /// member offset
unsigned int memberOffset = *p_Word;
- endian_swap(memberOffset);
- pSymbolTable[i].fileOffset = static_cast<off_t>(memberOffset);
+ if(llvm::sys::isLittleEndianHost())
+ memberOffset = bswap32(memberOffset);
+ entry.fileOffset = static_cast<off_t>(memberOffset);
++p_Word;
- /// assign member name
+ /// member name
off_t nameEnd = strlen(p_Name) + 1;
- pSymbolTable[i].name.assign(p_Name, nameEnd);
+ entry.name.assign(p_Name, nameEnd);
p_Name += nameEnd;
+ /// the symbol is found in symbol pool
+ if (m_pLDInfo.getNamePool().findSymbol(entry.name))
+ pSymbolTable.push_back(entry);
}
}
diff --git a/lib/LD/InputSymbolTable.cpp b/lib/LD/InputSymbolTable.cpp
deleted file mode 100644
index e34679c..0000000
--- a/lib/LD/InputSymbolTable.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-//===- InputSymbolTable.cpp -----------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include "mcld/LD/InputSymbolTable.h"
-#include <vector>
-
-using namespace mcld;
-
-//==========================
-// InputSymbolTable
-
-InputSymbolTable::InputSymbolTable(StrSymPool &pStrSymPool,
- size_t pNumOfSymbols,
- StringTable &pEntireStringTable,
- StringTable &pDynamicStringTable)
- : SymbolTableIF(pStrSymPool)
-{
- f_StrSymPool.addIndirectClient(*this);
-
- f_pCategorySet->at(CategorySet::Entire).reserve(pNumOfSymbols);
-
- f_pCategorySet->at(CategorySet::Entire).interpose(&pEntireStringTable);
- f_pCategorySet->at(CategorySet::Dynamic).interpose(&pDynamicStringTable);
-}
-
-void InputSymbolTable::doInsertSymbol(LDSymbol *pSym)
-{
- f_pCategorySet->insertSymbolPointer(pSym);
-}
-
-void InputSymbolTable::doMerge(const SymbolTableIF &pSymTab)
-{
- if (this == &pSymTab)
- return;
- for (size_t i = 0; i < CategorySet::NumOfCategories; ++i)
- f_pCategorySet->at(i).insert(f_pCategorySet->at(i).end(),
- pSymTab.begin(i),
- pSymTab.end(i));
-}
-
-InputSymbolTable::~InputSymbolTable()
-{
-}
diff --git a/lib/LD/Layout.cpp b/lib/LD/Layout.cpp
index 9328d74..bc91cee 100644
--- a/lib/LD/Layout.cpp
+++ b/lib/LD/Layout.cpp
@@ -8,14 +8,14 @@
//===----------------------------------------------------------------------===//
#include <llvm/ADT/Twine.h>
-#include <llvm/Support/ErrorHandling.h>
#include <mcld/ADT/SizeTraits.h>
#include <mcld/LD/Layout.h>
+#include <mcld/LD/LDContext.h>
#include <mcld/LD/LDFileFormat.h>
+#include <mcld/LD/LDSection.h>
#include <mcld/MC/MCLinker.h>
#include <mcld/MC/MCLDInfo.h>
-#include <mcld/LD/LDSection.h>
-#include <mcld/LD/LDContext.h>
+#include <mcld/Support/MsgHandling.h>
#include <mcld/Target/TargetLDBackend.h>
#include <cassert>
@@ -132,16 +132,6 @@
}
else {
range_list = m_SDRangeMap[&pSD];
-#ifdef MCLD_DEBUG
- RangeList::iterator rangeIter, rangeEnd = range_list->end();
- for (rangeIter = range_list->begin(); rangeIter != rangeEnd; ++rangeIter) {
- if (&pInputHdr == rangeIter->header) {
- llvm::report_fatal_error(llvm::Twine("Trying to map the same LDSection: ") +
- pInputHdr.name() +
- llvm::Twine(" into the different ranges.\n"));
- }
- }
-#endif
}
// make a range and push it into the range list
@@ -425,9 +415,7 @@
// range not found
if (range == rangeEnd) {
- llvm::report_fatal_error(llvm::Twine("section ") +
- pInputSection.name() +
- llvm::Twine(" never be in the range list.\n"));
+ fatal(diag::err_section_not_laid_out) << pInputSection.name();
}
return getFragmentRef(*range, pOffset);
@@ -481,7 +469,7 @@
llvm::Twine(" never be in the range list.\n"));
}
- return getFragmentRef(*range, target_offset);
+ return getFragmentRef(*range, pBigOffset);
}
uint64_t Layout::getOutputOffset(const llvm::MCFragment& pFrag)
@@ -516,7 +504,8 @@
}
void Layout::sortSectionOrder(const Output& pOutput,
- const TargetLDBackend& pBackend)
+ const TargetLDBackend& pBackend,
+ const MCLDInfo& pInfo)
{
typedef std::pair<LDSection*, unsigned int> SectOrder;
typedef std::vector<SectOrder > SectListTy;
@@ -525,7 +514,7 @@
for (size_t index = 0; index < m_SectionOrder.size(); ++index)
sect_list.push_back(std::make_pair(
m_SectionOrder[index],
- pBackend.getSectionOrder(pOutput, *m_SectionOrder[index])));
+ pBackend.getSectionOrder(pOutput, *m_SectionOrder[index], pInfo)));
// simple insertion sort should be fine for general cases such as so and exec
for (unsigned int i = 1; i < sect_list.size(); ++i) {
@@ -545,7 +534,9 @@
}
}
-bool Layout::layout(Output& pOutput, const TargetLDBackend& pBackend)
+bool Layout::layout(Output& pOutput,
+ const TargetLDBackend& pBackend,
+ const MCLDInfo& pInfo)
{
// determine what sections in output context will go into final output, and
// push the needed sections into m_SectionOrder for later processing
@@ -558,10 +549,12 @@
switch (sect->kind()) {
// ignore if there is no SectionData for certain section kinds
case LDFileFormat::Regular:
- case LDFileFormat::Note:
case LDFileFormat::Target:
case LDFileFormat::MetaData:
case LDFileFormat::BSS:
+ case LDFileFormat::Debug:
+ case LDFileFormat::EhFrame:
+ case LDFileFormat::GCCExceptTable:
if (0 != sect->size()) {
if (NULL != sect->getSectionData() &&
!sect->getSectionData()->getFragmentList().empty()) {
@@ -581,6 +574,8 @@
// ignore if section size is 0
case LDFileFormat::NamePool:
case LDFileFormat::Relocation:
+ case LDFileFormat::Note:
+ case LDFileFormat::EhFrameHdr:
if (0 != sect->size())
m_SectionOrder.push_back(sect);
break;
@@ -590,47 +585,22 @@
;
}
break;
- case LDFileFormat::Debug:
- if (0 != sect->size()) {
- m_SectionOrder.push_back(sect);
- llvm::errs() << "WARNING: DWRAF debugging has not been fully supported yet.\n"
- << "section `" << sect->name() << "'.\n";
- }
- break;
- case LDFileFormat::Exception:
- if (0 != sect->size()) {
- llvm::errs() << "WARNING: Exception handling has not been fully supported yet.\n"
- << "section `" << sect->name() << "'.\n";
- if (NULL != sect->getSectionData() &&
- !sect->getSectionData()->getFragmentList().empty()) {
- // make sure that all fragments are valid
- llvm::MCFragment& frag =
- sect->getSectionData()->getFragmentList().back();
- setFragmentLayoutOrder(&frag);
- setFragmentLayoutOffset(&frag);
- }
- m_SectionOrder.push_back(sect);
- }
- break;
case LDFileFormat::Version:
if (0 != sect->size()) {
m_SectionOrder.push_back(sect);
- llvm::errs() << "WARNING: Symbolic versioning has not been fully supported yet.\n"
- << "section `" << sect->name() << "'.\n";
+ warning(diag::warn_unsupported_symbolic_versioning) << sect->name();
}
break;
default:
- llvm::report_fatal_error(llvm::Twine("Unsupported section kind of `") +
- sect->name() +
- llvm::Twine("': ") +
- llvm::Twine(sect->kind()) +
- llvm::Twine(".\n"));
+ if (0 != sect->size()) {
+ error(diag::err_unsupported_section) << sect->name() << sect->kind();
+ }
break;
}
}
// perform sorting on m_SectionOrder to get a ordering for final layout
- sortSectionOrder(pOutput, pBackend);
+ sortSectionOrder(pOutput, pBackend, pInfo);
// Backend defines the section start offset for section 1.
uint64_t offset = pBackend.sectionStartOffset();
diff --git a/lib/LD/MsgHandler.cpp b/lib/LD/MsgHandler.cpp
new file mode 100644
index 0000000..96310a2
--- /dev/null
+++ b/lib/LD/MsgHandler.cpp
@@ -0,0 +1,52 @@
+//===- MsgHandler.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/MsgHandler.h>
+#include <mcld/LD/DiagnosticEngine.h>
+
+using namespace mcld;
+
+MsgHandler::MsgHandler(DiagnosticEngine& pEngine)
+ : m_Engine(pEngine), m_NumArgs(0) {
+}
+
+MsgHandler::~MsgHandler()
+{
+ emit();
+}
+
+bool MsgHandler::emit()
+{
+ flushCounts();
+ return m_Engine.emit();
+}
+
+void MsgHandler::addString(llvm::StringRef pStr) const
+{
+ assert(m_NumArgs < DiagnosticEngine::MaxArguments &&
+ "Too many arguments to diagnostic!");
+ m_Engine.state().ArgumentKinds[m_NumArgs] = DiagnosticEngine::ak_std_string;
+ m_Engine.state().ArgumentStrs[m_NumArgs++] = pStr.data();
+}
+
+void MsgHandler::addString(const std::string& pStr) const
+{
+ assert(m_NumArgs < DiagnosticEngine::MaxArguments &&
+ "Too many arguments to diagnostic!");
+ m_Engine.state().ArgumentKinds[m_NumArgs] = DiagnosticEngine::ak_std_string;
+ m_Engine.state().ArgumentStrs[m_NumArgs++] = pStr;
+}
+
+void MsgHandler::addTaggedVal(intptr_t pValue, DiagnosticEngine::ArgumentKind pKind) const
+{
+ assert(m_NumArgs < DiagnosticEngine::MaxArguments &&
+ "Too many arguments to diagnostic!");
+ m_Engine.state().ArgumentKinds[m_NumArgs] = pKind;
+ m_Engine.state().ArgumentVals[m_NumArgs++] = pValue;
+}
+
diff --git a/lib/LD/StrSymPool.cpp b/lib/LD/NamePool.cpp
similarity index 69%
rename from lib/LD/StrSymPool.cpp
rename to lib/LD/NamePool.cpp
index abe3fb7..1247057 100644
--- a/lib/LD/StrSymPool.cpp
+++ b/lib/LD/NamePool.cpp
@@ -1,4 +1,4 @@
-//===- StrSymPool.cpp -----------------------------------------------------===//
+//===- NamePool.cpp -------------------------------------------------------===//
//
// The MCLinker Project
//
@@ -6,27 +6,24 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-
-#include "mcld/LD/StrSymPool.h"
-#include "mcld/LD/Resolver.h"
#include <llvm/Support/raw_ostream.h>
+#include <mcld/LD/NamePool.h>
+#include <mcld/LD/Resolver.h>
using namespace mcld;
//==========================
-// StrSymPool
-StrSymPool::StrSymPool(const Resolver& pResolver, StrSymPool::size_type pSize)
- : m_pResolver(pResolver.clone()), m_Table(pSize) {
+// NamePool
+NamePool::NamePool(const Resolver& pResolver, NamePool::size_type pSize)
+ : m_pResolver(&pResolver), m_Table(pSize) {
}
-StrSymPool::~StrSymPool()
+NamePool::~NamePool()
{
- if (0 != m_pResolver)
- delete m_pResolver;
}
/// createSymbol - create a symbol
-ResolveInfo* StrSymPool::createSymbol(const llvm::StringRef& pName,
+ResolveInfo* NamePool::createSymbol(const llvm::StringRef& pName,
bool pIsDyn,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
@@ -48,7 +45,7 @@
/// insertSymbol - insert a symbol and resolve it immediately
/// @return the pointer of resolved ResolveInfo
/// @return is the symbol existent?
-void StrSymPool::insertSymbol(const llvm::StringRef& pName,
+void NamePool::insertSymbol(const llvm::StringRef& pName,
bool pIsDyn,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
@@ -98,69 +95,49 @@
// symbol resolution
bool override = false;
unsigned int action = Resolver::LastAction;
- switch(m_pResolver->resolve(*old_symbol, *new_symbol, override)) {
- case Resolver::Success: {
- pResult.info = old_symbol;
- pResult.existent = true;
- pResult.overriden = override;
- break;
- }
- case Resolver::Warning: {
- llvm::errs() << "WARNING: " << m_pResolver->mesg() << "\n";
- m_pResolver->clearMesg();
- pResult.info = old_symbol;
- pResult.existent = true;
- pResult.overriden = override;
- break;
- }
- case Resolver::Abort: {
- llvm::report_fatal_error(m_pResolver->mesg());
- pResult.info = old_symbol;
- pResult.existent = true;
- pResult.overriden = override;
- break;
- }
- default: {
- m_pResolver->resolveAgain(*this, action, *old_symbol, *new_symbol, pResult);
- break;
- }
+ if (m_pResolver->resolve(*old_symbol, *new_symbol, override)) {
+ pResult.info = old_symbol;
+ pResult.existent = true;
+ pResult.overriden = override;
}
+ else
+ m_pResolver->resolveAgain(*this, action, *old_symbol, *new_symbol, pResult);
return;
}
-llvm::StringRef StrSymPool::insertString(const llvm::StringRef& pString)
+llvm::StringRef NamePool::insertString(const llvm::StringRef& pString)
{
bool exist = false;
ResolveInfo* resolve_info = m_Table.insert(pString, exist);
return llvm::StringRef(resolve_info->name(), resolve_info->nameSize());
}
-void StrSymPool::reserve(StrSymPool::size_type pSize)
+void NamePool::reserve(NamePool::size_type pSize)
{
m_Table.rehash(pSize);
}
-StrSymPool::size_type StrSymPool::capacity() const
+NamePool::size_type NamePool::capacity() const
{
return (m_Table.numOfBuckets() - m_Table.numOfEntries());
}
/// findInfo - find the resolved ResolveInfo
-ResolveInfo* StrSymPool::findInfo(const llvm::StringRef& pName)
+ResolveInfo* NamePool::findInfo(const llvm::StringRef& pName)
{
Table::iterator iter = m_Table.find(pName);
return iter.getEntry();
}
/// findInfo - find the resolved ResolveInfo
-const ResolveInfo* StrSymPool::findInfo(const llvm::StringRef& pName) const
+const ResolveInfo* NamePool::findInfo(const llvm::StringRef& pName) const
{
Table::const_iterator iter = m_Table.find(pName);
return iter.getEntry();
}
/// findSymbol - find the resolved output LDSymbol
-LDSymbol* StrSymPool::findSymbol(const llvm::StringRef& pName)
+LDSymbol* NamePool::findSymbol(const llvm::StringRef& pName)
{
ResolveInfo* info = findInfo(pName);
if (NULL == info)
@@ -169,7 +146,7 @@
}
/// findSymbol - find the resolved output LDSymbol
-const LDSymbol* StrSymPool::findSymbol(const llvm::StringRef& pName) const
+const LDSymbol* NamePool::findSymbol(const llvm::StringRef& pName) const
{
const ResolveInfo* info = findInfo(pName);
if (NULL == info)
diff --git a/lib/LD/OutputSymbolTable.cpp b/lib/LD/OutputSymbolTable.cpp
deleted file mode 100644
index a17a211..0000000
--- a/lib/LD/OutputSymbolTable.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-//===- OutputSymbolTable.cpp ----------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include "mcld/LD/OutputSymbolTable.h"
-
-using namespace mcld;
-
-//==========================
-// OutputSymbolTable
-
-
-OutputSymbolTable::OutputSymbolTable(StrSymPool &pStrSymPool,
- size_t pNumOfSymbols,
- StringTable &pEntireStringTable,
- StringTable &pDynamicStringTable)
- : SymbolTableIF(pStrSymPool)
-{
- f_StrSymPool.addDirectClient(*this);
-
- f_pCategorySet->at(CategorySet::Entire).reserve(pNumOfSymbols);
-
- f_pCategorySet->at(CategorySet::Entire).interpose(&pEntireStringTable);
- f_pCategorySet->at(CategorySet::Dynamic).interpose(&pDynamicStringTable);
-}
-
-void OutputSymbolTable::doInsertSymbol(LDSymbol *sym)
-{
- // OutputSymbolTable didn't have any real containers,
- // so no need to do anything.
-}
-
-void OutputSymbolTable::doMerge(const SymbolTableIF &pSymTab)
-{
- // OutputSymbolTable didn't have any real containers,
- // so no need to do anything.
-}
diff --git a/lib/LD/Relocation.cpp b/lib/LD/Relocation.cpp
index 73db39b..0b84ad0 100644
--- a/lib/LD/Relocation.cpp
+++ b/lib/LD/Relocation.cpp
@@ -40,7 +40,7 @@
Relocation::Address Relocation::symValue() const
{
- if(m_pSymInfo->type() == ResolveInfo::Section &&
+ if (m_pSymInfo->type() == ResolveInfo::Section &&
m_pSymInfo->outSymbol()->hasFragRef()) {
return llvm::cast<LDSection>(
m_pSymInfo->outSymbol()->fragRef()->frag()->getParent()->getSection()).addr();
diff --git a/lib/LD/Resolver.cpp b/lib/LD/Resolver.cpp
index 0f7f06e..aa39b13 100644
--- a/lib/LD/Resolver.cpp
+++ b/lib/LD/Resolver.cpp
@@ -6,28 +6,13 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/LD/Resolver.h"
-#include <cassert>
+#include <mcld/LD/Resolver.h>
using namespace mcld;
//==========================
// Resolver
-Resolver::Resolver()
- : m_Mesg() {
-}
-
-Resolver::Resolver(const Resolver& pCopy)
- : m_Mesg(pCopy.m_Mesg) {
-}
-
Resolver::~Resolver()
{
- m_Mesg.clear();
-}
-
-void Resolver::clearMesg()
-{
- m_Mesg.clear();
}
diff --git a/lib/LD/SectionMap.cpp b/lib/LD/SectionMap.cpp
index d81dfdd..9d32391 100644
--- a/lib/LD/SectionMap.cpp
+++ b/lib/LD/SectionMap.cpp
@@ -12,9 +12,8 @@
using namespace mcld;
-//==========================
+//===----------------------------------------------------------------------===//
// SectionMap
-
SectionMap::SectionMap()
{
}
@@ -38,13 +37,11 @@
// if still no matching, just let a output seciton has the same input name
if (it == end())
return pInput;
-
return (*it).outputStr;
}
bool SectionMap::push_back(const std::string& pInput,
- const std::string& pOutput,
- const uint64_t pOffset)
+ const std::string& pOutput)
{
// Now only check if the mapping exists in the map already
// TODO: handle the cases such as overriding the exist mapping and drawing
@@ -57,7 +54,6 @@
struct Mapping mapping = {
pInput,
pOutput,
- pOffset,
};
m_SectMap.push_back(mapping);
return true;
diff --git a/lib/LD/SectionMerger.cpp b/lib/LD/SectionMerger.cpp
index f6aef9e..f3a5b65 100644
--- a/lib/LD/SectionMerger.cpp
+++ b/lib/LD/SectionMerger.cpp
@@ -18,7 +18,7 @@
SectionMerger::SectionMerger(SectionMap& pSectionMap, LDContext& pContext)
: m_SectionNameMap(pSectionMap),
m_Output(pContext),
- m_LDSectionMap(pSectionMap.size())
+ m_LDSectionMap()
{
}
diff --git a/lib/LD/StaticResolver.cpp b/lib/LD/StaticResolver.cpp
index 3ba49e2..09cbc11 100644
--- a/lib/LD/StaticResolver.cpp
+++ b/lib/LD/StaticResolver.cpp
@@ -8,28 +8,19 @@
//===----------------------------------------------------------------------===//
#include <mcld/LD/StaticResolver.h>
#include <mcld/LD/LDSymbol.h>
-#include <cassert>
+#include <mcld/Support/MsgHandling.h>
using namespace mcld;
-
//==========================
// StaticResolver
-StaticResolver::StaticResolver()
-{
-}
-
StaticResolver::~StaticResolver()
{
}
-StaticResolver::StaticResolver(const StaticResolver& pCopy)
- : Resolver(pCopy) {
-}
-
-unsigned int StaticResolver::resolve(ResolveInfo& __restrict__ pOld,
- const ResolveInfo& __restrict__ pNew,
- bool &pOverride)
+bool StaticResolver::resolve(ResolveInfo& __restrict__ pOld,
+ const ResolveInfo& __restrict__ pNew,
+ bool &pOverride) const
{
/* The state table itself.
@@ -41,13 +32,13 @@
static const enum LinkAction link_action[LAST_ORD][LAST_ORD] =
{
/* new\old U w_U d_U wd_U D w_D d_D wd_D C w_C, Cs, Is */
- /* U */ {NOACT, UND, UND, UND, NOACT, NOACT, DUND, DUNDW, NOACT, NOACT, NOACT, REFC },
- /* w_U */ {NOACT, NOACT, NOACT, WEAK, NOACT, NOACT, DUND, DUNDW, NOACT, NOACT, NOACT, REFC },
+ /* U */ {NOACT, UND, UND, UND, NOACT, NOACT, DUND, DUND, NOACT, NOACT, NOACT, REFC },
+ /* w_U */ {NOACT, NOACT, NOACT, WEAK, NOACT, NOACT, DUNDW, DUNDW, NOACT, NOACT, NOACT, REFC },
/* d_U */ {NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC },
/* wd_U */ {NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC },
/* D */ {DEF, DEF, DEF, DEF, MDEF, DEF, DEF, DEF, CDEF, CDEF, CDEF, MDEF },
/* w_D */ {DEFW, DEFW, DEFW, DEFW, NOACT, NOACT, DEFW, DEFW, NOACT, NOACT, NOACT, NOACT},
- /* d_D */ {DEFD, MDEFD, DEFD, DEFD, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, MDEF },
+ /* d_D */ {MDEFD, MDEFD, DEFD, DEFD, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, MDEF },
/* wd_D */ {MDEFWD, MDEFWD, DEFWD, DEFWD, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT},
/* C */ {COM, COM, COM, COM, CREF, COM, COM, COM, MBIG, COM, BIG, REFC },
/* w_C */ {COM, COM, COM, COM, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC },
@@ -71,26 +62,23 @@
unsigned int col = getOrdinate(pOld);
bool cycle = false;
- unsigned int result = Resolver::Success;
pOverride = false;
ResolveInfo* old = &pOld;
LinkAction action;
do {
- result = Resolver::Success;
cycle = false;
action = link_action[row][col];
switch(action) {
case FAIL: { /* abort. */
- m_Mesg = std::string("internal error [StaticResolver.cpp:loc 86].\n") +
- std::string("Please report to `mclinker@googlegroups.com'.\n");
- result = Resolver::Abort;
- break;
+ fatal(diag::fail_sym_resolution)
+ << __FILE__ << __LINE__
+ << "mclinker@googlegroups.com";
+ return false;
}
case NOACT: { /* no action. */
pOverride = false;
old->overrideVisibility(pNew);
- result = Resolver::Success;
break;
}
case UND: /* override by symbol undefined symbol. */
@@ -102,7 +90,6 @@
case COM: { /* override by symbol common defined. */
pOverride = true;
old->override(pNew);
- result = Resolver::Success;
break;
}
case MDEFD: /* mark symbol dynamic defined. */
@@ -110,31 +97,22 @@
uint32_t binding = old->binding();
old->override(pNew);
old->setBinding(binding);
- m_Mesg = std::string("symbol `") +
- old->name() +
- std::string("' uses the type, dynamic, size and type in the dynamic symbol.");
+ ignore(diag::mark_dynamic_defined) << old->name();
pOverride = true;
- result = Resolver::Warning;
break;
}
case DUND:
case DUNDW: {
- if (old->binding() == ResolveInfo::Weak &&
- pNew.binding() != ResolveInfo::Weak) {
- old->setBinding(pNew.binding());
- }
+ old->override(pNew);
old->overrideVisibility(pNew);
+ old->setDynamic();
pOverride = false;
- result = Resolver::Success;
break;
}
case CREF: { /* Possibly warn about common reference to defined symbol. */
// A common symbol does not override a definition.
- m_Mesg = std::string("common '") +
- pNew.name() +
- std::string("' overriden by previous definition.");
+ ignore(diag::comm_refer_to_define) << old->name();
pOverride = false;
- result = Resolver::Warning;
break;
}
case CDEF: { /* redefine existing common symbol. */
@@ -142,12 +120,9 @@
// definition overrides.
//
// NOTE: m_Mesg uses 'name' instead of `name' for being compatible to GNU ld.
- m_Mesg = std::string("definition of '") +
- old->name() +
- std::string("' is overriding common.");
+ ignore(diag::redefine_common) << old->name();
old->override(pNew);
pOverride = true;
- result = Resolver::Warning;
break;
}
case BIG: { /* override by symbol common using largest size. */
@@ -156,7 +131,6 @@
old->overrideAttributes(pNew);
old->overrideVisibility(pNew);
pOverride = true;
- result = Resolver::Success;
break;
}
case MBIG: { /* mark common symbol by larger size. */
@@ -164,22 +138,15 @@
old->setSize(pNew.size());
old->overrideVisibility(pNew);
pOverride = false;
- result = Resolver::Success;
break;
}
case CIND: { /* mark indirect symbol from existing common symbol. */
- m_Mesg = std::string("indirect symbol `") +
- pNew.name()+
- std::string("' point to a common symbol.\n");
- result = Resolver::Warning;
+ ignore(diag::indirect_refer_to_common) << old->name();
}
/* Fall through */
case IND: { /* override by indirect symbol. */
- if (0 == pNew.link()) {
- m_Mesg = std::string("indirect symbol `") +
- pNew.name() +
- std::string("' point to a inexistent symbol.");
- result = Resolver::Abort;
+ if (NULL == pNew.link()) {
+ fatal(diag::indirect_refer_to_inexist) << pNew.name();
break;
}
@@ -203,18 +170,12 @@
}
/* Fall through */
case MDEF: { /* multiple definition error. */
- m_Mesg = std::string("multiple definitions of `") +
- pNew.name() +
- std::string("'.");
- result = Resolver::Abort;
+ error(diag::multiple_definitions) << pNew.name();
break;
}
case REFC: { /* Mark indirect symbol referenced and then CYCLE. */
- if (0 == old->link()) {
- m_Mesg = std::string("indirect symbol `") +
- old->name() +
- std::string("' point to a inexistent symbol.");
- result = Resolver::Abort;
+ if (NULL == old->link()) {
+ fatal(diag::indirect_refer_to_inexist) << old->name();
break;
}
@@ -223,8 +184,12 @@
cycle = true;
break;
}
+ default: {
+ error(diag::undefined_situation) << action << old->name() << pNew.name();
+ return false;
+ }
} // end of the big switch (action)
} while(cycle);
- return result;
+ return true;
}
diff --git a/lib/LD/SymbolTableFactory.cpp b/lib/LD/SymbolTableFactory.cpp
deleted file mode 100644
index 180a4a9..0000000
--- a/lib/LD/SymbolTableFactory.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-//===- SymbolTableFactory.cpp ---------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include "mcld/LD/SymbolTableFactory.h"
-
-using namespace mcld;
-
-//==========================
-// SymbolTableFactory
-
-SymbolTableFactory::SymbolTableFactory(size_t pNumOfSymbolTables,
- StrSymPool& pStrSymPool)
- : m_StrSymPool(pStrSymPool),
- m_InputFactory(pNumOfSymbolTables),
- m_OutputFactory(pNumOfSymbolTables)
-{
-}
-
-SymbolTableFactory::~SymbolTableFactory()
-{
-}
-
-SymbolTableIF *SymbolTableFactory::
-createInputTable(StringTable &pEntireStringTable,
- StringTable &pDynamicStringTable,
- size_t pReserve)
-{
- InputSymbolTable *inputSymTab = m_InputFactory.allocate();
- new (inputSymTab) InputSymbolTable(m_StrSymPool,
- pReserve,
- pEntireStringTable,
- pDynamicStringTable);
- return inputSymTab;
-}
-
-SymbolTableIF *SymbolTableFactory::
-createOutputTable(StringTable &pEntireStringTable,
- StringTable &pDynamicStringTable,
- size_t pReserve)
-{
- OutputSymbolTable *outputSymTab = m_OutputFactory.allocate();
- new (outputSymTab) OutputSymbolTable(m_StrSymPool,
- pReserve,
- pEntireStringTable,
- pDynamicStringTable);
- return outputSymTab;
-}
diff --git a/lib/LD/TextDiagnosticPrinter.cpp b/lib/LD/TextDiagnosticPrinter.cpp
new file mode 100644
index 0000000..466d16d
--- /dev/null
+++ b/lib/LD/TextDiagnosticPrinter.cpp
@@ -0,0 +1,167 @@
+//===- TextDiagnosticPrinter.cpp ------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/TextDiagnosticPrinter.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <llvm/Support/Signals.h>
+#include <string>
+
+using namespace mcld;
+
+static const enum llvm::raw_ostream::Colors UnreachableColor = llvm::raw_ostream::RED;
+static const enum llvm::raw_ostream::Colors FatalColor = llvm::raw_ostream::YELLOW;
+static const enum llvm::raw_ostream::Colors ErrorColor = llvm::raw_ostream::RED;
+static const enum llvm::raw_ostream::Colors WarningColor = llvm::raw_ostream::MAGENTA;
+static const enum llvm::raw_ostream::Colors DebugColor = llvm::raw_ostream::CYAN;
+static const enum llvm::raw_ostream::Colors NoteColor = llvm::raw_ostream::GREEN;
+static const enum llvm::raw_ostream::Colors IgnoreColor = llvm::raw_ostream::BLUE;
+
+// Used for changing only the bold attribute.
+static const enum llvm::raw_ostream::Colors SavedColor = llvm::raw_ostream::SAVEDCOLOR;
+
+//===----------------------------------------------------------------------===//
+// TextDiagnosticPrinter
+TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream& pOStream,
+ const MCLDInfo& pLDInfo)
+ : m_OStream(pOStream), m_LDInfo(pLDInfo), m_pInput(NULL) {
+}
+
+TextDiagnosticPrinter::~TextDiagnosticPrinter()
+{
+}
+
+/// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
+/// capturing it to a log as needed.
+void
+TextDiagnosticPrinter::handleDiagnostic(DiagnosticEngine::Severity pSeverity,
+ const Diagnostic& pInfo)
+{
+ DiagnosticPrinter::handleDiagnostic(pSeverity, pInfo);
+
+ std::string out_string;
+ pInfo.format(out_string);
+
+ switch (pSeverity) {
+ case DiagnosticEngine::Unreachable: {
+ m_OStream.changeColor(UnreachableColor, true);
+ m_OStream << "Unreachable: ";
+ m_OStream.resetColor();
+ m_OStream << out_string << "\n";
+ break;
+ }
+ case DiagnosticEngine::Fatal: {
+ m_OStream.changeColor(FatalColor, true);
+ m_OStream << "Fatal: ";
+ m_OStream.resetColor();
+ m_OStream << out_string << "\n";
+ break;
+ }
+ case DiagnosticEngine::Error: {
+ m_OStream.changeColor(ErrorColor, true);
+ m_OStream << "Error: ";
+ m_OStream.resetColor();
+ m_OStream << out_string << "\n";
+ break;
+ }
+ case DiagnosticEngine::Warning: {
+ m_OStream.changeColor(WarningColor, true);
+ m_OStream << "Warning: ";
+ m_OStream.resetColor();
+ m_OStream << out_string << "\n";
+ break;
+ }
+ case DiagnosticEngine::Debug: {
+ // show debug message only if verbose >= 0
+ if (0 <= m_LDInfo.options().verbose()) {
+ m_OStream.changeColor(DebugColor, true);
+ m_OStream << "Debug: ";
+ m_OStream.resetColor();
+ m_OStream << out_string << "\n";
+ }
+ break;
+ }
+ case DiagnosticEngine::Note: {
+ // show ignored message only if verbose >= 1
+ if (1 <= m_LDInfo.options().verbose()) {
+ m_OStream.changeColor(NoteColor, true);
+ m_OStream << "Note: ";
+ m_OStream.resetColor();
+ m_OStream << out_string << "\n";
+ }
+ break;
+ }
+ case DiagnosticEngine::Ignore: {
+ // show ignored message only if verbose >= 2
+ if (2 <= m_LDInfo.options().verbose()) {
+ m_OStream.changeColor(IgnoreColor, true);
+ m_OStream << "Ignore: ";
+ m_OStream.resetColor();
+ m_OStream << out_string << "\n";
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ switch (pSeverity) {
+ case DiagnosticEngine::Unreachable: {
+ m_OStream << "\n\n";
+ m_OStream.changeColor(llvm::raw_ostream::YELLOW);
+ m_OStream << "You encounter a bug of MCLinker, please report to:\n"
+ << " mclinker@googlegroups.com\n";
+ m_OStream.resetColor();
+ }
+ /** fall through **/
+ case DiagnosticEngine::Fatal: {
+ // If we reached here, we are failing ungracefully. Run the interrupt handlers
+ // to make sure any special cleanups get done, in particular that we remove
+ // files registered with RemoveFileOnSignal.
+ llvm::sys::RunInterruptHandlers();
+ exit(1);
+ break;
+ }
+ case DiagnosticEngine::Error: {
+ int16_t error_limit = m_LDInfo.options().maxErrorNum();
+ if ((error_limit != -1) &&
+ (getNumErrors() > static_cast<unsigned>(error_limit))) {
+ m_OStream << "\n\n";
+ m_OStream.changeColor(llvm::raw_ostream::YELLOW);
+ m_OStream << "too many error messages (>" << error_limit << ")...\n";
+ m_OStream.resetColor();
+ llvm::sys::RunInterruptHandlers();
+ exit(1);
+ }
+ break;
+ }
+ case DiagnosticEngine::Warning: {
+ int16_t warning_limit = m_LDInfo.options().maxWarnNum();
+ if ((warning_limit != -1) &&
+ (getNumWarnings() > static_cast<unsigned>(warning_limit))) {
+ m_OStream << "\n\n";
+ m_OStream.changeColor(llvm::raw_ostream::YELLOW);
+ m_OStream << "too many warning messages (>" << warning_limit << ")...\n";
+ m_OStream.resetColor();
+ llvm::sys::RunInterruptHandlers();
+ exit(1);
+ }
+ }
+ default:
+ break;
+ }
+}
+
+void TextDiagnosticPrinter::beginInput(const Input& pInput, const MCLDInfo& pLDInfo)
+{
+ m_pInput = &pInput;
+}
+
+void TextDiagnosticPrinter::endInput()
+{
+ m_pInput = NULL;
+}
diff --git a/lib/MC/ContextFactory.cpp b/lib/MC/ContextFactory.cpp
index d32ea8b..5b698c7 100644
--- a/lib/MC/ContextFactory.cpp
+++ b/lib/MC/ContextFactory.cpp
@@ -33,3 +33,10 @@
return result;
}
+LDContext* ContextFactory::produce()
+{
+ LDContext* result = allocate();
+ new (result) LDContext();
+ return result;
+}
+
diff --git a/lib/MC/MCLDInputTree.cpp b/lib/MC/InputTree.cpp
similarity index 70%
rename from lib/MC/MCLDInputTree.cpp
rename to lib/MC/InputTree.cpp
index b423988..a1d1449 100644
--- a/lib/MC/MCLDInputTree.cpp
+++ b/lib/MC/InputTree.cpp
@@ -1,4 +1,4 @@
-//===- MCLDInputTree.cpp --------------------------------------------------===//
+//===- InputTree.cpp ------------------------------------------------------===//
//
// The MCLinker Project
//
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/MC/MCLDInputTree.h"
-#include "mcld/MC/InputFactory.h"
+#include <mcld/MC/InputTree.h>
+#include <mcld/MC/InputFactory.h>
using namespace mcld;
@@ -24,15 +24,15 @@
{
}
-InputTree& InputTree::merge(InputTree::iterator pPosition,
- const InputTree::Connector& pConnector,
+InputTree& InputTree::merge(InputTree::iterator pRoot,
+ const InputTree::Mover& pMover,
InputTree& pTree)
{
if (this == &pTree)
return *this;
if (!pTree.empty()) {
- pConnector.connect(pPosition, iterator(pTree.m_Root.node.right));
+ pMover.connect(pRoot, iterator(pTree.m_Root.node.right));
BinaryTreeBase<Input>::m_Root.summon(
pTree.BinaryTreeBase<Input>::m_Root);
BinaryTreeBase<Input>::m_Root.delegate(pTree.m_Root);
@@ -41,33 +41,33 @@
return *this;
}
-InputTree& InputTree::insert(InputTree::iterator pPosition,
- const InputTree::Connector& pConnector,
+InputTree& InputTree::insert(InputTree::iterator pRoot,
+ const InputTree::Mover& pMover,
const std::string& pNamespec,
const sys::fs::Path& pPath,
unsigned int pType)
{
BinaryTree<Input>::node_type* node = createNode();
node->data = m_FileFactory.produce(pNamespec, pPath, pType);
- pConnector.connect(pPosition, iterator(node));
+ pMover.connect(pRoot, iterator(node));
return *this;
}
-InputTree& InputTree::enterGroup(InputTree::iterator pPosition,
- const InputTree::Connector& pConnector)
+InputTree& InputTree::enterGroup(InputTree::iterator pRoot,
+ const InputTree::Mover& pMover)
{
NodeBase* node = createNode();
- pConnector.connect(pPosition, iterator(node));
+ pMover.connect(pRoot, iterator(node));
return *this;
}
-InputTree& InputTree::insert(InputTree::iterator pPosition,
- const InputTree::Connector& pConnector,
+InputTree& InputTree::insert(InputTree::iterator pRoot,
+ const InputTree::Mover& pMover,
const mcld::Input& pInput)
{
BinaryTree<Input>::node_type* node = createNode();
node->data = const_cast<mcld::Input*>(&pInput);
- pConnector.connect(pPosition, iterator(node));
+ pMover.connect(pRoot, iterator(node));
return *this;
}
diff --git a/lib/MC/MCLDAttribute.cpp b/lib/MC/MCLDAttribute.cpp
index a361691..f7b7e47 100644
--- a/lib/MC/MCLDAttribute.cpp
+++ b/lib/MC/MCLDAttribute.cpp
@@ -6,40 +6,40 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/MC/MCLDAttribute.h"
-#include "mcld/MC/AttributeFactory.h"
+#include <mcld/MC/MCLDAttribute.h>
+#include <mcld/MC/AttributeFactory.h>
+#include <mcld/Support/MsgHandling.h>
using namespace mcld;
//==========================
// AttrConstraint
-bool AttrConstraint::isLegal(const Attribute& pAttr, std::string &pErrMesg) const
+bool AttrConstraint::isLegal(const Attribute& pAttr) const
{
if (!isWholeArchive() && pAttr.isWholeArchive()) {
- pErrMesg = std::string("Target does not support --whole-archive");
+ error(diag::err_unsupported_whole_archive);
return false;
}
if (!isAsNeeded() && pAttr.isAsNeeded()) {
- pErrMesg = std::string("Target does not support --as-needed");
+ error(diag::err_unsupported_as_needed);
return false;
}
if (!isAddNeeded() && pAttr.isAddNeeded()) {
- pErrMesg = std::string("Target does not support --add-needed");
+ error(diag::err_unsupported_add_needed);
return false;
}
if (isStaticSystem() && pAttr.isDynamic()) {
- pErrMesg = std::string("Target does not support --Bdynamic");
+ error(diag::err_unsupported_Bdynamic);
return false;
}
- // FIXME: may be it's legal, but ignored by GNU ld.
if (isStaticSystem() && pAttr.isAsNeeded()) {
- pErrMesg = std::string("Can't enable --as-needed on a target which does not support dynamic linking");
- return false;
+ warning(diag::err_enable_as_needed_on_static_system);
+ return true;
}
// FIXME: may be it's legal, but ignored by GNU ld.
if (pAttr.isAsNeeded() && pAttr.isStatic()) {
- pErrMesg = std::string("Can't mix --static with --as-needed");
- return false;
+ warning(diag::err_mix_static_as_needed);
+ return true;
}
return true;
}
diff --git a/lib/MC/MCLDDriver.cpp b/lib/MC/MCLDDriver.cpp
index 5e89097..a86983d 100644
--- a/lib/MC/MCLDDriver.cpp
+++ b/lib/MC/MCLDDriver.cpp
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include <mcld/MC/InputTree.h>
#include <mcld/MC/MCLinker.h>
-#include <mcld/MC/MCLDInputTree.h>
#include <mcld/MC/MCLDDriver.h>
#include <mcld/MC/MCLDInfo.h>
#include <mcld/LD/ArchiveReader.h>
@@ -15,10 +15,12 @@
#include <mcld/LD/DynObjReader.h>
#include <mcld/LD/ObjectWriter.h>
#include <mcld/LD/DynObjWriter.h>
+#include <mcld/LD/ExecWriter.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/Support/RealPath.h>
+#include <mcld/Support/MemoryAreaFactory.h>
#include <mcld/Target/TargetLDBackend.h>
-#include <llvm/Support/ErrorHandling.h>
+#include <mcld/Support/MsgHandling.h>
using namespace llvm;
using namespace mcld;
@@ -26,91 +28,83 @@
MCLDDriver::MCLDDriver(MCLDInfo& pLDInfo, TargetLDBackend& pLDBackend)
: m_LDInfo(pLDInfo),
m_LDBackend(pLDBackend),
- m_pLinker(0) {
+ m_pLinker(NULL) {
+
}
MCLDDriver::~MCLDDriver()
{
- if (0 != m_pLinker)
+ if (NULL != m_pLinker)
delete m_pLinker;
+
}
-void MCLDDriver::normalize() {
-
+void MCLDDriver::normalize()
+{
+ // ----- set up inputs ----- //
InputTree::dfs_iterator input, inEnd = m_LDInfo.inputs().dfs_end();
for (input = m_LDInfo.inputs().dfs_begin(); input!=inEnd; ++input) {
- // already got type - for example, bitcode
+ // already got type - for example, bitcode or external OIR (object
+ // intermediate representation)
if ((*input)->type() == Input::Script ||
(*input)->type() == Input::Object ||
(*input)->type() == Input::DynObj ||
- (*input)->type() == Input::Archive)
+ (*input)->type() == Input::Archive ||
+ (*input)->type() == Input::External)
continue;
-
- MemoryArea *input_memory =
- m_LDInfo.memAreaFactory().produce((*input)->path(), O_RDONLY);
- if ((input_memory != NULL) && input_memory->isGood()) {
- (*input)->setMemArea(input_memory);
- }
- else {
- llvm::report_fatal_error("can not open file: " + (*input)->path().native());
- return;
- }
-
// is a relocatable object file
if (m_LDBackend.getObjectReader()->isMyFormat(**input)) {
(*input)->setType(Input::Object);
- (*input)->setContext(m_LDInfo.contextFactory().produce((*input)->path()));
m_LDBackend.getObjectReader()->readObject(**input);
}
// is a shared object file
else if (m_LDBackend.getDynObjReader()->isMyFormat(**input)) {
(*input)->setType(Input::DynObj);
- (*input)->setContext(m_LDInfo.contextFactory().produce((*input)->path()));
- (*input)->setSOName((*input)->path().native());
m_LDBackend.getDynObjReader()->readDSO(**input);
}
// is an archive
else if (m_LDBackend.getArchiveReader()->isMyFormat(*(*input))) {
(*input)->setType(Input::Archive);
- mcld::InputTree* archive_member = m_LDBackend.getArchiveReader()->readArchive(**input);
- if(!archive_member) {
- llvm::report_fatal_error("wrong format archive" + (*input)->path().string());
+ mcld::InputTree* archive_member =
+ m_LDBackend.getArchiveReader()->readArchive(**input);
+ if(NULL == archive_member) {
+ error(diag::err_empty_input) << (*input)->name() << (*input)->path();
return;
}
m_LDInfo.inputs().merge<InputTree::Inclusive>(input, *archive_member);
}
else {
- llvm::report_fatal_error(llvm::Twine("can not recognize file format: ") +
- (*input)->path().native() +
- llvm::Twine("\nobject format or target machine is wrong\n"));
+ fatal(diag::err_unrecognized_input_file) << (*input)->path()
+ << m_LDInfo.triple().str();
}
- }
+ } // end of for
}
-
bool MCLDDriver::linkable() const
{
+ // check we have input and output files
+ if (m_LDInfo.inputs().empty()) {
+ error(diag::err_no_inputs);
+ return false;
+ }
+
// check all attributes are legal
mcld::AttributeFactory::const_iterator attr, attrEnd = m_LDInfo.attrFactory().end();
for (attr=m_LDInfo.attrFactory().begin(); attr!=attrEnd; ++attr) {
- std::string error_code;
- if (!m_LDInfo.attrFactory().constraint().isLegal((**attr), error_code)) {
- report_fatal_error(error_code);
+ if (!m_LDInfo.attrFactory().constraint().isLegal((**attr))) {
return false;
}
}
-
- bool hasDynObj = false;
// can not mix -static with shared objects
mcld::InputTree::const_bfs_iterator input, inEnd = m_LDInfo.inputs().bfs_end();
for (input=m_LDInfo.inputs().bfs_begin(); input!=inEnd; ++input) {
- if ((*input)->type() == mcld::Input::DynObj ) {
- hasDynObj = true;
+ if ((*input)->type() == mcld::Input::DynObj) {
if((*input)->attribute()->isStatic()) {
- report_fatal_error("Can't link shared object with -static option");
+ error(diag::err_mixed_shared_static_objects)
+ << (*input)->name() << (*input)->path();
return false;
}
}
@@ -127,7 +121,6 @@
if (0 == m_pLinker)
m_pLinker = new MCLinker(m_LDBackend,
m_LDInfo,
- *m_LDInfo.output().context(),
m_SectionMap);
// initialize the readers and writers
@@ -137,16 +130,32 @@
!m_LDBackend.initObjectReader(*m_pLinker) ||
!m_LDBackend.initDynObjReader(*m_pLinker) ||
!m_LDBackend.initObjectWriter(*m_pLinker) ||
- !m_LDBackend.initDynObjWriter(*m_pLinker))
+ !m_LDBackend.initDynObjWriter(*m_pLinker) ||
+ !m_LDBackend.initExecWriter(*m_pLinker))
return false;
+ // initialize RelocationFactory
+ m_LDBackend.initRelocFactory(*m_pLinker);
+ return true;
+}
+
+/// initStdSections - initialize standard sections
+bool MCLDDriver::initStdSections()
+{
/// initialize section mapping for standard format, target-dependent section,
/// (and user-defined mapping)
if (!m_SectionMap.initStdSectionMap() ||
!m_LDBackend.initTargetSectionMap(m_SectionMap))
return false;
- // initialize standard segments and sections
+ /// A technical debt. We need to initialize section map here because
+ /// we do not separate output file and temporary data structure. So far,
+ /// MCLinker directly use output file's LDContext as the temporary data
+ /// structure. We will create a new data structure mcld::Module to collect
+ /// all temporary data structures togather.
+ m_pLinker->initSectionMap();
+
+ // initialize standard sections
switch (m_LDInfo.output().type()) {
case Output::DynObj: {
// intialize standard and target-dependent sections
@@ -174,12 +183,9 @@
}
} // end of switch
- // initialize target-dependent segments and sections
+ // initialize target-dependent sections
m_LDBackend.initTargetSections(*m_pLinker);
- // initialize RelocationFactory
- m_LDBackend.initRelocFactory(*m_pLinker);
-
return true;
}
@@ -226,25 +232,13 @@
return true;
}
-/// mergeSymbolTables - merge the symbol tables of input files into the
-/// output's symbol table.
-bool MCLDDriver::mergeSymbolTables()
-{
- mcld::InputTree::dfs_iterator input, inEnd = m_LDInfo.inputs().dfs_end();
- for (input=m_LDInfo.inputs().dfs_begin(); input!=inEnd; ++input) {
- if (!m_pLinker->mergeSymbolTable(**input))
- return false;
- }
- return true;
-}
-
/// addStandardSymbols - shared object and executable files need some
/// standard symbols
/// @return if there are some input symbols with the same name to the
/// standard symbols, return false
bool MCLDDriver::addStandardSymbols()
{
- return m_LDBackend.initStandardSymbols(*m_pLinker);
+ return m_LDBackend.initStandardSymbols(*m_pLinker, m_LDInfo.output());
}
/// addTargetSymbols - some targets, such as MIPS and ARM, need some
@@ -253,7 +247,7 @@
/// target symbols, return false
bool MCLDDriver::addTargetSymbols()
{
- m_LDBackend.initTargetSymbols(*m_pLinker);
+ m_LDBackend.initTargetSymbols(*m_pLinker, m_LDInfo.output());
return true;
}
@@ -284,6 +278,11 @@
m_LDBackend.allocateCommonSymbols(m_LDInfo, *m_pLinker);
+ /// check program interpreter - computer the name size of the runtime dyld
+ /// FIXME: check if we are doing static linking!
+ if (m_LDInfo.output().type() == Output::Exec)
+ m_LDBackend.sizeInterp(m_LDInfo.output(), m_LDInfo);
+
/// measure NamePools - compute the size of name pool sections
/// In ELF, will compute the size of.symtab, .strtab, .dynsym, .dynstr,
/// and .hash sections.
@@ -314,16 +313,6 @@
return true;
}
-/// relocate - applying relocation entries and create relocation
-/// section in the output files
-/// Create relocation section, asking TargetLDBackend to
-/// read the relocation information into RelocationEntry
-/// and push_back into the relocation section
-bool MCLDDriver::relocate()
-{
- return m_pLinker->applyRelocations();
-}
-
/// finalizeSymbolValue - finalize the resolved symbol value.
/// Before relocate(), after layout(), MCLinker should correct value of all
/// symbol.
@@ -332,6 +321,16 @@
return m_pLinker->finalizeSymbols();
}
+/// relocate - applying relocation entries and create relocation
+/// section in the output files
+/// Create relocation section, asking TargetLDBackend to
+/// read the relocation information into RelocationEntry
+/// and push_back into the relocation section
+bool MCLDDriver::relocation()
+{
+ return m_pLinker->applyRelocations();
+}
+
/// emitOutput - emit the output file.
bool MCLDDriver::emitOutput()
{
@@ -342,10 +341,9 @@
case Output::DynObj:
m_LDBackend.getDynObjWriter()->writeDynObj(m_LDInfo.output());
return true;
- /** TODO: open the executable file writer **/
- // case Output::Exec:
- // m_LDBackend.getExecWriter()->writeObject(m_LDInfo.output());
- // return true;
+ case Output::Exec:
+ m_LDBackend.getExecWriter()->writeExecutable(m_LDInfo.output());
+ return true;
}
return false;
}
@@ -354,5 +352,9 @@
bool MCLDDriver::postProcessing()
{
m_pLinker->syncRelocationResult();
+
+ m_LDBackend.postProcessing(m_LDInfo.output(),
+ m_LDInfo,
+ *m_pLinker);
return true;
}
diff --git a/lib/MC/MCLDInfo.cpp b/lib/MC/MCLDInfo.cpp
index 3cd0838..7ac154c 100644
--- a/lib/MC/MCLDInfo.cpp
+++ b/lib/MC/MCLDInfo.cpp
@@ -6,12 +6,14 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include <mcld/Config/Config.h>
#include <mcld/MC/MCLDInfo.h>
-#include <mcld/Support/FileSystem.h>
#include <mcld/MC/InputFactory.h>
#include <mcld/MC/AttributeFactory.h>
#include <mcld/MC/ContextFactory.h>
-#include <mcld/Config/Config.h>
+#include <mcld/LD/NamePool.h>
+#include <mcld/LD/StaticResolver.h>
+#include <mcld/Support/FileSystem.h>
#include <string>
using namespace mcld;
@@ -22,16 +24,17 @@
size_t pAttrNum,
size_t pInputNum)
: m_Options(),
- m_pBitcode(0),
- m_Triple(pTripleString),
- m_pStrSymPool(0)
+ m_Scripts(),
+ m_pBitcode(NULL),
+ m_Triple(pTripleString)
{
m_pAttrFactory = new AttributeFactory(pAttrNum);
m_pCntxtFactory = new ContextFactory(pInputNum);
- m_pMemAreaFactory = new MemoryAreaFactory(pInputNum);
m_pInputFactory = new InputFactory(pInputNum, *m_pAttrFactory);
m_pInputTree = new InputTree(*m_pInputFactory);
m_pOutput = new mcld::Output();
+ m_pResolver = new StaticResolver();
+ m_pNamePool = new NamePool(*m_pResolver, 1024);
}
MCLDInfo::~MCLDInfo()
@@ -39,9 +42,10 @@
delete m_pOutput;
delete m_pAttrFactory;
delete m_pCntxtFactory;
- delete m_pMemAreaFactory;
delete m_pInputFactory;
delete m_pInputTree;
+ delete m_pResolver;
+ delete m_pNamePool;
}
void MCLDInfo::setBitcode(const Input& pInput)
@@ -63,5 +67,5 @@
const char* MCLDInfo::version()
{
- return mcld::internal::version;
+ return MCLD_VERSION;
}
diff --git a/lib/MC/MCLDOptions.cpp b/lib/MC/MCLDOptions.cpp
index ae07f26..47dbc35 100644
--- a/lib/MC/MCLDOptions.cpp
+++ b/lib/MC/MCLDOptions.cpp
@@ -6,13 +6,59 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/MC/MCLDOptions.h"
-#include "mcld/MC/MCLDInput.h"
+#include <mcld/MC/MCLDOptions.h>
+#include <mcld/MC/MCLDInput.h>
using namespace mcld;
-//==========================
-// MCLDOptions
+//===----------------------------------------------------------------------===//
+// ScriptOptions
+ScriptOptions::ScriptOptions()
+{
+}
+
+ScriptOptions::~ScriptOptions()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// GeneralOptions
+GeneralOptions::GeneralOptions()
+ : m_pDefaultBitcode(NULL),
+ m_Verbose(-1),
+ m_MaxErrorNum(-1),
+ m_MaxWarnNum(-1),
+ m_ExecStack(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),
+ m_bNoDLOpen(false),
+ m_bNoDump(false),
+ m_bRelro(false),
+ m_bNow(false),
+ m_bOrigin(false),
+ m_bTrace(false),
+ m_Bsymbolic(false),
+ m_Bgroup(false),
+ m_bPIE(false),
+ m_bColor(true),
+ m_bAllowShlibUndefined(true),
+ m_bCreateEhFrameHdr(false)
+{
+}
+
+GeneralOptions::~GeneralOptions()
+{
+}
+
bool GeneralOptions::hasDefaultLDScript() const
{
return true;
@@ -32,3 +78,75 @@
m_Sysroot.assign(pSysroot);
}
+void GeneralOptions::addZOption(const ZOption& pOption)
+{
+ switch (pOption.kind()) {
+ case ZOption::CombReloc:
+ m_bCombReloc = true;
+ break;
+ case ZOption::NoCombReloc:
+ m_bCombReloc = false;
+ break;
+ case ZOption::Defs:
+ m_bNoUndefined = true;
+ break;
+ case ZOption::ExecStack:
+ m_ExecStack = YES;
+ break;
+ case ZOption::NoExecStack:
+ m_ExecStack = NO;
+ break;
+ case ZOption::InitFirst:
+ m_bInitFirst = true;
+ break;
+ case ZOption::InterPose:
+ m_bInterPose = true;
+ break;
+ case ZOption::LoadFltr:
+ m_bLoadFltr = true;
+ break;
+ case ZOption::MulDefs:
+ m_bMulDefs = true;
+ break;
+ case ZOption::NoCopyReloc:
+ m_bNoCopyReloc = true;
+ break;
+ case ZOption::NoDefaultLib:
+ m_bNoDefaultLib = true;
+ break;
+ case ZOption::NoDelete:
+ m_bNoDelete = true;
+ break;
+ case ZOption::NoDLOpen:
+ m_bNoDLOpen = true;
+ break;
+ case ZOption::NoDump:
+ m_bNoDump = true;
+ break;
+ case ZOption::NoRelro:
+ m_bRelro = false;
+ break;
+ case ZOption::Relro:
+ m_bRelro = true;
+ break;
+ case ZOption::Lazy:
+ m_bNow = false;
+ break;
+ case ZOption::Now:
+ m_bNow = true;
+ break;
+ case ZOption::Origin:
+ m_bOrigin = true;
+ break;
+ case ZOption::CommPageSize:
+ m_CommPageSize = pOption.pageSize();
+ break;
+ case ZOption::MaxPageSize:
+ m_MaxPageSize = pOption.pageSize();
+ break;
+ case ZOption::Unknown:
+ default:
+ assert(false && "Not a recognized -z option.");
+ break;
+ }
+}
diff --git a/lib/MC/MCLinker.cpp b/lib/MC/MCLinker.cpp
index e5327e8..4b9c50f 100644
--- a/lib/MC/MCLinker.cpp
+++ b/lib/MC/MCLinker.cpp
@@ -10,7 +10,6 @@
// This file implements the MCLinker class
//
//===----------------------------------------------------------------------===//
-
#include <mcld/MC/MCLinker.h>
#include <mcld/MC/MCLDInput.h>
#include <mcld/MC/MCLDInfo.h>
@@ -20,7 +19,10 @@
#include <mcld/LD/LDSectionFactory.h>
#include <mcld/LD/SectionMap.h>
#include <mcld/LD/RelocationFactory.h>
+#include <mcld/LD/EhFrame.h>
+#include <mcld/LD/EhFrameHdr.h>
#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
#include <mcld/Target/TargetLDBackend.h>
#include <llvm/Support/Host.h>
#include <llvm/Support/raw_ostream.h>
@@ -30,25 +32,22 @@
/// Constructor
MCLinker::MCLinker(TargetLDBackend& pBackend,
MCLDInfo& pInfo,
- LDContext& pContext,
- SectionMap& pSectionMap,
- const Resolver& pResolver)
+ SectionMap& pSectionMap)
: m_Backend(pBackend),
- m_Info(pInfo),
- m_Output(pContext),
+ m_LDInfo(pInfo),
m_SectionMap(pSectionMap),
m_LDSymbolFactory(128),
m_LDSectHdrFactory(10), // the average number of sections. (assuming 10.)
m_LDSectDataFactory(10),
- m_SectionMerger(pSectionMap, pContext),
- m_StrSymPool(pResolver, 128)
+ m_pSectionMerger(NULL)
{
- m_Info.setNamePool(m_StrSymPool);
}
/// Destructor
MCLinker::~MCLinker()
{
+ if (NULL != m_pSectionMerger)
+ delete m_pSectionMerger;
}
/// addSymbolFromObject - add a symbol from object file and resolve it
@@ -70,7 +69,7 @@
if (pBinding == ResolveInfo::Local) {
// if the symbol is a local symbol, create a LDSymbol for input, but do not
// resolve them.
- resolved_result.info = m_StrSymPool.createSymbol(pName,
+ resolved_result.info = m_LDInfo.getNamePool().createSymbol(pName,
false,
pType,
pDesc,
@@ -85,8 +84,9 @@
}
else {
// if the symbol is not local, insert and resolve it immediately
- m_StrSymPool.insertSymbol(pName, false, pType, pDesc, pBinding, pSize,
- pVisibility, &old_info, resolved_result);
+ m_LDInfo.getNamePool().insertSymbol(pName, false, pType, pDesc, pBinding,
+ pSize, pVisibility,
+ &old_info, resolved_result);
}
// the return ResolveInfo should not NULL
@@ -188,7 +188,8 @@
// insert symbol and resolve it immediately
// resolved_result is a triple <resolved_info, existent, override>
Resolver::Result resolved_result;
- m_StrSymPool.insertSymbol(pName, true, pType, pDesc, pBinding, pSize, pVisibility,
+ m_LDInfo.getNamePool().insertSymbol(pName, true, pType, pDesc,
+ pBinding, pSize, pVisibility,
NULL, resolved_result);
// the return ResolveInfo should not NULL
@@ -238,14 +239,15 @@
MCFragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
- ResolveInfo* info = m_StrSymPool.findInfo(pName);
+ ResolveInfo* info = m_LDInfo.getNamePool().findInfo(pName);
LDSymbol* output_sym = NULL;
if (NULL == info) {
// the symbol is not in the pool, create a new one.
// create a ResolveInfo
Resolver::Result result;
- m_StrSymPool.insertSymbol(pName, pIsDyn, pType, pDesc, pBinding, pSize, pVisibility,
- NULL, result);
+ m_LDInfo.getNamePool().insertSymbol(pName, pIsDyn, pType, pDesc,
+ pBinding, pSize, pVisibility,
+ NULL, result);
assert(!result.existent);
// create a output LDSymbol
@@ -307,7 +309,7 @@
MCFragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
- ResolveInfo* info = m_StrSymPool.findInfo(pName);
+ ResolveInfo* info = m_LDInfo.getNamePool().findInfo(pName);
if (NULL == info || !info->isUndef()) {
// only undefined symbol can make a reference.
@@ -361,8 +363,9 @@
// Result is <info, existent, override>
Resolver::Result result;
ResolveInfo old_info;
- m_StrSymPool.insertSymbol(pName, pIsDyn, pType, pDesc, pBinding, pSize, pVisibility,
- &old_info, result);
+ m_LDInfo.getNamePool().insertSymbol(pName, pIsDyn, pType, pDesc, pBinding,
+ pSize, pVisibility,
+ &old_info, result);
LDSymbol* output_sym = result.info->outSymbol();
bool has_output_sym = (NULL != output_sym);
@@ -403,7 +406,7 @@
MCFragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
- ResolveInfo* info = m_StrSymPool.findInfo(pName);
+ ResolveInfo* info = m_LDInfo.getNamePool().findInfo(pName);
if (NULL == info || !info->isUndef()) {
// only undefined symbol can make a reference
@@ -427,20 +430,22 @@
uint32_t pType,
uint32_t pFlag)
{
+ assert(m_LDInfo.output().hasContext());
+
// for user such as reader, standard/target fromat
LDSection* result =
m_LDSectHdrFactory.produce(pName, pKind, pType, pFlag);
// check if we need to create a output section for output LDContext
std::string sect_name = m_SectionMap.getOutputSectName(pName);
- LDSection* output_sect = m_Output.getSection(sect_name);
+ LDSection* output_sect = m_LDInfo.output().context()->getSection(sect_name);
if (NULL == output_sect) {
// create a output section and push it into output LDContext
output_sect =
m_LDSectHdrFactory.produce(sect_name, pKind, pType, pFlag);
- m_Output.getSectionTable().push_back(output_sect);
- m_SectionMerger.addMapping(pName, output_sect);
+ m_LDInfo.output().context()->getSectionTable().push_back(output_sect);
+ m_pSectionMerger->addMapping(pName, output_sect);
}
return *result;
}
@@ -453,17 +458,19 @@
uint32_t pFlag,
uint32_t pAlign)
{
+ assert(m_LDInfo.output().hasContext());
+
// check if we need to create a output section for output LDContext
std::string sect_name = m_SectionMap.getOutputSectName(pName);
- LDSection* output_sect = m_Output.getSection(sect_name);
+ LDSection* output_sect = m_LDInfo.output().context()->getSection(sect_name);
if (NULL == output_sect) {
// create a output section and push it into output LDContext
output_sect =
m_LDSectHdrFactory.produce(sect_name, pKind, pType, pFlag);
output_sect->setAlign(pAlign);
- m_Output.getSectionTable().push_back(output_sect);
- m_SectionMerger.addMapping(pName, output_sect);
+ m_LDInfo.output().context()->getSectionTable().push_back(output_sect);
+ m_pSectionMerger->addMapping(pName, output_sect);
}
return *output_sect;
}
@@ -481,7 +488,7 @@
// try to get one from output LDSection
LDSection* output_sect =
- m_SectionMerger.getOutputSectHdr(pSection.name());
+ m_pSectionMerger->getOutputSectHdr(pSection.name());
assert(NULL != output_sect);
@@ -509,8 +516,17 @@
const LDSymbol& pSym,
ResolveInfo& pResolveInfo,
MCFragmentRef& pFragmentRef,
+ const LDSection& pSection,
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.
+ if (pSym.fragRef() == NULL &&
+ pResolveInfo.type() == ResolveInfo::Section &&
+ pResolveInfo.desc() == ResolveInfo::Undefined)
+ return NULL;
+
Relocation* relocation = m_Backend.getRelocFactory()->produce(pType,
pFragmentRef,
pAddend);
@@ -519,9 +535,11 @@
m_RelocationList.push_back(relocation);
- m_Backend.scanRelocation(*relocation, pSym, *this, m_Info,
- m_Info.output());
+ m_Backend.scanRelocation(*relocation, pSym, *this, m_LDInfo,
+ m_LDInfo.output(), pSection);
+ if (pResolveInfo.isUndef() && !pResolveInfo.isDyn() && !pResolveInfo.isWeak())
+ fatal(diag::undefined_reference) << pResolveInfo.name();
return relocation;
}
@@ -531,7 +549,7 @@
for (relocIter = m_RelocationList.begin(); relocIter != relocEnd; ++relocIter) {
llvm::MCFragment* frag = (llvm::MCFragment*)relocIter;
- static_cast<Relocation*>(frag)->apply(*m_Backend.getRelocFactory(), m_Info);
+ static_cast<Relocation*>(frag)->apply(*m_Backend.getRelocFactory(), m_LDInfo);
}
return true;
}
@@ -539,9 +557,8 @@
void MCLinker::syncRelocationResult()
{
- m_Info.output().memArea()->clean();
- MemoryRegion* region = m_Info.output().memArea()->request(0,
- m_Info.output().memArea()->size());
+ MemoryRegion* region = m_LDInfo.output().memArea()->request(0,
+ m_LDInfo.output().memArea()->handler()->size());
uint8_t* data = region->getBuffer();
@@ -580,13 +597,19 @@
}
} // end of for
- m_Info.output().memArea()->sync();
+ m_LDInfo.output().memArea()->clear();
}
+void MCLinker::initSectionMap()
+{
+ assert(m_LDInfo.output().hasContext());
+ if (NULL == m_pSectionMerger)
+ m_pSectionMerger = new SectionMerger(m_SectionMap, *m_LDInfo.output().context());
+}
bool MCLinker::layout()
{
- return m_Layout.layout(m_Info.output(), m_Backend);
+ return m_Layout.layout(m_LDInfo.output(), m_Backend, m_LDInfo);
}
bool MCLinker::finalizeSymbols()
@@ -594,18 +617,9 @@
SymbolCategory::iterator symbol, symEnd = m_OutputSymbols.end();
for (symbol = m_OutputSymbols.begin(); symbol != symEnd; ++symbol) {
- if (0x0 != (*symbol)->resolveInfo()->reserved()) {
- // if the symbol is target reserved, target backend is responsible
- // for finalizing the value.
- // if target backend does not know this symbol, it will return false
- // and we have to take over the symbol.
- if (m_Backend.finalizeSymbol(**symbol))
- continue;
- }
-
if ((*symbol)->resolveInfo()->isAbsolute() ||
(*symbol)->resolveInfo()->type() == ResolveInfo::File) {
- // absolute symbols and symbols with function type should have
+ // absolute symbols or symbols with function type should have
// zero value
(*symbol)->setValue(0x0);
continue;
@@ -623,7 +637,8 @@
}
}
- return true;
+ // finialize target-dependent symbols
+ return m_Backend.finalizeSymbols(*this, m_LDInfo.output());
}
bool MCLinker::shouldForceLocal(const ResolveInfo& pInfo) const
@@ -633,7 +648,7 @@
// 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 (m_Info.output().type() != Output::Object &&
+ if (m_LDInfo.output().type() != Output::Object &&
(pInfo.visibility() == ResolveInfo::Hidden ||
pInfo.visibility() == ResolveInfo::Internal) &&
(pInfo.isGlobal() || pInfo.isWeak()) &&
@@ -642,3 +657,44 @@
return false;
}
+/// addEhFrame - add an exception handling section
+/// @param pSection - the input section
+/// @param pArea - the memory area which pSection is within.
+uint64_t MCLinker::addEhFrame(LDSection& pSection, MemoryArea& pArea)
+{
+ uint64_t size = 0;
+
+ // get the SectionData of this eh_frame
+ llvm::MCSectionData& sect_data = getOrCreateSectData(pSection);
+
+ // parse the eh_frame if the option --eh-frame-hdr is given
+ if (m_LDInfo.options().hasEhFrameHdr()) {
+ EhFrame* ehframe = m_Backend.getEhFrame();
+ assert(NULL != ehframe);
+ if (ehframe->canRecognizeAllEhFrame()) {
+ size = ehframe->readEhFrame(m_Layout, m_Backend, sect_data, pSection,
+ pArea);
+ // zero size indicate that this is an empty section or we can't recognize
+ // this eh_frame, handle it as a regular section.
+ if (0 != size)
+ return size;
+ }
+ }
+
+ // handle eh_frame as a regular section
+ MemoryRegion* region = pArea.request(pSection.offset(),
+ pSection.size());
+
+ llvm::MCFragment* frag = NULL;
+ if (NULL == region) {
+ // If the input section's size is zero, we got a NULL region.
+ // use a virtual fill fragment
+ frag = new llvm::MCFillFragment(0x0, 0, 0);
+ }
+ else
+ frag = new MCRegionFragment(*region);
+
+ size = m_Layout.appendFragment(*frag, sect_data, pSection.align());
+ return size;
+}
+
diff --git a/lib/MC/README b/lib/MC/README
deleted file mode 100644
index f020b50..0000000
--- a/lib/MC/README
+++ /dev/null
@@ -1,8 +0,0 @@
-MCLDStreamer is similar to MCObjectStreamer
-MCLinker is similar to MCAssembler
-MCLDWriter is similar to MCObjectWriter
-
-MCELFObjectReader parses ELF object files
-to MCInst classes
-
-
diff --git a/lib/MC/SearchDirs.cpp b/lib/MC/SearchDirs.cpp
index 0d21e46..40d625b 100644
--- a/lib/MC/SearchDirs.cpp
+++ b/lib/MC/SearchDirs.cpp
@@ -6,16 +6,13 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include <llvm/Support/ErrorHandling.h>
-#include <llvm/ADT/Twine.h>
-
-#include "mcld/MC/SearchDirs.h"
-#include "mcld/Support/FileSystem.h"
-#include "mcld/MC/MCLDDirectory.h"
+#include <mcld/MC/SearchDirs.h>
+#include <mcld/MC/MCLDDirectory.h>
+#include <mcld/Support/FileSystem.h>
using namespace mcld;
-//==========================
+//===----------------------------------------------------------------------===//
// Non-member functions
static void SpecToFilename(const std::string& pSpec, std::string& pFile)
{
@@ -23,7 +20,7 @@
pFile += pSpec;
}
-//==========================
+//===----------------------------------------------------------------------===//
// SearchDirs
SearchDirs::SearchDirs()
{
@@ -47,6 +44,8 @@
mcld::sys::fs::Path* SearchDirs::find(const std::string& pNamespec, mcld::Input::Type pType)
{
+ assert(Input::DynObj == pType || Input::Archive == pType);
+
std::string file;
SpecToFilename(pNamespec, file);
// for all MCLDDirectorys
@@ -64,11 +63,10 @@
return entry.path();
}
}
-
++entry;
}
}
-
+ /** Fall through **/
case Input::Archive : {
entry = (*mcld_dir)->begin();
enEnd = (*mcld_dir)->end();
@@ -78,15 +76,12 @@
return entry.path();
}
++entry;
- }
- }
- default: {
- llvm::report_fatal_error(llvm::Twine("SearchDir can not recoginize namespec: `") +
- pNamespec +
- llvm::Twine("'."));
- }
- }
- }
- return 0;
+ }
+ }
+ default:
+ break;
+ } // end of switch
+ } // end of while
+ return NULL;
}
diff --git a/lib/MC/ZOption.cpp b/lib/MC/ZOption.cpp
new file mode 100644
index 0000000..a58562d
--- /dev/null
+++ b/lib/MC/ZOption.cpp
@@ -0,0 +1,25 @@
+//===- ZOption.cpp --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/MC/ZOption.h>
+
+using namespace mcld;
+
+//==========================
+// ZOption
+
+ZOption::ZOption()
+ : m_Kind(Unknown),
+ m_PageSize(0x0)
+{
+}
+
+ZOption::~ZOption()
+{
+}
+
diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp
index 57b82df..cc15e37 100644
--- a/lib/Support/CommandLine.cpp
+++ b/lib/Support/CommandLine.cpp
@@ -6,12 +6,16 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/Support/CommandLine.h"
+#include <mcld/Support/CommandLine.h>
#include <llvm/ADT/StringRef.h>
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ErrorHandling.h>
using namespace llvm;
using namespace llvm::cl;
+using namespace mcld;
+
//--------------------------------------------------
// parser<mcld::sys::fs::Path>
//
@@ -82,3 +86,81 @@
// do nothing
}
+//--------------------------------------------------
+// parser<mcld::ZOption>
+//
+bool parser<mcld::ZOption>::parse(llvm::cl::Option &O,
+ llvm::StringRef ArgName,
+ llvm::StringRef Arg,
+ mcld::ZOption &Val)
+{
+ if (0 == Arg.compare("combreloc"))
+ Val.setKind(ZOption::CombReloc);
+ else if (0 == Arg.compare("nocombreloc"))
+ Val.setKind(ZOption::NoCombReloc);
+ else if (0 == Arg.compare("defs"))
+ Val.setKind(ZOption::Defs);
+ else if (0 == Arg.compare("execstack"))
+ Val.setKind(ZOption::ExecStack);
+ else if (0 == Arg.compare("noexecstack"))
+ Val.setKind(ZOption::NoExecStack);
+ else if (0 == Arg.compare("initfirst"))
+ Val.setKind(ZOption::InitFirst);
+ else if (0 == Arg.compare("interpose"))
+ Val.setKind(ZOption::InterPose);
+ else if (0 == Arg.compare("loadfltr"))
+ Val.setKind(ZOption::LoadFltr);
+ else if (0 == Arg.compare("muldefs"))
+ Val.setKind(ZOption::MulDefs);
+ else if (0 == Arg.compare("nocopyreloc"))
+ Val.setKind(ZOption::NoCopyReloc);
+ else if (0 == Arg.compare("nodefaultlib"))
+ Val.setKind(ZOption::NoDefaultLib);
+ else if (0 == Arg.compare("nodelete"))
+ Val.setKind(ZOption::NoDelete);
+ else if (0 == Arg.compare("nodlopen"))
+ Val.setKind(ZOption::NoDLOpen);
+ else if (0 == Arg.compare("nodump"))
+ Val.setKind(ZOption::NoDump);
+ else if (0 == Arg.compare("relro"))
+ Val.setKind(ZOption::Relro);
+ else if (0 == Arg.compare("norelro"))
+ Val.setKind(ZOption::NoRelro);
+ else if (0 == Arg.compare("lazy"))
+ Val.setKind(ZOption::Lazy);
+ else if (0 == Arg.compare("now"))
+ Val.setKind(ZOption::Now);
+ else if (0 == Arg.compare("origin"))
+ Val.setKind(ZOption::Origin);
+ else if (Arg.startswith("common-page-size=")) {
+ Val.setKind(ZOption::CommPageSize);
+ 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=")) {
+ Val.setKind(ZOption::MaxPageSize);
+ long long unsigned size = 0;
+ Arg.drop_front(14).getAsInteger(0, size);
+ Val.setPageSize(static_cast<uint64_t>(size));
+ }
+
+ if (ZOption::Unknown == Val.kind())
+ llvm::report_fatal_error(llvm::Twine("unknown -z option: `") +
+ Arg +
+ llvm::Twine("'\n"));
+ return false;
+}
+
+void parser<mcld::ZOption>::printOptionDiff(const llvm::cl::Option &O,
+ const mcld::ZOption &V,
+ parser<mcld::ZOption>::OptVal Default,
+ size_t GlobalWidth) const
+{
+ // TODO
+}
+
+void parser<mcld::ZOption>::anchor()
+{
+ // do nothing
+}
+
diff --git a/lib/Support/Directory.cpp b/lib/Support/Directory.cpp
index 211b42a..78bb761 100644
--- a/lib/Support/Directory.cpp
+++ b/lib/Support/Directory.cpp
@@ -32,7 +32,7 @@
: m_Path(),
m_FileStatus(),
m_SymLinkStatus(),
- m_Handler(NULL),
+ m_Handler(0),
m_Cache(),
m_CacheFull(false) {
}
@@ -43,7 +43,7 @@
: m_Path(pPath),
m_FileStatus(st),
m_SymLinkStatus(symlink_st),
- m_Handler(NULL),
+ m_Handler(0),
m_Cache(),
m_CacheFull(false) {
if (m_Path.native() == ".")
@@ -56,7 +56,7 @@
: m_Path(pCopy.m_Path),
m_FileStatus(pCopy.m_FileStatus),
m_SymLinkStatus(pCopy.m_SymLinkStatus),
- m_Handler(NULL),
+ m_Handler(0),
m_Cache(),
m_CacheFull(false) {
mcld::sys::fs::detail::open_dir(*this);
diff --git a/lib/Support/FileHandle.cpp b/lib/Support/FileHandle.cpp
new file mode 100644
index 0000000..f6b898c
--- /dev/null
+++ b/lib/Support/FileHandle.cpp
@@ -0,0 +1,332 @@
+//===- FileHandle.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 <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// FileHandle
+FileHandle::FileHandle()
+ : m_Path(),
+ m_Handler(-1),
+ m_Size(0),
+ m_State(GoodBit),
+ m_OpenMode(NotOpen) {
+}
+
+FileHandle::~FileHandle()
+{
+ if (isOpened())
+ close();
+}
+
+inline static int oflag(FileHandle::OpenMode pMode)
+{
+ int result = 0x0;
+ if (FileHandle::Unknown == pMode)
+ return result;
+
+ if (FileHandle::ReadWrite == (pMode & FileHandle::ReadWrite))
+ result |= O_RDWR;
+ else if (pMode & FileHandle::ReadOnly)
+ result |= O_RDONLY;
+ else if (pMode & FileHandle::WriteOnly)
+ result |= O_WRONLY;
+
+ if (pMode & FileHandle::Append)
+ result |= O_APPEND;
+
+ if (pMode & FileHandle::Create)
+ result |= O_CREAT;
+
+ if (pMode & FileHandle::Truncate)
+ result |= O_TRUNC;
+
+ return result;
+}
+
+inline static bool get_size(int pHandler, unsigned int &pSize)
+{
+ struct ::stat file_stat;
+ if (-1 == ::fstat(pHandler, &file_stat)) {
+ pSize = 0;
+ return false;
+ }
+ pSize = file_stat.st_size;
+ return true;
+}
+
+bool FileHandle::open(const sys::fs::Path& pPath,
+ FileHandle::OpenMode pMode)
+{
+ if (isOpened() || Unknown == pMode) {
+ setState(BadBit);
+ return false;
+ }
+
+ m_OpenMode = pMode;
+ m_Handler = ::open(pPath.native().c_str(), oflag(pMode));
+ m_Path = pPath;
+ if (-1 == m_Handler) {
+ m_OpenMode = NotOpen;
+ setState(FailBit);
+ return false;
+ }
+
+ if (!get_size(m_Handler, m_Size)) {
+ setState(FailBit);
+ return false;
+ }
+
+ return true;
+}
+
+bool FileHandle::open(const sys::fs::Path& pPath,
+ FileHandle::OpenMode pMode,
+ FileHandle::Permission pPerm)
+{
+ if (isOpened() || Unknown == pMode) {
+ setState(BadBit);
+ return false;
+ }
+
+ m_OpenMode = pMode;
+ m_Handler = sys::fs::detail::open(pPath, oflag(pMode), (int)pPerm);
+ m_Path = pPath;
+ if (-1 == m_Handler) {
+ m_OpenMode = NotOpen;
+ setState(FailBit);
+ return false;
+ }
+
+ if (!get_size(m_Handler, m_Size)) {
+ setState(FailBit);
+ return false;
+ }
+
+ return true;
+}
+
+bool FileHandle::delegate(int pFD, FileHandle::OpenMode pMode)
+{
+ if (isOpened()) {
+ setState(BadBit);
+ return false;
+ }
+
+ m_Handler = pFD;
+ m_OpenMode = pMode;
+ m_State = GoodBit;
+
+ if (!get_size(m_Handler, m_Size)) {
+ setState(FailBit);
+ return false;
+ }
+
+ return true;
+}
+
+bool FileHandle::close()
+{
+ if (!isOpened()) {
+ setState(BadBit);
+ return false;
+ }
+
+ if (-1 == ::close(m_Handler)) {
+ setState(FailBit);
+ return false;
+ }
+
+ m_Path.native().clear();
+ m_Size = 0;
+ m_OpenMode = NotOpen;
+ cleanState();
+ return true;
+}
+
+bool FileHandle::truncate(size_t pSize)
+{
+ if (!isOpened() || !isWritable()) {
+ setState(BadBit);
+ return false;
+ }
+
+ if (-1 == sys::fs::detail::ftruncate(m_Handler, pSize)) {
+ setState(FailBit);
+ return false;
+ }
+
+ m_Size = pSize;
+ return true;
+}
+
+bool FileHandle::read(void* pMemBuffer, size_t pStartOffset, size_t pLength)
+{
+ if (!isOpened() || !isReadable()) {
+ setState(BadBit);
+ return false;
+ }
+
+ if (0 == pLength)
+ return true;
+
+ ssize_t read_bytes = sys::fs::detail::pread(m_Handler,
+ pMemBuffer,
+ pLength,
+ pStartOffset);
+
+ if (-1 == read_bytes) {
+ setState(FailBit);
+ return false;
+ }
+
+ return true;
+}
+
+bool FileHandle::write(const void* pMemBuffer, size_t pStartOffset, size_t pLength)
+{
+ if (!isOpened() || !isWritable()) {
+ setState(BadBit);
+ return false;
+ }
+
+ if (0 == pLength)
+ return true;
+
+
+ ssize_t write_bytes = sys::fs::detail::pwrite(m_Handler,
+ pMemBuffer,
+ pLength,
+ pStartOffset);
+
+ if (-1 == write_bytes) {
+ setState(FailBit);
+ return false;
+ }
+
+ return true;
+}
+
+#include <iostream>
+using namespace std;
+
+bool FileHandle::mmap(void*& pMemBuffer, size_t pStartOffset, size_t pLength)
+{
+ if (!isOpened()) {
+ setState(BadBit);
+ return false;
+ }
+
+ if (0 == pLength)
+ return true;
+
+ int prot, flag;
+ if (isReadable() && !isWritable()) {
+ // read-only
+ prot = PROT_READ;
+ flag = MAP_FILE | MAP_PRIVATE;
+ }
+ else if (!isReadable() && isWritable()) {
+ // write-only
+ prot = PROT_WRITE;
+ flag = MAP_FILE | MAP_SHARED;
+ }
+ else if (isReadWrite()) {
+ // read and write
+ prot = PROT_READ | PROT_WRITE;
+ flag = MAP_FILE | MAP_SHARED;
+ }
+ else {
+ // can not read/write
+ setState(BadBit);
+ return false;
+ }
+
+ pMemBuffer = ::mmap(NULL, pLength, prot, flag, m_Handler, pStartOffset);
+
+ if (MAP_FAILED == pMemBuffer) {
+ setState(FailBit);
+ return false;
+ }
+
+ return true;
+}
+
+bool FileHandle::munmap(void* pMemBuffer, size_t pLength)
+{
+ if (!isOpened()) {
+ setState(BadBit);
+ return false;
+ }
+
+ if (-1 == ::munmap(pMemBuffer, pLength)) {
+ setState(FailBit);
+ return false;
+ }
+
+ return true;
+}
+
+void FileHandle::setState(FileHandle::IOState pState)
+{
+ m_State |= pState;
+}
+
+void FileHandle::cleanState(FileHandle::IOState pState)
+{
+ m_State = pState;
+}
+
+bool FileHandle::isOpened() const
+{
+ if (-1 != m_Handler && m_OpenMode != NotOpen && isGood())
+ return true;
+
+ return false;
+}
+
+// Assume Unknown OpenMode is readable
+bool FileHandle::isReadable() const
+{
+ return (m_OpenMode & ReadOnly);
+}
+
+// Assume Unknown OpenMode is writable
+bool FileHandle::isWritable() const
+{
+ return (m_OpenMode & WriteOnly);
+}
+
+// Assume Unknown OpenMode is both readable and writable
+bool FileHandle::isReadWrite() const
+{
+ return (FileHandle::ReadWrite == (m_OpenMode & FileHandle::ReadWrite));
+}
+
+bool FileHandle::isGood() const
+{
+ return !(m_State & (BadBit | FailBit));
+}
+
+bool FileHandle::isBad() const
+{
+ return (m_State & BadBit);
+}
+
+bool FileHandle::isFailed() const
+{
+ return (m_State & (BadBit | FailBit));
+}
+
diff --git a/lib/Support/FileSystem.cpp b/lib/Support/FileSystem.cpp
index d3366c0..fb2633d 100644
--- a/lib/Support/FileSystem.cpp
+++ b/lib/Support/FileSystem.cpp
@@ -9,10 +9,6 @@
#include "mcld/Support/FileSystem.h"
#include "mcld/Support/Path.h"
-#if defined(ANDROID)
-#include <llvm/Config/config.h>
-#endif
-
using namespace mcld::sys::fs;
@@ -22,12 +18,12 @@
//===--------------------------------------------------------------------===//
// non-member functions
-// Include the truly platform-specific parts.
-#if defined(LLVM_ON_UNIX)
+// Include the truly platform-specific parts.
+#if defined(MCLD_ON_UNIX)
#include "Unix/FileSystem.inc"
-#include "Unix/PathV3.inc"
-#endif
-#if defined(LLVM_ON_WIN32)
+#include "Unix/PathV3.inc"
+#endif
+#if defined(MCLD_ON_WIN32)
#include "Windows/FileSystem.inc"
-#include "Windows/PathV3.inc"
-#endif
+#include "Windows/PathV3.inc"
+#endif
diff --git a/lib/Support/HandleToArea.cpp b/lib/Support/HandleToArea.cpp
new file mode 100644
index 0000000..f580e64
--- /dev/null
+++ b/lib/Support/HandleToArea.cpp
@@ -0,0 +1,94 @@
+//===- 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 f388e94..78a9d36 100644
--- a/lib/Support/MemoryArea.cpp
+++ b/lib/Support/MemoryArea.cpp
@@ -6,164 +6,31 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include <llvm/Support/ErrorHandling.h>
-#include <llvm/ADT/Twine.h>
-
#include <mcld/Support/RegionFactory.h>
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/MemoryRegion.h>
-#include <mcld/Support/FileSystem.h>
-
-#include <cerrno>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
+#include <mcld/Support/FileHandle.h>
+#include <mcld/Support/MsgHandling.h>
using namespace mcld;
//===--------------------------------------------------------------------===//
// MemoryArea
-MemoryArea::MemoryArea(RegionFactory& pRegionFactory)
- : m_RegionFactory(pRegionFactory),
- m_FileDescriptor(-1),
- m_FileSize(0),
- m_AccessFlags(ReadOnly),
- m_State(BadBit) {
+
+// MemoryArea - special constructor
+// This constructor is used for *SPECIAL* situation. I'm sorry I can not
+// reveal what is the special situation.
+MemoryArea::MemoryArea(RegionFactory& pRegionFactory, Space& pUniverse)
+ : m_RegionFactory(pRegionFactory), m_pFileHandle(NULL) {
+ m_SpaceList.push_back(&pUniverse);
+}
+
+MemoryArea::MemoryArea(RegionFactory& pRegionFactory, FileHandle& pFileHandle)
+ : m_RegionFactory(pRegionFactory), m_pFileHandle(&pFileHandle) {
}
MemoryArea::~MemoryArea()
{
- // truncate the file to real size
- if (isWritable())
- truncate(m_FileSize);
-
- unmap();
-}
-
-void MemoryArea::truncate(size_t pLength)
-{
- if (!isWritable())
- return;
-
- if (-1 == ::ftruncate(m_FileDescriptor, static_cast<off_t>(pLength))) {
- llvm::report_fatal_error(llvm::Twine("Cannot truncate `") +
- m_FilePath.native() +
- llvm::Twine("' to size: ") +
- llvm::Twine(pLength) +
- llvm::Twine(".\n"));
- }
-}
-
-void MemoryArea::map(const sys::fs::Path& pPath, int pFlags)
-{
- m_AccessFlags = pFlags;
- m_FilePath = pPath;
- m_FileDescriptor = ::open(m_FilePath.c_str(), m_AccessFlags);
-
- if (-1 == m_FileDescriptor) {
- m_State |= FailBit;
- }
- else {
- struct stat st;
- int stat_result = ::stat(m_FilePath.native().c_str(), &st);
- if (0x0 == stat_result) {
- m_FileSize = static_cast<size_t>(st.st_size);
- m_State = GoodBit;
- }
- else {
- m_FileSize = 0x0;
- m_State |= FailBit;
- m_State |= BadBit;
- }
- }
-}
-
-void MemoryArea::map(const sys::fs::Path& pPath, int pFlags, int pMode)
-{
- m_AccessFlags = pFlags;
- m_FilePath = pPath;
- m_FileDescriptor = ::open(m_FilePath.c_str(), m_AccessFlags, pMode);
-
- if (-1 == m_FileDescriptor) {
- m_State |= FailBit;
- }
- else {
- struct stat st;
- int stat_result = ::stat(m_FilePath.native().c_str(), &st);
- if (0x0 == stat_result) {
- m_FileSize = static_cast<size_t>(st.st_size);
- m_State = GoodBit;
- }
- else {
- m_FileSize = 0x0;
- m_State |= FailBit;
- m_State |= BadBit;
- }
- }
-}
-
-void MemoryArea::unmap()
-{
- if (isMapped()) {
- if (-1 == ::close(m_FileDescriptor))
- m_State |= FailBit;
- else {
- m_FileDescriptor = -1;
- m_AccessFlags = ReadOnly;
- }
- }
-}
-
-bool MemoryArea::isMapped() const
-{
- return (-1 != m_FileDescriptor);
-}
-
-bool MemoryArea::isGood() const
-{
- return 0x0 == (m_State & (BadBit | FailBit));
-}
-
-bool MemoryArea::isBad() const
-{
- return 0x0 != (m_State & BadBit);
-}
-
-bool MemoryArea::isFailed() const
-{
- return 0x0 != (m_State & FailBit);
-}
-
-bool MemoryArea::isEOF() const
-{
- return 0x0 != (m_State & EOFBit);
-}
-
-bool MemoryArea::isReadable() const
-{
- return (((m_AccessFlags & AccessMask) == ReadOnly) ||
- ((m_AccessFlags & AccessMask) == ReadWrite));
-}
-
-bool MemoryArea::isWritable() const
-{
- return (((m_AccessFlags & AccessMask) == WriteOnly) ||
- ((m_AccessFlags & AccessMask) == ReadWrite));
-}
-
-int MemoryArea::rdstate() const
-{
- return m_State;
-}
-
-void MemoryArea::setState(MemoryArea::IOState pState)
-{
- m_State |= pState;
-}
-
-void MemoryArea::clear(MemoryArea::IOState pState)
-{
- m_State = pState;
}
// The layout of MemorySpace in the virtual memory space
@@ -185,242 +52,100 @@
//
MemoryRegion* MemoryArea::request(size_t pOffset, size_t pLength)
{
- if (!isMapped() || !isGood())
- return NULL;
-
- if (0x0 == pLength)
- return NULL;
-
- if (!isWritable() && (pOffset + pLength) > m_FileSize)
- return NULL;
-
- if (isWritable() && (pOffset + pLength) > m_FileSize) {
- // If the memory area is writable, user can expand the size of file by
- // request a region larger than the file.
- // MemoryArea should enlarge the file if the requested region is larger
- // than the file.
- m_FileSize = page_boundary(pOffset + pLength + 1);
- truncate(m_FileSize);
- }
-
Space* space = find(pOffset, pLength);
- MemoryArea::Address r_start = 0;
if (NULL == space) {
- // the space does not exist, create a new space.
- space = new Space(this, pOffset, pLength);
+
+ // 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);
+ }
+
+ space = Space::createSpace(*m_pFileHandle, pOffset, pLength);
m_SpaceList.push_back(space);
- switch(space->type = policy(pOffset, pLength)) {
- case Space::MMAPED: {
- int mm_prot, mm_flag;
- if (isWritable()) {
- mm_prot = PROT_READ | PROT_WRITE;
- mm_flag = MAP_FILE | MAP_SHARED;
- }
- else {
- mm_prot = PROT_READ;
- mm_flag = MAP_FILE | MAP_PRIVATE;
- }
-
- space->file_offset = page_offset(pOffset);
-
- // The space's size may be larger than filesize.
- space->size = page_boundary(pLength + pOffset + 1 - space->file_offset);
- space->data = (Address) ::mmap(NULL,
- space->size,
- mm_prot, mm_flag,
- m_FileDescriptor,
- space->file_offset);
-
- if (space->data == MAP_FAILED) {
- llvm::report_fatal_error(llvm::Twine("cannot open memory map file :") +
- m_FilePath.native() +
- llvm::Twine(" (") +
- sys::fs::detail::strerror(errno) +
- llvm::Twine(").\n"));
- }
-
- r_start = space->data + (pOffset - space->file_offset);
- break;
- }
- case Space::ALLOCATED_ARRAY: {
- // space->offset and space->size are set in constructor. We only need
- // to set up data.
- space->data = new unsigned char[pLength];
- r_start = space->data;
- if ((m_AccessFlags & AccessMask) != WriteOnly) {
- // Read data from the backend file.
- if (!read(*space)) {
- llvm::report_fatal_error(llvm::Twine("Failed to read data from ") +
- m_FilePath.native() +
- llvm::Twine(" (") +
- sys::fs::detail::strerror(errno) +
- llvm::Twine(") at offset ") +
- llvm::Twine(pOffset) +
- llvm::Twine(" lenght ") +
- llvm::Twine(pLength) + llvm::Twine(".\n"));
- }
- }
- break;
- } // case
- default: {
- llvm::report_fatal_error("unhandled space type\n");
- }
- } // switch
}
- else { // found
- off_t distance = pOffset - space->file_offset;
- r_start = space->data + distance;
- }
+
+ // 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 m_RegionFactory.produce(space, r_start, pLength);
+ return m_RegionFactory.produce(*space, r_start, pLength);
}
// release - release a MemoryRegion
void MemoryArea::release(MemoryRegion* pRegion)
{
- if (!isMapped() || !isGood())
+ if (NULL == pRegion)
return;
Space *space = pRegion->parent();
m_RegionFactory.destruct(pRegion);
- if (0 == space->region_num) {
- write(*space);
- m_SpaceList.remove(*space);
- release(space);
+ 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::syncSpace(space, *m_pFileHandle);
+ }
+ Space::releaseSpace(space, *m_pFileHandle);
+ }
+ m_SpaceList.erase(space);
}
}
-void MemoryArea::clean()
+// clear - release all MemoryRegions
+void MemoryArea::clear()
{
- m_RegionFactory.clear();
+ if (NULL == m_pFileHandle)
+ return;
- SpaceList::iterator sIter, sEnd = m_SpaceList.end();
- for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
- write(*sIter);
- release(sIter);
+ if (m_pFileHandle->isWritable()) {
+ SpaceList::iterator space, sEnd = m_SpaceList.end();
+ for (space = m_SpaceList.begin(); space != sEnd; ++space) {
+ Space::syncSpace(space, *m_pFileHandle);
+ Space::releaseSpace(space, *m_pFileHandle);
+ }
}
+ else {
+ SpaceList::iterator space, sEnd = m_SpaceList.end();
+ for (space = m_SpaceList.begin(); space != sEnd; ++space)
+ Space::releaseSpace(space, *m_pFileHandle);
+ }
+
m_SpaceList.clear();
}
-void MemoryArea::sync()
+//===--------------------------------------------------------------------===//
+// SpaceList methods
+Space* MemoryArea::find(size_t pOffset, size_t pLength)
{
SpaceList::iterator sIter, sEnd = m_SpaceList.end();
for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
- write(*sIter);
- }
-}
-
-MemoryArea::Space* MemoryArea::find(size_t pOffset, size_t pLength)
-{
- SpaceList::iterator sIter, sEnd = m_SpaceList.end();
- for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
- if (sIter->file_offset <= pOffset &&
- (pOffset+pLength) <= (sIter->file_offset+sIter->size) ) { // within
+ if (sIter->start() <= pOffset &&
+ (pOffset+pLength) <= (sIter->start()+sIter->size()) ) {
+ // within
return sIter;
}
}
return NULL;
}
-void MemoryArea::release(MemoryArea::Space* pSpace)
+const Space* MemoryArea::find(size_t pOffset, size_t pLength) const
{
- switch (pSpace->type) {
- case Space::ALLOCATED_ARRAY: {
- delete [] pSpace->data;
- break;
- }
- case Space::MMAPED: {
- ::munmap(pSpace->data, pSpace->size);
- break;
- }
- default:
- break;
- }
-}
-
-MemoryArea::Space::Type MemoryArea::policy(off_t pOffset, size_t pLength)
-{
- const size_t threshold = (PageSize*3)/4; // 3/4 page size in Linux
- if (pLength < threshold)
- return Space::ALLOCATED_ARRAY;
- else
- return Space::MMAPED;
-}
-
-ssize_t MemoryArea::readToBuffer(sys::fs::detail::Address pBuf,
- size_t pSize, size_t pOffset) {
- assert(((m_AccessFlags & AccessMask) != WriteOnly) &&
- "Write-only file cannot be read!");
-
- ssize_t read_bytes = sys::fs::detail::pread(m_FileDescriptor, pBuf,
- pSize, pOffset);
- if (static_cast<size_t>(read_bytes) != pSize) {
- // Some error occurred during pread().
- if (read_bytes < 0) {
- m_State |= FailBit;
- }
- else if (static_cast<size_t>(read_bytes) < pSize) {
- m_State |= EOFBit;
- if ((m_AccessFlags & AccessMask) != ReadWrite) {
- // Files which is not read-write are not allowed read beyonds the EOF
- // marker.
- m_State |= BadBit;
- }
- }
- else {
- m_State |= BadBit;
+ SpaceList::const_iterator sIter, sEnd = m_SpaceList.end();
+ for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
+ if (sIter->start() <= pOffset &&
+ (pOffset+pLength) <= (sIter->start()+sIter->size()) ) {
+ // within
+ return sIter;
}
}
- return read_bytes;
-}
-
-bool MemoryArea::read(Space& pSpace) {
- if (!isGood() || !isReadable())
- return false;
-
- if (pSpace.type == Space::ALLOCATED_ARRAY) {
- readToBuffer(pSpace.data, pSpace.size, pSpace.file_offset);
- return isGood();
- }
- else {
- // Data associated with mmap()'ed space is already at the position the
- // pSpace points to.
- assert((pSpace.type == Space::MMAPED) && "Unknown type of Space!");
- return true;
- }
-}
-
-
-void MemoryArea::write(const Space& pSpace)
-{
- if (!isMapped() || !isGood() || !isWritable())
- return;
-
- switch(pSpace.type) {
- case Space::MMAPED: {
- if(-1 == ::msync(pSpace.data, pSpace.size, MS_SYNC))
- m_State |= FailBit;
- return;
- }
- case Space::ALLOCATED_ARRAY: {
- ssize_t write_bytes = sys::fs::detail::pwrite(m_FileDescriptor,
- pSpace.data,
- pSpace.size,
- pSpace.file_offset);
- if (0 > write_bytes) {
- m_State |= FailBit;
- return;
- }
- if (0 == write_bytes && 0 != pSpace.size)
- m_State |= BadBit;
- if ( pSpace.size > static_cast<size_t>(write_bytes) )
- m_State |= EOFBit;
- return;
- }
- default:
- return;
- }
+ return NULL;
}
diff --git a/lib/Support/MemoryAreaFactory.cpp b/lib/Support/MemoryAreaFactory.cpp
index 1f7e523..3da07d5 100644
--- a/lib/Support/MemoryAreaFactory.cpp
+++ b/lib/Support/MemoryAreaFactory.cpp
@@ -6,15 +6,18 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/Support/MemoryAreaFactory.h"
-#include "mcld/Support/RegionFactory.h"
+#include <mcld/Support/MemoryAreaFactory.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/RegionFactory.h>
+#include <mcld/Support/SystemUtils.h>
+#include <mcld/Support/Space.h>
using namespace mcld;
-//==========================
+//===----------------------------------------------------------------------===//
// MemoryAreaFactory
MemoryAreaFactory::MemoryAreaFactory(size_t pNum)
- : UniqueGCFactoryBase<sys::fs::Path, MemoryArea, 0>(pNum) {
+ : GCFactory<MemoryArea, 0>(pNum) {
// For each loaded file, MCLinker must load ELF header, section header,
// symbol table, and string table. So, we set the size of chunk quadruple
// larger than the number of input files.
@@ -23,30 +26,91 @@
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;
+ }
+
delete m_pRegionFactory;
}
-MemoryArea* MemoryAreaFactory::produce(const sys::fs::Path& pPath, int pFlags)
+MemoryArea*
+MemoryAreaFactory::produce(const sys::fs::Path& pPath,
+ FileHandle::OpenMode pMode)
{
- MemoryArea* result = find(pPath);
- if (0 == result) {
- result = allocate();
- new (result) MemoryArea(*m_pRegionFactory);
- result->map(pPath, pFlags);
- f_KeyMap.insert(std::make_pair(pPath, result));
+ 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());
+ }
+
+ MemoryArea* result = allocate();
+ new (result) MemoryArea(*m_pRegionFactory, *handler);
+
+ m_HandleToArea.push_back(handler, result);
+ return result;
}
+
+ return map_result.area;
+}
+
+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());
+ }
+
+ MemoryArea* result = allocate();
+ new (result) MemoryArea(*m_pRegionFactory, *handler);
+
+ m_HandleToArea.push_back(handler, result);
+ return result;
+ }
+
+ return map_result.area;
+}
+
+void MemoryAreaFactory::destruct(MemoryArea* pArea)
+{
+ m_HandleToArea.erase(pArea);
+ pArea->clear();
+ pArea->handler()->close();
+ destroy(pArea);
+ deallocate(pArea);
+}
+
+MemoryArea*
+MemoryAreaFactory::create(void* pMemBuffer, size_t pSize)
+{
+ Space* space = new Space(Space::EXTERNAL, pMemBuffer, pSize);
+ MemoryArea* result = allocate();
+ new (result) MemoryArea(*m_pRegionFactory, *space);
return result;
}
-MemoryArea* MemoryAreaFactory::produce(const sys::fs::Path& pPath, int pFlags, mode_t pMode)
+MemoryArea*
+MemoryAreaFactory::create(int pFD, FileHandle::OpenMode pMode)
{
- MemoryArea* result = find(pPath);
- if (0 == result) {
- result = allocate();
- new (result) MemoryArea(*m_pRegionFactory);
- result->map(pPath, pFlags, pMode);
- f_KeyMap.insert(std::make_pair(pPath, result));
- }
+ FileHandle* handler = new FileHandle();
+ handler->delegate(pFD, pMode);
+
+ MemoryArea* result = allocate();
+ new (result) MemoryArea(*m_pRegionFactory, *handler);
+
return result;
}
diff --git a/lib/Support/MemoryRegion.cpp b/lib/Support/MemoryRegion.cpp
index 3a35f4e..32e790b 100644
--- a/lib/Support/MemoryRegion.cpp
+++ b/lib/Support/MemoryRegion.cpp
@@ -12,23 +12,13 @@
//==========================
// MemoryRegion
-MemoryRegion::MemoryRegion(MemoryArea::Space *pParentSpace,
- const MemoryRegion::Address pVMAStart,
+MemoryRegion::MemoryRegion(Space& pParent,
+ MemoryRegion::Address pVMAStart,
size_t pSize)
- : m_pParentSpace(pParentSpace), m_VMAStart(pVMAStart), m_Length(pSize) {
- m_pParentSpace->region_num++;
+ : m_Parent(pParent), m_VMAStart(pVMAStart), m_Length(pSize) {
}
MemoryRegion::~MemoryRegion()
{
- drift();
-}
-
-void MemoryRegion::drift()
-{
- if (NULL == m_pParentSpace)
- return;
- m_pParentSpace->region_num--;
- m_pParentSpace = NULL;
}
diff --git a/lib/Support/MsgHandling.cpp b/lib/Support/MsgHandling.cpp
new file mode 100644
index 0000000..5b45289
--- /dev/null
+++ b/lib/Support/MsgHandling.cpp
@@ -0,0 +1,74 @@
+//===- MsgHandling.cpp ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/DiagnosticEngine.h>
+#include <mcld/LD/DiagnosticLineInfo.h>
+#include <mcld/LD/DiagnosticPrinter.h>
+#include <mcld/LD/MsgHandler.h>
+#include <mcld/Support/MsgHandling.h>
+#include <llvm/Support/ManagedStatic.h>
+#include <llvm/Support/raw_ostream.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// DiagnosticInitializer
+class DiagnosticInitializer : public llvm::ManagedStaticBase
+{
+public:
+ DiagnosticEngine* initialize(const MCLDInfo& pLDInfo,
+ DiagnosticLineInfo* pLineInfo,
+ DiagnosticPrinter* pPrinter)
+ {
+ RegisterManagedStatic(NULL, llvm::object_deleter<DiagnosticEngine>::call);
+ if (llvm::llvm_is_multithreaded()) {
+ llvm::llvm_acquire_global_lock();
+ void* tmp = NULL;
+ if (NULL != pPrinter)
+ tmp = new DiagnosticEngine(pLDInfo, pLineInfo, pPrinter, false);
+ else
+ tmp = new DiagnosticEngine(pLDInfo, pLineInfo, NULL, false);
+
+ TsanHappensBefore(this);
+ llvm::sys::MemoryFence();
+ TsanIgnoreWritesBegin();
+ Ptr = tmp;
+ TsanIgnoreWritesEnd();
+ llvm::llvm_release_global_lock();
+ }
+ else {
+ if (NULL != pPrinter)
+ Ptr = new DiagnosticEngine(pLDInfo, pLineInfo, pPrinter, false);
+ else
+ Ptr = new DiagnosticEngine(pLDInfo, pLineInfo, NULL, false);
+ }
+ return static_cast<DiagnosticEngine*>(Ptr);
+ }
+};
+
+static DiagnosticInitializer g_DiagInitializer;
+static DiagnosticEngine* g_pDiagnosticEngine = NULL;
+
+void mcld::InitializeDiagnosticEngine(const mcld::MCLDInfo& pLDInfo,
+ DiagnosticLineInfo* pLineInfo,
+ DiagnosticPrinter* pPrinter)
+{
+ if (NULL == g_pDiagnosticEngine) {
+ g_pDiagnosticEngine = g_DiagInitializer.initialize(pLDInfo,
+ pLineInfo,
+ pPrinter);
+ }
+}
+
+DiagnosticEngine& mcld::getDiagnosticEngine()
+{
+ assert(NULL != g_pDiagnosticEngine &&
+ "mcld::InitializeDiagnostics() is not called");
+ return *g_pDiagnosticEngine;
+}
+
diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp
index ffb449f..8cc384d 100644
--- a/lib/Support/Path.cpp
+++ b/lib/Support/Path.cpp
@@ -11,11 +11,8 @@
#include <llvm/ADT/StringRef.h>
#include <locale>
-#include <stdio.h>
#include <string.h>
-#include <iostream>
-
using namespace mcld;
using namespace mcld::sys::fs;
@@ -119,7 +116,7 @@
Path::StringType::size_type Path::m_append_separator_if_needed()
{
if (!m_PathName.empty() &&
-#ifdef LLVM_ON_WIN32
+#if defined(MCLD_ON_WIN32)
*(m_PathName.end()-1) != colon &&
#endif
!is_separator(*(m_PathName.end()-1))) {
@@ -171,7 +168,7 @@
bool mcld::sys::fs::is_separator(char value)
{
return (value == separator
-#ifdef LLVM_ON_WIN32
+#if defined(MCLD_ON_WIN32)
|| value == preferred_separator
#endif
);
diff --git a/lib/Support/RegionFactory.cpp b/lib/Support/RegionFactory.cpp
index e87d389..ddce433 100644
--- a/lib/Support/RegionFactory.cpp
+++ b/lib/Support/RegionFactory.cpp
@@ -6,8 +6,9 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/Support/RegionFactory.h"
-#include "mcld/Support/MemoryArea.h"
+#include <mcld/Support/RegionFactory.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/Space.h>
using namespace mcld;
@@ -21,18 +22,19 @@
{
}
-MemoryRegion* RegionFactory::produce(MemoryArea::Space* pSpace,
- const sys::fs::detail::Address pVMAStart,
- size_t pSize)
+MemoryRegion* RegionFactory::produce(Space& pSpace, void* pVMAStart, size_t pSize)
{
MemoryRegion* result = Alloc::allocate();
- new (result) MemoryRegion(pSpace, pVMAStart, pSize);
+ new (result) MemoryRegion(pSpace,
+ static_cast<const MemoryRegion::Address>(pVMAStart),
+ pSize);
+ pSpace.addRegion(*result);
return result;
}
void RegionFactory::destruct(MemoryRegion* pRegion)
{
- pRegion->drift();
+ pRegion->parent()->removeRegion(*pRegion);
destroy(pRegion);
deallocate(pRegion);
}
diff --git a/lib/Support/Space.cpp b/lib/Support/Space.cpp
new file mode 100644
index 0000000..4024da1
--- /dev/null
+++ b/lib/Support/Space.cpp
@@ -0,0 +1,179 @@
+//===- 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 <cstdlib>
+#include <unistd.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// constant data
+static const off_t PageSize = 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)
+{
+ 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::createSpace(FileHandle& pHandler,
+ size_t pStart, size_t pSize)
+{
+ Type type;
+ void* memory;
+ Space* result = NULL;
+ size_t start, size = 0, total_offset;
+ 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)
+ 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 = 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::releaseSpace(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::syncSpace(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/SystemUtils.cpp b/lib/Support/SystemUtils.cpp
new file mode 100644
index 0000000..5dfea36
--- /dev/null
+++ b/lib/Support/SystemUtils.cpp
@@ -0,0 +1,20 @@
+//===- SystemUtils.cpp ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/SystemUtils.h>
+
+using namespace mcld::sys;
+
+//===----------------------------------------------------------------------===//
+// Non-member functions
+#if defined(MCLD_ON_UNIX)
+#include "Unix/System.inc"
+#endif
+#if defined(MCLD_ON_WIN32)
+#include "Windows/System.inc"
+#endif
diff --git a/lib/Support/TargetRegistry.cpp b/lib/Support/TargetRegistry.cpp
index 246cbe8..8bfa235 100644
--- a/lib/Support/TargetRegistry.cpp
+++ b/lib/Support/TargetRegistry.cpp
@@ -6,13 +6,11 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/Support/TargetRegistry.h"
+#include <mcld/Support/TargetRegistry.h>
mcld::TargetRegistry::TargetListTy mcld::TargetRegistry::s_TargetList;
-/* ** */
-
void mcld::TargetRegistry::RegisterTarget(mcld::Target &T)
{
s_TargetList.push_back(&T);
@@ -34,7 +32,7 @@
const mcld::Target *mcld::TargetRegistry::lookupTarget(const std::string &pTriple,
std::string &pError)
{
- const llvm::Target* target = llvm::TargetRegistry::lookupTarget( pTriple, pError );
+ const llvm::Target* target = llvm::TargetRegistry::lookupTarget(pTriple, pError);
if (!target)
return 0;
return lookupTarget( *target );
diff --git a/lib/Support/Unix/FileSystem.inc b/lib/Support/Unix/FileSystem.inc
index 6499d66..ce6d0df 100644
--- a/lib/Support/Unix/FileSystem.inc
+++ b/lib/Support/Unix/FileSystem.inc
@@ -9,6 +9,7 @@
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
+#include <unistd.h>
#include <fcntl.h>
namespace mcld{
@@ -23,19 +24,29 @@
std::string assembly_extension = ".s";
std::string bitcode_extension = ".bc";
-size_t pread(int pFD, Address pBuf, size_t pCount, off_t pOffset)
+int open(const Path& pPath, int pOFlag)
{
- return ::pread(pFD, (void*) pBuf, pCount, pOffset);
+ return ::open(pPath.native().c_str(), pOFlag);
}
-size_t pwrite(int pFD, const Address pBuf, size_t pCount, off_t pOffset)
+int open(const Path& pPath, int pOFlag, int pPerm)
{
- return ::pwrite(pFD, (const void*) pBuf, pCount, pOffset);
+ return ::open(pPath.native().c_str(), pOFlag, pPerm);
}
-char *strerror(int errnum)
+ssize_t pread(int pFD, void* pBuf, size_t pCount, size_t pOffset)
{
- return ::strerror(errnum);
+ return ::pread(pFD, pBuf, pCount, pOffset);
+}
+
+ssize_t pwrite(int pFD, const void* pBuf, size_t pCount, size_t pOffset)
+{
+ return ::pwrite(pFD, pBuf, pCount, pOffset);
+}
+
+int ftruncate(int pFD, size_t pLength)
+{
+ return ::ftruncate(pFD, pLength);
}
} // namespace of detail
diff --git a/lib/Support/Unix/PathV3.inc b/lib/Support/Unix/PathV3.inc
index 2e8e6d0..68b0c36 100644
--- a/lib/Support/Unix/PathV3.inc
+++ b/lib/Support/Unix/PathV3.inc
@@ -282,7 +282,7 @@
{
if (pDir.m_Handler)
closedir(reinterpret_cast<DIR *>(pDir.m_Handler));
- pDir.m_Handler = NULL;
+ pDir.m_Handler = 0;
}
void get_pwd(std::string& pPWD)
diff --git a/lib/Support/Unix/System.inc b/lib/Support/Unix/System.inc
new file mode 100644
index 0000000..716aaa2
--- /dev/null
+++ b/lib/Support/Unix/System.inc
@@ -0,0 +1,24 @@
+//===- System.inc ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <string>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace mcld{
+namespace sys{
+
+char *strerror(int errnum)
+{
+ return ::strerror(errnum);
+}
+
+} // namespace of sys
+} // namespace of mcld
+
diff --git a/lib/Support/Windows/System.inc b/lib/Support/Windows/System.inc
new file mode 100644
index 0000000..bfd75ee
--- /dev/null
+++ b/lib/Support/Windows/System.inc
@@ -0,0 +1,19 @@
+//===- System.inc ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <string>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace mcld{
+namespace sys{
+
+} // namespace of sys
+} // namespace of mcld
+
diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp
new file mode 100644
index 0000000..2453c2c
--- /dev/null
+++ b/lib/Support/raw_ostream.cpp
@@ -0,0 +1,95 @@
+//===- raw_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_ostream.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// raw_ostream
+mcld::raw_fd_ostream::raw_fd_ostream(const char *pFilename,
+ std::string &pErrorInfo,
+ unsigned int pFlags,
+ const MCLDInfo* pLDInfo)
+ : llvm::raw_fd_ostream(pFilename, pErrorInfo, pFlags), m_pLDInfo(pLDInfo) {
+}
+
+mcld::raw_fd_ostream::raw_fd_ostream(int pFD,
+ bool pShouldClose,
+ bool pUnbuffered,
+ const MCLDInfo* pLDInfo)
+ : llvm::raw_fd_ostream(pFD, pShouldClose, pUnbuffered), m_pLDInfo(pLDInfo) {
+}
+
+mcld::raw_fd_ostream::~raw_fd_ostream()
+{
+}
+
+void mcld::raw_fd_ostream::setLDInfo(const MCLDInfo& pLDInfo)
+{
+ m_pLDInfo = &pLDInfo;
+}
+
+llvm::raw_ostream &
+mcld::raw_fd_ostream::changeColor(enum llvm::raw_ostream::Colors pColor,
+ bool pBold,
+ bool pBackground)
+{
+ if (!is_displayed())
+ return *this;
+ return llvm::raw_fd_ostream::changeColor(pColor, pBold, pBackground);
+}
+
+llvm::raw_ostream& mcld::raw_fd_ostream::resetColor()
+{
+ if (!is_displayed())
+ return *this;
+ return llvm::raw_fd_ostream::resetColor();
+}
+
+// FIXME: migrate to newer LLVM
+/**
+llvm::raw_ostream& mcld::raw_fd_ostream::reverseColor()
+{
+ if (!is_displayed())
+ return *this;
+ return llvm::raw_ostream::reverseColor();
+}
+**/
+
+bool mcld::raw_fd_ostream::is_displayed() const
+{
+ if (NULL == m_pLDInfo)
+ return llvm::raw_fd_ostream::is_displayed();
+
+ return m_pLDInfo->options().color();
+}
+
+//===----------------------------------------------------------------------===//
+// outs(), errs(), nulls()
+//===----------------------------------------------------------------------===//
+mcld::raw_fd_ostream& mcld::outs() {
+ // Set buffer settings to model stdout behavior.
+ // Delete the file descriptor when the program exists, forcing error
+ // detection. If you don't want this behavior, don't use outs().
+ static mcld::raw_fd_ostream S(STDOUT_FILENO, true, NULL);
+ return S;
+}
+
+mcld::raw_fd_ostream& mcld::errs() {
+ // Set standard error to be unbuffered by default.
+ static mcld::raw_fd_ostream S(STDERR_FILENO, false, true, NULL);
+ return S;
+}
+
+void mcld::InitializeOStreams(const MCLDInfo& pLDInfo)
+{
+ outs().setLDInfo(pLDInfo);
+ errs().setLDInfo(pLDInfo);
+}
+
diff --git a/lib/Target/ARM/ARM.h b/lib/Target/ARM/ARM.h
index b833151..53e4795 100644
--- a/lib/Target/ARM/ARM.h
+++ b/lib/Target/ARM/ARM.h
@@ -9,15 +9,17 @@
#ifndef MCLD_ARM_H
#define MCLD_ARM_H
#include <string>
-#include "mcld/Target/TargetMachine.h"
+#include <mcld/Target/TargetMachine.h>
namespace mcld {
class TargetLDBackend;
extern mcld::Target TheARMTarget;
+extern mcld::Target TheThumbTarget;
TargetLDBackend *createARMLDBackend(const llvm::Target&, const std::string&);
} // namespace of mcld
#endif
+
diff --git a/lib/Target/ARM/ARMAndroidSectLinker.cpp b/lib/Target/ARM/ARMAndroidSectLinker.cpp
deleted file mode 100644
index a704cfa..0000000
--- a/lib/Target/ARM/ARMAndroidSectLinker.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-//===- ARMAndroidSectLinker.cpp -------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ARMAndroidSectLinker.h"
-
-#include <mcld/CodeGen/SectLinkerOption.h>
-
-using namespace mcld;
-
-ARMAndroidSectLinker::ARMAndroidSectLinker(SectLinkerOption &pOption,
- TargetLDBackend &pLDBackend)
- : AndroidSectLinker(pOption,
- pLDBackend) {
- MCLDInfo &info = pOption.info();
- // set up target-dependent constraints of attributes
- info.attrFactory().constraint().disableWholeArchive();
- info.attrFactory().constraint().disableAsNeeded();
- info.attrFactory().constraint().setSharedSystem();
-
- // set up the predefined attributes
- info.attrFactory().predefined().unsetWholeArchive();
- info.attrFactory().predefined().setDynamic();
-
-}
-
-ARMAndroidSectLinker::~ARMAndroidSectLinker()
-{
-}
-
diff --git a/lib/Target/ARM/ARMAndroidSectLinker.h b/lib/Target/ARM/ARMAndroidSectLinker.h
deleted file mode 100644
index 8a47a94..0000000
--- a/lib/Target/ARM/ARMAndroidSectLinker.h
+++ /dev/null
@@ -1,40 +0,0 @@
-//===- ARMAndroidSectLinker.h ---------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef ARM_ANDROIDSECTLINKER_H
-#define ARM_ANDROIDSECTLINKER_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-#include <mcld/Target/AndroidSectLinker.h>
-
-namespace mcld
-{
-
-class MCLDInfo;
-
-/** \class ARMAndroidSectLinker
- * \brief ARMAndroidSectLinker sets up the environment for linking.
- *
- * \see
- * \author Anders Cheng <Anders.Cheng@mediatek.com>
- */
-class ARMAndroidSectLinker : public AndroidSectLinker
-{
-public:
- ARMAndroidSectLinker(SectLinkerOption &pOption,
- mcld::TargetLDBackend &pLDBackend);
-
- ~ARMAndroidSectLinker();
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/lib/Target/ARM/ARMDiagnostic.cpp b/lib/Target/ARM/ARMDiagnostic.cpp
new file mode 100644
index 0000000..1ecf7df
--- /dev/null
+++ b/lib/Target/ARM/ARMDiagnostic.cpp
@@ -0,0 +1,39 @@
+//===- ARMDiagnostic.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// 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 llvm::Target& pTarget,
+ const std::string &pTriple)
+{
+ return new DWARFLineInfo();
+}
+
+} // namespace of mcld
+
+//==========================
+// InitializeARMDiagnostic
+extern "C" void LLVMInitializeARMDiagnosticLineInfo() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheARMTarget, createARMDiagLineInfo);
+ mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheThumbTarget, createARMDiagLineInfo);
+}
+
diff --git a/lib/Target/ARM/ARMELFArchiveReader.h b/lib/Target/ARM/ARMELFArchiveReader.h
index b60a12d..2fa9ce2 100644
--- a/lib/Target/ARM/ARMELFArchiveReader.h
+++ b/lib/Target/ARM/ARMELFArchiveReader.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef ARMELFARCHIVEREADER_H
-#define ARMELFARCHIVEREADER_H
+#ifndef MCLD_ARM_ELF_ARCHIVE_READER_H
+#define MCLD_ARM_ELF_ARCHIVE_READER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/lib/Target/ARM/ARMELFSectLinker.h b/lib/Target/ARM/ARMELFSectLinker.h
index 7493d59..ab626b9 100644
--- a/lib/Target/ARM/ARMELFSectLinker.h
+++ b/lib/Target/ARM/ARMELFSectLinker.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef ARM_ELFSECTLINKER_H
-#define ARM_ELFSECTLINKER_H
+#ifndef ARM_ELF_SECTION_LINKER_H
+#define ARM_ELF_SECTION_LINKER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/lib/Target/ARM/ARMFixupKinds.h b/lib/Target/ARM/ARMFixupKinds.h
index 1bf82f5..f42b940 100644
--- a/lib/Target/ARM/ARMFixupKinds.h
+++ b/lib/Target/ARM/ARMFixupKinds.h
@@ -41,9 +41,9 @@
// instruction.
fixup_t2_adr_pcrel_12,
// fixup_arm_condbranch - 24-bit PC relative relocation for conditional branch
- // instructions.
+ // instructions.
fixup_arm_condbranch,
- // fixup_arm_uncondbranch - 24-bit PC relative relocation for
+ // 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
diff --git a/lib/Target/ARM/ARMGOT.cpp b/lib/Target/ARM/ARMGOT.cpp
index 37d8e6b..7430203 100644
--- a/lib/Target/ARM/ARMGOT.cpp
+++ b/lib/Target/ARM/ARMGOT.cpp
@@ -9,7 +9,7 @@
#include "ARMGOT.h"
#include <mcld/LD/LDFileFormat.h>
#include <mcld/Support/MemoryRegion.h>
-#include <llvm/Support/ErrorHandling.h>
+#include <mcld/Support/MsgHandling.h>
#include <new>
namespace {
@@ -33,7 +33,7 @@
&m_SectionData);
if (!Entry)
- llvm::report_fatal_error("Allocating GOT0 entries failed!");
+ fatal(diag::fail_allocate_memory) << "GOT0";
m_Section.setSize(m_Section.size() + ARMGOTEntrySize);
}
@@ -43,9 +43,7 @@
iterator ie = m_SectionData.end();
for (int i = 1; i < ARMGOT0Num; ++i) {
- if (it == ie)
- llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
-
+ assert((it != ie) && "Generation of GOT0 entries is incomplete!");
++it;
}
@@ -69,7 +67,7 @@
&m_SectionData);
if (!Entry)
- llvm::report_fatal_error("Allocating new memory for GOTEntry failed");
+ fatal(diag::fail_allocate_memory) << "GOTEntry";
m_Section.setSize(m_Section.size() + ARMGOTEntrySize);
}
@@ -82,7 +80,7 @@
got_entry= new GOTEntry(0, getEntrySize(),&(getSectionData()));
if (!got_entry)
- llvm::report_fatal_error("Allocating new memory for GOT failed!");
+ fatal(diag::fail_allocate_memory) << "GOTEntry";
m_Section.setSize(m_Section.size() + getEntrySize());
@@ -182,3 +180,4 @@
}
return result;
}
+
diff --git a/lib/Target/ARM/ARMGOT.h b/lib/Target/ARM/ARMGOT.h
index 4667421..90f0f53 100644
--- a/lib/Target/ARM/ARMGOT.h
+++ b/lib/Target/ARM/ARMGOT.h
@@ -89,3 +89,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/ARM/ARMLDBackend.cpp b/lib/Target/ARM/ARMLDBackend.cpp
index fe57fd6..e0f5dcf 100644
--- a/lib/Target/ARM/ARMLDBackend.cpp
+++ b/lib/Target/ARM/ARMLDBackend.cpp
@@ -9,7 +9,6 @@
#include <llvm/ADT/Triple.h>
#include <llvm/ADT/Twine.h>
#include <llvm/Support/ELF.h>
-#include <llvm/Support/ErrorHandling.h>
#include <mcld/LD/SectionMap.h>
#include <mcld/MC/MCLDInfo.h>
@@ -17,6 +16,7 @@
#include <mcld/MC/MCLinker.h>
#include <mcld/MC/MCRegionFragment.h>
#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/TargetRegistry.h>
#include <cstring>
@@ -42,17 +42,17 @@
ARMGNULDBackend::~ARMGNULDBackend()
{
- if (m_pRelocFactory)
+ if (NULL != m_pRelocFactory)
delete m_pRelocFactory;
- if(m_pGOT)
+ if (NULL != m_pGOT)
delete m_pGOT;
- if(m_pPLT)
+ if (NULL != m_pPLT)
delete m_pPLT;
- if(m_pRelDyn)
+ if (NULL != m_pRelDyn)
delete m_pRelDyn;
- if(m_pRelPLT)
+ if (NULL != m_pRelPLT)
delete m_pRelPLT;
- if(m_pDynamic)
+ if (NULL != m_pDynamic)
delete m_pDynamic;
}
@@ -85,12 +85,12 @@
// FIXME: Currently we set exidx and extab to "Exception" and directly emit
// them from input
m_pEXIDX = &pLinker.getOrCreateOutputSectHdr(".ARM.exidx",
- LDFileFormat::Exception,
+ LDFileFormat::Target,
llvm::ELF::SHT_ARM_EXIDX,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_LINK_ORDER,
bitclass() / 8);
m_pEXTAB = &pLinker.getOrCreateOutputSectHdr(".ARM.extab",
- LDFileFormat::Exception,
+ LDFileFormat::Target,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC,
0x1);
@@ -101,7 +101,7 @@
0x1);
}
-void ARMGNULDBackend::initTargetSymbols(MCLinker& pLinker)
+void ARMGNULDBackend::initTargetSymbols(MCLinker& pLinker, const Output& pOutput)
{
// Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
// same name in input
@@ -122,7 +122,7 @@
MCLinker& pLinker)
{
// when building shared object, the .got section is must.
- if(pOutput.type() == Output::DynObj && (NULL == m_pGOT)) {
+ if (pOutput.type() == Output::DynObj && (NULL == m_pGOT)) {
createARMGOT(pLinker, pOutput);
}
}
@@ -131,11 +131,7 @@
const MCLDInfo& pInfo,
MCLinker& pLinker)
{
- // emit program headers
- if(pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec)
- emitProgramHdrs(pLinker.getLDInfo().output());
-
- ELFFileFormat *file_format = getOutputFormat(pOutput);
+ const ELFFileFormat *file_format = getOutputFormat(pOutput);
// apply PLT
if (file_format->hasPLT()) {
@@ -177,11 +173,6 @@
return *m_pDynamic;
}
-bool ARMGNULDBackend::isPIC(const MCLDInfo& pLDInfo, const Output& pOutput) const
-{
- return (pOutput.type() == Output::DynObj);
-}
-
void ARMGNULDBackend::createARMGOT(MCLinker& pLinker, const Output& pOutput)
{
// get .got LDSection and create MCSectionData
@@ -191,7 +182,7 @@
m_pGOT = new ARMGOT(got, pLinker.getOrCreateSectData(got));
// define symbol _GLOBAL_OFFSET_TABLE_ when .got create
- if( m_pGOTSymbol != NULL ) {
+ if (m_pGOTSymbol != NULL) {
pLinker.defineSymbol<MCLinker::Force, MCLinker::Unresolve>(
"_GLOBAL_OFFSET_TABLE_",
false,
@@ -249,62 +240,73 @@
8);
}
-ELFFileFormat* ARMGNULDBackend::getOutputFormat(const Output& pOutput) const
+void ARMGNULDBackend::addCopyReloc(ResolveInfo& pSym)
{
- switch (pOutput.type()) {
- case Output::DynObj:
- return getDynObjFileFormat();
- case Output::Exec:
- return getExecFileFormat();
- // FIXME: We do not support building .o now
- case Output::Object:
- default:
- llvm::report_fatal_error(llvm::Twine("Unsupported output file format: ") +
- llvm::Twine(pOutput.type()));
- return NULL;
+ bool exist;
+ Relocation& rel_entry = *m_pRelDyn->getEntry(pSym, false, exist);
+ rel_entry.setType(llvm::ELF::R_ARM_COPY);
+ assert(pSym.outSymbol()->hasFragRef());
+ rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef());
+ rel_entry.setSymInfo(&pSym);
+}
+
+LDSymbol& ARMGNULDBackend::defineSymbolforCopyReloc(MCLinker& pLinker,
+ const ResolveInfo& pSym)
+{
+ // For a symbol needing copy relocation, define a copy symbol in the BSS
+ // section and all other reference to this symbol should refer to this
+ // copy.
+
+ // get or create corresponding BSS LDSection
+ LDSection* bss_sect_hdr = NULL;
+ if (ResolveInfo::ThreadLocal == pSym.type()) {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
+ ".tbss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
}
-}
+ else {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
-bool ARMGNULDBackend::isSymbolNeedsPLT(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) const
-{
- return (Output::DynObj == pOutput.type() &&
- ResolveInfo::Function == pSym.type() &&
- (pSym.isDyn() || pSym.isUndef() ||
- isSymbolPreemptible(pSym, pLDInfo, pOutput)));
-}
+ // get or create corresponding BSS MCSectionData
+ assert(NULL != bss_sect_hdr);
+ llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(
+ *bss_sect_hdr);
-bool ARMGNULDBackend::isSymbolNeedsDynRel(const ResolveInfo& pSym,
- const Output& pOutput,
- bool isAbsReloc) const
-{
- if(pSym.isUndef() && (Output::Exec == pOutput.type()))
- return false;
- if(pSym.isAbsolute())
- return false;
- if(Output::DynObj == pOutput.type() && isAbsReloc)
- return true;
- if(pSym.isDyn() || pSym.isUndef())
- return true;
+ // Determine the alignment by the symbol value
+ // FIXME: here we use the largest alignment
+ uint32_t addralign = bitclass() / 8;
- return false;
-}
+ // allocate space in BSS for the copy symbol
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, pSym.size());
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ bss_section,
+ addralign);
+ bss_sect_hdr->setSize(bss_sect_hdr->size() + size);
-bool ARMGNULDBackend::isSymbolPreemptible(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) const
-{
- if(pSym.other() != ResolveInfo::Default)
- return false;
+ // 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;
- if(Output::DynObj != pOutput.type())
- return false;
+ // Define the copy symbol in the bss section and resolve it
+ LDSymbol* cpy_sym = pLinker.defineSymbol<MCLinker::Force, MCLinker::Resolve>(
+ pSym.name(),
+ false,
+ (ResolveInfo::Type)pSym.type(),
+ ResolveInfo::Define,
+ binding,
+ pSym.size(), // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*frag, 0x0),
+ (ResolveInfo::Visibility)pSym.other());
- if(pLDInfo.options().Bsymbolic())
- return false;
-
- return true;
+ return *cpy_sym;
}
/// checkValidReloc - When we attempt to generate a dynamic relocation for
@@ -314,7 +316,7 @@
const Output& pOutput) const
{
// If not building a PIC object, no relocation type is invalid
- if (!isPIC(pLDInfo, pOutput))
+ if (!isOutputPIC(pOutput, pLDInfo))
return;
switch(pReloc.type()) {
@@ -331,13 +333,8 @@
break;
default:
- llvm::report_fatal_error(llvm::Twine("Attempt to generate unsupported") +
- llvm::Twine(" relocation type ") +
- llvm::Twine((int)pReloc.type()) +
- llvm::Twine(" for symbol '") +
- llvm::Twine(pReloc.symInfo()->name()) +
- llvm::Twine("', recompile with -fPIC")
- );
+ error(diag::non_pic_relocation) << (int)pReloc.type()
+ << pReloc.symInfo()->name();
break;
}
}
@@ -347,7 +344,7 @@
const Layout& pLayout) const
{
// Update value keep in addend if we meet a section symbol
- if(pReloc.symInfo()->type() == ResolveInfo::Section) {
+ if (pReloc.symInfo()->type() == ResolveInfo::Section) {
pReloc.setAddend(pLayout.getOutputOffset(
*pInputSym.fragRef()) + pReloc.addend());
}
@@ -368,6 +365,8 @@
// Set R_ARM_TARGET1 to R_ARM_ABS32
// Ref: GNU gold 1.11 arm.cc, line 9892
+ // FIXME: R_ARM_TARGET1 should be set by option --target1-rel
+ // or --target1-rel
case llvm::ELF::R_ARM_TARGET1:
pReloc.setType(llvm::ELF::R_ARM_ABS32);
case llvm::ELF::R_ARM_ABS32:
@@ -375,13 +374,13 @@
// 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(isPIC(pLDInfo, pOutput)) {
- // create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (isOutputPIC(pOutput, pLDInfo)) {
+ //create .rel.dyn section if not exist
+ if (NULL == m_pRelDyn)
createARMRelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
// set Rel bit
- rsym->setReserved(rsym->reserved() | 0x1u);
+ rsym->setReserved(rsym->reserved() | ReserveRel);
}
return;
}
@@ -395,53 +394,41 @@
case llvm::ELF::R_ARM_MOVT_ABS:
case llvm::ELF::R_ARM_THM_MOVW_ABS_NC:
case llvm::ELF::R_ARM_THM_MOVT_ABS: {
- // Update value keep in relocation place if we meet a section symbol
- if(rsym->type() == ResolveInfo::Section) {
- pReloc.target() = pLinker.getLayout().getOutputOffset(
- *pInputSym.fragRef()) + pReloc.target();
- }
-
- // If building PIC object (shared library or PIC executable),
- // a dynamic relocation for this location is needed.
- // Reserve an entry in .rel.dyn
- if(isPIC(pLDInfo, pOutput)) {
- checkValidReloc(pReloc, pLDInfo, pOutput);
- // create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
- createARMRelDyn(pLinker, pOutput);
- m_pRelDyn->reserveEntry(*m_pRelocFactory);
- // set Rel bit
- rsym->setReserved(rsym->reserved() | 0x1u);
+ // PIC code should not contain these kinds of relocation
+ if (isOutputPIC(pOutput, pLDInfo)) {
+ error(diag::non_pic_relocation) << (int)pReloc.type()
+ << pReloc.symInfo()->name();
}
return;
}
case llvm::ELF::R_ARM_GOTOFF32:
case llvm::ELF::R_ARM_GOTOFF12: {
// A GOT section is needed
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createARMGOT(pLinker, pOutput);
return;
}
// Set R_ARM_TARGET2 to R_ARM_GOT_PREL
// Ref: GNU gold 1.11 arm.cc, line 9892
+ // FIXME: R_ARM_TARGET2 should be set by option --target2
case llvm::ELF::R_ARM_TARGET2:
pReloc.setType(llvm::ELF::R_ARM_GOT_PREL);
case llvm::ELF::R_ARM_GOT_BREL:
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() & 0x6u)
+ if (rsym->reserved() & (ReserveGOT | GOTRel))
return;
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createARMGOT(pLinker, pOutput);
m_pGOT->reserveEntry();
// If building PIC object, a dynamic relocation with
// type RELATIVE is needed to relocate this GOT entry.
// Reserve an entry in .rel.dyn
- if(isPIC(pLDInfo, pOutput)) {
+ if (isOutputPIC(pOutput, pLDInfo)) {
// create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (NULL == m_pRelDyn)
createARMRelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
// set GOTRel bit
@@ -456,12 +443,9 @@
case llvm::ELF::R_ARM_BASE_PREL: {
// FIXME: Currently we only support R_ARM_BASE_PREL against
// symbol _GLOBAL_OFFSET_TABLE_
- if(rsym != m_pGOTSymbol->resolveInfo()) {
- llvm::report_fatal_error(llvm::Twine("Do not support relocation '") +
- llvm::Twine("R_ARM_BASE_PREL' against symbol '") +
- llvm::Twine(rsym->name()) +
- llvm::Twine(".'"));
- }
+ if (rsym != m_pGOTSymbol->resolveInfo())
+ fatal(diag::base_relocation) << (int)pReloc.type() << rsym->name()
+ << "mclinker@googlegroups.com";
return;
}
case llvm::ELF::R_ARM_COPY:
@@ -470,9 +454,7 @@
case llvm::ELF::R_ARM_RELATIVE: {
// These are relocation type for dynamic linker, shold not
// appear in object file.
- llvm::report_fatal_error(llvm::Twine("unexpected reloc ") +
- llvm::Twine((int)pReloc.type()) +
- llvm::Twine(" in object file"));
+ fatal(diag::dynamic_relocation) << (int)pReloc.type();
break;
}
default: {
@@ -494,6 +476,8 @@
// Set R_ARM_TARGET1 to R_ARM_ABS32
// Ref: GNU gold 1.11 arm.cc, line 9892
+ // FIXME: R_ARM_TARGET1 should be set by option --target1-rel
+ // or --target1-rel
case llvm::ELF::R_ARM_TARGET1:
pReloc.setType(llvm::ELF::R_ARM_ABS32);
case llvm::ELF::R_ARM_ABS32:
@@ -509,14 +493,14 @@
case llvm::ELF::R_ARM_ABS32_NOI: {
// Absolute relocation type, symbol may needs PLT entry or
// dynamic relocation entry
- if(isSymbolNeedsPLT(*rsym, pLDInfo, pOutput)) {
+ if (symbolNeedsPLT(*rsym, pLDInfo, pOutput)) {
// create plt for this symbol if it does not have one
- if(!(rsym->reserved() & 0x8u)){
+ if (!(rsym->reserved() & ReservePLT)){
// Create .got section if it doesn't exist
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createARMGOT(pLinker, pOutput);
// create .plt and .rel.plt if not exist
- if(NULL == m_pPLT)
+ if (NULL == m_pPLT)
createARMPLTandRelPLT(pLinker, pOutput);
// Symbol needs PLT entry, we need to reserve a PLT entry
// and the corresponding GOT and dynamic relocation entry
@@ -525,19 +509,27 @@
m_pPLT->reserveEntry();
m_pRelPLT->reserveEntry(*m_pRelocFactory);
// set PLT bit
- rsym->setReserved(rsym->reserved() | 0x8u);
+ rsym->setReserved(rsym->reserved() | ReservePLT);
}
}
- if(isSymbolNeedsDynRel(*rsym, pOutput, true)) {
- checkValidReloc(pReloc, pLDInfo, pOutput);
+ if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT),
+ pLDInfo, pOutput, true)) {
// symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
// create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (NULL == m_pRelDyn)
createARMRelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
- // set Rel bit
- rsym->setReserved(rsym->reserved() | 0x1u);
+ if (symbolNeedsCopyReloc(pLinker.getLayout(), pReloc, *rsym, pLDInfo,
+ pOutput)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym);
+ addCopyReloc(*cpy_sym.resolveInfo());
+ }
+ else {
+ checkValidReloc(pReloc, pLDInfo, pOutput);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
}
return;
}
@@ -545,19 +537,20 @@
case llvm::ELF::R_ARM_GOTOFF32:
case llvm::ELF::R_ARM_GOTOFF12: {
// A GOT section is needed
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createARMGOT(pLinker, pOutput);
return;
}
case llvm::ELF::R_ARM_BASE_PREL:
- // FIXME: Currently we only support R_ARM_BASE_PREL against
+ case llvm::ELF::R_ARM_THM_MOVW_BREL_NC:
+ case llvm::ELF::R_ARM_THM_MOVW_BREL:
+ case llvm::ELF::R_ARM_THM_MOVT_BREL:
+ // FIXME: Currently we only support these relocations against
// symbol _GLOBAL_OFFSET_TABLE_
- if(rsym != m_pGOTSymbol->resolveInfo()) {
- llvm::report_fatal_error(llvm::Twine("Do not support relocation '") +
- llvm::Twine("R_ARM_BASE_PREL' against symbol '") +
- llvm::Twine(rsym->name()) +
- llvm::Twine(".'"));
+ if (rsym != m_pGOTSymbol->resolveInfo()) {
+ fatal(diag::base_relocation) << (int)pReloc.type() << rsym->name()
+ << "mclinker@googlegroups.com";
}
case llvm::ELF::R_ARM_REL32:
case llvm::ELF::R_ARM_LDR_PC_G0:
@@ -599,19 +592,25 @@
case llvm::ELF::R_ARM_LDC_SB_G2:
case llvm::ELF::R_ARM_MOVW_BREL_NC:
case llvm::ELF::R_ARM_MOVT_BREL:
- case llvm::ELF::R_ARM_MOVW_BREL:
- case llvm::ELF::R_ARM_THM_MOVW_BREL_NC:
- case llvm::ELF::R_ARM_THM_MOVT_BREL:
- case llvm::ELF::R_ARM_THM_MOVW_BREL: {
+ case llvm::ELF::R_ARM_MOVW_BREL: {
// Relative addressing relocation, may needs dynamic relocation
- if(isSymbolNeedsDynRel(*rsym, pOutput, false)) {
- checkValidReloc(pReloc, pLDInfo, pOutput);
+ if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT),
+ pLDInfo, pOutput, false)) {
+ // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
// create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (NULL == m_pRelDyn)
createARMRelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
- // set Rel bit
- rsym->setReserved(rsym->reserved() | 0x1u);
+ if (symbolNeedsCopyReloc(pLinker.getLayout(), pReloc, *rsym, pLDInfo,
+ pOutput)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym);
+ addCopyReloc(*cpy_sym.resolveInfo());
+ }
+ else {
+ checkValidReloc(pReloc, pLDInfo, pOutput);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
}
return;
}
@@ -631,22 +630,22 @@
// A PLT entry is needed when building shared library
// return if we already create plt for this symbol
- if(rsym->reserved() & 0x8u)
+ if (rsym->reserved() & ReservePLT)
return;
// if symbol is defined in the ouput file and it's not
// preemptible, no need plt
- if(rsym->isDefine() && !rsym->isDyn() &&
+ if (rsym->isDefine() && !rsym->isDyn() &&
!isSymbolPreemptible(*rsym, pLDInfo, pOutput)) {
return;
}
// Create .got section if it doesn't exist
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createARMGOT(pLinker, pOutput);
// create .plt and .rel.plt if not exist
- if(NULL == m_pPLT)
+ if (NULL == m_pPLT)
createARMPLTandRelPLT(pLinker, pOutput);
// Symbol needs PLT entry, we need to reserve a PLT entry
// and the corresponding GOT and dynamic relocation entry
@@ -655,12 +654,13 @@
m_pPLT->reserveEntry();
m_pRelPLT->reserveEntry(*m_pRelocFactory);
// set PLT bit
- rsym->setReserved(rsym->reserved() | 0x8u);
+ rsym->setReserved(rsym->reserved() | ReservePLT);
return;
}
// Set R_ARM_TARGET2 to R_ARM_GOT_PREL
// Ref: GNU gold 1.11 arm.cc, line 9892
+ // FIXME: R_ARM_TARGET2 should be set by option --target2
case llvm::ELF::R_ARM_TARGET2:
pReloc.setType(llvm::ELF::R_ARM_GOT_PREL);
case llvm::ELF::R_ARM_GOT_BREL:
@@ -668,25 +668,25 @@
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() & 0x6u)
+ if (rsym->reserved() & (ReserveGOT | GOTRel))
return;
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createARMGOT(pLinker, pOutput);
m_pGOT->reserveEntry();
// 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(Output::DynObj == pOutput.type() || rsym->isUndef() || rsym->isDyn()) {
+ if (Output::DynObj == pOutput.type() || rsym->isUndef() || rsym->isDyn()) {
// create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (NULL == m_pRelDyn)
createARMRelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
// set GOTRel bit
- rsym->setReserved(rsym->reserved() | 0x4u);
+ rsym->setReserved(rsym->reserved() | GOTRel);
return;
}
// set GOT bit
- rsym->setReserved(rsym->reserved() | 0x2u);
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
}
@@ -696,9 +696,7 @@
case llvm::ELF::R_ARM_RELATIVE: {
// These are relocation type for dynamic linker, shold not
// appear in object file.
- llvm::report_fatal_error(llvm::Twine("Unexpected reloc ") +
- llvm::Twine((int)pReloc.type()) +
- llvm::Twine(" in object file"));
+ fatal(diag::dynamic_relocation) << (int)pReloc.type();
break;
}
default: {
@@ -711,12 +709,21 @@
const LDSymbol& pInputSym,
MCLinker& pLinker,
const MCLDInfo& pLDInfo,
- const Output& pOutput)
+ const Output& pOutput,
+ const LDSection& pSection)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
+ assert(NULL != pSection.getLink());
+ if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC)) {
+ if (rsym->isLocal()) {
+ updateAddend(pReloc, pInputSym, pLinker.getLayout());
+ }
+ return;
+ }
+
// Scan relocation type to determine if an GOT/PLT/Dynamic Relocation
// entries should be created.
// FIXME: Below judgements concern only .so is generated as output
@@ -724,14 +731,14 @@
// A refernece to symbol _GLOBAL_OFFSET_TABLE_ implies that a .got section
// is needed
- if(NULL == m_pGOT && NULL != m_pGOTSymbol) {
- if(rsym == m_pGOTSymbol->resolveInfo()) {
+ if (NULL == m_pGOT && NULL != m_pGOTSymbol) {
+ if (rsym == m_pGOTSymbol->resolveInfo()) {
createARMGOT(pLinker, pOutput);
}
}
// rsym is local
- if(rsym->isLocal())
+ if (rsym->isLocal())
scanLocalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
// rsym is external
@@ -743,25 +750,54 @@
uint64_t ARMGNULDBackend::emitSectionData(const Output& pOutput,
const LDSection& pSection,
const MCLDInfo& pInfo,
+ const Layout& pLayout,
MemoryRegion& pRegion) const
{
assert(pRegion.size() && "Size of MemoryRegion is zero!");
- ELFFileFormat* file_format = getOutputFormat(pOutput);
+ const ELFFileFormat* file_format = getOutputFormat(pOutput);
- if (&pSection == m_pAttributes) {
- // FIXME: Currently Emitting .ARM.attributes directly from the input file.
+ 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 llvm::MCSectionData* sect_data = pSection.getSectionData();
- assert(sect_data &&
- "Emit .ARM.attribute failed, MCSectionData doesn't exist!");
-
- uint8_t* start =
- llvm::cast<MCRegionFragment>(
- sect_data->getFragmentList().front()).getRegion().start();
-
- memcpy(pRegion.start(), start, pRegion.size());
+ llvm::MCSectionData::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 = computeFragmentSize(pLayout, *frag_iter);
+ switch(frag_iter->getKind()) {
+ case llvm::MCFragment::FT_Region: {
+ const MCRegionFragment& region_frag =
+ llvm::cast<MCRegionFragment>(*frag_iter);
+ const uint8_t* start = region_frag.getRegion().start();
+ memcpy(out_offset, start, size);
+ break;
+ }
+ case llvm::MCFragment::FT_Align: {
+ llvm::MCAlignFragment& align_frag =
+ llvm::cast<llvm::MCAlignFragment>(*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;
+ }
+ 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!");
@@ -774,116 +810,15 @@
uint64_t result = m_pGOT->emit(pRegion);
return result;
}
-
- llvm::report_fatal_error(llvm::Twine("Unable to emit section `") +
- pSection.name() +
- llvm::Twine("'.\n"));
+ fatal(diag::unrecognized_output_sectoin)
+ << pSection.name()
+ << "mclinker@googlegroups.com";
return 0x0;
}
/// finalizeSymbol - finalize the symbol value
-/// If the symbol's reserved field is not zero, MCLinker will call back this
-/// function to ask the final value of the symbol
-bool ARMGNULDBackend::finalizeSymbol(LDSymbol& pSymbol) const
+bool ARMGNULDBackend::finalizeTargetSymbols(MCLinker& pLinker, const Output& pOutput)
{
- return false;
-}
-
-/// allocateCommonSymbols - allocate common symbols in the corresponding
-/// sections.
-/// @refer Google gold linker: common.cc: 214
-bool
-ARMGNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const
-{
- SymbolCategory& symbol_list = pLinker.getOutputSymbols();
-
- if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
- return true;
-
- // addralign := max value of all common symbols
- uint64_t addralign = 0x0;
-
- // Due to the visibility, some common symbols may be forcefully local.
- SymbolCategory::iterator com_sym, com_end = symbol_list.localEnd();
- for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
- if (ResolveInfo::Common == (*com_sym)->desc()) {
- if ((*com_sym)->value() > addralign)
- addralign = (*com_sym)->value();
- }
- }
-
- // global common symbols.
- com_end = symbol_list.commonEnd();
- for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
- if ((*com_sym)->value() > addralign)
- addralign = (*com_sym)->value();
- }
-
- // FIXME: If the order of common symbols is defined, then sort common symbols
- // com_sym = symbol_list.commonBegin();
- // std::sort(com_sym, com_end, some kind of order);
-
- // get or create corresponding BSS LDSection
- LDSection* bss_sect_hdr = NULL;
- if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
- bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
- ".tbss",
- LDFileFormat::BSS,
- llvm::ELF::SHT_NOBITS,
- llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
- }
- else {
- bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
- LDFileFormat::BSS,
- llvm::ELF::SHT_NOBITS,
- llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
- }
-
- // get or create corresponding BSS MCSectionData
- assert(NULL != bss_sect_hdr);
- llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(*bss_sect_hdr);
-
- // allocate all common symbols
- uint64_t offset = bss_sect_hdr->size();
-
- // allocate all local common symbols
- com_end = symbol_list.localEnd();
- for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
- if (ResolveInfo::Common == (*com_sym)->desc()) {
- // We have to reset the description of the symbol here. When doing
- // incremental linking, the output relocatable object may have common
- // symbols. Therefore, we can not treat common symbols as normal symbols
- // when emitting the regular name pools. We must change the symbols'
- // description here.
- (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
- llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
- (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
- uint64_t size = pLinker.getLayout().appendFragment(*frag,
- bss_section,
- (*com_sym)->value());
- offset += size;
- }
- }
-
- // allocate all global common symbols
- com_end = symbol_list.commonEnd();
- for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
- // We have to reset the description of the symbol here. When doing
- // incremental linking, the output relocatable object may have common
- // symbols. Therefore, we can not treat common symbols as normal symbols
- // when emitting the regular name pools. We must change the symbols'
- // description here.
- (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
- llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
- (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
- uint64_t size = pLinker.getLayout().appendFragment(*frag,
- bss_section,
- (*com_sym)->value());
- offset += size;
- }
-
- bss_sect_hdr->setSize(offset);
- symbol_list.changeCommonsToGlobal();
return true;
}
@@ -910,9 +845,20 @@
llvm::MCSectionData& sect_data = pLinker.getOrCreateSectData(pInputSectHdr);
- new MCRegionFragment(*region, §_data);
+ llvm::MCFragment* frag = NULL;
+ if (NULL == region) {
+ // If the input section's size is zero, we got a NULL region.
+ // use a virtual fill fragment
+ frag = new llvm::MCFillFragment(0x0, 0, 0);
+ }
+ else
+ frag = new MCRegionFragment(*region);
- out_sect.setSize(out_sect.size() + pInputSectHdr.size());
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ sect_data,
+ pInputSectHdr.align());
+
+ out_sect.setSize(out_sect.size() + size);
return true;
}
@@ -966,16 +912,25 @@
unsigned int
ARMGNULDBackend::getTargetSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const
{
- ELFFileFormat* file_format = getOutputFormat(pOutput);
+ const ELFFileFormat* file_format = getOutputFormat(pOutput);
- if (&pSectHdr == &file_format->getGOT())
+ if (&pSectHdr == &file_format->getGOT()) {
+ if (pInfo.options().hasNow())
+ return SHO_RELRO_LAST;
return SHO_DATA;
+ }
if (&pSectHdr == &file_format->getPLT())
return SHO_PLT;
+ if (&pSectHdr == m_pEXIDX || &pSectHdr == m_pEXTAB) {
+ // put ARM.exidx and ARM.extab in the same order of .eh_frame
+ return SHO_EXCEPTION;
+ }
+
return SHO_UNDEFINED;
}
@@ -1014,4 +969,6 @@
extern "C" void LLVMInitializeARMLDBackend() {
// Register the linker backend
mcld::TargetRegistry::RegisterTargetLDBackend(TheARMTarget, createARMLDBackend);
+ mcld::TargetRegistry::RegisterTargetLDBackend(TheThumbTarget, createARMLDBackend);
}
+
diff --git a/lib/Target/ARM/ARMLDBackend.h b/lib/Target/ARM/ARMLDBackend.h
index 27acdf1..3e46cd7 100644
--- a/lib/Target/ARM/ARMLDBackend.h
+++ b/lib/Target/ARM/ARMLDBackend.h
@@ -86,7 +86,7 @@
void initTargetSections(MCLinker& pLinker);
/// initTargetSymbols - initialize target dependent symbols in output.
- void initTargetSymbols(MCLinker& pLinker);
+ void initTargetSymbols(MCLinker& pLinker, const Output& pOutput);
/// initRelocFactory - create and initialize RelocationFactory
bool initRelocFactory(const MCLinker& pLinker);
@@ -104,7 +104,8 @@
const LDSymbol& pInputSym,
MCLinker& pLinker,
const MCLDInfo& pLDInfo,
- const Output& pOutput);
+ const Output& pOutput,
+ const LDSection& pSection);
uint32_t machine() const
{ return llvm::ELF::EM_ARM; }
@@ -127,6 +128,9 @@
unsigned int bitclass() const
{ return 32; }
+ uint64_t defaultTextSegmentAddr() const
+ { return 0x8000; }
+
/// doPreLayout - Backend can do any needed modification before layout
void doPreLayout(const Output& pOutput,
const MCLDInfo& pInfo,
@@ -160,11 +164,13 @@
/// @param pOutput - the output file
/// @param pSection - the given LDSection
/// @param pInfo - all options in the command line.
+ /// @param pLayout - for comouting the size of fragment
/// @param pRegion - the region to write out data
/// @return the size of the table in the file.
uint64_t emitSectionData(const Output& pOutput,
const LDSection& pSection,
const MCLDInfo& pInfo,
+ const Layout& pLayout,
MemoryRegion& pRegion) const;
ARMGOT& getGOT();
@@ -185,29 +191,17 @@
/// getTargetSectionOrder - compute the layout order of ARM target sections
unsigned int getTargetSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const;
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const;
- /// finalizeSymbol - finalize the symbol value
- /// If the symbol's reserved field is not zero, MCLinker will call back this
- /// function to ask the final value of the symbol
- bool finalizeSymbol(LDSymbol& pSymbol) const;
-
- /// allocateCommonSymbols - allocate common symbols in the corresponding
- /// sections.
- bool allocateCommonSymbols(const MCLDInfo& pLDInfo, MCLinker& pLinker) const;
+ /// finalizeTargetSymbols - finalize the symbol value
+ bool finalizeTargetSymbols(MCLinker& pLinker, const Output& pOutput);
/// readSection - read target dependent sections
bool readSection(Input& pInput,
MCLinker& pLinker,
LDSection& pInputSectHdr);
-public:
- bool isSymbolPreemptible(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) const;
-
- bool isPIC(const MCLDInfo& pLDInfo, const Output& pOutput) const;
-
private:
void scanLocalReloc(Relocation& pReloc,
const LDSymbol& pInputSym,
@@ -221,19 +215,20 @@
const MCLDInfo& pLDInfo,
const Output& pOutput);
- bool isSymbolNeedsPLT(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) const;
-
- bool isSymbolNeedsDynRel(const ResolveInfo& pSym,
- const Output& pOutput,
- bool isAbsReloc) const;
-
-
void checkValidReloc(Relocation& pReloc,
const MCLDInfo& pLDInfo,
const Output& pOutput) 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(MCLinker& pLinker,
+ const ResolveInfo& pSym);
+
/// updateAddend - update addend value of the relocation if the
/// the target symbol is a section symbol. Addend is the offset
/// in the section. This value should be updated after section
@@ -251,8 +246,6 @@
void createARMRelDyn(MCLinker& pLinker, const Output& pOutput);
- ELFFileFormat* getOutputFormat(const Output& pOutput) const;
-
private:
RelocationFactory* m_pRelocFactory;
ARMGOT* m_pGOT;
@@ -294,3 +287,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/ARM/ARMPLT.cpp b/lib/Target/ARM/ARMPLT.cpp
index b3461d0..5528ef7 100644
--- a/lib/Target/ARM/ARMPLT.cpp
+++ b/lib/Target/ARM/ARMPLT.cpp
@@ -9,8 +9,8 @@
#include "ARMGOT.h"
#include "ARMPLT.h"
#include <llvm/Support/raw_ostream.h>
-#include <llvm/Support/ErrorHandling.h>
#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
#include <new>
namespace {
@@ -65,7 +65,7 @@
plt1_entry = new (std::nothrow) ARMPLT1(&m_SectionData);
if (!plt1_entry)
- llvm::report_fatal_error("Allocating new memory for ARMPLT1 failed!");
+ fatal(diag::fail_allocate_memory) << "ARMPLT1";
m_Section.setSize(m_Section.size() + plt1_entry->getEntrySize());
@@ -167,7 +167,7 @@
data = static_cast<uint32_t*>(malloc(plt0->getEntrySize()));
if (!data)
- llvm::report_fatal_error("Allocating new memory for plt0 failed!");
+ fatal(diag::fail_allocate_memory) << "plt0";
memcpy(data, arm_plt0, plt0->getEntrySize());
data[4] = offset;
@@ -204,7 +204,7 @@
Out = static_cast<uint32_t*>(malloc(plt1->getEntrySize()));
if (!Out)
- llvm::report_fatal_error("Allocating new memory for plt1 failed!");
+ fatal(diag::fail_allocate_memory) << "plt1";
// Offset is the distance between the last PLT entry and the associated
// GOT entry.
@@ -247,3 +247,4 @@
}
return result;
}
+
diff --git a/lib/Target/ARM/ARMPLT.h b/lib/Target/ARM/ARMPLT.h
index 11d0bd0..f55aaa3 100644
--- a/lib/Target/ARM/ARMPLT.h
+++ b/lib/Target/ARM/ARMPLT.h
@@ -84,3 +84,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/ARM/ARMRelocationFactory.cpp b/lib/Target/ARM/ARMRelocationFactory.cpp
index 2763b3b..4911658 100644
--- a/lib/Target/ARM/ARMRelocationFactory.cpp
+++ b/lib/Target/ARM/ARMRelocationFactory.cpp
@@ -8,11 +8,12 @@
//===--------------------------------------------------------------------===//
#include <llvm/ADT/Twine.h>
-#include <llvm/Support/ErrorHandling.h>
#include <llvm/Support/DataTypes.h>
#include <llvm/Support/ELF.h>
+#include <llvm/Support/Host.h>
#include <mcld/MC/MCLDInfo.h>
#include <mcld/LD/Layout.h>
+#include <mcld/Support/MsgHandling.h>
#include "ARMRelocationFactory.h"
#include "ARMRelocationFunctions.h"
@@ -38,10 +39,8 @@
{
Relocation::Type type = pRelocation.type();
if (type > 130) { // 131-255 doesn't noted in ARM spec
- llvm::report_fatal_error(llvm::Twine("Unknown relocation type. "
- "To symbol `") +
- pRelocation.symInfo()->name() +
- llvm::Twine("'."));
+ fatal(diag::unknown_relocation) << (int)type
+ << pRelocation.symInfo()->name();
return;
}
@@ -70,29 +69,18 @@
return;
}
if (Overflow == result) {
- llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
- llvm::Twine(apply_functions[type].name) +
- llvm::Twine("' causes overflow. on symbol: `") +
- llvm::Twine(pRelocation.symInfo()->name()) +
- llvm::Twine("'."));
+ error(diag::result_overflow) << apply_functions[type].name
+ << pRelocation.symInfo()->name();
return;
}
-
if (BadReloc == result) {
- llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
- llvm::Twine(apply_functions[type].name) +
- llvm::Twine("' encounters unexpected opcode. "
- "on symbol: `") +
- llvm::Twine(pRelocation.symInfo()->name()) +
- llvm::Twine("'."));
+ error(diag::result_badreloc) << apply_functions[type].name
+ << pRelocation.symInfo()->name();
return;
}
if (Unsupport == result) {
- llvm::report_fatal_error(llvm::Twine("Encounter unsupported relocation `") +
- llvm::Twine(apply_functions[type].name) +
- llvm::Twine("' on symbol: `") +
- llvm::Twine(pRelocation.symInfo()->name()) +
- llvm::Twine("'."));
+ fatal(diag::unsupported_relocation) << type
+ << "mclinker@googlegroups.com";
return;
}
}
@@ -106,7 +94,7 @@
// Set thumb bit if
// - symbol has type of STT_FUNC, is defined and with bit 0 of its value set
RelocationFactory::DWord thumbBit =
- ((pReloc.symInfo()->desc() != ResolveInfo::Undefined) &&
+ ((!pReloc.symInfo()->isUndef() || pReloc.symInfo()->isDyn()) &&
(pReloc.symInfo()->type() == ResolveInfo::Function) &&
((pReloc.symValue() & 0x1) != 0))?
1:0;
@@ -144,11 +132,11 @@
const ARMRelocationFactory& pFactory)
{
// if symbol is dynamic or undefine or preemptible
- if(pSym.isDyn() ||
- pSym.isUndef() ||
- pFactory.getTarget().isSymbolPreemptible(pSym,
- pLDInfo,
- pLDInfo.output()))
+ if (pSym.isDyn() ||
+ pSym.isUndef() ||
+ pFactory.getTarget().isSymbolPreemptible(pSym,
+ pLDInfo,
+ pLDInfo.output()))
return false;
return true;
}
@@ -176,7 +164,7 @@
Relocation& rel_entry =
*ld_backend.getRelDyn().getEntry(*rsym, true, exist);
assert(!exist && "GOT entry not exist, but DynRel entry exist!");
- if( rsym->isLocal() ||
+ if ( rsym->isLocal() ||
helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
// Initialize got entry to target symbol address
got_entry.setContent(pReloc.symValue());
@@ -192,7 +180,7 @@
rel_entry.targetRef().assign(got_entry);
}
else {
- llvm::report_fatal_error("No GOT entry reserved for GOT type relocation!");
+ fatal(diag::reserve_entry_number_mismatch) << "GOT";
}
}
return got_entry;
@@ -239,7 +227,7 @@
rel_entry.setSymInfo(rsym);
}
else {
- llvm::report_fatal_error("No PLT entry reserved for PLT type relocation!");
+ fatal(diag::reserve_entry_number_mismatch) << "PLT";
}
}
return plt_entry;
@@ -279,7 +267,7 @@
rel_entry.setType(pType);
rel_entry.targetRef() = pReloc.targetRef();
- if(pType == llvm::ELF::R_ARM_RELATIVE)
+ if (pType == llvm::ELF::R_ARM_RELATIVE)
rel_entry.setSymInfo(0);
else
rel_entry.setSymInfo(rsym);
@@ -307,13 +295,17 @@
static ARMRelocationFactory::DWord
helper_extract_thumb_movw_movt_addend(ARMRelocationFactory::DWord pTarget)
{
- // TODO: By the rsloader experience: If we use 32bit, we need to consider
- // endianness problem. We'd better have a thumb instruction type.
+ // Consider the endianness problem, get the target data value from lower
+ // and upper 16 bits
+ ARMRelocationFactory::DWord val =
+ (*(reinterpret_cast<uint16_t*>(&pTarget)) << 16) |
+ *(reinterpret_cast<uint16_t*>(&pTarget) + 1);
+
// imm16: [19-16][26][14-12][7-0]
- return helper_sign_extend((((pTarget >> 4) & 0xf000U) |
- ((pTarget >> 15) & 0x0800U) |
- ((pTarget >> 4) & 0x0700U) |
- (pTarget & 0x00ffU)),
+ return helper_sign_extend((((val >> 4) & 0xf000U) |
+ ((val >> 15) & 0x0800U) |
+ ((val >> 4) & 0x0700U) |
+ (val & 0x00ffU)),
16);
}
@@ -321,15 +313,19 @@
helper_insert_val_thumb_movw_movt_inst(ARMRelocationFactory::DWord pTarget,
ARMRelocationFactory::DWord pImm)
{
- // TODO: By the rsloader experience: If we use 32bit, we need to consider
- // endianness problem. We'd better have a thumb instruction type.
+ ARMRelocationFactory::DWord val;
// imm16: [19-16][26][14-12][7-0]
pTarget &= 0xfbf08f00U;
pTarget |= (pImm & 0xf000U) << 4;
pTarget |= (pImm & 0x0800U) << 15;
pTarget |= (pImm & 0x0700U) << 4;
pTarget |= (pImm & 0x00ffU);
- return pTarget;
+
+ // Consider the endianness problem, write back data from lower and
+ // upper 16 bits
+ val = (*(reinterpret_cast<uint16_t*>(&pTarget)) << 16) |
+ *(reinterpret_cast<uint16_t*>(&pTarget) + 1);
+ return val;
}
static ARMRelocationFactory::DWord
@@ -408,13 +404,27 @@
ARMRelocationFactory::DWord A = pReloc.target() + pReloc.addend();
ARMRelocationFactory::DWord S = pReloc.symValue();
- if(rsym->isLocal() && (rsym->reserved() & 0x1u)) {
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+
+ // 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) | T;
+ return ARMRelocationFactory::OK;
+ }
+
+ // A local symbol may need REL Type dynamic relocation
+ if (rsym->isLocal() && (rsym->reserved() & ARMGNULDBackend::ReserveRel)) {
helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent);
pReloc.target() = (S + A) | T ;
return ARMRelocationFactory::OK;
}
- else if(!rsym->isLocal()) {
- if(rsym->reserved() & 0x8u) {
+
+ // An external symbol may need PLT and dynamic relocation
+ if (!rsym->isLocal()) {
+ if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
S = helper_PLT(pReloc, pParent);
T = 0 ; // PLT is not thumb
pReloc.target() = (S + A) | T;
@@ -422,8 +432,8 @@
// 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() & 0x1u) {
- if(helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
+ if (rsym->reserved() & ARMGNULDBackend::ReserveRel) {
+ if (helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent);
}
else {
@@ -433,6 +443,7 @@
}
}
+
// perform static relocation
pReloc.target() = (S + A) | T;
return ARMRelocationFactory::OK;
@@ -481,7 +492,8 @@
const MCLDInfo& pLDInfo,
ARMRelocationFactory& pParent)
{
- if(!(pReloc.symInfo()->reserved() & 0x6u)) {
+ if (!(pReloc.symInfo()->reserved() &
+ (ARMGNULDBackend::ReserveGOT | ARMGNULDBackend::GOTRel))) {
return ARMRelocationFactory::BadReloc;
}
ARMRelocationFactory::Address GOT_S = helper_GOT(pReloc, pLDInfo, pParent);
@@ -497,7 +509,8 @@
const MCLDInfo& pLDInfo,
ARMRelocationFactory& pParent)
{
- if(!(pReloc.symInfo()->reserved() & 0x6u)) {
+ if (!(pReloc.symInfo()->reserved() &
+ (ARMGNULDBackend::ReserveGOT | ARMGNULDBackend::GOTRel))) {
return ARMRelocationFactory::BadReloc;
}
ARMRelocationFactory::Address GOT_S = helper_GOT(pReloc, pLDInfo, pParent);
@@ -515,18 +528,23 @@
const MCLDInfo& pLDInfo,
ARMRelocationFactory& pParent)
{
- // TODO: Some issue have not been considered, e.g. thumb, overflow?
+ // TODO: Some issue have not been considered:
+ // 1. Add stub when switching mode or jump target too far
+ // 2. We assume the blx is available
// If target is undefined weak symbol, we only need to jump to the
- // next instruction unless it has PLT entry.
- if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
+ // next instruction unless it has PLT entry. Rewrite instruction
+ // to NOP.
+ if (pReloc.symInfo()->isWeak() &&
+ pReloc.symInfo()->isUndef() &&
+ !pReloc.symInfo()->isDyn() &&
!(pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT)) {
// change target to NOP : mov r0, r0
pReloc.target() = (pReloc.target() & 0xf0000000U) | 0x01a00000;
return ARMRelocationFactory::OK;
}
- ARMRelocationFactory::Address S; // S dependent on exist PLT or not.
+ ARMRelocationFactory::Address S; // S depends on PLT exists or not.
ARMRelocationFactory::DWord T = getThumbBit(pReloc);
ARMRelocationFactory::DWord A =
helper_sign_extend((pReloc.target() & 0x00FFFFFFu) << 2, 26)
@@ -534,16 +552,23 @@
ARMRelocationFactory::Address P = pReloc.place(pParent.getLayout());
S = pReloc.symValue();
- if( pReloc.symInfo()->reserved() & 0x8u) {
+ if (pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) {
S = helper_PLT(pReloc, pParent);
T = 0; // PLT is not thumb.
}
- ARMRelocationFactory::DWord X = ((S + A) | T) - P;
-
- if (X & 0x03u) { // Lowest two bit is not zero.
- llvm::report_fatal_error("Target is thumb, need stub!");
+ // If the jump target is thumb instruction, switch mode is needed, rewrite
+ // the instruction to BLX
+ if (T != 0) {
+ // cannot rewrite R_ARM_JUMP24 instruction to blx
+ assert((pReloc.type() != llvm::ELF::R_ARM_JUMP24)&&
+ "Invalid instruction to rewrite to blx for switching mode.");
+ pReloc.target() = (pReloc.target() & 0xffffff) |
+ 0xfa000000 |
+ (((S + A - P) & 2) << 23);
}
+
+ ARMRelocationFactory::DWord X = ((S + A) | T) - P;
// Check X is 24bit sign int. If not, we should use stub or PLT before apply.
assert(!helper_check_signed_overflow(X, 26) && "Jump or Call target too far!");
// Make sure the Imm is 0. Result Mask.
@@ -552,29 +577,25 @@
}
// R_ARM_THM_CALL: ((S + A) | T) - P
+// R_ARM_THM_JUMP24: (((S + A) | T) - P)
ARMRelocationFactory::Result thm_call(Relocation& pReloc,
const MCLDInfo& pLDInfo,
ARMRelocationFactory& pParent)
{
// If target is undefined weak symbol, we only need to jump to the
- // next instruction unless it has PLT entry.
- if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
+ // next instruction unless it has PLT entry. Rewrite instruction
+ // to NOP.
+ if (pReloc.symInfo()->isWeak() &&
+ pReloc.symInfo()->isUndef() &&
+ !pReloc.symInfo()->isDyn() &&
!(pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT)) {
pReloc.target() = (0xe000U << 16) | 0xbf00U;
return ARMRelocationFactory::OK;
}
- // TODO: By the rsloader experience: If we use 32bit, we need to consider
- // endianness problem. Here is an ugly solution. We'd better have a thumb
- // instruction type.
- //uint16_t upper16 = *(
- // reinterpret_cast<uint16_t*>(&pReloc.target())
- // ),
- // lower16 = *(
- // reinterpret_cast<uint16_t*>(&pReloc.target()) + 1
- // );
- ARMRelocationFactory::DWord upper16 = ((pReloc.target() & 0xffff0000U) >> 16),
- lower16 = (pReloc.target() & 0xffffU);
+ // get lower and upper 16 bit instructions from relocation targetData
+ uint16_t upper16 = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
+ uint16_t lower16 = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
ARMRelocationFactory::DWord T = getThumbBit(pReloc);
ARMRelocationFactory::DWord A = helper_thumb32_branch_offset(upper16,
@@ -582,44 +603,52 @@
ARMRelocationFactory::Address P = pReloc.place(pParent.getLayout());
ARMRelocationFactory::Address S;
- S = pReloc.symValue();
// if symbol has plt
- if( pReloc.symInfo()->reserved() & 0x8u) {
+ if (pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) {
S = helper_PLT(pReloc, pParent);
T = 0; // PLT is not thumb.
}
-
- // TODO: If the target is not thumb, we should rewrite instruction to BLX.
-
- ARMRelocationFactory::DWord X = ((S + A) | T) - P;
- X >>= 1;
-
- // FIXME: Check bit size is 24(thumb2) or 22?
- if (helper_check_signed_overflow(X, 24)) {
- assert(!"Offset is too far. We need stub or PLT for it.");
- return ARMRelocationFactory::Overflow;
+ else {
+ S = pReloc.symValue();
}
- // For a BLX instruction, make sure that the relocation is rounded up
- // to a word boundary. This follows the semantics of the instruction
- // which specifies that bit 1 of the target address will come from bit
- // 1 of the base address.
- if ((X & 0x5000U) == 0x4000U) {
- X = (X + 2) & ~0x3U;
+ S = S + A;
+
+ // FIXME: check if we can use BLX instruction (check from .ARM.attribute
+ // CPU ARCH TAG, which should be ARMv5 or above)
+
+ // If the jump target is not thumb, switch mode is needed, rewrite
+ // instruction to BLX
+ if (T == 0) {
+ // for BLX, select bit 1 from relocation base address to jump target
+ // address
+ S = helper_bit_select(S, P, 0x2);
+ // rewrite instruction to BLX
+ lower16 &= ~0x1000U;
+ }
+ else {
+ // otherwise, the instruction should be BL
+ lower16 |= 0x1000U;
+ }
+
+ ARMRelocationFactory::DWord X = (S | T) - P;
+
+ // TODO: check if we need stub when building non-shared object,
+ // overflow or switch-mode.
+
+ // FIXME: Check bit size is 24(thumb2) or 22?
+ if (helper_check_signed_overflow(X, 25)) {
+ assert(!"Offset is too far. We need stub or PLT for it.");
+ return ARMRelocationFactory::Overflow;
}
upper16 = helper_thumb32_branch_upper(upper16, X);
lower16 = helper_thumb32_branch_lower(lower16, X);
- // TODO: By the rsloader experience: If we use 32bit, we need to consider
- // endianness problem. Here is an ugly solution. We'd better have a thumb
- // instruction type.
- //*(reinterpret_cast<uint16_t*>(&preloc.target())) = upper16;
- //*(reinterpret_cast<uint16_t*>(&preloc.target()) + 1) = lower16;
- pReloc.target() = (upper16 << 16);
- pReloc.target() |= lower16;
+ *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper16;
+ *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower16;
- return ARMRelocationFactory::OK;
+ return ARMRelocationFactory::OK;
}
// R_ARM_MOVW_ABS_NC: (S + A) | T
@@ -634,11 +663,19 @@
helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
ARMRelocationFactory::DWord X;
- // use plt
- if(rsym->reserved() & 0x8u) {
- S = helper_PLT(pReloc, pParent);
- T = 0 ; // PLT is not thumb
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+ // 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())) {
+ // use plt
+ if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0 ; // PLT is not thumb
+ }
}
+
X = (S + A) | T ;
// perform static relocation
pReloc.target() = (S + A) | T;
@@ -683,9 +720,16 @@
helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
ARMRelocationFactory::DWord X;
- // use plt
- if(rsym->reserved() & 0x8u) {
- S = helper_PLT(pReloc, pParent);
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+ // 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())) {
+ // use plt
+ if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
+ S = helper_PLT(pReloc, pParent);
+ }
}
X = S + A;
@@ -725,20 +769,22 @@
helper_extract_thumb_movw_movt_addend(pReloc.target()) + pReloc.addend();
ARMRelocationFactory::DWord X;
- // use plt
- if(rsym->reserved() & 0x8u) {
- S = helper_PLT(pReloc, pParent);
- T = 0; // PLT is not thumb
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+ // 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())) {
+ // use plt
+ if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0; // PLT is not thumb
+ }
}
X = (S + A) | T;
- // check 16-bit overflow
- if (helper_check_signed_overflow(X, 16)) {
- return ARMRelocationFactory::Overflow;
- } else {
- pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
- X);
- return ARMRelocationFactory::OK;
- }
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ X);
+ return ARMRelocationFactory::OK;
}
// R_ARM_THM_MOVW_PREL_NC: ((S + A) | T) - P
@@ -756,13 +802,30 @@
X = ((S + A) | T) - P;
// check 16-bit overflow
- if (helper_check_signed_overflow(X, 16)) {
- return ARMRelocationFactory::Overflow;
- } else {
- pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
- X);
- return ARMRelocationFactory::OK;
- }
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ X);
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_THM_MOVW_BREL_NC: ((S + A) | T) - B(S)
+// R_ARM_THM_MOVW_BREL: ((S + A) | T) - B(S)
+ARMRelocationFactory::Result thm_movw_brel(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord P = pReloc.place(pParent.getLayout());
+ ARMRelocationFactory::DWord A =
+ helper_extract_thumb_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ X = ((S + A) | T) - P;
+
+ // check 16-bit overflow
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ X);
+ return ARMRelocationFactory::OK;
}
// R_ARM_THM_MOVT_ABS: S + A
@@ -776,10 +839,18 @@
helper_extract_thumb_movw_movt_addend(pReloc.target()) + pReloc.addend();
ARMRelocationFactory::DWord X;
- // use plt
- if(rsym->reserved() & 0x8u) {
- S = helper_PLT(pReloc, pParent);
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+ // 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())) {
+ // use plt
+ if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
+ S = helper_PLT(pReloc, pParent);
+ }
}
+
X = S + A;
X >>= 16;
@@ -794,6 +865,7 @@
}
// R_ARM_THM_MOVT_PREL: S + A - P
+// R_ARM_THM_MOVT_BREL: S + A - B(S)
ARMRelocationFactory::Result thm_movt_prel(Relocation& pReloc,
const MCLDInfo& pLDInfo,
ARMRelocationFactory& pParent)
@@ -806,15 +878,9 @@
X = S + A - P;
X >>= 16;
-
- // check 16-bit overflow
- if (helper_check_signed_overflow(X, 16)) {
- return ARMRelocationFactory::Overflow;
- } else {
- pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
X);
- return ARMRelocationFactory::OK;
- }
+ return ARMRelocationFactory::OK;
}
// R_ARM_PREL31: (S + A) | T
@@ -830,14 +896,14 @@
S = pReloc.symValue();
// if symbol has plt
- if( pReloc.symInfo()->reserved() & 0x8u) {
+ if ( pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) {
S = helper_PLT(pReloc, pParent);
T = 0; // PLT is not thumb.
}
ARMRelocationFactory::DWord X = (S + A) | T ;
pReloc.target() = helper_bit_select(target, X, 0x7fffffffU);
- if(helper_check_signed_overflow(X, 31))
+ if (helper_check_signed_overflow(X, 31))
return ARMRelocationFactory::Overflow;
return ARMRelocationFactory::OK;
}
@@ -849,7 +915,6 @@
const MCLDInfo& pLDInfo,
ARMRelocationFactory& pParent)
{
- llvm::report_fatal_error("We don't support TLS relocation yet.");
return ARMRelocationFactory::Unsupport;
}
diff --git a/lib/Target/ARM/ARMRelocationFactory.h b/lib/Target/ARM/ARMRelocationFactory.h
index 0426100..636dbee 100644
--- a/lib/Target/ARM/ARMRelocationFactory.h
+++ b/lib/Target/ARM/ARMRelocationFactory.h
@@ -56,3 +56,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/ARM/ARMRelocationFunctions.h b/lib/Target/ARM/ARMRelocationFunctions.h
index 10d27a4..bb6e727 100644
--- a/lib/Target/ARM/ARMRelocationFunctions.h
+++ b/lib/Target/ARM/ARMRelocationFunctions.h
@@ -27,6 +27,7 @@
DECL_ARM_APPLY_RELOC_FUNC(movt_prel) \
DECL_ARM_APPLY_RELOC_FUNC(thm_movw_abs_nc) \
DECL_ARM_APPLY_RELOC_FUNC(thm_movw_prel_nc) \
+DECL_ARM_APPLY_RELOC_FUNC(thm_movw_brel) \
DECL_ARM_APPLY_RELOC_FUNC(thm_movt_abs) \
DECL_ARM_APPLY_RELOC_FUNC(thm_movt_prel) \
DECL_ARM_APPLY_RELOC_FUNC(prel31) \
@@ -66,7 +67,7 @@
{ &call, 27, "R_ARM_PLT32" }, \
{ &call, 28, "R_ARM_CALL" }, \
{ &call, 29, "R_ARM_JUMP24" }, \
- { &unsupport, 30, "R_ARM_THM_JUMP24" }, \
+ { &thm_call, 30, "R_ARM_THM_JUMP24" }, \
{ &unsupport, 31, "R_ARM_BASE_ABS" }, \
{ &unsupport, 32, "R_ARM_ALU_PCREL_7_0" }, \
{ &unsupport, 33, "R_ARM_ALU_PCREL_15_8" }, \
@@ -123,9 +124,9 @@
{ &unsupport, 84, "R_ARM_MOVW_BREL_NC" }, \
{ &unsupport, 85, "R_ARM_MOVT_BREL" }, \
{ &unsupport, 86, "R_ARM_MOVW_BREL" }, \
- { &unsupport, 87, "R_ARM_THM_MOVW_BREL_NC" }, \
- { &unsupport, 88, "R_ARM_THM_MOVT_BREL" }, \
- { &unsupport, 89, "R_ARM_THM_MOVW_BREL" }, \
+ { &thm_movw_brel, 87, "R_ARM_THM_MOVW_BREL_NC" }, \
+ { &thm_movt_prel, 88, "R_ARM_THM_MOVT_BREL" }, \
+ { &thm_movw_brel, 89, "R_ARM_THM_MOVW_BREL" }, \
{ &unsupport, 90, "R_ARM_TLS_GOTDESC" }, \
{ &unsupport, 91, "R_ARM_TLS_CALL" }, \
{ &unsupport, 92, "R_ARM_TLS_DESCSEQ" }, \
diff --git a/lib/Target/ARM/ARMSectLinker.cpp b/lib/Target/ARM/ARMSectLinker.cpp
index 16d2126..06dba05 100644
--- a/lib/Target/ARM/ARMSectLinker.cpp
+++ b/lib/Target/ARM/ARMSectLinker.cpp
@@ -9,7 +9,6 @@
#include <llvm/ADT/Triple.h>
#include <mcld/Support/TargetRegistry.h>
#include "ARM.h"
-#include "ARMAndroidSectLinker.h"
#include "ARMELFSectLinker.h"
@@ -32,8 +31,7 @@
}
// For now, use Android SectLinker directly
- return new ARMAndroidSectLinker(pOption,
- pLDBackend);
+ return new ARMELFSectLinker(pOption, pLDBackend);
}
} // namespace of mcld
@@ -43,4 +41,6 @@
extern "C" void LLVMInitializeARMSectLinker() {
// Register the linker frontend
mcld::TargetRegistry::RegisterSectLinker(TheARMTarget, createARMSectLinker);
+ mcld::TargetRegistry::RegisterSectLinker(TheThumbTarget, createARMSectLinker);
}
+
diff --git a/lib/Target/ARM/ARMTargetMachine.cpp b/lib/Target/ARM/ARMTargetMachine.cpp
index 3cb7793..54e1b3d 100644
--- a/lib/Target/ARM/ARMTargetMachine.cpp
+++ b/lib/Target/ARM/ARMTargetMachine.cpp
@@ -15,6 +15,7 @@
extern "C" void LLVMInitializeARMLDTarget() {
// Register createTargetMachine function pointer to mcld::Target
mcld::RegisterTargetMachine<mcld::ARMBaseTargetMachine> X(mcld::TheARMTarget);
+ mcld::RegisterTargetMachine<mcld::ARMBaseTargetMachine> Y(mcld::TheThumbTarget);
}
mcld::ARMBaseTargetMachine::ARMBaseTargetMachine(llvm::TargetMachine& pPM,
@@ -30,3 +31,4 @@
{
delete m_pLDInfo;
}
+
diff --git a/lib/Target/ARM/ARMTargetMachine.h b/lib/Target/ARM/ARMTargetMachine.h
index 419826c..19f8aa2 100644
--- a/lib/Target/ARM/ARMTargetMachine.h
+++ b/lib/Target/ARM/ARMTargetMachine.h
@@ -37,3 +37,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/ARM/README b/lib/Target/ARM/README
index 2110344..ea88bfe 100644
--- a/lib/Target/ARM/README
+++ b/lib/Target/ARM/README
@@ -1,2 +1,2 @@
-ARMLDBackend stands like ARMAsmBackend. It's a backend of linker,
+ARMLDBackend stands like ARMAsmBackend. It's a backend of linker,
and all target-dependent behavior and data are here.
diff --git a/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp b/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
index 7e6a41a..4f2f815 100644
--- a/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
+++ b/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
@@ -12,10 +12,12 @@
namespace mcld {
mcld::Target TheARMTarget;
+mcld::Target TheThumbTarget;
extern "C" void LLVMInitializeARMLDTargetInfo() {
// register into mcld::TargetRegistry
mcld::RegisterTarget X(TheARMTarget, "arm" );
+ mcld::RegisterTarget Y(TheThumbTarget, "thumb" );
}
} // namespace of mcld
diff --git a/lib/Target/AndroidSectLinker.cpp b/lib/Target/AndroidSectLinker.cpp
deleted file mode 100644
index 8f3acbf..0000000
--- a/lib/Target/AndroidSectLinker.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-//===- AndroidSectLinker.cpp ----------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include <mcld/Target/AndroidSectLinker.h>
-
-#include <llvm/Support/ErrorHandling.h>
-#include <mcld/MC/MCLDDirectory.h>
-#include <mcld/CodeGen/SectLinkerOption.h>
-
-using namespace mcld;
-
-//==========================
-// AndroidSectLinker
-
-AndroidSectLinker::AndroidSectLinker(SectLinkerOption &pOption,
- TargetLDBackend &pLDBackend)
- : SectLinker(pOption, pLDBackend) {
-}
-
-AndroidSectLinker::~AndroidSectLinker()
-{
- // SectLinker will delete m_pLDBackend and m_pLDDriver;
-}
-
-void AndroidSectLinker::addTargetOptions(llvm::Module &pM,
- SectLinkerOption &pOption)
-{
- // ----- Set up General Options ----- //
- MCLDInfo &info = pOption.info();
- MCLDDirectory search_path("=/system/lib");
- search_path.setSysroot(info.options().sysroot());
- if (exists(search_path.path()) && is_directory(search_path.path()))
- info.options().directories().add(search_path);
- else {
- // FIXME: need a warning function
- llvm::errs() << "WARNING: can not open search directory: `-L" << search_path.name() << "'.\n";
- }
-}
-
diff --git a/lib/Target/ELFDynamic.cpp b/lib/Target/ELFDynamic.cpp
index b863ab1..cb7c435 100644
--- a/lib/Target/ELFDynamic.cpp
+++ b/lib/Target/ELFDynamic.cpp
@@ -84,7 +84,6 @@
++m_Idx;
}
-
/// reserveEntries - reserve entries
void ELFDynamic::reserveEntries(const MCLDInfo& pLDInfo,
const ELFFileFormat& pFormat)
@@ -146,6 +145,28 @@
reserveOne(llvm::ELF::DT_RELASZ); // DT_RELASZ
reserveOne(llvm::ELF::DT_RELAENT); // DT_RELAENT
}
+
+ if (pLDInfo.options().hasOrigin() ||
+ pLDInfo.options().Bsymbolic() ||
+ pLDInfo.options().hasNow()) {
+ // TODO: add checks for DF_TEXTREL and DF_STATIC_TLS
+ reserveOne(llvm::ELF::DT_FLAGS); // DT_FLAGS
+ }
+
+ if (pLDInfo.options().hasNow() ||
+ pLDInfo.options().hasLoadFltr() ||
+ pLDInfo.options().hasOrigin() ||
+ pLDInfo.options().hasInterPose() ||
+ pLDInfo.options().hasNoDefaultLib() ||
+ pLDInfo.options().hasNoDump() ||
+ pLDInfo.options().Bgroup() ||
+ ((pLDInfo.output().type() == Output::DynObj) &&
+ (pLDInfo.options().hasNoDelete() ||
+ pLDInfo.options().hasInitFirst() ||
+ pLDInfo.options().hasNoDLOpen()))) {
+ reserveOne(llvm::ELF::DT_FLAGS_1); // DT_FLAGS_1
+ }
+
reserveOne(llvm::ELF::DT_NULL); // for DT_NULL
}
@@ -217,6 +238,44 @@
applyOne(llvm::ELF::DT_RELAENT, m_pEntryFactory->relaSize()); // DT_RELAENT
}
+ uint64_t dt_flags = 0x0;
+ if (pInfo.options().hasOrigin())
+ dt_flags |= llvm::ELF::DF_ORIGIN;
+ if (pInfo.options().Bsymbolic())
+ dt_flags |= llvm::ELF::DF_SYMBOLIC;
+ if (pInfo.options().hasNow())
+ dt_flags |= llvm::ELF::DF_BIND_NOW;
+ // TODO: add checks for DF_TEXTREL and DF_STATIC_TLS
+ if (0x0 != dt_flags) {
+ applyOne(llvm::ELF::DT_FLAGS, dt_flags); // DT_FLAGS
+ }
+
+ uint64_t dt_flags_1 = 0x0;
+ if (pInfo.options().hasNow())
+ dt_flags_1 |= llvm::ELF::DF_1_NOW;
+ if (pInfo.options().hasLoadFltr())
+ dt_flags_1 |= llvm::ELF::DF_1_LOADFLTR;
+ if (pInfo.options().hasOrigin())
+ dt_flags_1 |= llvm::ELF::DF_1_ORIGIN;
+ if (pInfo.options().hasInterPose())
+ dt_flags_1 |= llvm::ELF::DF_1_INTERPOSE;
+ if (pInfo.options().hasNoDefaultLib())
+ dt_flags_1 |= llvm::ELF::DF_1_NODEFLIB;
+ if (pInfo.options().hasNoDump())
+ dt_flags_1 |= llvm::ELF::DF_1_NODUMP;
+ if (pInfo.options().Bgroup())
+ dt_flags_1 |= llvm::ELF::DF_1_GROUP;
+ if (pInfo.output().type() == Output::DynObj) {
+ if (pInfo.options().hasNoDelete())
+ dt_flags_1 |= llvm::ELF::DF_1_NODELETE;
+ if (pInfo.options().hasInitFirst())
+ dt_flags_1 |= llvm::ELF::DF_1_INITFIRST;
+ if (pInfo.options().hasNoDLOpen())
+ dt_flags_1 |= llvm::ELF::DF_1_NOOPEN;
+ }
+ if (0x0 != dt_flags_1)
+ applyOne(llvm::ELF::DT_FLAGS_1, dt_flags_1); // DT_FLAGS_1
+
applyOne(llvm::ELF::DT_NULL, 0x0); // for DT_NULL
}
diff --git a/lib/Target/ELFSectLinker.cpp b/lib/Target/ELFSectLinker.cpp
new file mode 100644
index 0000000..b95ed0b
--- /dev/null
+++ b/lib/Target/ELFSectLinker.cpp
@@ -0,0 +1,25 @@
+//===- ELFSectLinker.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Target/ELFSectLinker.h>
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+//==========================
+// ELFSectLinker
+ELFSectLinker::ELFSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : SectLinker(pOption, pLDBackend) {
+}
+
+ELFSectLinker::~ELFSectLinker()
+{
+ // SectLinker will delete m_pLDBackend and m_pLDDriver;
+}
+
diff --git a/lib/Target/GNULDBackend.cpp b/lib/Target/GNULDBackend.cpp
index b82af73..9fff9e3 100644
--- a/lib/Target/GNULDBackend.cpp
+++ b/lib/Target/GNULDBackend.cpp
@@ -11,12 +11,14 @@
#include <mcld/Target/GNULDBackend.h>
#include <mcld/MC/MCLDInfo.h>
#include <mcld/MC/MCLDOutput.h>
-#include <mcld/MC/MCLDInputTree.h>
+#include <mcld/MC/InputTree.h>
#include <mcld/MC/SymbolCategory.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/Layout.h>
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/MC/MCLinker.h>
#include <string>
#include <cstring>
#include <cassert>
@@ -26,36 +28,57 @@
//===----------------------------------------------------------------------===//
// GNULDBackend
GNULDBackend::GNULDBackend()
- : m_pArchiveReader(0),
- m_pObjectReader(0),
- m_pDynObjReader(0),
- m_pObjectWriter(0),
- m_pDynObjWriter(0),
- m_pDynObjFileFormat(0),
- m_pExecFileFormat(0),
- m_ELFSegmentTable(9)// magic number
-{
+ : m_pArchiveReader(NULL),
+ m_pObjectReader(NULL),
+ m_pDynObjReader(NULL),
+ m_pObjectWriter(NULL),
+ m_pDynObjWriter(NULL),
+ m_pExecWriter(NULL),
+ m_pDynObjFileFormat(NULL),
+ m_pExecFileFormat(NULL),
+ m_ELFSegmentTable(9), // magic number
+ m_pEhFrameHdr(NULL),
+ f_pPreInitArrayStart(NULL),
+ f_pPreInitArrayEnd(NULL),
+ f_pInitArrayStart(NULL),
+ f_pInitArrayEnd(NULL),
+ f_pFiniArrayStart(NULL),
+ f_pFiniArrayEnd(NULL),
+ f_pStack(NULL),
+ f_pExecutableStart(NULL),
+ f_pEText(NULL),
+ f_p_EText(NULL),
+ f_p__EText(NULL),
+ f_pEData(NULL),
+ f_p_EData(NULL),
+ f_pBSSStart(NULL),
+ f_pEnd(NULL),
+ f_p_End(NULL) {
m_pSymIndexMap = new HashTableType(1024);
}
GNULDBackend::~GNULDBackend()
{
- if (m_pArchiveReader)
+ if (NULL != m_pArchiveReader)
delete m_pArchiveReader;
- if (m_pObjectReader)
+ if (NULL != m_pObjectReader)
delete m_pObjectReader;
- if (m_pDynObjReader)
+ if (NULL != m_pDynObjReader)
delete m_pDynObjReader;
- if (m_pObjectWriter)
+ if (NULL != m_pObjectWriter)
delete m_pObjectWriter;
- if (m_pDynObjWriter)
+ if (NULL != m_pDynObjWriter)
delete m_pDynObjWriter;
- if (m_pDynObjFileFormat)
+ if (NULL != m_pExecWriter)
+ delete m_pExecWriter;
+ if (NULL != m_pDynObjFileFormat)
delete m_pDynObjFileFormat;
- if (m_pExecFileFormat)
+ if (NULL != m_pExecFileFormat)
delete m_pExecFileFormat;
- if(m_pSymIndexMap)
+ if (NULL != m_pSymIndexMap)
delete m_pSymIndexMap;
+ if (NULL != m_pEhFrameHdr)
+ delete m_pEhFrameHdr;
}
size_t GNULDBackend::sectionStartOffset() const
@@ -64,13 +87,20 @@
return sizeof(llvm::ELF::Elf64_Ehdr)+10*sizeof(llvm::ELF::Elf64_Phdr);
}
+uint64_t GNULDBackend::segmentStartAddr(const Output& pOutput,
+ const MCLDInfo& pInfo) const
+{
+ // TODO: handle the user option: -TText=
+ if (isOutputPIC(pOutput, pInfo))
+ return 0x0;
+ else
+ return defaultTextSegmentAddr();
+}
+
bool GNULDBackend::initArchiveReader(MCLinker&, MCLDInfo &pInfo)
{
if (0 == m_pArchiveReader)
- {
- LDReader::Endian isLittleEndian = LDReader::LittleEndian;
- m_pArchiveReader = new GNUArchiveReader(pInfo, isLittleEndian);
- }
+ m_pArchiveReader = new GNUArchiveReader(pInfo);
return true;
}
@@ -96,11 +126,18 @@
bool GNULDBackend::initDynObjWriter(MCLinker& pLinker)
{
- if (0 == m_pDynObjWriter)
+ if (NULL == m_pDynObjWriter)
m_pDynObjWriter = new ELFDynObjWriter(*this, pLinker);
return true;
}
+bool GNULDBackend::initExecWriter(MCLinker& pLinker)
+{
+ if (NULL == m_pExecWriter)
+ m_pExecWriter = new ELFExecWriter(*this, pLinker);
+ return true;
+}
+
bool GNULDBackend::initExecSections(MCLinker& pMCLinker)
{
if (0 == m_pExecFileFormat)
@@ -121,8 +158,395 @@
return true;
}
-bool GNULDBackend::initStandardSymbols(MCLinker& pLinker)
+bool GNULDBackend::initStandardSymbols(MCLinker& pLinker, const Output& pOutput)
{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ // ----- section symbols ----- //
+ // .preinit_array
+ MCFragmentRef* preinit_array = NULL;
+ if (file_format->hasPreInitArray()) {
+ preinit_array = pLinker.getLayout().getFragmentRef(
+ *(file_format->getPreInitArray().getSectionData()->begin()),
+ 0x0);
+ }
+ f_pPreInitArrayStart =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__preinit_array_start",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Global,
+ 0x0, // size
+ 0x0, // value
+ preinit_array, // FragRef
+ ResolveInfo::Hidden);
+ f_pPreInitArrayEnd =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__preinit_array_end",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Global,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Hidden);
+
+ // .init_array
+ MCFragmentRef* init_array = NULL;
+ if (file_format->hasInitArray()) {
+ init_array = pLinker.getLayout().getFragmentRef(
+ *(file_format->getInitArray().getSectionData()->begin()),
+ 0x0);
+ }
+
+ f_pInitArrayStart =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__init_array_start",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Global,
+ 0x0, // size
+ 0x0, // value
+ init_array, // FragRef
+ ResolveInfo::Hidden);
+ f_pInitArrayEnd =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__init_array_end",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Global,
+ 0x0, // size
+ 0x0, // value
+ init_array, // FragRef
+ ResolveInfo::Hidden);
+
+ // .fini_array
+ MCFragmentRef* fini_array = NULL;
+ if (file_format->hasFiniArray()) {
+ fini_array = pLinker.getLayout().getFragmentRef(
+ *(file_format->getFiniArray().getSectionData()->begin()),
+ 0x0);
+ }
+
+ f_pFiniArrayStart =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__fini_array_start",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Global,
+ 0x0, // size
+ 0x0, // value
+ fini_array, // FragRef
+ ResolveInfo::Hidden);
+ f_pFiniArrayEnd =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__fini_array_end",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Global,
+ 0x0, // size
+ 0x0, // value
+ fini_array, // FragRef
+ ResolveInfo::Hidden);
+
+ // .stack
+ MCFragmentRef* stack = NULL;
+ if (file_format->hasStack()) {
+ stack = pLinker.getLayout().getFragmentRef(
+ *(file_format->getStack().getSectionData()->begin()),
+ 0x0);
+ }
+ f_pStack =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__stack",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Global,
+ 0x0, // size
+ 0x0, // value
+ stack, // FragRef
+ ResolveInfo::Hidden);
+
+ // ----- segment symbols ----- //
+ f_pExecutableStart =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__executable_start",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+ f_pEText =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("etext",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+ f_p_EText =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("_etext",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+ f_p__EText =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__etext",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+ f_pEData =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("edata",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+
+ f_pEnd =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("end",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+
+ // _edata is defined forcefully.
+ // @ref Google gold linker: defstd.cc: 186
+ f_p_EData =
+ pLinker.defineSymbol<MCLinker::Force,
+ MCLinker::Resolve>("_edata",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+
+ // __bss_start is defined forcefully.
+ // @ref Google gold linker: defstd.cc: 214
+ f_pBSSStart =
+ pLinker.defineSymbol<MCLinker::Force,
+ MCLinker::Resolve>("__bss_start",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+
+ // _end is defined forcefully.
+ // @ref Google gold linker: defstd.cc: 228
+ f_p_End =
+ pLinker.defineSymbol<MCLinker::Force,
+ MCLinker::Resolve>("_end",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+
+ return true;
+}
+
+bool
+GNULDBackend::finalizeStandardSymbols(MCLinker& pLinker, const Output& pOutput)
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ // ----- section symbols ----- //
+ if (NULL != f_pPreInitArrayStart) {
+ if (!f_pPreInitArrayStart->hasFragRef()) {
+ f_pPreInitArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute);
+ f_pPreInitArrayStart->setValue(0x0);
+ }
+ }
+
+ if (NULL != f_pPreInitArrayEnd) {
+ if (f_pPreInitArrayEnd->hasFragRef()) {
+ f_pPreInitArrayEnd->setValue(f_pPreInitArrayEnd->value() +
+ file_format->getPreInitArray().size());
+ }
+ else {
+ f_pPreInitArrayEnd->resolveInfo()->setBinding(ResolveInfo::Absolute);
+ f_pPreInitArrayEnd->setValue(0x0);
+ }
+ }
+
+ if (NULL != f_pInitArrayStart) {
+ if (!f_pInitArrayStart->hasFragRef()) {
+ f_pInitArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute);
+ f_pInitArrayStart->setValue(0x0);
+ }
+ }
+
+ if (NULL != f_pInitArrayEnd) {
+ if (f_pInitArrayEnd->hasFragRef()) {
+ f_pInitArrayEnd->setValue(f_pInitArrayEnd->value() +
+ file_format->getInitArray().size());
+ }
+ else {
+ f_pInitArrayEnd->resolveInfo()->setBinding(ResolveInfo::Absolute);
+ f_pInitArrayEnd->setValue(0x0);
+ }
+ }
+
+ if (NULL != f_pFiniArrayStart) {
+ if (!f_pFiniArrayStart->hasFragRef()) {
+ f_pFiniArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute);
+ f_pFiniArrayStart->setValue(0x0);
+ }
+ }
+
+ if (NULL != f_pFiniArrayEnd) {
+ if (f_pFiniArrayEnd->hasFragRef()) {
+ f_pFiniArrayEnd->setValue(f_pFiniArrayEnd->value() +
+ file_format->getFiniArray().size());
+ }
+ else {
+ f_pFiniArrayEnd->resolveInfo()->setBinding(ResolveInfo::Absolute);
+ f_pFiniArrayEnd->setValue(0x0);
+ }
+ }
+
+ if (NULL != f_pStack) {
+ if (!f_pStack->hasFragRef()) {
+ f_pStack->resolveInfo()->setBinding(ResolveInfo::Absolute);
+ f_pStack->setValue(0x0);
+ }
+ }
+
+ // ----- segment symbols ----- //
+ if (NULL != f_pExecutableStart) {
+ ELFSegment* exec_start = m_ELFSegmentTable.find(llvm::ELF::PT_LOAD, 0x0, 0x0);
+ if (NULL != exec_start) {
+ if (ResolveInfo::ThreadLocal != f_pExecutableStart->type()) {
+ f_pExecutableStart->setValue(f_pExecutableStart->value() +
+ exec_start->vaddr());
+ }
+ }
+ else
+ f_pExecutableStart->setValue(0x0);
+ }
+
+ 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) {
+ if (NULL != f_pEText && ResolveInfo::ThreadLocal != f_pEText->type()) {
+ f_pEText->setValue(f_pEText->value() +
+ 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());
+ }
+ if (NULL != f_p__EText && ResolveInfo::ThreadLocal != f_p__EText->type()) {
+ f_p__EText->setValue(f_p__EText->value() +
+ etext->vaddr() +
+ etext->memsz());
+ }
+ }
+ else {
+ if (NULL != f_pEText)
+ f_pEText->setValue(0x0);
+ if (NULL != f_p_EText)
+ f_p_EText->setValue(0x0);
+ if (NULL != f_p__EText)
+ f_p__EText->setValue(0x0);
+ }
+ }
+
+ 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) {
+ if (NULL != f_pEData && ResolveInfo::ThreadLocal != f_pEData->type()) {
+ f_pEData->setValue(f_pEData->value() +
+ 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());
+ }
+ if (NULL != f_pBSSStart && ResolveInfo::ThreadLocal != f_pBSSStart->type()) {
+ f_pBSSStart->setValue(f_pBSSStart->value() +
+ edata->vaddr() +
+ edata->filesz());
+ }
+
+ if (NULL != f_pEnd && ResolveInfo::ThreadLocal != f_pEnd->type()) {
+ f_pEnd->setValue(f_pEnd->value() +
+ 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());
+ }
+ }
+ else {
+ if (NULL != f_pEData)
+ f_pEData->setValue(0x0);
+ if (NULL != f_p_EData)
+ f_p_EData->setValue(0x0);
+ if (NULL != f_pBSSStart)
+ f_pBSSStart->setValue(0x0);
+
+ if (NULL != f_pEnd)
+ f_pEnd->setValue(0x0);
+ if (NULL != f_p_End)
+ f_p_End->setValue(0x0);
+ }
+ }
+
return true;
}
@@ -132,7 +556,7 @@
return m_pArchiveReader;
}
-GNUArchiveReader *GNULDBackend::getArchiveReader() const
+const GNUArchiveReader *GNULDBackend::getArchiveReader() const
{
assert(0 != m_pArchiveReader);
return m_pArchiveReader;
@@ -144,7 +568,7 @@
return m_pObjectReader;
}
-ELFObjectReader *GNULDBackend::getObjectReader() const
+const ELFObjectReader *GNULDBackend::getObjectReader() const
{
assert(0 != m_pObjectReader);
return m_pObjectReader;
@@ -156,7 +580,7 @@
return m_pDynObjReader;
}
-ELFDynObjReader *GNULDBackend::getDynObjReader() const
+const ELFDynObjReader *GNULDBackend::getDynObjReader() const
{
assert(0 != m_pDynObjReader);
return m_pDynObjReader;
@@ -168,7 +592,7 @@
return NULL;
}
-ELFObjectWriter *GNULDBackend::getObjectWriter() const
+const ELFObjectWriter *GNULDBackend::getObjectWriter() const
{
// TODO
return NULL;
@@ -180,19 +604,61 @@
return m_pDynObjWriter;
}
-ELFDynObjWriter *GNULDBackend::getDynObjWriter() const
+const ELFDynObjWriter *GNULDBackend::getDynObjWriter() const
{
assert(0 != m_pDynObjWriter);
return m_pDynObjWriter;
}
+ELFExecWriter *GNULDBackend::getExecWriter()
+{
+ assert(NULL != m_pExecWriter);
+ return m_pExecWriter;
+}
+
+const ELFExecWriter *GNULDBackend::getExecWriter() const
+{
+ assert(NULL != m_pExecWriter);
+ return m_pExecWriter;
+}
+
+ELFFileFormat* GNULDBackend::getOutputFormat(const Output& pOutput)
+{
+ switch (pOutput.type()) {
+ case Output::DynObj:
+ return getDynObjFileFormat();
+ case Output::Exec:
+ return getExecFileFormat();
+ // FIXME: We do not support building .o now
+ case Output::Object:
+ default:
+ fatal(diag::unrecognized_output_file) << pOutput.type();
+ return NULL;
+ }
+}
+
+const ELFFileFormat* GNULDBackend::getOutputFormat(const Output& pOutput) const
+{
+ switch (pOutput.type()) {
+ case Output::DynObj:
+ return getDynObjFileFormat();
+ case Output::Exec:
+ return getExecFileFormat();
+ // FIXME: We do not support building .o now
+ case Output::Object:
+ default:
+ fatal(diag::unrecognized_output_file) << pOutput.type();
+ return NULL;
+ }
+}
+
ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat()
{
assert(0 != m_pDynObjFileFormat);
return m_pDynObjFileFormat;
}
-ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat() const
+const ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat() const
{
assert(0 != m_pDynObjFileFormat);
return m_pDynObjFileFormat;
@@ -204,7 +670,7 @@
return m_pExecFileFormat;
}
-ELFExecFileFormat* GNULDBackend::getExecFileFormat() const
+const ELFExecFileFormat* GNULDBackend::getExecFileFormat() const
{
assert(0 != m_pExecFileFormat);
return m_pExecFileFormat;
@@ -241,20 +707,7 @@
strtab += str_size;
}
- ELFFileFormat* file_format = NULL;
- switch(pOutput.type()) {
- // compute size of .dynstr and .hash
- case Output::DynObj:
- file_format = getDynObjFileFormat();
- break;
- case Output::Exec:
- file_format = getExecFileFormat();
- break;
- case Output::Object:
- default:
- // TODO: not support yet
- return;
- }
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
switch(pOutput.type()) {
// compute size of .dynstr and .hash
@@ -335,23 +788,14 @@
bool sym_exist = false;
HashTableType::entry_type* entry = 0;
- ELFFileFormat* file_format = NULL;
- switch(pOutput.type()) {
- // compute size of .dynstr and .hash
- case Output::DynObj:
- file_format = getDynObjFileFormat();
- break;
- case Output::Exec:
- file_format = getExecFileFormat();
- break;
- case Output::Object:
- default:
- // add first symbol into m_pSymIndexMap
- entry = m_pSymIndexMap->insert(NULL, sym_exist);
- entry->setValue(0);
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+ if (pOutput.type() == Output::Object) {
+ // add first symbol into m_pSymIndexMap
+ entry = m_pSymIndexMap->insert(NULL, sym_exist);
+ entry->setValue(0);
- // TODO: not support yet
- return;
+ // TODO: not support yet
+ return;
}
LDSection& symtab_sect = file_format->getSymTab();
@@ -446,25 +890,11 @@
const MCLDInfo& pLDInfo)
{
assert(pOutput.hasMemArea());
- ELFFileFormat* file_format = NULL;
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
bool sym_exist = false;
HashTableType::entry_type* entry = 0;
- switch(pOutput.type()) {
- // compute size of .dynstr and .hash
- case Output::DynObj:
- file_format = getDynObjFileFormat();
- break;
- case Output::Exec:
- file_format = getExecFileFormat();
- break;
- case Output::Object:
- default:
- // TODO: not support yet
- return;
- }
-
LDSection& symtab_sect = file_format->getDynSymTab();
LDSection& strtab_sect = file_format->getDynStrTab();
LDSection& hash_sect = file_format->getHashTab();
@@ -587,7 +1017,8 @@
// emit soname
// initialize value of ELF .dynamic section
- dynamic().applySoname(strtabsize);
+ if (Output::DynObj == pOutput.type())
+ dynamic().applySoname(strtabsize);
dynamic().applyEntries(pLDInfo, *file_format);
dynamic().emit(dyn_sect, *dyn_region);
@@ -633,9 +1064,44 @@
}
}
+/// sizeInterp - compute the size of the .interp section
+void GNULDBackend::sizeInterp(const Output& pOutput, const MCLDInfo& pLDInfo)
+{
+ assert(pOutput.type() == Output::Exec);
+
+ const char* dyld_name;
+ if (pLDInfo.options().hasDyld())
+ dyld_name = pLDInfo.options().dyld().c_str();
+ else
+ dyld_name = dyld();
+
+ LDSection& interp = getExecFileFormat()->getInterp();
+ interp.setSize(std::strlen(dyld_name) + 1);
+}
+
+/// emitInterp - emit the .interp
+void GNULDBackend::emitInterp(Output& pOutput, const MCLDInfo& pLDInfo)
+{
+ assert(pOutput.type() == Output::Exec &&
+ getExecFileFormat()->hasInterp() &&
+ pOutput.hasMemArea());
+
+ const LDSection& interp = getExecFileFormat()->getInterp();
+ MemoryRegion *region = pOutput.memArea()->request(
+ interp.offset(), interp.size());
+ const char* dyld_name;
+ if (pLDInfo.options().hasDyld())
+ dyld_name = pLDInfo.options().dyld().c_str();
+ else
+ dyld_name = dyld();
+
+ std::memcpy(region->start(), dyld_name, interp.size());
+}
+
/// getSectionOrder
unsigned int GNULDBackend::getSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const
{
// NULL section should be the "1st" section
if (LDFileFormat::Null == pSectHdr.kind())
@@ -647,19 +1113,7 @@
bool is_write = (pSectHdr.flag() & llvm::ELF::SHF_WRITE) != 0;
bool is_exec = (pSectHdr.flag() & llvm::ELF::SHF_EXECINSTR) != 0;
- ELFFileFormat* file_format = NULL;
- switch (pOutput.type()) {
- case Output::DynObj:
- file_format = getDynObjFileFormat();
- break;
- case Output::Exec:
- file_format = getExecFileFormat();
- break;
- case Output::Object:
- default:
- assert(0 && "Not support yet.\n");
- break;
- }
+ const ELFFileFormat* file_format = getOutputFormat(pOutput);
// TODO: need to take care other possible output sections
switch (pSectHdr.kind()) {
@@ -673,13 +1127,18 @@
} else if (!is_write) {
return SHO_RO;
} else {
- if (pSectHdr.type() == llvm::ELF::SHT_PREINIT_ARRAY ||
- pSectHdr.type() == llvm::ELF::SHT_INIT_ARRAY ||
- pSectHdr.type() == llvm::ELF::SHT_FINI_ARRAY ||
- &pSectHdr == &file_format->getCtors() ||
- &pSectHdr == &file_format->getDtors())
- return SHO_RELRO;
-
+ if (pInfo.options().hasRelro()) {
+ if (pSectHdr.type() == llvm::ELF::SHT_PREINIT_ARRAY ||
+ pSectHdr.type() == llvm::ELF::SHT_INIT_ARRAY ||
+ pSectHdr.type() == llvm::ELF::SHT_FINI_ARRAY ||
+ &pSectHdr == &file_format->getCtors() ||
+ &pSectHdr == &file_format->getDtors() ||
+ &pSectHdr == &file_format->getJCR() ||
+ 0 == pSectHdr.name().compare(".data.rel.ro"))
+ return SHO_RELRO;
+ if (0 == pSectHdr.name().compare(".data.rel.ro.local"))
+ return SHO_RELRO_LOCAL;
+ }
return SHO_DATA;
}
@@ -699,14 +1158,16 @@
// get the order from target for target specific sections
case LDFileFormat::Target:
- return getTargetSectionOrder(pOutput, pSectHdr);
+ return getTargetSectionOrder(pOutput, pSectHdr, pInfo);
// handle .interp
case LDFileFormat::Note:
return SHO_INTERP;
- case LDFileFormat::Exception:
- return SHO_EHFRAME;
+ case LDFileFormat::EhFrame:
+ case LDFileFormat::EhFrameHdr:
+ case LDFileFormat::GCCExceptTable:
+ return SHO_EXCEPTION;
case LDFileFormat::MetaData:
case LDFileFormat::Debug:
@@ -745,7 +1206,12 @@
pSymbol.visibility() == llvm::ELF::STV_HIDDEN)
bind = llvm::ELF::STB_LOCAL;
- return (pSymbol.resolveInfo()->type() | (bind << 4));
+ uint32_t type = pSymbol.resolveInfo()->type();
+ // if the IndirectFunc symbol (i.e., STT_GNU_IFUNC) is from dynobj, change
+ // its type to Function
+ if (type == ResolveInfo::IndirectFunc && pSymbol.isDyn())
+ type = ResolveInfo::Function;
+ return (type | (bind << 4));
}
/// getSymbolValue - this function is called after layout()
@@ -776,7 +1242,7 @@
}
}
- assert(pSymbol.hasFragRef());
+ assert(pSymbol.hasFragRef() && "symbols must have fragment reference to get its index");
return pLayout.getOutputLDSection(*pSymbol.fragRef()->frag())->index();
}
@@ -787,38 +1253,154 @@
return entry.getEntry()->value();
}
-/// emitProgramHdrs - emit ELF program headers
-void GNULDBackend::emitProgramHdrs(Output& pOutput)
+/// allocateCommonSymbols - allocate common symbols in the corresponding
+/// sections.
+/// @refer Google gold linker: common.cc: 214
+bool
+GNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const
{
- assert(NULL != pOutput.context());
- createProgramHdrs(*pOutput.context());
+ SymbolCategory& symbol_list = pLinker.getOutputSymbols();
- if (32 == bitclass())
- writeELF32ProgramHdrs(pOutput);
- else
- writeELF64ProgramHdrs(pOutput);
+ if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
+ return true;
+
+ SymbolCategory::iterator com_sym, com_end;
+
+ // FIXME: If the order of common symbols is defined, then sort common symbols
+ // std::sort(com_sym, com_end, some kind of order);
+
+ // get or create corresponding BSS LDSection
+ LDSection* bss_sect = &pLinker.getOrCreateOutputSectHdr(".bss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+
+ LDSection* tbss_sect = &pLinker.getOrCreateOutputSectHdr(
+ ".tbss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+
+ assert(NULL != bss_sect && NULL !=tbss_sect);
+
+ // get or create corresponding BSS MCSectionData
+ llvm::MCSectionData& bss_sect_data = pLinker.getOrCreateSectData(*bss_sect);
+ llvm::MCSectionData& tbss_sect_data = pLinker.getOrCreateSectData(*tbss_sect);
+
+ // remember original BSS size
+ uint64_t bss_offset = bss_sect->size();
+ uint64_t tbss_offset = tbss_sect->size();
+
+ // allocate all local common symbols
+ com_end = symbol_list.localEnd();
+
+ for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+ if (ResolveInfo::Common == (*com_sym)->desc()) {
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+
+ if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
+ // allocate TLS common symbol in tbss section
+ tbss_offset += pLinker.getLayout().appendFragment(*frag,
+ tbss_sect_data,
+ (*com_sym)->value());
+ }
+ else {
+ bss_offset += pLinker.getLayout().appendFragment(*frag,
+ bss_sect_data,
+ (*com_sym)->value());
+ }
+ }
+ }
+
+ // allocate all global common symbols
+ com_end = symbol_list.commonEnd();
+ for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+
+ if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
+ // allocate TLS common symbol in tbss section
+ tbss_offset += pLinker.getLayout().appendFragment(*frag,
+ tbss_sect_data,
+ (*com_sym)->value());
+ }
+ else {
+ bss_offset += pLinker.getLayout().appendFragment(*frag,
+ bss_sect_data,
+ (*com_sym)->value());
+ }
+ }
+
+ bss_sect->setSize(bss_offset);
+ tbss_sect->setSize(tbss_offset);
+ symbol_list.changeCommonsToGlobal();
+ return true;
}
+
/// createProgramHdrs - base on output sections to create the program headers
-void GNULDBackend::createProgramHdrs(LDContext& pContext)
+void GNULDBackend::createProgramHdrs(Output& pOutput, const MCLDInfo& pInfo)
{
+ assert(pOutput.hasContext());
+ ELFFileFormat *file_format = getOutputFormat(pOutput);
+
// make PT_PHDR
m_ELFSegmentTable.produce(llvm::ELF::PT_PHDR);
// make PT_INTERP
- LDSection* interp = pContext.getSection(".interp");
- if (NULL != interp) {
+ if (file_format->hasInterp()) {
ELFSegment* interp_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_INTERP);
- interp_seg->addSection(interp);
- interp_seg->setAlign(bitclass() / 8);
+ interp_seg->addSection(&file_format->getInterp());
+ }
+
+ if (pInfo.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
+ LDContext::SectionTable& sect_table = pOutput.context()->getSectionTable();
+ size_t idx = 0;
+ while (idx < pOutput.context()->numOfSections()) {
+ // find the first non-relro section, and align its offset to a page
+ // boundary
+ if (getSectionOrder(pOutput, *sect_table[idx], pInfo) > SHO_RELRO_LAST) {
+ uint64_t offset = sect_table[idx]->offset();
+ alignAddress(offset, commonPageSize(pInfo));
+ sect_table[idx]->setOffset(offset);
+ ++idx;
+ break;
+ }
+ ++idx;
+ }
+ while (idx < pOutput.context()->numOfSections()) {
+ // adjust the remaining sections' offset
+ uint64_t offset = sect_table[idx - 1]->offset();
+ if (LDFileFormat::BSS != sect_table[idx - 1]->kind())
+ offset += sect_table[idx - 1]->size();
+ alignAddress(offset, sect_table[idx]->align());
+ sect_table[idx]->setOffset(offset);
+ ++idx;
+ }
}
uint32_t cur_seg_flag, prev_seg_flag = getSegmentFlag(0);
uint64_t padding = 0;
ELFSegment* load_seg = NULL;
// make possible PT_LOAD segments
- LDContext::sect_iterator sect, sect_end = pContext.sectEnd();
- for (sect = pContext.sectBegin(); sect != sect_end; ++sect) {
+ LDContext::sect_iterator sect, sect_end = pOutput.context()->sectEnd();
+ for (sect = pOutput.context()->sectBegin(); sect != sect_end; ++sect) {
+
if (0 == ((*sect)->flag() & llvm::ELF::SHF_ALLOC) &&
LDFileFormat::Null != (*sect)->kind())
continue;
@@ -829,36 +1411,60 @@
LDFileFormat::Null == (*sect)->kind()) {
// create new PT_LOAD segment
load_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_LOAD);
- load_seg->setAlign(pagesize());
+ load_seg->setAlign(commonPageSize(pInfo));
// check if this segment needs padding
padding = 0;
- if (((*sect)->offset() & (load_seg->align() - 1)) != 0)
- padding = load_seg->align();
+ if (((*sect)->offset() & (abiPageSize(pInfo) - 1)) != 0)
+ padding = abiPageSize(pInfo);
}
assert(NULL != load_seg);
- load_seg->addSection(*sect);
- load_seg->updateFlag(cur_seg_flag);
+ load_seg->addSection((*sect));
+ if (cur_seg_flag != prev_seg_flag)
+ load_seg->updateFlag(cur_seg_flag);
- // FIXME: set section's vma
- // need to handle start vma for user-defined one or for executable.
- (*sect)->setAddr((*sect)->offset() + padding);
+ if (LDFileFormat::Null != (*sect)->kind())
+ (*sect)->setAddr(segmentStartAddr(pOutput, pInfo) +
+ (*sect)->offset() +
+ padding);
prev_seg_flag = cur_seg_flag;
}
// make PT_DYNAMIC
- LDSection* dynamic = pContext.getSection(".dynamic");
- if (NULL != dynamic) {
- ELFSegment* dyn_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_DYNAMIC);
- dyn_seg->setFlag(llvm::ELF::PF_R | llvm::ELF::PF_W);
- dyn_seg->addSection(dynamic);
- dyn_seg->setAlign(bitclass() / 8);
+ if (file_format->hasDynamic()) {
+ ELFSegment* dyn_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_DYNAMIC,
+ llvm::ELF::PF_R |
+ llvm::ELF::PF_W);
+ dyn_seg->addSection(&file_format->getDynamic());
}
+ if (pInfo.options().hasRelro()) {
+ // make PT_GNU_RELRO
+ ELFSegment* relro_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_GNU_RELRO);
+ for (LDContext::sect_iterator sect = pOutput.context()->sectBegin();
+ sect != pOutput.context()->sectEnd(); ++sect) {
+ unsigned int order = getSectionOrder(pOutput, **sect, pInfo);
+ if (SHO_RELRO_LOCAL == order ||
+ SHO_RELRO == order ||
+ SHO_RELRO_LAST == order) {
+ relro_seg->addSection(*sect);
+ }
+ }
+ }
+
+ // 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());
+ }
+}
+
+/// setupProgramHdrs - set up the attributes of segments
+void GNULDBackend:: setupProgramHdrs(const Output& pOutput, const MCLDInfo& pInfo)
+{
// update segment info
- uint64_t file_size = 0;
ELFSegmentFactory::iterator seg, seg_end = m_ELFSegmentTable.end();
for (seg = m_ELFSegmentTable.begin(); seg != seg_end; ++seg) {
ELFSegment& segment = *seg;
@@ -875,7 +1481,7 @@
phdr_size = sizeof(llvm::ELF::Elf64_Phdr);
}
segment.setOffset(offset);
- segment.setVaddr(offset);
+ segment.setVaddr(segmentStartAddr(pOutput, pInfo) + offset);
segment.setPaddr(segment.vaddr());
segment.setFilesz(numOfSegments() * phdr_size);
segment.setMemsz(numOfSegments() * phdr_size);
@@ -883,14 +1489,21 @@
continue;
}
- assert(NULL != segment.getFirstSection());
+ // bypass if there is no section in this segment (e.g., PT_GNU_STACK)
+ if (segment.numOfSections() == 0)
+ continue;
+
segment.setOffset(segment.getFirstSection()->offset());
- segment.setVaddr(segment.getFirstSection()->addr());
+ if (llvm::ELF::PT_LOAD == segment.type() &&
+ LDFileFormat::Null == segment.getFirstSection()->kind())
+ segment.setVaddr(segmentStartAddr(pOutput, pInfo));
+ else
+ segment.setVaddr(segment.getFirstSection()->addr());
segment.setPaddr(segment.vaddr());
const LDSection* last_sect = segment.getLastSection();
assert(NULL != last_sect);
- file_size = last_sect->offset() - segment.offset();
+ uint64_t file_size = last_sect->offset() - segment.offset();
if (LDFileFormat::BSS != last_sect->kind())
file_size += last_sect->size();
segment.setFilesz(file_size);
@@ -899,61 +1512,58 @@
}
}
-/// writeELF32ProgramHdrs - write out the ELF32 program headers
-void GNULDBackend::writeELF32ProgramHdrs(Output& pOutput)
+/// createGNUStackInfo - create an output GNU stack section or segment if needed
+/// @ref gold linker: layout.cc:2608
+void GNULDBackend::createGNUStackInfo(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
{
- assert(pOutput.hasMemArea());
+ uint32_t flag = 0x0;
+ if (pInfo.options().hasStackSet()) {
+ // 1. check the command line option (-z execstack or -z noexecstack)
+ if (pInfo.options().hasExecStack())
+ flag = llvm::ELF::SHF_EXECINSTR;
+ } else {
+ // 2. check the stack info from the input objects
+ size_t object_count = 0, stack_note_count = 0;
+ mcld::InputTree::const_bfs_iterator input, inEnd = pInfo.inputs().bfs_end();
+ for (input=pInfo.inputs().bfs_begin(); input!=inEnd; ++input) {
+ if ((*input)->type() == Input::Object) {
+ ++object_count;
+ const LDSection* sect = (*input)->context()->getSection(
+ ".note.GNU-stack");
+ if (NULL != sect) {
+ ++stack_note_count;
+ // 2.1 found a stack note that is set as executable
+ if (0 != (llvm::ELF::SHF_EXECINSTR & sect->flag())) {
+ flag = llvm::ELF::SHF_EXECINSTR;
+ break;
+ }
+ }
+ }
+ }
- uint64_t start_offset, phdr_size;
+ // 2.2 there are no stack note sections in all input objects
+ if (0 == stack_note_count)
+ return;
- start_offset = sizeof(llvm::ELF::Elf32_Ehdr);
- phdr_size = sizeof(llvm::ELF::Elf32_Phdr);
- // Program header must start directly after ELF header
- MemoryRegion *region = pOutput.memArea()->request(start_offset,
- numOfSegments()*phdr_size);
-
- llvm::ELF::Elf32_Phdr* phdr = (llvm::ELF::Elf32_Phdr*)region->start();
-
- size_t index = 0;
- ELFSegmentFactory::iterator seg, segEnd = m_ELFSegmentTable.end();
- for (seg = m_ELFSegmentTable.begin(); 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();
+ // 2.3 a special case. Use the target default to decide if the stack should
+ // be executable
+ if (llvm::ELF::SHF_EXECINSTR != flag && object_count != stack_note_count)
+ if (isDefaultExecStack())
+ flag = llvm::ELF::SHF_EXECINSTR;
}
-}
-/// writeELF64ProgramHdrs - write out the ELF64 program headers
-void GNULDBackend::writeELF64ProgramHdrs(Output& pOutput)
-{
- assert(pOutput.hasMemArea());
-
- uint64_t start_offset, phdr_size;
-
- start_offset = sizeof(llvm::ELF::Elf64_Ehdr);
- phdr_size = sizeof(llvm::ELF::Elf64_Phdr);
- // Program header must start directly after ELF header
- MemoryRegion *region = pOutput.memArea()->request(start_offset,
- numOfSegments() *phdr_size);
- llvm::ELF::Elf64_Phdr* phdr = (llvm::ELF::Elf64_Phdr*)region->start();
-
- size_t index = 0;
- ELFSegmentFactory::iterator seg, segEnd = m_ELFSegmentTable.end();
- for (seg = m_ELFSegmentTable.begin(); 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();
- }
+ if (pOutput.type() != Output::Object)
+ m_ELFSegmentTable.produce(llvm::ELF::PT_GNU_STACK,
+ llvm::ELF::PF_R |
+ llvm::ELF::PF_W |
+ getSegmentFlag(flag));
+ else
+ pLinker.getOrCreateOutputSectHdr(".note.GNU-stack",
+ LDFileFormat::Note,
+ llvm::ELF::SHT_PROGBITS,
+ flag);
}
/// preLayout - Backend can do any needed modification before layout
@@ -963,6 +1573,16 @@
{
// prelayout target first
doPreLayout(pOutput, pLDInfo, pLinker);
+
+ if (pLDInfo.options().hasEhFrameHdr()) {
+ // init EhFrameHdr and size the output section
+ ELFFileFormat* format = getOutputFormat(pOutput);
+ assert(NULL != getEhFrame());
+ m_pEhFrameHdr = new EhFrameHdr(*getEhFrame(),
+ format->getEhFrame(),
+ format->getEhFrameHdr());
+ m_pEhFrameHdr->sizeOutput();
+ }
}
/// postLayout -Backend can do any needed modification after layout
@@ -970,10 +1590,36 @@
const MCLDInfo& pInfo,
MCLinker& pLinker)
{
- // post layout target first
+ // 1. emit program headers
+ if (pOutput.type() != Output::Object) {
+ // 1.1 create program headers
+ createProgramHdrs(pLinker.getLDInfo().output(), pInfo);
+ }
+
+ // 1.2 create special GNU Stack note section or segment
+ createGNUStackInfo(pOutput, pInfo, pLinker);
+
+ if (pOutput.type() != Output::Object) {
+ // 1.3 set up the attributes of program headers
+ setupProgramHdrs(pOutput, pInfo);
+ }
+
+ // 2. target specific post layout
doPostLayout(pOutput, pInfo, pLinker);
}
+void GNULDBackend::postProcessing(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ if (pInfo.options().hasEhFrameHdr()) {
+ // emit eh_frame_hdr
+ if (bitclass() == 32)
+ m_pEhFrameHdr->emitOutput<32>(pLinker.getLDInfo().output(),
+ pLinker);
+ }
+}
+
/// getHashBucketCount - calculate hash bucket count.
/// @ref Google gold linker, dynobj.cc:791
unsigned GNULDBackend::getHashBucketCount(unsigned pNumOfSymbols,
@@ -1012,10 +1658,147 @@
// If we are building shared object, and the visibility is external, we
// need to add it.
- if (Output::DynObj == pOutput.type())
+ if (Output::DynObj == pOutput.type() || Output::Exec == pOutput.type())
if (pSymbol.resolveInfo()->visibility() == ResolveInfo::Default ||
pSymbol.resolveInfo()->visibility() == ResolveInfo::Protected)
return true;
+ return false;
+}
+
+/// commonPageSize - the common page size of the target machine.
+/// @ref gold linker: target.h:135
+uint64_t GNULDBackend::commonPageSize(const MCLDInfo& pInfo) const
+{
+ if (pInfo.options().commPageSize() > 0)
+ return std::min(pInfo.options().commPageSize(), abiPageSize(pInfo));
+ else
+ return std::min(static_cast<uint64_t>(0x1000), abiPageSize(pInfo));
+}
+
+/// abiPageSize - the abi page size of the target machine.
+/// @ref gold linker: target.h:125
+uint64_t GNULDBackend::abiPageSize(const MCLDInfo& pInfo) const
+{
+ if (pInfo.options().maxPageSize() > 0)
+ return pInfo.options().maxPageSize();
+ else
+ return static_cast<uint64_t>(0x1000);
+}
+
+/// isOutputPIC - return whether the output is position-independent
+bool GNULDBackend::isOutputPIC(const Output& pOutput,
+ const MCLDInfo& pInfo) const
+{
+ if (Output::DynObj == pOutput.type() || pInfo.options().isPIE())
+ return true;
+ return false;
+}
+
+/// isStaticLink - return whether we're doing static link
+bool GNULDBackend::isStaticLink(const Output& pOutput,
+ const MCLDInfo& pInfo) const
+{
+ InputTree::const_iterator it = pInfo.inputs().begin();
+ if (!isOutputPIC(pOutput, pInfo) && (*it)->attribute()->isStatic())
+ return true;
+ return false;
+}
+
+/// isSymbolPreemtible - whether the symbol can be preemted by other
+/// link unit
+/// @ref Google gold linker, symtab.h:551
+bool GNULDBackend::isSymbolPreemptible(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ if (pSym.other() != ResolveInfo::Default)
+ return false;
+
+ if (Output::DynObj != pOutput.type())
+ return false;
+
+ if (pLDInfo.options().Bsymbolic())
+ return false;
+
+ return true;
+}
+
+/// symbolNeedsPLT - return whether the symbol needs a PLT entry
+/// @ref Google gold linker, symtab.h:596
+bool GNULDBackend::symbolNeedsPLT(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ if (pSym.isUndef() && !pSym.isDyn() && pOutput.type() != Output::DynObj)
+ return false;
+
+ // An IndirectFunc symbol (i.e., STT_GNU_IFUNC) always needs a plt entry
+ if (pSym.type() == ResolveInfo::IndirectFunc)
+ return true;
+
+ if (pSym.type() != ResolveInfo::Function)
+ return false;
+
+ if (isStaticLink(pOutput, pLDInfo) || pLDInfo.options().isPIE())
+ return false;
+
+ return (pSym.isDyn() ||
+ pSym.isUndef() ||
+ isSymbolPreemptible(pSym, pLDInfo, pOutput));
+}
+
+/// symbolNeedsDynRel - return whether the symbol needs a dynamic relocation
+/// @ref Google gold linker, symtab.h:645
+bool GNULDBackend::symbolNeedsDynRel(const ResolveInfo& pSym,
+ bool pSymHasPLT,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput,
+ bool isAbsReloc) const
+{
+ // an undefined reference in the executables should be statically
+ // resolved to 0 and no need a dynamic relocation
+ if (pSym.isUndef() && !pSym.isDyn() && (Output::Exec == pOutput.type()))
+ return false;
+ if (pSym.isAbsolute())
+ return false;
+ if (isOutputPIC(pOutput, pLDInfo) && isAbsReloc)
+ return true;
+ if (pSymHasPLT && ResolveInfo::Function == pSym.type())
+ return false;
+ if (!isOutputPIC(pOutput, pLDInfo) && pSymHasPLT)
+ return false;
+ if (pSym.isDyn() || pSym.isUndef() ||
+ isSymbolPreemptible(pSym, pLDInfo, pOutput))
+ return true;
return false;
}
+
+/// symbolNeedsCopyReloc - return whether the symbol needs a copy relocation
+bool GNULDBackend::symbolNeedsCopyReloc(const Layout& pLayout,
+ const Relocation& pReloc,
+ const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ // only the reference from dynamic executable to non-function symbol in
+ // the dynamic objects may need copy relocation
+ if (isOutputPIC(pOutput, pLDInfo) ||
+ !pSym.isDyn() ||
+ pSym.type() == ResolveInfo::Function ||
+ pSym.size() == 0)
+ return false;
+
+ // check if the option -z nocopyreloc is given
+ if (pLDInfo.options().hasNoCopyReloc())
+ return false;
+
+ // TODO: Is this check necessary?
+ // if relocation target place is readonly, a copy relocation is needed
+ if ((pLayout.getOutputLDSection(*pReloc.targetRef().frag())->flag() &
+ llvm::ELF::SHF_WRITE) == 0)
+ return true;
+
+ return false;
+}
+
diff --git a/lib/Target/Mips/MipsAndroidSectLinker.cpp b/lib/Target/Mips/MipsAndroidSectLinker.cpp
deleted file mode 100644
index e697fbc..0000000
--- a/lib/Target/Mips/MipsAndroidSectLinker.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-//===- MipsAndroidSectLinker.cpp ------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MipsAndroidSectLinker.h"
-
-#include <mcld/CodeGen/SectLinkerOption.h>
-
-using namespace mcld;
-
-MipsAndroidSectLinker::MipsAndroidSectLinker(SectLinkerOption &pOption,
- TargetLDBackend &pLDBackend)
- : AndroidSectLinker(pOption,
- pLDBackend) {
- MCLDInfo &info = pOption.info();
- // set up target-dependent constraints of attibutes
- info.attrFactory().constraint().disableWholeArchive();
- info.attrFactory().constraint().disableAsNeeded();
- info.attrFactory().constraint().setSharedSystem();
-
- // set up the predefined attributes
- info.attrFactory().predefined().unsetWholeArchive();
- info.attrFactory().predefined().setDynamic();
-}
-
-MipsAndroidSectLinker::~MipsAndroidSectLinker()
-{
-}
diff --git a/lib/Target/Mips/MipsAndroidSectLinker.h b/lib/Target/Mips/MipsAndroidSectLinker.h
deleted file mode 100644
index ba216e4..0000000
--- a/lib/Target/Mips/MipsAndroidSectLinker.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//===- MipsAndroidSectLinker.h --------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MIPS_ANDROIDSECTLINKER_H
-#define MIPS_ANDROIDSECTLINKER_H
-
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-
-#include "mcld/Target/AndroidSectLinker.h"
-
-namespace mcld
-{
-
-/** \class MipsAndroidSectLinker
- * \brief MipsAndroidSectLinker sets up the environment for linking.
- *
- */
-class MipsAndroidSectLinker : public AndroidSectLinker
-{
-public:
- MipsAndroidSectLinker(SectLinkerOption &pOption,
- mcld::TargetLDBackend &pLDBackend);
-
- ~MipsAndroidSectLinker();
-};
-
-} // namespace of mcld
-
-#endif
diff --git a/lib/Target/Mips/MipsDiagnostic.cpp b/lib/Target/Mips/MipsDiagnostic.cpp
new file mode 100644
index 0000000..c90c6ef
--- /dev/null
+++ b/lib/Target/Mips/MipsDiagnostic.cpp
@@ -0,0 +1,35 @@
+//===- MipsDiagnostic.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// 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 mcld {
+//===----------------------------------------------------------------------===//
+// createMipsDiagnostic - the help function to create corresponding
+// MipsDiagnostic
+DiagnosticLineInfo* createMipsDiagLineInfo(const llvm::Target& pTarget,
+ const std::string &pTriple)
+{
+ return new DWARFLineInfo();
+}
+
+} // namespace of mcld
+
+//==========================
+// InitializeMipsDiagnostic
+extern "C" void LLVMInitializeMipsDiagnosticLineInfo() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheMipselTarget, createMipsDiagLineInfo);
+}
+
diff --git a/lib/Target/Mips/MipsELFSectLinker.cpp b/lib/Target/Mips/MipsELFSectLinker.cpp
index aa41f36..dedf505 100644
--- a/lib/Target/Mips/MipsELFSectLinker.cpp
+++ b/lib/Target/Mips/MipsELFSectLinker.cpp
@@ -6,7 +6,6 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-
#include "MipsELFSectLinker.h"
#include <mcld/CodeGen/SectLinkerOption.h>
@@ -31,3 +30,4 @@
MipsELFSectLinker::~MipsELFSectLinker()
{
}
+
diff --git a/lib/Target/Mips/MipsELFSectLinker.h b/lib/Target/Mips/MipsELFSectLinker.h
index 949508d..1aacfef 100644
--- a/lib/Target/Mips/MipsELFSectLinker.h
+++ b/lib/Target/Mips/MipsELFSectLinker.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MIPS_ELFSECTLINKER_H
-#define MIPS_ELFSECTLINKER_H
+#ifndef MIPS_ELF_SECTION_LINKER_H
+#define MIPS_ELF_SECTION_LINKER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -31,3 +31,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/Mips/MipsGOT.cpp b/lib/Target/Mips/MipsGOT.cpp
index e1185ca..9baa033 100644
--- a/lib/Target/Mips/MipsGOT.cpp
+++ b/lib/Target/Mips/MipsGOT.cpp
@@ -7,9 +7,9 @@
//
//===----------------------------------------------------------------------===//
-#include <llvm/Support/ErrorHandling.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
#include "MipsGOT.h"
namespace {
@@ -31,7 +31,7 @@
new (std::nothrow) GOTEntry(0, MipsGOTEntrySize, &m_SectionData);
if (NULL == entry)
- llvm::report_fatal_error("Allocating GOT0 entries failed!");
+ fatal(diag::fail_allocate_memory) << "GOT0";
m_Section.setSize(m_Section.size() + MipsGOTEntrySize);
}
@@ -41,8 +41,7 @@
iterator ie = m_SectionData.end();
for (size_t i = 1; i < MipsGOT0Num; ++i) {
- if (it == ie)
- llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
+ assert((it != ie) && "Generation of GOT0 entries is incomplete!");
++it;
}
@@ -95,7 +94,7 @@
new (std::nothrow) GOTEntry(0, MipsGOTEntrySize, &m_SectionData);
if (NULL == entry)
- llvm::report_fatal_error("Allocating new GOTEntry failed");
+ fatal(diag::fail_allocate_memory) << "GOTEntry";
m_Section.setSize(m_Section.size() + MipsGOTEntrySize);
}
@@ -118,12 +117,22 @@
GOTEntry* MipsGOT::getEntry(const ResolveInfo& pInfo, bool& pExist)
{
+ if (isLocal(&pInfo) && pInfo.type() == ResolveInfo::Section) {
+ pExist = false;
+ iterator& it = m_LocalGOTIterator;
+ ++it;
+ assert(it != m_SectionData.getFragmentList().end() &&
+ "The number of GOT Entries and ResolveInfo doesn't match");
+ GOTEntry* entry = llvm::cast<GOTEntry>(&(*it));
+ return entry;
+ }
+
GOTEntry*& entry = m_GeneralGOTMap[&pInfo];
pExist = NULL != entry;
if (!pExist) {
- iterator& it = pInfo.isLocal() ? m_LocalGOTIterator : m_GlobalGOTIterator;
+ iterator& it = isLocal(&pInfo) ? m_LocalGOTIterator : m_GlobalGOTIterator;
++it;
@@ -145,3 +154,4 @@
{
return m_pLocalNum;
}
+
diff --git a/lib/Target/Mips/MipsGOT.h b/lib/Target/Mips/MipsGOT.h
index dc8a23e..2f04ef4 100644
--- a/lib/Target/Mips/MipsGOT.h
+++ b/lib/Target/Mips/MipsGOT.h
@@ -26,6 +26,7 @@
{
private:
typedef llvm::DenseMap<const ResolveInfo*, GOTEntry*> SymbolIndexMapType;
+ typedef llvm::DenseMap<const ResolveInfo*, bool> SymbolTypeMapType;
public:
typedef llvm::MCSectionData::iterator iterator;
@@ -50,8 +51,26 @@
size_t getTotalNum() const;
size_t getLocalNum() const;
+ 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;
+ }
+
private:
- SymbolIndexMapType m_GeneralGOTMap;
+ SymbolIndexMapType m_GeneralGOTMap; // Map ResolveInfo* to GOTEntry *.
+ SymbolTypeMapType m_GOTTypeMap;
+
iterator m_LocalGOTIterator; // last local GOT entries
iterator m_GlobalGOTIterator; // last global GOT entries
size_t m_pLocalNum;
@@ -64,3 +83,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/Mips/MipsLDBackend.cpp b/lib/Target/Mips/MipsLDBackend.cpp
index c7a6b23..87e43b8 100644
--- a/lib/Target/Mips/MipsLDBackend.cpp
+++ b/lib/Target/Mips/MipsLDBackend.cpp
@@ -14,6 +14,7 @@
#include <mcld/MC/MCLDInfo.h>
#include <mcld/MC/MCLinker.h>
#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/TargetRegistry.h>
#include <mcld/Target/OutputRelocSection.h>
@@ -66,11 +67,24 @@
void MipsGNULDBackend::initTargetSections(MCLinker& pLinker)
{
- // Nothing to do because we do not support
- // any MIPS specific sections now.
+ // Set up .dynamic
+ ELFFileFormat* file_format = NULL;
+ switch(pLinker.getLDInfo().output().type()) {
+ case Output::DynObj:
+ file_format = getDynObjFileFormat();
+ break;
+ case Output::Exec:
+ file_format = getExecFileFormat();
+ break;
+ case Output::Object:
+ default:
+ // TODO: not support yet
+ return;
+ }
+ file_format->getDynamic().setFlag(llvm::ELF::SHF_ALLOC);
}
-void MipsGNULDBackend::initTargetSymbols(MCLinker& pLinker)
+void MipsGNULDBackend::initTargetSymbols(MCLinker& pLinker, const Output& pOutput)
{
// Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
// same name in input
@@ -120,12 +134,21 @@
const LDSymbol& pInputSym,
MCLinker& pLinker,
const MCLDInfo& pLDInfo,
- const Output& pOutput)
+ const Output& pOutput,
+ const LDSection& pSection)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
+ assert(NULL != pSection.getLink());
+ if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC)) {
+ if (rsym->isLocal()) {
+ updateAddend(pReloc, pInputSym, pLinker.getLayout());
+ }
+ return;
+ }
+
// A refernece to symbol _GLOBAL_OFFSET_TABLE_ implies
// that a .got section is needed.
if (NULL == m_pGOT && NULL != m_pGOTSymbol) {
@@ -134,7 +157,15 @@
}
}
- if (rsym->isLocal())
+ // Skip relocation against _gp_disp
+ if (strcmp("_gp_disp", pInputSym.name()) == 0)
+ 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() || !isDynamicSymbol(pInputSym, pOutput) ||
+ !rsym->isDyn()) && !rsym->isUndef())
scanLocalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
else
scanGlobalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
@@ -177,6 +208,11 @@
return 32;
}
+uint64_t MipsGNULDBackend::defaultTextSegmentAddr() const
+{
+ return 0x80000;
+}
+
void MipsGNULDBackend::doPreLayout(const Output& pOutput,
const MCLDInfo& pInfo,
MCLinker& pLinker)
@@ -191,9 +227,6 @@
const MCLDInfo& pInfo,
MCLinker& pLinker)
{
- // emit program headers
- if (pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec)
- emitProgramHdrs(pLinker.getLDInfo().output());
}
/// dynamic - the dynamic section of the target machine.
@@ -217,11 +250,12 @@
uint64_t MipsGNULDBackend::emitSectionData(const Output& pOutput,
const LDSection& pSection,
const MCLDInfo& pInfo,
+ const Layout& pLayout,
MemoryRegion& pRegion) const
{
assert(pRegion.size() && "Size of MemoryRegion is zero!");
- ELFFileFormat* file_format = getOutputFormat(pOutput);
+ const ELFFileFormat* file_format = getOutputFormat(pOutput);
if (&pSection == &(file_format->getGOT())) {
assert(NULL != m_pGOT && "emitSectionData failed, m_pGOT is NULL!");
@@ -229,17 +263,15 @@
return result;
}
- llvm::report_fatal_error(llvm::Twine("Unable to emit section `") +
- pSection.name() +
- llvm::Twine("'.\n"));
+ fatal(diag::unrecognized_output_sectoin)
+ << pSection.name()
+ << "mclinker@googlegroups.com";
return 0;
}
-/// isGOTSymbol - return true if the symbol is the GOT entry.
-bool MipsGNULDBackend::isGOTSymbol(const LDSymbol& pSymbol) const
+/// isGlobalGOTSymbol - return true if the symbol is the global GOT entry.
+bool MipsGNULDBackend::isGlobalGOTSymbol(const LDSymbol& pSymbol) const
{
- return std::find(m_LocalGOTSyms.begin(),
- m_LocalGOTSyms.end(), &pSymbol) != m_LocalGOTSyms.end() ||
- std::find(m_GlobalGOTSyms.begin(),
+ return std::find(m_GlobalGOTSyms.begin(),
m_GlobalGOTSyms.end(), &pSymbol) != m_GlobalGOTSyms.end();
}
@@ -326,7 +358,7 @@
if (!isDynamicSymbol(**symbol, pOutput))
continue;
- if (isGOTSymbol(**symbol))
+ if (isGlobalGOTSymbol(**symbol))
continue;
emitDynamicSymbol(symtab32[symtabIdx], pOutput, **symbol, pLayout, strtab,
@@ -342,6 +374,12 @@
symbol_end = m_GlobalGOTSyms.end();
symbol != symbol_end; ++symbol) {
+ // Make sure this golbal GOT entry is a dynamic symbol.
+ // If not, something is wrong earlier when putting this symbol into
+ // global GOT.
+ if (!isDynamicSymbol(**symbol, pOutput))
+ fatal(diag::mips_got_symbol) << (*symbol)->name();
+
emitDynamicSymbol(symtab32[symtabIdx], pOutput, **symbol, pLayout, strtab,
strtabsize, symtabIdx);
@@ -382,7 +420,8 @@
// emit soname
// initialize value of ELF .dynamic section
- dynamic().applySoname(strtabsize);
+ if (Output::DynObj == pOutput.type())
+ dynamic().applySoname(strtabsize);
dynamic().applyEntries(pLDInfo, *file_format);
dynamic().emit(dyn_sect, *dyn_region);
@@ -445,9 +484,10 @@
unsigned int
MipsGNULDBackend::getTargetSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const
{
- ELFFileFormat* file_format = getOutputFormat(pOutput);
+ const ELFFileFormat* file_format = getOutputFormat(pOutput);
if (&pSectHdr == &file_format->getGOT())
return SHO_DATA;
@@ -456,15 +496,10 @@
}
/// finalizeSymbol - finalize the symbol value
-/// If the symbol's reserved field is not zero, MCLinker will call back this
-/// function to ask the final value of the symbol
-bool MipsGNULDBackend::finalizeSymbol(LDSymbol& pSymbol) const
+bool MipsGNULDBackend::finalizeTargetSymbols(MCLinker& pLinker, const Output& pOutput)
{
- if (&pSymbol == m_pGpDispSymbol) {
- m_pGpDispSymbol->setValue(m_pGOT->getSection().addr() + 0x7FF0);
- return true;
- }
- return false;
+ m_pGpDispSymbol->setValue(m_pGOT->getSection().addr() + 0x7FF0);
+ return true;
}
/// allocateCommonSymbols - allocate common symbols in the corresponding
@@ -474,96 +509,112 @@
bool
MipsGNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const
{
- // SymbolCategory contains all symbols that must emit to the output files.
- // We are not like Google gold linker, we don't remember symbols before symbol
- // resolution. All symbols in SymbolCategory are already resolved. Therefore, we
- // don't need to care about some symbols may be changed its category due to symbol
- // resolution.
SymbolCategory& symbol_list = pLinker.getOutputSymbols();
if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
return true;
- // addralign := max value of all common symbols
- uint64_t addralign = 0x0;
-
- // Due to the visibility, some common symbols may be forcefully local.
- SymbolCategory::iterator com_sym, com_end = symbol_list.localEnd();
- for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
- if (ResolveInfo::Common == (*com_sym)->desc()) {
- if ((*com_sym)->value() > addralign)
- addralign = (*com_sym)->value();
- }
- }
-
- // global common symbols.
- com_end = symbol_list.commonEnd();
- for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
- if ((*com_sym)->value() > addralign)
- addralign = (*com_sym)->value();
- }
+ SymbolCategory::iterator com_sym, com_end;
// FIXME: If the order of common symbols is defined, then sort common symbols
- // com_sym = symbol_list.commonBegin();
// std::sort(com_sym, com_end, some kind of order);
// get or create corresponding BSS LDSection
- LDSection* bss_sect_hdr = NULL;
- if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
- bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
+ LDSection* bss_sect = &pLinker.getOrCreateOutputSectHdr(".bss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+
+ LDSection* tbss_sect = &pLinker.getOrCreateOutputSectHdr(
".tbss",
LDFileFormat::BSS,
llvm::ELF::SHT_NOBITS,
llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
- }
- else {
- bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
+
+ // FIXME: .sbss amd .lbss currently unused.
+ /*
+ LDSection* sbss_sect = &pLinker.getOrCreateOutputSectHdr(
+ ".sbss",
LDFileFormat::BSS,
llvm::ELF::SHT_NOBITS,
- llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
- }
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC |
+ llvm::ELF::SHF_MIPS_GPREL);
+
+ LDSection* lbss_sect = &pLinker.getOrCreateOutputSectHdr(
+ ".lbss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC |
+ llvm::ELF::SHF_MIPS_LOCAL);
+ */
+
+ assert(NULL != bss_sect && NULL != tbss_sect);
// get or create corresponding BSS MCSectionData
- assert(NULL != bss_sect_hdr);
- llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(*bss_sect_hdr);
+ llvm::MCSectionData& bss_sect_data = pLinker.getOrCreateSectData(*bss_sect);
+ llvm::MCSectionData& tbss_sect_data = pLinker.getOrCreateSectData(*tbss_sect);
- // allocate all common symbols
- uint64_t offset = bss_sect_hdr->size();
+ // remember original BSS size
+ uint64_t bss_offset = bss_sect->size();
+ uint64_t tbss_offset = tbss_sect->size();
// allocate all local common symbols
com_end = symbol_list.localEnd();
+
for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
if (ResolveInfo::Common == (*com_sym)->desc()) {
- alignAddress(offset, (*com_sym)->value());
// We have to reset the description of the symbol here. When doing
// incremental linking, the output relocatable object may have common
// symbols. Therefore, we can not treat common symbols as normal symbols
// when emitting the regular name pools. We must change the symbols'
// description here.
(*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
- llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size(), &bss_section);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
(*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
- offset += (*com_sym)->size();
+
+ if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
+ // allocate TLS common symbol in tbss section
+ tbss_offset += pLinker.getLayout().appendFragment(*frag,
+ tbss_sect_data,
+ (*com_sym)->value());
+ }
+ // FIXME: how to identify small and large common symbols?
+ else {
+ bss_offset += pLinker.getLayout().appendFragment(*frag,
+ bss_sect_data,
+ (*com_sym)->value());
+ }
}
}
// allocate all global common symbols
com_end = symbol_list.commonEnd();
for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
- alignAddress(offset, (*com_sym)->value());
-
// We have to reset the description of the symbol here. When doing
// incremental linking, the output relocatable object may have common
// symbols. Therefore, we can not treat common symbols as normal symbols
// when emitting the regular name pools. We must change the symbols'
// description here.
(*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
- llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size(), &bss_section);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
(*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
- offset += (*com_sym)->size();
+
+ if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
+ // allocate TLS common symbol in tbss section
+ tbss_offset += pLinker.getLayout().appendFragment(*frag,
+ tbss_sect_data,
+ (*com_sym)->value());
+ }
+ // FIXME: how to identify small and large common symbols?
+ else {
+ bss_offset += pLinker.getLayout().appendFragment(*frag,
+ bss_sect_data,
+ (*com_sym)->value());
+ }
}
- bss_sect_hdr->setSize(offset);
+ bss_sect->setSize(bss_offset);
+ tbss_sect->setSize(tbss_offset);
symbol_list.changeCommonsToGlobal();
return true;
}
@@ -573,7 +624,7 @@
const Layout& pLayout) const
{
// Update value keep in addend if we meet a section symbol
- if(pReloc.symInfo()->type() == ResolveInfo::Section) {
+ if (pReloc.symInfo()->type() == ResolveInfo::Section) {
pReloc.setAddend(pLayout.getOutputOffset(
*pInputSym.fragRef()) + pReloc.addend());
}
@@ -604,6 +655,12 @@
m_pRelDyn->reserveEntry(*m_pRelocFactory);
rsym->setReserved(rsym->reserved() | ReserveRel);
+
+ // Remeber this rsym is a local GOT entry (as if it needs an entry).
+ // Actually we don't allocate an GOT entry.
+ if (NULL == m_pGOT)
+ createGOT(pLinker, pOutput);
+ m_pGOT->setLocal(rsym);
}
break;
case llvm::ELF::R_MIPS_REL32:
@@ -637,10 +694,19 @@
if (NULL == m_pGOT)
createGOT(pLinker, pOutput);
+ // For got16 section based relocations, we need to reserve got entries.
+ if (rsym->type() == ResolveInfo::Section) {
+ m_pGOT->reserveLocalEntry();
+ // Remeber this rsym is a local GOT entry
+ m_pGOT->setLocal(rsym);
+ return;
+ }
+
if (!(rsym->reserved() & MipsGNULDBackend::ReserveGot)) {
m_pGOT->reserveLocalEntry();
rsym->setReserved(rsym->reserved() | ReserveGot);
- m_LocalGOTSyms.push_back(rsym->outSymbol());
+ // Remeber this rsym is a local GOT entry
+ m_pGOT->setLocal(rsym);
}
break;
case llvm::ELF::R_MIPS_GPREL32:
@@ -668,11 +734,8 @@
case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
break;
default:
- llvm::report_fatal_error(llvm::Twine("Unknown relocation ") +
- llvm::Twine(pReloc.type()) +
- llvm::Twine("for the local symbol `") +
- pReloc.symInfo()->name() +
- llvm::Twine("'."));
+ fatal(diag::unknown_relocation) << (int)pReloc.type()
+ << pReloc.symInfo()->name();
}
}
@@ -701,12 +764,18 @@
case llvm::ELF::R_MIPS_64:
case llvm::ELF::R_MIPS_HI16:
case llvm::ELF::R_MIPS_LO16:
- if (isSymbolNeedsDynRel(*rsym, pOutput)) {
+ if (symbolNeedsDynRel(*rsym, false, pLDInfo, pOutput, true)) {
if (NULL == m_pRelDyn)
createRelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
rsym->setReserved(rsym->reserved() | ReserveRel);
+
+ // Remeber this rsym is a global GOT entry (as if it needs an entry).
+ // Actually we don't allocate an GOT entry.
+ if (NULL == m_pGOT)
+ createGOT(pLinker, pOutput);
+ m_pGOT->setGlobal(rsym);
}
break;
case llvm::ELF::R_MIPS_GOT16:
@@ -725,16 +794,14 @@
m_pGOT->reserveGlobalEntry();
rsym->setReserved(rsym->reserved() | ReserveGot);
m_GlobalGOTSyms.push_back(rsym->outSymbol());
+ // Remeber this rsym is a global GOT entry
+ m_pGOT->setGlobal(rsym);
}
break;
case llvm::ELF::R_MIPS_LITERAL:
case llvm::ELF::R_MIPS_GPREL32:
- llvm::report_fatal_error(llvm::Twine("Relocation ") +
- llvm::Twine(pReloc.type()) +
- llvm::Twine(" is not defined for the "
- "global symbol `") +
- pReloc.symInfo()->name() +
- llvm::Twine("'."));
+ fatal(diag::invalid_global_relocation) << (int)pReloc.type()
+ << pReloc.symInfo()->name();
break;
case llvm::ELF::R_MIPS_GPREL16:
break;
@@ -766,45 +833,14 @@
case llvm::ELF::R_MIPS_COPY:
case llvm::ELF::R_MIPS_GLOB_DAT:
case llvm::ELF::R_MIPS_JUMP_SLOT:
- llvm::report_fatal_error(llvm::Twine("Relocation ") +
- llvm::Twine(pReloc.type()) +
- llvm::Twine("for the global symbol `") +
- pReloc.symInfo()->name() +
- llvm::Twine("' should only be seen "
- "by the dynamic linker"));
+ fatal(diag::dynamic_relocation) << (int)pReloc.type();
break;
default:
- llvm::report_fatal_error(llvm::Twine("Unknown relocation ") +
- llvm::Twine(pReloc.type()) +
- llvm::Twine("for the global symbol `") +
- pReloc.symInfo()->name() +
- llvm::Twine("'."));
+ fatal(diag::unknown_relocation) << (int)pReloc.type()
+ << pReloc.symInfo()->name();
}
}
-bool MipsGNULDBackend::isSymbolNeedsPLT(ResolveInfo& pSym,
- const Output& pOutput) const
-{
- return (Output::DynObj == pOutput.type() &&
- ResolveInfo::Function == pSym.type() &&
- (pSym.isDyn() || pSym.isUndef()));
-}
-
-bool MipsGNULDBackend::isSymbolNeedsDynRel(ResolveInfo& pSym,
- const Output& pOutput) const
-{
- if(pSym.isUndef() && Output::Exec == pOutput.type())
- return false;
- if(pSym.isAbsolute())
- return false;
- if(Output::DynObj == pOutput.type())
- return true;
- if(pSym.isDyn() || pSym.isUndef())
- return true;
-
- return false;
-}
-
void MipsGNULDBackend::createGOT(MCLinker& pLinker, const Output& pOutput)
{
ELFFileFormat* file_format = getOutputFormat(pOutput);
@@ -813,7 +849,7 @@
m_pGOT = new MipsGOT(got, pLinker.getOrCreateSectData(got));
// define symbol _GLOBAL_OFFSET_TABLE_ when .got create
- if( m_pGOTSymbol != NULL ) {
+ if ( m_pGOTSymbol != NULL ) {
pLinker.defineSymbol<MCLinker::Force, MCLinker::Unresolve>(
"_GLOBAL_OFFSET_TABLE_",
false,
@@ -851,22 +887,6 @@
8);
}
-ELFFileFormat* MipsGNULDBackend::getOutputFormat(const Output& pOutput) const
-{
- switch (pOutput.type()) {
- case Output::DynObj:
- return getDynObjFileFormat();
- case Output::Exec:
- return getExecFileFormat();
- case Output::Object:
- return NULL;
- default:
- llvm::report_fatal_error(llvm::Twine("Unsupported output file format: ") +
- llvm::Twine(pOutput.type()));
- return NULL;
- }
-}
-
//===----------------------------------------------------------------------===//
/// createMipsLDBackend - the help funtion to create corresponding MipsLDBackend
///
diff --git a/lib/Target/Mips/MipsLDBackend.h b/lib/Target/Mips/MipsLDBackend.h
index c4f1d46..f9742ed 100644
--- a/lib/Target/Mips/MipsLDBackend.h
+++ b/lib/Target/Mips/MipsLDBackend.h
@@ -43,7 +43,7 @@
void initTargetSections(MCLinker& pLinker);
/// initTargetSymbols - initialize target dependent symbols in output.
- void initTargetSymbols(MCLinker& pLinker);
+ void initTargetSymbols(MCLinker& pLinker, const Output& pOutput);
/// initRelocFactory - create and initialize RelocationFactory.
bool initRelocFactory(const MCLinker& pLinker);
@@ -58,7 +58,8 @@
const LDSymbol& pInputSym,
MCLinker& pLinker,
const MCLDInfo& pLDInfo,
- const Output& pOutput);
+ const Output& pOutput,
+ const LDSection& pSection);
uint32_t machine() const;
@@ -75,6 +76,8 @@
unsigned int bitclass() const;
+ uint64_t defaultTextSegmentAddr() const;
+
/// preLayout - Backend can do any needed modification before layout
void doPreLayout(const Output& pOutput,
const MCLDInfo& pInfo,
@@ -107,11 +110,13 @@
/// @param pOutput - the output file
/// @param pSection - the given LDSection
/// @param pInfo - all options in the command line.
+ /// @param pLayout - for comouting the size of fragment
/// @param pRegion - the region to write out data
/// @return the size of the table in the file.
uint64_t emitSectionData(const Output& pOutput,
const LDSection& pSection,
const MCLDInfo& pInfo,
+ const Layout& pLayout,
MemoryRegion& pRegion) const;
/// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash
@@ -128,12 +133,11 @@
/// getTargetSectionOrder - compute the layout order of ARM target sections
unsigned int getTargetSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const;
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const;
/// finalizeSymbol - finalize the symbol value
- /// If the symbol's reserved field is not zero, MCLinker will call back this
- /// function to ask the final value of the symbol
- bool finalizeSymbol(LDSymbol& pSymbol) const;
+ bool finalizeTargetSymbols(MCLinker& pLinker, const Output& pOutput);
/// allocateCommonSymbols - allocate common symbols in the corresponding
/// sections.
@@ -152,14 +156,9 @@
const MCLDInfo& pLDInfo,
const Output& pOutput);
- bool isSymbolNeedsPLT(ResolveInfo& pSym, const Output& pOutput) const;
- bool isSymbolNeedsDynRel(ResolveInfo& pSym, const Output& pOutput) const;
-
void createGOT(MCLinker& pLinker, const Output& pOutput);
void createRelDyn(MCLinker& pLinker, const Output& pOutput);
- ELFFileFormat* getOutputFormat(const Output& pOutput) const;
-
/// updateAddend - update addend value of the relocation if the
/// the target symbol is a section symbol. Addend is the offset
/// in the section. This value should be updated after section
@@ -178,12 +177,11 @@
LDSymbol* m_pGOTSymbol;
LDSymbol* m_pGpDispSymbol;
- std::vector<LDSymbol*> m_LocalGOTSyms;
std::vector<LDSymbol*> m_GlobalGOTSyms;
private:
- /// isGOTSymbol - return true if the symbol is the GOT entry.
- bool isGOTSymbol(const LDSymbol& pSymbol) const;
+ /// isGlobalGOTSymbol - return true if the symbol is the global GOT entry.
+ bool isGlobalGOTSymbol(const LDSymbol& pSymbol) const;
/// emitDynamicSymbol - emit dynamic symbol.
void emitDynamicSymbol(llvm::ELF::Elf32_Sym& sym32,
Output& pOutput,
@@ -197,3 +195,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/Mips/MipsRelocationFactory.cpp b/lib/Target/Mips/MipsRelocationFactory.cpp
index e3a7793..948e026 100644
--- a/lib/Target/Mips/MipsRelocationFactory.cpp
+++ b/lib/Target/Mips/MipsRelocationFactory.cpp
@@ -9,9 +9,9 @@
#include <llvm/ADT/Twine.h>
#include <llvm/Support/ELF.h>
-#include <llvm/Support/ErrorHandling.h>
#include <mcld/LD/Layout.h>
#include <mcld/Target/OutputRelocSection.h>
+#include <mcld/Support/MsgHandling.h>
#include "MipsRelocationFactory.h"
#include "MipsRelocationFunctions.h"
@@ -54,32 +54,26 @@
Relocation::Type type = pRelocation.type();
if (type >= sizeof(apply_functions) / sizeof(apply_functions[0])) {
- llvm::report_fatal_error(llvm::Twine("Unknown relocation type. "
- "To symbol `") +
- pRelocation.symInfo()->name() +
- llvm::Twine("'."));
+ fatal(diag::unknown_relocation) << (int)type
+ << pRelocation.symInfo()->name();
}
// apply the relocation
Result result = apply_functions[type].func(pRelocation, pLDInfo, *this);
// check result
+ if (OK == result) {
+ return;
+ }
if (Overflow == result) {
- llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
- llvm::Twine(apply_functions[type].name) +
- llvm::Twine("' causes overflow. on symbol: `") +
- llvm::Twine(pRelocation.symInfo()->name()) +
- llvm::Twine("'."));
+ error(diag::result_overflow) << apply_functions[type].name
+ << pRelocation.symInfo()->name();
return;
}
if (BadReloc == result) {
- llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
- llvm::Twine(apply_functions[type].name) +
- llvm::Twine("' encounters unexpected opcode. "
- "on symbol: `") +
- llvm::Twine(pRelocation.symInfo()->name()) +
- llvm::Twine("'."));
+ error(diag::result_badreloc) << apply_functions[type].name
+ << pRelocation.symInfo()->name();
return;
}
}
@@ -90,26 +84,6 @@
static const char * const GP_DISP_NAME = "_gp_disp";
-// Get an relocation entry in .rel.dyn and set its type to R_MIPS_REL32,
-// its FragmentRef to pReloc->targetFrag() and its ResolveInfo
-// to pReloc->symInfo()
-static
-void helper_SetRelDynEntry(Relocation& pReloc,
- MipsRelocationFactory& pParent)
-{
- // rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
- MipsGNULDBackend& ld_backend = pParent.getTarget();
-
- bool exist;
- Relocation& rel_entry =
- *ld_backend.getRelDyn().getEntry(*rsym, false, exist);
-
- rel_entry.setType(llvm::ELF::R_MIPS_REL32);
- rel_entry.targetRef() = pReloc.targetRef();
- rel_entry.setSymInfo(0);
-}
-
// Find next R_MIPS_LO16 relocation paired to pReloc.
static
Relocation* helper_FindLo16Reloc(Relocation& pReloc)
@@ -142,24 +116,27 @@
static
GOTEntry& helper_GetGOTEntry(Relocation& pReloc,
- MipsRelocationFactory& pParent)
+ MipsRelocationFactory& pParent,
+ bool& pExist, int32_t value)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
MipsGNULDBackend& ld_backend = pParent.getTarget();
+ MipsGOT& got = ld_backend.getGOT();
- bool exist;
- GOTEntry& got_entry = *ld_backend.getGOT().getEntry(*rsym, exist);
+ GOTEntry& got_entry = *got.getEntry(*rsym, pExist);
- if (exist)
+ if (pExist)
return got_entry;
// If we first get this GOT entry, we should initialize it.
- if (rsym->reserved() & MipsGNULDBackend::ReserveGot) {
- got_entry.setContent(pReloc.symValue());
- }
- else {
- llvm::report_fatal_error("No GOT entry reserved for GOT type relocation!");
+ if (!(got.isLocal(rsym) && rsym->type() == ResolveInfo::Section)) {
+ if (rsym->reserved() & MipsGNULDBackend::ReserveGot) {
+ got_entry.setContent(pReloc.symValue());
+ }
+ else {
+ fatal(diag::reserve_entry_number_mismatch) << "GOT";
+ }
}
return got_entry;
@@ -169,7 +146,8 @@
RelocationFactory::Address helper_GetGOTOffset(Relocation& pReloc,
MipsRelocationFactory& pParent)
{
- GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent);
+ bool exist;
+ GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent, exist, 0);
return pParent.getLayout().getOutputOffset(got_entry) - 0x7FF0;
}
@@ -196,6 +174,7 @@
{
ResolveInfo* rsym = pReloc.symInfo();
MipsGNULDBackend& ld_backend = pParent.getTarget();
+ MipsGOT& got = ld_backend.getGOT();
bool exist;
Relocation& rel_entry =
@@ -203,7 +182,19 @@
rel_entry.setType(llvm::ELF::R_MIPS_REL32);
rel_entry.targetRef() = pReloc.targetRef();
- rel_entry.setSymInfo(rsym->isLocal() ? NULL : rsym);
+
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ RelocationFactory::DWord S = pReloc.symValue();
+
+ if (got.isLocal(rsym)) {
+ rel_entry.setSymInfo(NULL);
+ pReloc.target() = A + S;
+ }
+ else {
+ rel_entry.setSymInfo(rsym);
+ // Don't add symbol value that will be resolved by the dynamic linker
+ pReloc.target() = A;
+ }
}
//=========================================//
@@ -227,14 +218,26 @@
{
ResolveInfo* rsym = pReloc.symInfo();
- if (rsym->reserved() & MipsGNULDBackend::ReserveRel) {
- helper_DynRel(pReloc, pParent);
- }
-
RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
RelocationFactory::DWord S = pReloc.symValue();
- pReloc.target() |= (S + A);
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+ // 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;
+ return MipsRelocationFactory::OK;
+ }
+
+ if (rsym->reserved() & MipsGNULDBackend::ReserveRel) {
+ helper_DynRel(pReloc, pParent);
+
+ return MipsRelocationFactory::OK;
+ }
+
+ pReloc.target() = (S + A);
return MipsRelocationFactory::OK;
}
@@ -279,17 +282,21 @@
const MCLDInfo& pLDInfo,
MipsRelocationFactory& pParent)
{
- int32_t AHL = pParent.getAHL();
int32_t res = 0;
if (helper_isGpDisp(pReloc)) {
int32_t P = pReloc.place(pParent.getLayout());
int32_t GP = helper_GetGP(pParent);
+ int32_t AHL = pParent.getAHL();
res = AHL + GP - P + 4;
}
else {
int32_t S = pReloc.symValue();
- res = AHL + S;
+ // 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;
}
pReloc.target() &= 0xFFFF0000;
@@ -307,6 +314,7 @@
MipsRelocationFactory& pParent)
{
ResolveInfo* rsym = pReloc.symInfo();
+ RelocationFactory::Address G = 0;
if (rsym->isLocal()) {
Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
@@ -317,13 +325,16 @@
pParent.setAHL(AHL);
- GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent);
-
int32_t res = (AHL + S + 0x8000) & 0xFFFF0000;
- got_entry.setContent(res);
- }
+ bool exist;
+ GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent, exist, res);
- RelocationFactory::Address G = helper_GetGOTOffset(pReloc, pParent);
+ got_entry.setContent(res);
+ G = pParent.getLayout().getOutputOffset(got_entry) - 0x7FF0;
+ }
+ else {
+ G = helper_GetGOTOffset(pReloc, pParent);
+ }
pReloc.target() &= 0xFFFF0000;
pReloc.target() |= (G & 0xFFFF);
@@ -351,7 +362,8 @@
const MCLDInfo& pLDInfo,
MipsRelocationFactory& pParent)
{
- int32_t A = pReloc.target();
+ // 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);
diff --git a/lib/Target/Mips/MipsSectLinker.cpp b/lib/Target/Mips/MipsSectLinker.cpp
index af543c9..7a3082c 100644
--- a/lib/Target/Mips/MipsSectLinker.cpp
+++ b/lib/Target/Mips/MipsSectLinker.cpp
@@ -10,7 +10,7 @@
#include <llvm/ADT/Triple.h>
#include <mcld/Support/TargetRegistry.h>
#include "Mips.h"
-#include "MipsAndroidSectLinker.h"
+#include "MipsELFSectLinker.h"
using namespace mcld;
@@ -31,9 +31,7 @@
assert(0 && "COFF linker has not supported yet");
}
- // For now, use Android SectLinker directly
- return new MipsAndroidSectLinker(pOption,
- pLDBackend);
+ return new MipsELFSectLinker(pOption, pLDBackend);
}
} // namespace of mcld
diff --git a/lib/Target/OutputRelocSection.cpp b/lib/Target/OutputRelocSection.cpp
index 89b4f52..dbb8194 100644
--- a/lib/Target/OutputRelocSection.cpp
+++ b/lib/Target/OutputRelocSection.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include <mcld/LD/LDSection.h>
#include <mcld/Target/OutputRelocSection.h>
+#include <mcld/Support/MsgHandling.h>
using namespace mcld;
@@ -64,18 +65,18 @@
if(isForGOT) {
// get or create entry in m_SymRelMap
- Relocation *&Entry = m_SymRelMap[&pSymbol];
- pExist = 1;
+ Relocation *&entry = m_SymRelMap[&pSymbol];
+ pExist = true;
- if(!Entry) {
- pExist = 0;
- Entry = llvm::cast<Relocation>(&(*m_ValidEntryIterator));
+ if(NULL == entry) {
+ pExist = false;
+ entry = llvm::cast<Relocation>(&(*m_ValidEntryIterator));
++m_ValidEntryIterator;
}
- result = Entry;
+ result = entry;
}
else {
- pExist = 0;
+ pExist = false;
result = llvm::cast<Relocation>(&(*m_ValidEntryIterator));
++m_ValidEntryIterator;
}
diff --git a/lib/Target/Target.cpp b/lib/Target/Target.cpp
index 58178ec..ec8dc87 100644
--- a/lib/Target/Target.cpp
+++ b/lib/Target/Target.cpp
@@ -6,20 +6,19 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/Support/TargetRegistry.h"
-#include "mcld/Target/TargetMachine.h"
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/Target/TargetMachine.h>
#include <llvm/Support/TargetRegistry.h>
#include <llvm/Target/TargetMachine.h>
using namespace llvm;
-using namespace mcld;
-/* ** */
mcld::Target::Target()
- : TargetMachineCtorFn(0),
- SectLinkerCtorFn(0),
- TargetLDBackendCtorFn(0),
- m_pT(0)
+ : TargetMachineCtorFn(NULL),
+ SectLinkerCtorFn(NULL),
+ TargetLDBackendCtorFn(NULL),
+ DiagnosticLineInfoCtorFn(NULL),
+ m_pT(NULL)
{
}
diff --git a/lib/Target/TargetLDBackend.cpp b/lib/Target/TargetLDBackend.cpp
index 1a8ab6b..4eda0a6 100644
--- a/lib/Target/TargetLDBackend.cpp
+++ b/lib/Target/TargetLDBackend.cpp
@@ -14,10 +14,24 @@
/* ** */
TargetLDBackend::TargetLDBackend()
-{
+ : m_pEhFrame(NULL) {
}
TargetLDBackend::~TargetLDBackend()
{
+ if (NULL != m_pEhFrame)
+ delete m_pEhFrame;
}
+EhFrame* TargetLDBackend::getEhFrame()
+{
+ if (NULL == m_pEhFrame)
+ m_pEhFrame = new EhFrame();
+ return m_pEhFrame;
+}
+
+const EhFrame* TargetLDBackend::getEhFrame() const
+{
+ assert(NULL == m_pEhFrame);
+ return m_pEhFrame;
+}
diff --git a/lib/Target/X86/X86.h b/lib/Target/X86/X86.h
index c575d80..2d07314 100644
--- a/lib/Target/X86/X86.h
+++ b/lib/Target/X86/X86.h
@@ -21,3 +21,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/X86/X86AndroidSectLinker.cpp b/lib/Target/X86/X86AndroidSectLinker.cpp
deleted file mode 100644
index fe7a2cc..0000000
--- a/lib/Target/X86/X86AndroidSectLinker.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-//===- X86AndroidSectLinker.cpp -------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "X86AndroidSectLinker.h"
-
-#include <mcld/CodeGen/SectLinkerOption.h>
-
-using namespace mcld;
-
-X86AndroidSectLinker::X86AndroidSectLinker(SectLinkerOption &pOption,
- TargetLDBackend &pLDBackend)
- : AndroidSectLinker(pOption,
- pLDBackend) {
- MCLDInfo &info = pOption.info();
- // set up target-dependent constraints of attibutes
- info.attrFactory().constraint().disableWholeArchive();
- info.attrFactory().constraint().disableAsNeeded();
- info.attrFactory().constraint().setSharedSystem();
-
- // set up the predefined attributes
- info.attrFactory().predefined().unsetWholeArchive();
- info.attrFactory().predefined().setDynamic();
-
-}
-
-X86AndroidSectLinker::~X86AndroidSectLinker() {
-}
diff --git a/lib/Target/X86/X86AndroidSectLinker.h b/lib/Target/X86/X86AndroidSectLinker.h
deleted file mode 100644
index b275aca..0000000
--- a/lib/Target/X86/X86AndroidSectLinker.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//===- X86AndroidSectLinker.h ---------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef X86_ANDROIDSECTLINKER_H
-#define X86_ANDROIDSECTLINKER_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-#include <mcld/Target/AndroidSectLinker.h>
-
-namespace mcld
-{
-
-/** \class X86AndroidSectLinker
- * \brief X86AndroidSectLinker sets up the environment for linking.
- *
- * \see
- * \author Anders Cheng <Anders.Cheng@mediatek.com>
- */
-class X86AndroidSectLinker : public AndroidSectLinker
-{
-public:
- X86AndroidSectLinker(SectLinkerOption &pOption,
- mcld::TargetLDBackend &pLDBackend);
-
- ~X86AndroidSectLinker();
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/lib/Target/X86/X86Diagnostic.cpp b/lib/Target/X86/X86Diagnostic.cpp
new file mode 100644
index 0000000..db12dde
--- /dev/null
+++ b/lib/Target/X86/X86Diagnostic.cpp
@@ -0,0 +1,38 @@
+//===- X86Diagnostic.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// 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 llvm::Target& pTarget,
+ const std::string &pTriple)
+{
+ return new DWARFLineInfo();
+}
+
+} // namespace of mcld
+
+//==========================
+// InitializeX86Diagnostic
+extern "C" void LLVMInitializeX86DiagnosticLineInfo() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheX86Target, createX86DiagLineInfo);
+}
+
diff --git a/lib/Target/X86/X86ELFDynamic.cpp b/lib/Target/X86/X86ELFDynamic.cpp
index ee6b1f6..af86b2c 100644
--- a/lib/Target/X86/X86ELFDynamic.cpp
+++ b/lib/Target/X86/X86ELFDynamic.cpp
@@ -13,24 +13,25 @@
using namespace mcld;
X86ELFDynamic::X86ELFDynamic(const GNULDBackend& pParent)
- : ELFDynamic(pParent), m_HasGOTPLT(false) {
+ : ELFDynamic(pParent)
+{
}
-X86ELFDynamic::~X86ELFDynamic() {
+X86ELFDynamic::~X86ELFDynamic()
+{
}
-void X86ELFDynamic::reserveTargetEntries(const ELFFileFormat& pFormat) {
+void X86ELFDynamic::reserveTargetEntries(const ELFFileFormat& pFormat)
+{
// reservePLTGOT
- if (m_HasGOTPLT ? pFormat.hasGOTPLT() : pFormat.hasGOT())
+ if (pFormat.hasGOTPLT())
reserveOne(llvm::ELF::DT_PLTGOT);
}
-void X86ELFDynamic::applyTargetEntries(const ELFFileFormat& pFormat) {
+void X86ELFDynamic::applyTargetEntries(const ELFFileFormat& pFormat)
+{
// applyPLTGOT
- if (m_HasGOTPLT) {
- if (pFormat.hasGOTPLT())
- applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOTPLT().addr());
- }
- else if (pFormat.hasGOT())
- applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOT().addr());
+ if (pFormat.hasGOTPLT())
+ applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOTPLT().addr());
}
+
diff --git a/lib/Target/X86/X86ELFDynamic.h b/lib/Target/X86/X86ELFDynamic.h
index b9e70ce..7053a0b 100644
--- a/lib/Target/X86/X86ELFDynamic.h
+++ b/lib/Target/X86/X86ELFDynamic.h
@@ -25,12 +25,6 @@
private:
void reserveTargetEntries(const ELFFileFormat& pFormat);
void applyTargetEntries(const ELFFileFormat& pFormat);
-
-private:
- // True if we have .got.plt section, which will avoid GOT0 entries
- // when PLT isn't used. To support .got.plt section, we must combine
- // .got section and .got.plt section into a single GOT.
- bool m_HasGOTPLT;
};
} // namespace of mcld
diff --git a/lib/Target/X86/X86GOT.cpp b/lib/Target/X86/X86GOT.cpp
index 544b5e9..91c7d65 100644
--- a/lib/Target/X86/X86GOT.cpp
+++ b/lib/Target/X86/X86GOT.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "X86GOT.h"
#include <mcld/LD/LDFileFormat.h>
-#include <llvm/Support/ErrorHandling.h>
+#include <mcld/Support/MsgHandling.h>
#include <new>
namespace {
@@ -21,36 +21,8 @@
// X86GOT
X86GOT::X86GOT(LDSection& pSection, llvm::MCSectionData& pSectionData)
: GOT(pSection, pSectionData, X86GOTEntrySize),
- m_GeneralGOTNum(0), m_GOTPLTNum(0), m_GeneralGOTIterator(),
- m_GOTPLTIterator(), m_LastGOT0()
+ m_GOTIterator(), m_fIsVisit(false)
{
- GOTEntry* Entry = 0;
-
- // Create GOT0 entries.
- for (unsigned int i = 0; i < X86GOT0Num; i++) {
- Entry = new (std::nothrow) GOTEntry(0, X86GOTEntrySize,
- &m_SectionData);
-
- if (!Entry)
- llvm::report_fatal_error("Allocating GOT0 entries failed!");
-
- m_Section.setSize(m_Section.size() + X86GOTEntrySize);
- }
-
- // Skip GOT0 entries.
- iterator it = m_SectionData.begin();
- iterator ie = m_SectionData.end();
-
- for (unsigned int i = 1; i < X86GOT0Num; ++i) {
- if (it == ie)
- llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
-
- ++it;
- }
-
- m_LastGOT0 = it;
- m_GeneralGOTIterator = it;
- m_GOTPLTIterator = it;
}
X86GOT::~X86GOT()
@@ -66,38 +38,37 @@
&m_SectionData);
if (!Entry)
- llvm::report_fatal_error("Allocating new memory for GOTEntry failed");
+ fatal(diag::fail_allocate_memory) << "GOTEntry";
m_Section.setSize(m_Section.size() + X86GOTEntrySize);
- ++m_GeneralGOTNum;
}
}
GOTEntry* X86GOT::getEntry(const ResolveInfo& pInfo, bool& pExist)
{
- GOTEntry *&Entry = m_GeneralGOTMap[&pInfo];
+ // first time visit this function, set m_GOTIterator
+ if(!m_fIsVisit) {
+ assert( !m_SectionData.getFragmentList().empty() &&
+ "DynRelSection contains no entries.");
+ m_GOTIterator = m_SectionData.getFragmentList().begin();
+ m_fIsVisit = true;
+ }
+
+
+ GOTEntry *&Entry = m_GOTMap[&pInfo];
pExist = 1;
if (!Entry) {
pExist = 0;
-
- ++m_GeneralGOTIterator;
- assert(m_GeneralGOTIterator != m_SectionData.getFragmentList().end()
- && "The number of GOT Entries and ResolveInfo doesn't match!");
-
- Entry = llvm::cast<GOTEntry>(&(*m_GeneralGOTIterator));
+ assert(m_GOTIterator != m_SectionData.getFragmentList().end()
+ && "The number of GOT Entries and ResolveInfo doesn't match!");
+ Entry = llvm::cast<GOTEntry>(&(*m_GOTIterator));
+ ++m_GOTIterator;
}
-
return Entry;
}
-void X86GOT::applyGOT0(uint64_t pAddress)
-{
- llvm::cast<GOTEntry>
- (*(m_SectionData.getFragmentList().begin())).setContent(pAddress);
-}
-
X86GOT::iterator X86GOT::begin()
{
return m_SectionData.getFragmentList().begin();
@@ -118,11 +89,3 @@
return m_SectionData.getFragmentList().end();
}
-unsigned int X86GOT::getGOTPLTNum() const
-{ return m_GOTPLTNum; }
-
-X86GOT::iterator X86GOT::getLastGOT0()
-{ return m_LastGOT0; }
-
-const X86GOT::iterator X86GOT::getLastGOT0() const
-{ return m_LastGOT0; }
diff --git a/lib/Target/X86/X86GOT.h b/lib/Target/X86/X86GOT.h
index 37b48a3..d758de0 100644
--- a/lib/Target/X86/X86GOT.h
+++ b/lib/Target/X86/X86GOT.h
@@ -23,18 +23,8 @@
* \brief X86 Global Offset Table.
*/
-const unsigned int X86GOT0Num = 3;
-
class X86GOT : public GOT
{
- friend void mcld::X86PLT::reserveEntry(size_t pNum);
-
- friend mcld::PLTEntry* mcld::X86PLT::getPLTEntry(
- const mcld::ResolveInfo& pSymbol,bool& pExist);
-
- friend mcld::GOTEntry* mcld::X86PLT::getGOTPLTEntry(
- const mcld::ResolveInfo& pSymbol,bool& pExist);
-
typedef llvm::DenseMap<const ResolveInfo*, GOTEntry*> SymbolIndexMapType;
public:
@@ -51,8 +41,6 @@
GOTEntry* getEntry(const ResolveInfo& pSymbol, bool& pExist);
- void applyGOT0(uint64_t pAddress);
-
iterator begin();
const_iterator begin() const;
@@ -61,30 +49,17 @@
const_iterator end() const;
- unsigned int getGOTPLTNum() const;
-
- iterator getLastGOT0();
-
- const iterator getLastGOT0() const;
-
private:
+ /// m_GOTIterator - point to the first valid entry in GOT list
+ iterator m_GOTIterator;
- unsigned int m_GeneralGOTNum;
- unsigned int m_GOTPLTNum;
+ /// m_fIsVisit - first time visit the function getEntry() or not
+ bool m_fIsVisit;
- // Used by getGeneralGOTEntry()
- iterator m_GeneralGOTIterator;
-
- // Used by getGOTPLTEntry()
- iterator m_GOTPLTIterator;
-
- // The last GOT0 entry
- iterator m_LastGOT0;
-
- SymbolIndexMapType m_GOTPLTMap;
- SymbolIndexMapType m_GeneralGOTMap;
+ SymbolIndexMapType m_GOTMap;
};
} // namespace of mcld
#endif
+
diff --git a/lib/Target/X86/X86GOTPLT.cpp b/lib/Target/X86/X86GOTPLT.cpp
index 55596e3..960c86b 100644
--- a/lib/Target/X86/X86GOTPLT.cpp
+++ b/lib/Target/X86/X86GOTPLT.cpp
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
#include "X86GOTPLT.h"
-#include "mcld/LD/LDFileFormat.h"
-#include <llvm/Support/ErrorHandling.h>
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/Support/MsgHandling.h>
#include <new>
namespace {
@@ -25,12 +25,12 @@
GOTEntry* Entry = 0;
// Create GOT0 entries.
- for (int i = 0; i < 3; i++) {
+ for (size_t i = 0; i < X86GOTPLT0Num; i++) {
Entry = new (std::nothrow) GOTEntry(0, X86GOTPLTEntrySize,
&m_SectionData);
if (!Entry)
- llvm::report_fatal_error("Allocating GOT0 entries failed!");
+ fatal(diag::fail_allocate_memory) << "GOT0";
m_Section.setSize(m_Section.size() + X86GOTPLTEntrySize);
}
@@ -39,9 +39,8 @@
iterator it = m_SectionData.begin();
iterator ie = m_SectionData.end();
- for (size_t i = 1; i < X86GOT0Num; ++i) {
- if (it == ie)
- llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
+ for (size_t i = 1; i < X86GOTPLT0Num; ++i) {
+ assert((it != ie) && "Generation of GOT0 entries is incomplete!");
++it;
}
@@ -73,31 +72,38 @@
return m_SectionData.end();
}
-void X86GOTPLT::applyGOT0(const uint64_t pAddress)
+void X86GOTPLT::applyGOT0(uint64_t pAddress)
{
llvm::cast<GOTEntry>
(*(m_SectionData.getFragmentList().begin())).setContent(pAddress);
}
-void X86GOTPLT::reserveGOTPLTEntry()
+void X86GOTPLT::reserveEntry(size_t pNum)
{
- GOTEntry* got_entry = 0;
-
- got_entry= new GOTEntry(0, getEntrySize(),&(getSectionData()));
-
+ GOTEntry* got_entry = NULL;
+ for (size_t i = 0; i < pNum; ++i) {
+ got_entry = new GOTEntry(0, getEntrySize(),&(getSectionData()));
if (!got_entry)
- llvm::report_fatal_error("Allocating new memory for GOT failed!");
+ fatal(diag::fail_allocate_memory) << "GOT";
m_Section.setSize(m_Section.size() + getEntrySize());
+ }
}
-void X86GOTPLT::applyAllGOTPLT(const uint64_t pPLTBase)
+void X86GOTPLT::applyAllGOTPLT(uint64_t pPLTBase,
+ unsigned int pPLT0Size,
+ unsigned int pPLT1Size)
{
- iterator gotplt_it = begin();
- iterator gotplt_ie = end();
-
- for (; gotplt_it != gotplt_ie; ++gotplt_it)
- llvm::cast<GOTEntry>(*gotplt_it).setContent(pPLTBase);
+ iterator it = begin();
+ // skip GOT0
+ for (size_t i = 0; i < X86GOTPLT0Num; ++i)
+ ++it;
+ // address of corresponding plt entry
+ uint64_t plt_addr = pPLTBase + pPLT0Size;
+ for (; it != end() ; ++it) {
+ llvm::cast<GOTEntry>(*it).setContent(plt_addr + 6);
+ plt_addr += pPLT1Size;
+ }
}
GOTEntry*& X86GOTPLT::lookupGOTPLTMap(const ResolveInfo& pSymbol)
@@ -105,9 +111,22 @@
return m_GOTPLTMap[&pSymbol];
}
-X86GOTPLT::iterator X86GOTPLT::getNextGOTPLTEntry()
+GOTEntry* X86GOTPLT::getEntry(const ResolveInfo& pInfo, bool& pExist)
{
- return ++m_GOTPLTIterator;
+ GOTEntry *&Entry = m_GOTPLTMap[&pInfo];
+ pExist = 1;
+
+ if (!Entry) {
+ pExist = 0;
+
+ ++m_GOTPLTIterator;
+ assert(m_GOTPLTIterator != m_SectionData.getFragmentList().end()
+ && "The number of GOT Entries and ResolveInfo doesn't match!");
+
+ Entry = llvm::cast<GOTEntry>(&(*m_GOTPLTIterator));
+ }
+
+ return Entry;
}
} //end mcld namespace
diff --git a/lib/Target/X86/X86GOTPLT.h b/lib/Target/X86/X86GOTPLT.h
index 04bfad0..ae9f0f7 100644
--- a/lib/Target/X86/X86GOTPLT.h
+++ b/lib/Target/X86/X86GOTPLT.h
@@ -12,7 +12,7 @@
#include <gtest.h>
#endif
-#include "mcld/Target/GOT.h"
+#include <mcld/Target/GOT.h>
namespace mcld
{
@@ -22,7 +22,7 @@
* \brief X86 .got.plt section.
*/
-const unsigned int X86GOT0Num = 3;
+const unsigned int X86GOTPLT0Num = 3;
class X86GOTPLT : public GOT
{
@@ -47,18 +47,20 @@
// For GOT0
public:
- void applyGOT0(const uint64_t pAddress);
+ void applyGOT0(uint64_t pAddress);
// For GOTPLT
public:
- void reserveGOTPLTEntry();
+ void reserveEntry(size_t pNum = 1);
- void applyAllGOTPLT(const uint64_t pPLTBase);
+ GOTEntry* getEntry(const ResolveInfo& pSymbol, bool& pExist);
+
+ void applyAllGOTPLT(uint64_t pPLTBase,
+ unsigned int pPLT0Size,
+ unsigned int pPLT1Size);
GOTEntry*& lookupGOTPLTMap(const ResolveInfo& pSymbol);
- iterator getNextGOTPLTEntry();
-
private:
iterator m_GOTPLTIterator;
SymbolIndexMapType m_GOTPLTMap;
@@ -67,3 +69,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/X86/X86LDBackend.cpp b/lib/Target/X86/X86LDBackend.cpp
index 354cd51..79d160e 100644
--- a/lib/Target/X86/X86LDBackend.cpp
+++ b/lib/Target/X86/X86LDBackend.cpp
@@ -13,13 +13,14 @@
#include "X86RelocationFactory.h"
#include <llvm/ADT/Triple.h>
-#include <mcld/Support/MemoryRegion.h>
-#include <mcld/Support/TargetRegistry.h>
+#include <mcld/LD/SectionMap.h>
#include <mcld/MC/MCLDInfo.h>
#include <mcld/MC/MCLDOutput.h>
#include <mcld/MC/MCLinker.h>
-#include <mcld/LD/SectionMap.h>
#include <mcld/MC/MCRegionFragment.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/TargetRegistry.h>
#include <cstring>
@@ -29,6 +30,7 @@
: m_pRelocFactory(NULL),
m_pGOT(NULL),
m_pPLT(NULL),
+ m_pGOTPLT(NULL),
m_pRelDyn(NULL),
m_pRelPLT(NULL),
m_pDynamic(NULL) {
@@ -42,6 +44,8 @@
delete m_pGOT;
if (NULL != m_pPLT)
delete m_pPLT;
+ if (NULL != m_pGOTPLT)
+ delete m_pGOTPLT;
if (NULL !=m_pRelDyn)
delete m_pRelDyn;
if (NULL != m_pRelPLT)
@@ -70,17 +74,15 @@
MCLinker& pLinker)
{
// when building shared object, the .got section is needed
- if(pOutput.type() == Output::DynObj && (NULL == m_pGOT))
- createX86GOT(pLinker, pOutput);
+ if (Output::DynObj == pOutput.type() && (NULL == m_pGOTPLT)) {
+ createX86GOTPLT(pLinker, pOutput);
+ }
}
void X86GNULDBackend::doPostLayout(const Output& pOutput,
const MCLDInfo& pInfo,
MCLinker& pLinker)
{
- // emit program headers
- if(pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec)
- emitProgramHdrs(pLinker.getLDInfo().output());
}
/// dynamic - the dynamic section of the target machine.
@@ -108,9 +110,18 @@
LDSection& got = file_format->getGOT();
m_pGOT = new X86GOT(got, pLinker.getOrCreateSectData(got));
+}
- // define symbol _GLOBAL_OFFSET_TABLE_ when .got create
- if( m_pGOTSymbol != NULL ) {
+void X86GNULDBackend::createX86GOTPLT(MCLinker& pLinker, const Output& pOutput)
+{
+ // get .got.plt LDSection and create MCSectionData
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ LDSection& gotplt = file_format->getGOTPLT();
+ m_pGOTPLT = new X86GOTPLT(gotplt, pLinker.getOrCreateSectData(gotplt));
+
+ // define symbol _GLOBAL_OFFSET_TABLE_ when .got.plt create
+ if (m_pGOTSymbol != NULL) {
pLinker.defineSymbol<MCLinker::Force, MCLinker::Unresolve>(
"_GLOBAL_OFFSET_TABLE_",
false,
@@ -119,7 +130,8 @@
ResolveInfo::Local,
0x0, // size
0x0, // value
- pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ pLinker.getLayout().getFragmentRef(*(m_pGOTPLT->begin()),
+ 0x0),
ResolveInfo::Hidden);
}
else {
@@ -131,7 +143,8 @@
ResolveInfo::Local,
0x0, // size
0x0, // value
- pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ pLinker.getLayout().getFragmentRef(*(m_pGOTPLT->begin()),
+ 0x0),
ResolveInfo::Hidden);
}
}
@@ -143,8 +156,9 @@
LDSection& plt = file_format->getPLT();
LDSection& relplt = file_format->getRelPlt();
+ assert(m_pGOTPLT != NULL);
// create MCSectionData and X86PLT
- m_pPLT = new X86PLT(plt, pLinker.getOrCreateSectData(plt), *m_pGOT, pOutput);
+ m_pPLT = new X86PLT(plt, pLinker.getOrCreateSectData(plt), *m_pGOTPLT, pOutput);
// set info of .rel.plt to .plt
relplt.setLink(&plt);
@@ -167,63 +181,73 @@
8);
}
-ELFFileFormat* X86GNULDBackend::getOutputFormat(const Output& pOutput) const
+void X86GNULDBackend::addCopyReloc(ResolveInfo& pSym)
{
- switch (pOutput.type()) {
- case Output::DynObj:
- return getDynObjFileFormat();
- case Output::Exec:
- return getExecFileFormat();
- // FIXME: We do not support building .o now
- case Output::Object:
- default:
- llvm::report_fatal_error(llvm::Twine("Unsupported output file format: ") +
- llvm::Twine(pOutput.type()));
- return NULL;
+ bool exist;
+ Relocation& rel_entry = *m_pRelDyn->getEntry(pSym, false, exist);
+ rel_entry.setType(llvm::ELF::R_386_COPY);
+ assert(pSym.outSymbol()->hasFragRef());
+ rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef());
+ rel_entry.setSymInfo(&pSym);
+}
+
+LDSymbol& X86GNULDBackend::defineSymbolforCopyReloc(MCLinker& pLinker,
+ const ResolveInfo& pSym)
+{
+ // For a symbol needing copy relocation, define a copy symbol in the BSS
+ // section and all other reference to this symbol should refer to this
+ // copy.
+
+ // get or create corresponding BSS LDSection
+ LDSection* bss_sect_hdr = NULL;
+ if (ResolveInfo::ThreadLocal == pSym.type()) {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
+ ".tbss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
}
-}
+ else {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
-bool X86GNULDBackend::isSymbolNeedsPLT(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) const
-{
- return((Output::DynObj == pOutput.type())
- &&(ResolveInfo::Function == pSym.type())
- &&(pSym.isDyn() || pSym.isUndef() ||
- isSymbolPreemptible(pSym, pLDInfo, pOutput))
- );
-}
+ // get or create corresponding BSS MCSectionData
+ assert(NULL != bss_sect_hdr);
+ llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(
+ *bss_sect_hdr);
-bool X86GNULDBackend::isSymbolNeedsDynRel(const ResolveInfo& pSym,
- const Output& pOutput,
- bool isAbsReloc) const
-{
- if(pSym.isUndef() && (pOutput.type()==Output::Exec))
- return false;
- if(pSym.isAbsolute())
- return false;
- if(pOutput.type()==Output::DynObj && isAbsReloc)
- return true;
- if(pSym.isDyn() || pSym.isUndef())
- return true;
+ // Determine the alignment by the symbol value
+ // FIXME: here we use the largest alignment
+ uint32_t addralign = bitclass() / 8;
- return false;
-}
+ // allocate space in BSS for the copy symbol
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, pSym.size());
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ bss_section,
+ addralign);
+ bss_sect_hdr->setSize(bss_sect_hdr->size() + size);
-bool X86GNULDBackend::isSymbolPreemptible(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) const
-{
- if(pSym.other() != ResolveInfo::Default)
- return false;
+ // 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;
- if(pOutput.type() != Output::DynObj)
- return false;
+ // Define the copy symbol in the bss section and resolve it
+ LDSymbol* cpy_sym = pLinker.defineSymbol<MCLinker::Force, MCLinker::Resolve>(
+ pSym.name(),
+ false,
+ (ResolveInfo::Type)pSym.type(),
+ ResolveInfo::Define,
+ binding,
+ pSym.size(), // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*frag, 0x0),
+ (ResolveInfo::Visibility)pSym.other());
- if(pLDInfo.options().Bsymbolic())
- return false;
-
- return true;
+ return *cpy_sym;
}
void X86GNULDBackend::updateAddend(Relocation& pReloc,
@@ -231,7 +255,7 @@
const Layout& pLayout) const
{
// Update value keep in addend if we meet a section symbol
- if(pReloc.symInfo()->type() == ResolveInfo::Section) {
+ if (pReloc.symInfo()->type() == ResolveInfo::Section) {
pReloc.setAddend(pLayout.getOutputOffset(
*pInputSym.fragRef()) + pReloc.addend());
}
@@ -254,9 +278,9 @@
// 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(Output::DynObj == pOutput.type()) {
+ if (isOutputPIC(pOutput, pLDInfo)) {
// create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (NULL == m_pRelDyn)
createX86RelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
// set Rel bit
@@ -267,7 +291,7 @@
case llvm::ELF::R_386_GOTOFF:
case llvm::ELF::R_386_GOTPC:
// A GOT section is needed
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createX86GOT(pLinker, pOutput);
return;
@@ -275,9 +299,8 @@
return;
default:
- llvm::report_fatal_error(llvm::Twine("unexpected reloc ") +
- llvm::Twine((int) pReloc.type()) +
- llvm::Twine(" in object file"));
+ fatal(diag::unsupported_relocation) << (int)pReloc.type()
+ << "mclinker@googlegroups.com";
break;
} // end switch
}
@@ -295,14 +318,14 @@
case llvm::ELF::R_386_32:
// Absolute relocation type, symbol may needs PLT entry or
// dynamic relocation entry
- if(isSymbolNeedsPLT(*rsym, pLDInfo, pOutput)) {
+ if (symbolNeedsPLT(*rsym, pLDInfo, pOutput)) {
// create plt for this symbol if it does not have one
- if(!(rsym->reserved() & ReservePLT)){
+ if (!(rsym->reserved() & ReservePLT)){
// Create .got section if it dosen't exist
- if(NULL == m_pGOT)
- createX86GOT(pLinker, pOutput);
+ if (NULL == m_pGOTPLT)
+ createX86GOTPLT(pLinker, pOutput);
// create .plt and .rel.plt if not exist
- if(NULL == m_pPLT)
+ if (NULL == m_pPLT)
createX86PLTandRelPLT(pLinker, pOutput);
// Symbol needs PLT entry, we need to reserve a PLT entry
// and the corresponding GOT and dynamic relocation entry
@@ -315,21 +338,29 @@
}
}
- if(isSymbolNeedsDynRel(*rsym, pOutput, true)) {
+ if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT),
+ pLDInfo, pOutput, true)) {
// symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
// create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (NULL == m_pRelDyn)
createX86RelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
- // set Rel bit
- rsym->setReserved(rsym->reserved() | ReserveRel);
+ if (symbolNeedsCopyReloc(pLinker.getLayout(), pReloc, *rsym, pLDInfo,
+ pOutput)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym);
+ addCopyReloc(*cpy_sym.resolveInfo());
+ }
+ else {
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
}
return;
case llvm::ELF::R_386_GOTOFF:
case llvm::ELF::R_386_GOTPC: {
// A GOT section is needed
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createX86GOT(pLinker, pOutput);
return;
}
@@ -338,21 +369,21 @@
// A PLT entry is needed when building shared library
// return if we already create plt for this symbol
- if(rsym->reserved() & ReservePLT)
+ if (rsym->reserved() & ReservePLT)
return;
// if symbol is defined in the ouput file and it's not
// preemptible, no need plt
- if(rsym->isDefine() && !rsym->isDyn() &&
+ if (rsym->isDefine() && !rsym->isDyn() &&
!isSymbolPreemptible(*rsym, pLDInfo, pOutput)) {
return;
}
// Create .got section if it dosen't exist
- if(NULL == m_pGOT)
- createX86GOT(pLinker, pOutput);
+ if (NULL == m_pGOTPLT)
+ createX86GOTPLT(pLinker, pOutput);
// create .plt and .rel.plt if not exist
- if(NULL == m_pPLT)
+ if (NULL == m_pPLT)
createX86PLTandRelPLT(pLinker, pOutput);
// Symbol needs PLT entry, we need to reserve a PLT entry
// and the corresponding GOT and dynamic relocation entry
@@ -367,17 +398,17 @@
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 | GOTRel))
return;
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createX86GOT(pLinker, pOutput);
m_pGOT->reserveEntry();
// 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(Output::DynObj == pOutput.type() || rsym->isUndef() || rsym->isDyn()) {
+ if (Output::DynObj == pOutput.type() || rsym->isUndef() || rsym->isDyn()) {
// create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (NULL == m_pRelDyn)
createX86RelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
// set GOTRel bit
@@ -389,15 +420,49 @@
return;
case llvm::ELF::R_386_PC32:
- // We allow R_386_PC32 only if it isn't preemptible. Otherwise
- // we will generate writable text section in output.
- if (!isSymbolPreemptible(*rsym, pLDInfo, pOutput))
- return;
+ if (symbolNeedsPLT(*rsym, pLDInfo, pOutput) &&
+ pOutput.type() != Output::DynObj) {
+ // create plt for this symbol if it does not have one
+ if (!(rsym->reserved() & ReservePLT)){
+ // Create .got section if it dosen't exist
+ if (NULL == m_pGOTPLT)
+ createX86GOTPLT(pLinker, pOutput);
+ // create .plt and .rel.plt if not exist
+ if (NULL == m_pPLT)
+ createX86PLTandRelPLT(pLinker, pOutput);
+ // 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 X86PLT->reserveEntry())
+ m_pPLT->reserveEntry();
+ m_pRelPLT->reserveEntry(*m_pRelocFactory);
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | ReservePLT);
+ }
+ }
+
+ if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT),
+ pLDInfo, pOutput, false)) {
+ // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
+ // create .rel.dyn section if not exist
+ if (NULL == m_pRelDyn)
+ createX86RelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ if (symbolNeedsCopyReloc(pLinker.getLayout(), pReloc, *rsym, pLDInfo,
+ pOutput)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym);
+ addCopyReloc(*cpy_sym.resolveInfo());
+ }
+ else {
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
+ }
+ return;
default: {
- llvm::report_fatal_error(llvm::Twine("Unexpected reloc ") +
- llvm::Twine((int) pReloc.type()) +
- llvm::Twine(" in object file"));
+ fatal(diag::unsupported_relocation) << (int)pReloc.type()
+ << "mclinker@googlegroups.com";
break;
}
} // end switch
@@ -407,27 +472,36 @@
const LDSymbol& pInputSym,
MCLinker& pLinker,
const MCLDInfo& pLDInfo,
- const Output& pOutput)
+ const Output& pOutput,
+ const LDSection& pSection)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
+ assert(NULL != pSection.getLink());
+ if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC)) {
+ if (rsym->isLocal()) {
+ updateAddend(pReloc, pInputSym, pLinker.getLayout());
+ }
+ return;
+ }
+
// Scan relocation type to determine if an GOT/PLT/Dynamic Relocation
// entries should be created.
// FIXME: Below judgements concern only .so is generated as output
// FIXME: Below judgements concren nothing about TLS related relocation
- // A refernece to symbol _GLOBAL_OFFSET_TABLE_ implies that a .got section
- // is needed
- if(NULL == m_pGOT && NULL != m_pGOTSymbol) {
- if(rsym == m_pGOTSymbol->resolveInfo()) {
- createX86GOT(pLinker, pOutput);
+ // A refernece to symbol _GLOBAL_OFFSET_TABLE_ implies that a .got.plt
+ // section is needed
+ if (NULL == m_pGOTPLT && NULL != m_pGOTSymbol) {
+ if (rsym == m_pGOTSymbol->resolveInfo()) {
+ createX86GOTPLT(pLinker, pOutput);
}
}
// rsym is local
- if(rsym->isLocal())
+ if (rsym->isLocal())
scanLocalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
// rsym is external
@@ -439,11 +513,12 @@
uint64_t X86GNULDBackend::emitSectionData(const Output& pOutput,
const LDSection& pSection,
const MCLDInfo& pInfo,
+ const Layout& pLayout,
MemoryRegion& pRegion) const
{
assert(pRegion.size() && "Size of MemoryRegion is zero!");
- ELFFileFormat* FileFormat = getOutputFormat(pOutput);
+ const ELFFileFormat* FileFormat = getOutputFormat(pOutput);
assert(FileFormat &&
"ELFFileFormat is NULL in X86GNULDBackend::emitSectionData!");
@@ -479,8 +554,6 @@
else if (&pSection == &(FileFormat->getGOT())) {
assert(m_pGOT && "emitSectionData failed, m_pGOT is NULL!");
- m_pGOT->applyGOT0(FileFormat->getDynamic().addr());
-
uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
GOTEntry* got = 0;
@@ -494,10 +567,28 @@
}
}
- else
- llvm::report_fatal_error("unsupported section name "
- + pSection.name() + " !");
+ else if (&pSection == &(FileFormat->getGOTPLT())) {
+ assert(m_pGOTPLT && "emitSectionData failed, m_pGOTPLT is NULL!");
+ m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr());
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
+
+ GOTEntry* got = 0;
+ EntrySize = m_pGOTPLT->getEntrySize();
+
+ for (X86GOTPLT::iterator it = m_pGOTPLT->begin(),
+ ie = m_pGOTPLT->end(); it != ie; ++it, ++buffer) {
+ got = &(llvm::cast<GOTEntry>((*it)));
+ *buffer = static_cast<uint32_t>(got->getContent());
+ RegionSize += EntrySize;
+ }
+ }
+
+ else {
+ fatal(diag::unrecognized_output_sectoin)
+ << pSection.name()
+ << "mclinker@googlegroups.com";
+ }
return RegionSize;
}
uint32_t X86GNULDBackend::machine() const
@@ -517,6 +608,18 @@
return *m_pGOT;
}
+X86GOTPLT& X86GNULDBackend::getGOTPLT()
+{
+ assert(NULL != m_pGOTPLT);
+ return *m_pGOTPLT;
+}
+
+const X86GOTPLT& X86GNULDBackend::getGOTPLT() const
+{
+ assert(NULL != m_pGOTPLT);
+ return *m_pGOTPLT;
+}
+
X86PLT& X86GNULDBackend::getPLT()
{
assert(NULL != m_pPLT && "PLT section not exist");
@@ -555,17 +658,22 @@
unsigned int
X86GNULDBackend::getTargetSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const
{
- ELFFileFormat* file_format = getOutputFormat(pOutput);
+ const ELFFileFormat* file_format = getOutputFormat(pOutput);
- // FIXME: if command line option, "-z now", is given, we can let the order of
- // .got and .got.plt be the same as RELRO sections
- if (&pSectHdr == &file_format->getGOT())
+ if (&pSectHdr == &file_format->getGOT()) {
+ if (pInfo.options().hasNow())
+ return SHO_RELRO;
return SHO_RELRO_LAST;
+ }
- if (&pSectHdr == &file_format->getGOTPLT())
+ if (&pSectHdr == &file_format->getGOTPLT()) {
+ if (pInfo.options().hasNow())
+ return SHO_RELRO;
return SHO_NON_RELRO_FIRST;
+ }
if (&pSectHdr == &file_format->getPLT())
return SHO_PLT;
@@ -587,7 +695,7 @@
{
}
-void X86GNULDBackend::initTargetSymbols(MCLinker& pLinker)
+void X86GNULDBackend::initTargetSymbols(MCLinker& pLinker, const Output& pOutput)
{
// Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
// same name in input
@@ -604,113 +712,8 @@
}
/// finalizeSymbol - finalize the symbol value
-/// If the symbol's reserved field is not zero, MCLinker will call back this
-/// function to ask the final value of the symbol
-bool X86GNULDBackend::finalizeSymbol(LDSymbol& pSymbol) const
+bool X86GNULDBackend::finalizeTargetSymbols(MCLinker& pLinker, const Output& pOutput)
{
- return false;
-}
-
-/// allocateCommonSymbols - allocate common symbols in the corresponding
-/// sections.
-/// @refer Google gold linker: common.cc: 214
-bool
-X86GNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const
-{
- // SymbolCategory contains all symbols that must emit to the output files.
- // We are not like Google gold linker, we don't remember symbols before symbol
- // resolution. All symbols in SymbolCategory are already resolved. Therefore, we
- // don't need to care about some symbols may be changed its category due to symbol
- // resolution.
- SymbolCategory& symbol_list = pLinker.getOutputSymbols();
-
- if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
- return true;
-
- // addralign := max value of all common symbols
- uint64_t addralign = 0x0;
-
- // Due to the visibility, some common symbols may be forcefully local.
- SymbolCategory::iterator com_sym, com_end = symbol_list.localEnd();
- for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
- if (ResolveInfo::Common == (*com_sym)->desc()) {
- if ((*com_sym)->value() > addralign)
- addralign = (*com_sym)->value();
- }
- }
-
- // global common symbols.
- com_end = symbol_list.commonEnd();
- for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
- if ((*com_sym)->value() > addralign)
- addralign = (*com_sym)->value();
- }
-
- // FIXME: If the order of common symbols is defined, then sort common symbols
- // com_sym = symbol_list.commonBegin();
- // std::sort(com_sym, com_end, some kind of order);
-
- // get or create corresponding BSS LDSection
- LDSection* bss_sect_hdr = NULL;
- if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
- bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
- ".tbss",
- LDFileFormat::BSS,
- llvm::ELF::SHT_NOBITS,
- llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
- }
- else {
- bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
- LDFileFormat::BSS,
- llvm::ELF::SHT_NOBITS,
- llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
- }
-
- // get or create corresponding BSS MCSectionData
- assert(NULL != bss_sect_hdr);
- llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(*bss_sect_hdr);
-
- // allocate all common symbols
- uint64_t offset = bss_sect_hdr->size();
-
- // allocate all local common symbols
- com_end = symbol_list.localEnd();
- for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
- if (ResolveInfo::Common == (*com_sym)->desc()) {
- // We have to reset the description of the symbol here. When doing
- // incremental linking, the output relocatable object may have common
- // symbols. Therefore, we can not treat common symbols as normal symbols
- // when emitting the regular name pools. We must change the symbols'
- // description here.
- (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
- llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
- (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
- uint64_t size = pLinker.getLayout().appendFragment(*frag,
- bss_section,
- (*com_sym)->value());
- offset += size;
- }
- }
-
- // allocate all global common symbols
- com_end = symbol_list.commonEnd();
- for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
- // We have to reset the description of the symbol here. When doing
- // incremental linking, the output relocatable object may have common
- // symbols. Therefore, we can not treat common symbols as normal symbols
- // when emitting the regular name pools. We must change the symbols'
- // description here.
- (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
- llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
- (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
- uint64_t size = pLinker.getLayout().appendFragment(*frag,
- bss_section,
- (*com_sym)->value());
- offset += size;
- }
-
- bss_sect_hdr->setSize(offset);
- symbol_list.changeCommonsToGlobal();
return true;
}
diff --git a/lib/Target/X86/X86LDBackend.h b/lib/Target/X86/X86LDBackend.h
index a745999..7264c40 100644
--- a/lib/Target/X86/X86LDBackend.h
+++ b/lib/Target/X86/X86LDBackend.h
@@ -11,6 +11,7 @@
#include "X86ELFDynamic.h"
#include "X86GOT.h"
+#include "X86GOTPLT.h"
#include "X86PLT.h"
#include <mcld/LD/LDSection.h>
#include <mcld/Target/GNULDBackend.h>
@@ -82,6 +83,10 @@
const X86GOT& getGOT() const;
+ X86GOTPLT& getGOTPLT();
+
+ const X86GOTPLT& getGOTPLT() const;
+
X86PLT& getPLT();
const X86PLT& getPLT() const;
@@ -120,11 +125,13 @@
/// @param pOutput - the output file
/// @param pSection - the given LDSection
/// @param pInfo - all options in the command line.
+ /// @param pLayout - for comouting the size of fragment
/// @param pRegion - the region to write out data
/// @return the size of the table in the file.
uint64_t emitSectionData(const Output& pOutput,
const LDSection& pSection,
const MCLDInfo& pInfo,
+ const Layout& pLayout,
MemoryRegion& pRegion) const;
/// OSABI - the value of e_ident[EI_OSABI]
@@ -142,6 +149,9 @@
uint64_t flags() const
{ return 0x0; }
+ uint64_t defaultTextSegmentAddr() const
+ { return 0x08048000; }
+
/// initTargetSectionMap - initialize target dependent section mapping
bool initTargetSectionMap(SectionMap& pSectionMap);
@@ -150,7 +160,7 @@
void initTargetSections(MCLinker& pLinker);
- void initTargetSymbols(MCLinker& pLinker);
+ void initTargetSymbols(MCLinker& pLinker, const Output& pOutput);
/// scanRelocation - determine the empty entries are needed or not and create
/// the empty entries if needed.
@@ -162,7 +172,8 @@
const LDSymbol& pInputSym,
MCLinker& pLinker,
const MCLDInfo& pLDInfo,
- const Output& pOutput);
+ const Output& pOutput,
+ const LDSection& pSection);
OutputRelocSection& getRelDyn();
@@ -174,21 +185,11 @@
/// getTargetSectionOrder - compute the layout order of X86 target sections
unsigned int getTargetSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const;
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const;
- /// finalizeSymbol - finalize the symbol value
- /// If the symbol's reserved field is not zero, MCLinker will call back this
- /// function to ask the final value of the symbol
- bool finalizeSymbol(LDSymbol& pSymbol) const;
-
- /// allocateCommonSymbols - allocate common symbols in the corresponding
- /// sections.
- bool allocateCommonSymbols(const MCLDInfo& pLDInfo, MCLinker& pLinker) const;
-
-public:
- bool isSymbolPreemptible(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) const;
+ /// finalizeTargetSymbols - finalize the symbol value
+ bool finalizeTargetSymbols(MCLinker& pLinker, const Output& pOutput);
private:
void scanLocalReloc(Relocation& pReloc,
@@ -203,28 +204,30 @@
const MCLDInfo& pLDInfo,
const Output& pOutput);
- bool isSymbolNeedsPLT(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) 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);
- bool isSymbolNeedsDynRel(const ResolveInfo& pSym,
- const Output& pOutput,
- bool isAbsReloc) const;
+ /// 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(MCLinker& pLinker,
+ const ResolveInfo& pSym);
void updateAddend(Relocation& pReloc,
const LDSymbol& pInputSym,
const Layout& pLayout) const;
void createX86GOT(MCLinker& pLinker, const Output& pOutput);
+ void createX86GOTPLT(MCLinker& pLinker, const Output& pOutput);
void createX86PLTandRelPLT(MCLinker& pLinker, const Output& pOutput);
void createX86RelDyn(MCLinker& pLinker, const Output& pOutput);
- ELFFileFormat* getOutputFormat(const Output& pOutput) const;
-
private:
RelocationFactory* m_pRelocFactory;
X86GOT* m_pGOT;
X86PLT* m_pPLT;
+ X86GOTPLT* m_pGOTPLT;
/// m_RelDyn - dynamic relocation table of .rel.dyn
OutputRelocSection* m_pRelDyn;
/// m_RelPLT - dynamic relocation table of .rel.plt
@@ -254,3 +257,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/X86/X86PLT.cpp b/lib/Target/X86/X86PLT.cpp
index e9f9db1..caf6f32 100644
--- a/lib/Target/X86/X86PLT.cpp
+++ b/lib/Target/X86/X86PLT.cpp
@@ -6,38 +6,38 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "X86GOT.h"
+#include "X86GOTPLT.h"
#include "X86PLT.h"
#include <llvm/Support/raw_ostream.h>
-#include <llvm/Support/ErrorHandling.h>
#include <llvm/Support/ELF.h>
#include <mcld/MC/MCLDOutput.h>
+#include <mcld/Support/MsgHandling.h>
#include <new>
namespace {
const uint8_t x86_dyn_plt0[] = {
- 0xff, 0xb3, 0x04, 0, 0, 0, // pushl 0x4(%ebx)
- 0xff, 0xa3, 0x08, 0, 0, 0, // jmp *0x8(%ebx)
- 0xf, 0x1f, 0x4, 0 // nopl 0(%eax)
+ 0xff, 0xb3, 0x04, 0, 0, 0, // pushl 0x4(%ebx)
+ 0xff, 0xa3, 0x08, 0, 0, 0, // jmp *0x8(%ebx)
+ 0x0f, 0x1f, 0x4, 0 // nopl 0(%eax)
};
const uint8_t x86_dyn_plt1[] = {
- 0xff, 0xa3, 0, 0, 0, 0, // jmp *sym@GOT(%ebx)
- 0x68, 0, 0, 0, 0, // pushl $offset
- 0xe9, 0, 0, 0, 0 // jmp plt0
+ 0xff, 0xa3, 0, 0, 0, 0, // jmp *sym@GOT(%ebx)
+ 0x68, 0, 0, 0, 0, // pushl $offset
+ 0xe9, 0, 0, 0, 0 // jmp plt0
};
const uint8_t x86_exec_plt0[] = {
- 0xff, 0x35, 0, 0, 0, 0, // pushl .got + 4
- 0xff, 0x25, 0, 0, 0, 0, // jmp *(.got + 8)
- 0xf, 0x1f, 0x4, 0 // nopl 0(%eax)
+ 0xff, 0x35, 0, 0, 0, 0, // pushl .got + 4
+ 0xff, 0x25, 0, 0, 0, 0, // jmp *(.got + 8)
+ 0x0f, 0x1f, 0x4, 0 // nopl 0(%eax)
};
const uint8_t x86_exec_plt1[] = {
- 0xff, 0x25, 0, 0, 0, 0, // jmp *(sym in .got)
- 0x68, 0, 0, 0, 0, // pushl $offset
- 0xe9, 0, 0, 0, 0 // jmp plt0
+ 0xff, 0x25, 0, 0, 0, 0, // jmp *(sym in .got)
+ 0x68, 0, 0, 0, 0, // pushl $offset
+ 0xe9, 0, 0, 0, 0 // jmp plt0
};
}
@@ -55,9 +55,12 @@
X86PLT::X86PLT(LDSection& pSection,
llvm::MCSectionData& pSectionData,
- X86GOT &pGOTPLT,
- const Output& pOutput)
- : PLT(pSection, pSectionData), m_GOT(pGOTPLT), m_PLTEntryIterator()
+ X86GOTPLT &pGOTPLT,
+ const Output& pOutput)
+ : PLT(pSection, pSectionData),
+ m_GOTPLT(pGOTPLT),
+ m_PLTEntryIterator(),
+ m_Output(pOutput)
{
assert (Output::DynObj == pOutput.type() || Output::Exec == pOutput.type());
if (Output::DynObj == pOutput.type()) {
@@ -86,26 +89,17 @@
void X86PLT::reserveEntry(size_t pNum)
{
X86PLT1* plt1_entry = 0;
- GOTEntry* got_entry = 0;
for (size_t i = 0; i < pNum; ++i) {
plt1_entry = new (std::nothrow) X86PLT1(&m_SectionData, m_PLT1Size);
if (!plt1_entry)
- llvm::report_fatal_error("Allocating new memory for X86PLT1 failed!");
+ fatal(diag::fail_allocate_memory) << "X86PLT1";
m_Section.setSize(m_Section.size() + plt1_entry->getEntrySize());
- got_entry= new (std::nothrow) GOTEntry(0, m_GOT.getEntrySize(),
- &(m_GOT.m_SectionData));
-
- if (!got_entry)
- llvm::report_fatal_error("Allocating new memory for GOT failed!");
-
- m_GOT.m_Section.setSize(m_GOT.m_Section.size() + m_GOT.f_EntrySize);
-
- ++(m_GOT.m_GOTPLTNum);
- ++(m_GOT.m_GeneralGOTIterator);
+ // reserve corresponding entry in .got.plt
+ m_GOTPLT.reserveEntry(pNum);
}
}
@@ -116,47 +110,20 @@
pExist = 1;
if (!PLTEntry) {
- GOTEntry *&GOTPLTEntry = m_GOT.m_GOTPLTMap[&pSymbol];
- assert(!GOTPLTEntry && "PLT entry and got.plt entry doesn't match!");
-
pExist = 0;
// This will skip PLT0.
++m_PLTEntryIterator;
assert(m_PLTEntryIterator != m_SectionData.end() &&
"The number of PLT Entries and ResolveInfo doesn't match");
- ++(m_GOT.m_GOTPLTIterator);
-
PLTEntry = llvm::cast<X86PLT1>(&(*m_PLTEntryIterator));
- GOTPLTEntry = llvm::cast<GOTEntry>(&(*(m_GOT.m_GOTPLTIterator)));
}
-
return PLTEntry;
}
GOTEntry* X86PLT::getGOTPLTEntry(const ResolveInfo& pSymbol, bool& pExist)
{
- GOTEntry *&GOTPLTEntry = m_GOT.m_GOTPLTMap[&pSymbol];
-
- pExist = 1;
-
- if (!GOTPLTEntry) {
- X86PLT1 *&PLTEntry = m_PLTEntryMap[&pSymbol];
- assert(!PLTEntry && "PLT entry and got.plt entry doesn't match!");
-
- pExist = 0;
-
- // This will skip PLT0.
- ++m_PLTEntryIterator;
- assert(m_PLTEntryIterator != m_SectionData.end() &&
- "The number of PLT Entries and ResolveInfo doesn't match");
- ++(m_GOT.m_GOTPLTIterator);
-
- PLTEntry = llvm::cast<X86PLT1>(&(*m_PLTEntryIterator));
- GOTPLTEntry = llvm::cast<GOTEntry>(&(*(m_GOT.m_GOTPLTIterator)));
- }
-
- return GOTPLTEntry;
+ return m_GOTPLT.getEntry(pSymbol, pExist);
}
X86PLT0* X86PLT::getPLT0() const {
@@ -185,12 +152,12 @@
data = static_cast<unsigned char*>(malloc(plt0->getEntrySize()));
if (!data)
- llvm::report_fatal_error("Allocating new memory for plt0 failed!");
+ fatal(diag::fail_allocate_memory) << "plt0";
memcpy(data, m_PLT0, plt0->getEntrySize());
if (m_PLT0 == x86_exec_plt0) {
- uint64_t got_base = m_GOT.getSection().addr();
+ uint64_t got_base = m_GOTPLT.getSection().addr();
assert(got_base && ".got base address is NULL!");
uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2);
*offset = got_base + 4;
@@ -207,17 +174,17 @@
uint64_t plt_base = m_Section.addr();
assert(plt_base && ".plt base address is NULL!");
- uint64_t got_base = m_GOT.getSection().addr();
+ uint64_t got_base = m_GOTPLT.getSection().addr();
assert(got_base && ".got base address is NULL!");
X86PLT::iterator it = m_SectionData.begin();
X86PLT::iterator ie = m_SectionData.end();
assert(it!=ie && "FragmentList is empty, applyPLT1 failed!");
- uint64_t GOTEntrySize = m_GOT.getEntrySize();
+ uint64_t GOTEntrySize = m_GOTPLT.getEntrySize();
// Skip GOT0
- uint64_t GOTEntryOffset = GOTEntrySize * X86GOT0Num;
+ uint64_t GOTEntryOffset = GOTEntrySize * X86GOTPLT0Num;
//skip PLT0
uint64_t PLTEntryOffset = m_PLT0Size;
@@ -233,14 +200,19 @@
data = static_cast<unsigned char*>(malloc(plt1->getEntrySize()));
if (!data)
- llvm::report_fatal_error("Allocating new memory for plt1 failed!");
+ fatal(diag::fail_allocate_memory) << "plt1";
memcpy(data, m_PLT1, plt1->getEntrySize());
uint32_t* offset;
offset = reinterpret_cast<uint32_t*>(data + 2);
- *offset = GOTEntryOffset;
+ if (m_Output.type() == Output::DynObj) {
+ *offset = GOTEntryOffset;
+ } else {
+ // Exec
+ *offset = got_base + GOTEntryOffset;
+ }
GOTEntryOffset += GOTEntrySize;
offset = reinterpret_cast<uint32_t*>(data + 7);
@@ -255,24 +227,9 @@
++it;
}
- unsigned int GOTPLTNum = m_GOT.getGOTPLTNum();
-
- if (GOTPLTNum != 0) {
- X86GOT::iterator gotplt_it = m_GOT.getLastGOT0();
- X86GOT::iterator list_ie = m_GOT.getSectionData().getFragmentList().end();
-
- ++gotplt_it;
- uint64_t PLTEntryAddress = plt_base + m_PLT0Size;
- for (unsigned int i = 0; i < GOTPLTNum; ++i) {
- if (gotplt_it == list_ie)
- llvm::report_fatal_error(
- "The number of got.plt entries is inconsistent!");
-
- llvm::cast<GOTEntry>(*gotplt_it).setContent(PLTEntryAddress + 6);
- PLTEntryAddress += m_PLT1Size;
- ++gotplt_it;
- }
- }
+ // apply .got.plt
+ m_GOTPLT.applyAllGOTPLT(plt_base, m_PLT0Size, m_PLT1Size);
}
} // end namespace mcld
+
diff --git a/lib/Target/X86/X86PLT.h b/lib/Target/X86/X86PLT.h
index dd72f52..6c7002a 100644
--- a/lib/Target/X86/X86PLT.h
+++ b/lib/Target/X86/X86PLT.h
@@ -13,7 +13,7 @@
namespace mcld {
-class X86GOT;
+class X86GOTPLT;
class GOTEntry;
class Output;
@@ -41,8 +41,8 @@
public:
X86PLT(LDSection& pSection,
llvm::MCSectionData& pSectionData,
- X86GOT& pGOTPLT,
- const Output& pOutput);
+ X86GOTPLT& pGOTPLT,
+ const Output& pOutput);
~X86PLT();
// Override virtual function.
@@ -72,7 +72,7 @@
void applyPLT1();
private:
- X86GOT& m_GOT;
+ X86GOTPLT& m_GOTPLT;
// Used by getEntry() for mapping a ResolveInfo
// instance to a PLT1 Entry.
@@ -84,6 +84,8 @@
const uint8_t *m_PLT1;
unsigned int m_PLT0Size;
unsigned int m_PLT1Size;
+
+ const Output& m_Output;
};
} // namespace of mcld
diff --git a/lib/Target/X86/X86RelocationFactory.cpp b/lib/Target/X86/X86RelocationFactory.cpp
index 15b9a6b..9090d1a 100644
--- a/lib/Target/X86/X86RelocationFactory.cpp
+++ b/lib/Target/X86/X86RelocationFactory.cpp
@@ -8,11 +8,11 @@
//===----------------------------------------------------------------------===//
#include <llvm/ADT/Twine.h>
-#include <llvm/Support/ErrorHandling.h>
#include <llvm/Support/DataTypes.h>
#include <llvm/Support/ELF.h>
#include <mcld/MC/MCLDInfo.h>
#include <mcld/LD/Layout.h>
+#include <mcld/Support/MsgHandling.h>
#include "X86RelocationFactory.h"
#include "X86RelocationFunctions.h"
@@ -56,11 +56,8 @@
};
if (type >= sizeof (apply_functions) / sizeof (apply_functions[0]) ) {
- llvm::report_fatal_error(llvm::Twine("Unknown relocation type ") +
- llvm::Twine((int) type) +
- llvm::Twine(" to symbol `") +
- pRelocation.symInfo()->name() +
- llvm::Twine("'."));
+ fatal(diag::unknown_relocation) << (int)type <<
+ pRelocation.symInfo()->name();
return;
}
@@ -68,22 +65,18 @@
Result result = apply_functions[type].func(pRelocation, pLDInfo, *this);
// check result
+ if (OK == result) {
+ return;
+ }
if (Overflow == result) {
- llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
- llvm::Twine(apply_functions[type].name) +
- llvm::Twine("' causes overflow. on symbol: `") +
- llvm::Twine(pRelocation.symInfo()->name()) +
- llvm::Twine("'."));
+ error(diag::result_overflow) << apply_functions[type].name
+ << pRelocation.symInfo()->name();
return;
}
if (BadReloc == result) {
- llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
- llvm::Twine(apply_functions[type].name) +
- llvm::Twine("' encounters unexpected opcode. "
- "on symbol: `") +
- llvm::Twine(pRelocation.symInfo()->name()) +
- llvm::Twine("'."));
+ error(diag::result_badreloc) << apply_functions[type].name
+ << pRelocation.symInfo()->name();
return;
}
}
@@ -104,7 +97,7 @@
{
// if symbol is dynamic or undefine or preemptible
- if(pSym.isDyn() ||
+ if (pSym.isDyn() ||
pSym.isUndef() ||
pFactory.getTarget().isSymbolPreemptible(pSym, pLDInfo, pLDInfo.output()))
return false;
@@ -133,7 +126,7 @@
Relocation& rel_entry =
*ld_backend.getRelDyn().getEntry(*rsym, true, exist);
assert(!exist && "GOT entry not exist, but DynRel entry exist!");
- if(helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
+ if (helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
// Initialize got entry to target symbol address
got_entry.setContent(pReloc.symValue());
rel_entry.setType(llvm::ELF::R_386_RELATIVE);
@@ -147,7 +140,7 @@
rel_entry.targetRef().assign(got_entry);
}
else {
- llvm::report_fatal_error("No GOT entry reserved for GOT type relocation!");
+ fatal(diag::reserve_entry_number_mismatch) << "GOT";
}
}
return got_entry;
@@ -157,7 +150,7 @@
static
X86RelocationFactory::Address helper_GOT_ORG(X86RelocationFactory& pParent)
{
- return pParent.getTarget().getGOT().getSection().addr();
+ return pParent.getTarget().getGOTPLT().getSection().addr();
}
@@ -167,7 +160,9 @@
X86RelocationFactory& pParent)
{
GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pLDInfo, pParent);
- return helper_GOT_ORG(pParent) + pParent.getLayout().getOutputOffset(got_entry);
+ X86RelocationFactory::Address got_addr =
+ pParent.getTarget().getGOT().getSection().addr();
+ return got_addr + pParent.getLayout().getOutputOffset(got_entry);
}
@@ -195,7 +190,7 @@
rel_entry.setSymInfo(rsym);
}
else {
- llvm::report_fatal_error("No PLT entry reserved for PLT type relocation!");
+ fatal(diag::reserve_entry_number_mismatch) << "PLT";
}
}
return plt_entry;
@@ -235,7 +230,7 @@
rel_entry.setType(pType);
rel_entry.targetRef() = pReloc.targetRef();
- if(pType == llvm::ELF::R_386_RELATIVE)
+ if (pType == llvm::ELF::R_386_RELATIVE)
rel_entry.setSymInfo(0);
else
rel_entry.setSymInfo(rsym);
@@ -263,18 +258,34 @@
RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
RelocationFactory::DWord S = pReloc.symValue();
- if(rsym->isLocal() && (rsym->reserved() & X86GNULDBackend::ReserveRel)) {
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+ // 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;
+ return X86RelocationFactory::OK;
+ }
+
+ // A local symbol may need REL Type dynamic relocation
+ if (rsym->isLocal() && (rsym->reserved() & X86GNULDBackend::ReserveRel)) {
helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
pReloc.target() = S + A;
return X86RelocationFactory::OK;
}
- else if(!rsym->isLocal()) {
- if(rsym->reserved() & X86GNULDBackend::ReservePLT) {
+
+ // An external symbol may need PLT and dynamic relocation
+ if (!rsym->isLocal()) {
+ if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
S = helper_PLT(pReloc, pParent);
pReloc.target() = S + A;
}
- if(rsym->reserved() & X86GNULDBackend::ReserveRel) {
- if(helper_use_relative_reloc(*rsym, pLDInfo, 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 (rsym->reserved() & X86GNULDBackend::ReserveRel) {
+ if (helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
}
else {
@@ -294,10 +305,42 @@
const MCLDInfo& pLDInfo,
X86RelocationFactory& pParent)
{
- // perform static relocation
+ ResolveInfo* rsym = pReloc.symInfo();
RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
- pReloc.target() = pReloc.symValue() + A
- - pReloc.place(pParent.getLayout());
+ RelocationFactory::DWord S = pReloc.symValue();
+ RelocationFactory::DWord P = pReloc.place(pParent.getLayout());
+
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+ // 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 - P;
+ return X86RelocationFactory::OK;
+ }
+
+ // An external symbol may need PLT and dynamic relocation
+ if (!rsym->isLocal()) {
+ if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
+ S = helper_PLT(pReloc, pParent);
+ pReloc.target() = S + A - P;
+ }
+ if (pParent.getTarget().symbolNeedsDynRel(
+ *rsym, (rsym->reserved() & X86GNULDBackend::ReservePLT), pLDInfo,
+ pLDInfo.output(), false)) {
+ if (helper_use_relative_reloc(*rsym, pLDInfo, pParent) ) {
+ helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
+ }
+ else {
+ helper_DynRel(pReloc, pReloc.type(), pParent);
+ return X86RelocationFactory::OK;
+ }
+ }
+ }
+
+ // perform static relocation
+ pReloc.target() = S + A - P;
return X86RelocationFactory::OK;
}
@@ -331,7 +374,7 @@
const MCLDInfo& pLDInfo,
X86RelocationFactory& pParent)
{
- if(!(pReloc.symInfo()->reserved()
+ if (!(pReloc.symInfo()->reserved()
& (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) {
return X86RelocationFactory::BadReloc;
}
@@ -350,7 +393,7 @@
{
// PLT_S depends on if there is a PLT entry.
X86RelocationFactory::Address PLT_S;
- if((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT))
+ if ((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT))
PLT_S = helper_PLT(pReloc, pParent);
else
PLT_S = pReloc.symValue();
diff --git a/lib/Target/X86/X86RelocationFactory.h b/lib/Target/X86/X86RelocationFactory.h
index 779a21d..6a6c372 100644
--- a/lib/Target/X86/X86RelocationFactory.h
+++ b/lib/Target/X86/X86RelocationFactory.h
@@ -55,3 +55,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/X86/X86SectLinker.cpp b/lib/Target/X86/X86SectLinker.cpp
index 14621f3..a25a4c3 100644
--- a/lib/Target/X86/X86SectLinker.cpp
+++ b/lib/Target/X86/X86SectLinker.cpp
@@ -10,7 +10,6 @@
#include <mcld/Support/TargetRegistry.h>
#include "X86.h"
-#include "X86AndroidSectLinker.h"
#include "X86ELFSectLinker.h"
using namespace mcld;
@@ -31,9 +30,10 @@
assert(0 && "COFF linker has not supported yet");
}
- // For now, use Android SectLinker directly
- return new X86AndroidSectLinker(pOption,
- pLDBackend);
+ if (theTriple.isArch32Bit())
+ return new X86ELFSectLinker(pOption, pLDBackend);
+
+ assert(0 && "X86_64 has not supported yet");
}
} // namespace of mcld
@@ -44,3 +44,4 @@
// Register the linker frontend
mcld::TargetRegistry::RegisterSectLinker(TheX86Target, createX86SectLinker);
}
+
diff --git a/lib/Target/X86/X86TargetMachine.cpp b/lib/Target/X86/X86TargetMachine.cpp
index b3d7779..b036137 100644
--- a/lib/Target/X86/X86TargetMachine.cpp
+++ b/lib/Target/X86/X86TargetMachine.cpp
@@ -31,3 +31,4 @@
{
delete m_pLDInfo;
}
+
diff --git a/tools/llvm-mcld/llvm-mcld.cpp b/tools/llvm-mcld/llvm-mcld.cpp
index 835bb59..7e6b9c8 100644
--- a/tools/llvm-mcld/llvm-mcld.cpp
+++ b/tools/llvm-mcld/llvm-mcld.cpp
@@ -11,7 +11,14 @@
#include <mcld/Support/TargetRegistry.h>
#include <mcld/Support/CommandLine.h>
#include <mcld/Support/DerivedPositionDependentOptions.h>
+#include <mcld/Support/Path.h>
#include <mcld/Support/RealPath.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/FileSystem.h>
+#include <mcld/Support/raw_ostream.h>
+#include <mcld/LD/DiagnosticLineInfo.h>
+#include <mcld/LD/TextDiagnosticPrinter.h>
+#include <mcld/MC/MCLDInfo.h>
#include <mcld/CodeGen/SectLinkerOption.h>
#include <llvm/Module.h>
@@ -26,9 +33,11 @@
#include <llvm/Support/Host.h>
#include <llvm/Support/IRReader.h>
#include <llvm/Support/ManagedStatic.h>
+#include <llvm/Support/Signals.h>
#include <llvm/Support/TargetRegistry.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/ToolOutputFile.h>
+#include <llvm/Support/Process.h>
#include <llvm/Target/TargetData.h>
#include <llvm/Target/TargetMachine.h>
@@ -48,21 +57,10 @@
#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.
//
-static cl::opt<std::string>
-InputFilename("dB",
- cl::desc("set default bitcode"),
- cl::value_desc("bitcode"));
-
-static cl::opt<std::string>
-OutputFilename("o",
- cl::desc("Output filename"),
- cl::value_desc("filename"));
-
// Determine optimization level.
static cl::opt<char>
OptLevel("O",
@@ -90,21 +88,6 @@
cl::desc("Target specific attributes (-mattr=help for details)"),
cl::value_desc("a1,+a2,-a3,..."));
-static cl::opt<Reloc::Model>
-RelocModel("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<llvm::CodeModel::Model>
CMModel("code-model",
cl::desc("Choose code model"),
@@ -121,24 +104,6 @@
"Large code model"),
clEnumValEnd));
-cl::opt<mcld::CodeGenFileType>
-FileType("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_ARCFile, "arc",
- "Emit an archive ('.a') 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));
-
cl::opt<bool> NoVerify("disable-verify", cl::Hidden,
cl::desc("Do not verify input module"));
@@ -276,6 +241,21 @@
//===----------------------------------------------------------------------===//
// General 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"));
+
+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 cl::alias
+AliasOutputFilename("output",
+ cl::desc("alias for -o"),
+ cl::aliasopt(ArgOutputFilename));
+
+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"),
@@ -302,14 +282,25 @@
cl::desc("alias for -t"),
cl::aliasopt(ArgTrace));
-static cl::opt<bool>
-ArgVerbose("V",
- cl::desc("Display the version number for ld and list the linker emulations supported."));
+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::alias
-ArgVerboseAlias("verbose",
- cl::desc("alias for -V"),
- cl::aliasopt(ArgVerbose));
+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",
@@ -327,11 +318,116 @@
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::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<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::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));
+
//===----------------------------------------------------------------------===//
// Inputs
static cl::list<mcld::sys::fs::Path>
@@ -440,118 +536,139 @@
//===----------------------------------------------------------------------===//
// Scripting Options
+static cl::list<std::string>
+ArgWrapList("wrap",
+ cl::ZeroOrMore,
+ cl::desc("Use a wrap function fo symbol."),
+ 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"));
//===----------------------------------------------------------------------===//
/// non-member functions
-// GetFileNameRoot - Helper function to get the basename of a filename.
-static inline void
-GetFileNameRoot(const std::string &pInputFilename, std::string& pFileNameRoot)
-{
- std::string outputFilename;
- /* *** */
- const std::string& IFN = pInputFilename;
- int Len = IFN.length();
- if ((Len > 2) &&
- IFN[Len-3] == '.' &&
- ((IFN[Len-2] == 'b' && IFN[Len-1] == 'c') ||
- (IFN[Len-2] == 'l' && IFN[Len-1] == 'l')))
- pFileNameRoot = std::string(IFN.begin(), IFN.end()-3); // s/.bc/.s/
- else
- pFileNameRoot = std::string(IFN);
-}
-
+/// GetOutputStream - get the output stream.
static tool_output_file *GetOutputStream(const char* pTargetName,
- Triple::OSType pOSType,
- mcld::CodeGenFileType pFileType,
- const std::string& pInputFilename,
- std::string& pOutputFilename)
+ Triple::OSType pOSType,
+ mcld::CodeGenFileType pFileType,
+ const mcld::sys::fs::Path& pInputFilename,
+ mcld::sys::fs::Path& pOutputFilename)
{
- // If we don't yet have an output filename, make one.
if (pOutputFilename.empty()) {
- if (pInputFilename == "-")
- pOutputFilename = "-";
+ if (0 == pInputFilename.native().compare("-"))
+ pOutputFilename.assign("-");
else {
- GetFileNameRoot(pInputFilename, pOutputFilename);
+ switch(pFileType) {
+ case mcld::CGFT_ASMFile: {
+ if (0 == pInputFilename.native().compare("-"))
+ pOutputFilename.assign("_out");
+ else
+ pOutputFilename.assign(pInputFilename.stem().native());
- switch (pFileType) {
- case mcld::CGFT_ASMFile:
- if (pTargetName[0] == 'c') {
- if (pTargetName[1] == 0)
- pOutputFilename += ".cbe.c";
- else if (pTargetName[1] == 'p' && pTargetName[2] == 'p')
- pOutputFilename += ".cpp";
+ if (0 == strcmp(pTargetName, "c"))
+ pOutputFilename.native() += ".cbe.c";
+ else if (0 == strcmp(pTargetName, "cpp"))
+ pOutputFilename.native() += ".cpp";
+ else
+ pOutputFilename.native() += ".s";
+ }
+ break;
+
+ case mcld::CGFT_OBJFile: {
+ if (0 == pInputFilename.native().compare("-"))
+ pOutputFilename.assign("_out");
+ else
+ pOutputFilename.assign(pInputFilename.stem().native());
+
+ if (pOSType == Triple::Win32)
+ pOutputFilename.native() += ".obj";
+ else
+ pOutputFilename.native() += ".o";
+ }
+ break;
+
+ case mcld::CGFT_DSOFile: {
+ if (Triple::Win32 == pOSType) {
+ if (0 == pInputFilename.native().compare("-"))
+ pOutputFilename.assign("_out");
else
- pOutputFilename += ".s";
+ pOutputFilename.assign(pInputFilename.stem().native());
+ pOutputFilename.native() += ".dll";
}
else
- pOutputFilename += ".s";
- break;
- case mcld::CGFT_OBJFile:
- if (pOSType == Triple::Win32)
- pOutputFilename += ".obj";
+ 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 += ".o";
- break;
- case mcld::CGFT_DSOFile:
- if (pOSType == Triple::Win32)
- pOutputFilename += ".dll";
- else
- pOutputFilename += ".so";
- break;
- case mcld::CGFT_ARCFile:
- pOutputFilename += ".a";
- break;
- case mcld::CGFT_EXEFile:
+ pOutputFilename.assign("a.out");
+ }
+ break;
+
case mcld::CGFT_NULLFile:
- // do nothing
break;
default:
- assert(0 && "Unknown file type");
- }
- }
- }
+ llvm::report_fatal_error("Unknown output file type.\n");
+ } // end of switch
+ } // end of ! pInputFilename == "-"
+ } // end of if empty pOutputFilename
// Decide if we need "binary" output.
- bool Binary = false;
+ unsigned int fd_flags = 0x0;
switch (pFileType) {
default: assert(0 && "Unknown file type");
case mcld::CGFT_ASMFile:
break;
- case mcld::CGFT_ARCFile:
case mcld::CGFT_OBJFile:
case mcld::CGFT_DSOFile:
case mcld::CGFT_EXEFile:
case mcld::CGFT_NULLFile:
- Binary = true;
+ fd_flags |= raw_fd_ostream::F_Binary;
break;
}
// Open the file.
- std::string error;
- unsigned OpenFlags = 0;
- if (Binary) OpenFlags |= raw_fd_ostream::F_Binary;
- tool_output_file *FDOut = new tool_output_file(pOutputFilename.c_str(), error,
- OpenFlags);
- if (!error.empty()) {
- errs() << error << '\n';
- delete FDOut;
- return 0;
+ std::string err_mesg;
+ tool_output_file *result_output =
+ new tool_output_file(pOutputFilename.c_str(),
+ err_mesg,
+ fd_flags);
+ if (!err_mesg.empty()) {
+ errs() << err_mesg << '\n';
+ delete result_output;
+ return NULL;
}
- return FDOut;
+ return result_output;
}
-static bool ProcessLinkerInputsFromCommand(mcld::SectLinkerOption &pOption) {
+static bool ShouldColorize()
+{
+ const char* term = getenv("TERM");
+ return term && (0 != strcmp(term, "dumb"));
+}
+
+static bool ProcessLinkerOptionsFromCommand(mcld::MCLDInfo& pLDInfo) {
// ----- Set up General Options ----- //
// set up soname
- pOption.info().output().setSOName(ArgSOName);
+ pLDInfo.output().setSOName(ArgSOName);
// set up sysroot
if (!ArgSysRoot.empty()) {
if (exists(ArgSysRoot) && is_directory(ArgSysRoot))
- pOption.info().options().setSysroot(ArgSysRoot);
+ pLDInfo.options().setSysroot(ArgSysRoot);
}
// add all search directories
@@ -559,9 +676,9 @@
cl::list<mcld::MCLDDirectory>::iterator sdEnd = ArgSearchDirList.end();
for (sd=ArgSearchDirList.begin(); sd!=sdEnd; ++sd) {
if (sd->isInSysroot())
- sd->setSysroot(pOption.info().options().sysroot());
+ sd->setSysroot(pLDInfo.options().sysroot());
if (exists(sd->path()) && is_directory(sd->path())) {
- pOption.info().options().directories().add(*sd);
+ pLDInfo.options().directories().add(*sd);
}
else {
// FIXME: need a warning function
@@ -571,11 +688,98 @@
}
}
- pOption.info().options().setTrace(ArgTrace);
- pOption.info().options().setVerbose(ArgVerbose);
- pOption.info().options().setEntry(ArgEntry);
- pOption.info().options().setBsymbolic(ArgBsymbolic);
+ pLDInfo.options().setPIE(ArgPIE);
+ pLDInfo.options().setTrace(ArgTrace);
+ pLDInfo.options().setVerbose(ArgVerbose);
+ pLDInfo.options().setMaxErrorNum(ArgMaxErrorNum);
+ pLDInfo.options().setMaxWarnNum(ArgMaxWarnNum);
+ pLDInfo.options().setEntry(ArgEntry);
+ pLDInfo.options().setBsymbolic(ArgBsymbolic);
+ pLDInfo.options().setBgroup(ArgBgroup);
+ pLDInfo.options().setDyld(ArgDyld);
+ pLDInfo.options().setNoUndefined(ArgNoUndefined);
+ pLDInfo.options().setMulDefs(ArgAllowMulDefs);
+ pLDInfo.options().setEhFrameHdr(ArgEhFrameHdr);
+ // 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 =
+ pLDInfo.scripts().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 =
+ pLDInfo.scripts().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 =
+ pLDInfo.scripts().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 =
+ pLDInfo.scripts().renameMap().insert(from_real_str, exist);
+
+ from_real->setValue(*pname);
+ if (exist)
+ mcld::warning(mcld::diag::rewrap) << *pname << from_real_str;
+ } // end of for
+
+ // set up colorize
+ switch (ArgColor) {
+ case color::Never:
+ pLDInfo.options().setColor(false);
+ break;
+ case color::Always:
+ pLDInfo.options().setColor(true);
+ break;
+ case color::Auto:
+ bool color_option = ShouldColorize() &&
+ llvm::sys::Process::FileDescriptorIsDisplayed(STDOUT_FILENO);
+ pLDInfo.options().setColor(color_option);
+ break;
+ }
+
+ // add -z options
+ cl::list<mcld::ZOption>::iterator zOpt;
+ cl::list<mcld::ZOption>::iterator zOptEnd = ArgZOptionList.end();
+ for (zOpt = ArgZOptionList.begin(); zOpt != zOptEnd; ++zOpt) {
+ pLDInfo.options().addZOption(*zOpt);
+ }
+
+ // ----- Set up Script Options ----- //
+
+ return true;
+}
+
+static bool ProcessLinkerInputsFromCommand(mcld::SectLinkerOption &pOption) {
// ----- Set up Inputs ----- //
// add all start-group
cl::list<bool>::iterator sg;
@@ -685,16 +889,14 @@
++attr;
}
- // ----- Set up Scripting Options ----- //
-
- return false;
+ return true;
}
int main( int argc, char* argv[] )
{
-
LLVMContext &Context = getGlobalContext();
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
// Initialize targets first, so that --version shows registered targets.
InitializeAllTargets();
InitializeAllAsmPrinters();
@@ -702,7 +904,9 @@
InitializeAllTargetMCs();
mcld::InitializeAllTargets();
mcld::InitializeAllLinkers();
- cl::ParseCommandLineOptions(argc, argv, "llvm MCLinker\n");
+ mcld::InitializeAllDiagnostics();
+
+ cl::ParseCommandLineOptions(argc, argv, "MCLinker\n");
#ifdef ENABLE_UNITTEST
if (UnitTest) {
@@ -713,25 +917,45 @@
// Load the module to be compiled...
std::auto_ptr<Module> M;
- if (InputFilename.empty() && (FileType != mcld::CGFT_DSOFile)) {
- // Read from stdin
- InputFilename = "-";
+ // -shared
+ if (true == ArgShared) {
+ ArgFileType = mcld::CGFT_DSOFile;
}
- if (!InputFilename.empty()) {
+ // -V
+ if (ArgVersion) {
+ outs() << "MCLinker - ";
+ outs() << mcld::MCLDInfo::version();
+ outs() << "\n";
+ }
+
+ if (ArgBitcodeFilename.empty() &&
+ (mcld::CGFT_DSOFile != ArgFileType &&
+ mcld::CGFT_EXEFile != 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";
+ }
+
+ ArgBitcodeFilename.assign("-");
+ }
+
+ if (!ArgBitcodeFilename.empty()) {
SMDiagnostic Err;
- M.reset(ParseIRFile(InputFilename, Err, Context));
+ 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 '"
- << InputFilename << "'. **\n";
+ << ArgBitcodeFilename.native() << "'. **\n";
return 1;
}
- } else {
- // If here, output must be dynamic shared object (mcld::CGFT_DSOFile).
-
- // Create an empty Module
+ }
+ 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();
@@ -782,9 +1006,11 @@
std::string Err;
TheTarget = mcld::TargetRegistry::lookupTarget(TheTriple.getTriple(), Err);
if (TheTarget == 0) {
- errs() << argv[0] << ": error auto-selecting target for module '"
- << Err << "'. Please use the -march option to explicitly "
- << "pick a target.\n";
+ errs() << "error: auto-selecting target `" << TheTriple.getTriple()
+ << "'\n"
+ << "Please use the -march option to explicitly select a target.\n"
+ << "Example:\n"
+ << " $ " << argv[0] << " -march=arm\n";
return 1;
}
}
@@ -810,6 +1036,10 @@
case '3': OLvl = CodeGenOpt::Aggressive; break;
}
+ // set -fPIC
+ if (ArgFPIC)
+ ArgRelocModel = Reloc::PIC_;
+
TargetOptions Options;
Options.LessPreciseFPMADOption = EnableFPMAD;
Options.PrintMachineCode = PrintCode;
@@ -838,21 +1068,40 @@
std::auto_ptr<mcld::LLVMTargetMachine> target_machine(
TheTarget->createTargetMachine(TheTriple.getTriple(),
MCPU, FeaturesStr, Options,
- RelocModel, CMModel, OLvl));
+ ArgRelocModel, CMModel, OLvl));
assert(target_machine.get() && "Could not allocate target machine!");
mcld::LLVMTargetMachine &TheTargetMachine = *target_machine.get();
TheTargetMachine.getTM().setMCUseLoc(false);
TheTargetMachine.getTM().setMCUseCFI(false);
+ // Set up mcld::outs() and mcld::errs()
+ InitializeOStreams(TheTargetMachine.getLDInfo());
+
+ // Set up MsgHandler
+ OwningPtr<mcld::DiagnosticLineInfo>
+ diag_line_info(TheTarget->createDiagnosticLineInfo(*TheTarget->get(),
+ TheTriple.getTriple()));
+ OwningPtr<mcld::DiagnosticPrinter>
+ diag_printer(new mcld::TextDiagnosticPrinter(mcld::errs(),
+ TheTargetMachine.getLDInfo()));
+
+ mcld::InitializeDiagnosticEngine(TheTargetMachine.getLDInfo(),
+ diag_line_info.take(),
+ diag_printer.get());
+
+
// Figure out where we are going to send the output...
OwningPtr<tool_output_file>
Out(GetOutputStream(TheTarget->get()->getName(),
TheTriple.getOS(),
- FileType,
- InputFilename,
- OutputFilename));
- if (!Out) return 1;
+ 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;
@@ -870,7 +1119,12 @@
mcld::SectLinkerOption *LinkerOpt =
new mcld::SectLinkerOption(TheTargetMachine.getLDInfo());
- if (ProcessLinkerInputsFromCommand(*LinkerOpt)) {
+ if (!ProcessLinkerOptionsFromCommand(TheTargetMachine.getLDInfo())) {
+ errs() << argv[0] << ": failed to process linker options from command line!\n";
+ return 1;
+ }
+
+ if (!ProcessLinkerInputsFromCommand(*LinkerOpt)) {
errs() << argv[0] << ": failed to process inputs from command line!\n";
return 1;
}
@@ -881,8 +1135,8 @@
// Ask the target to add backend passes as necessary.
if( TheTargetMachine.addPassesToEmitFile(PM,
FOS,
- OutputFilename,
- FileType,
+ ArgOutputFilename.native(),
+ ArgFileType,
OLvl,
LinkerOpt,
NoVerify)) {
@@ -903,6 +1157,16 @@
// clean up
delete LinkerOpt;
+ if (0 != diag_printer->getNumErrors()) {
+ // If we reached here, we are failing ungracefully. Run the interrupt handlers
+ // to make sure any special cleanups get done, in particular that we remove
+ // files registered with RemoveFileOnSignal.
+ llvm::sys::RunInterruptHandlers();
+ diag_printer->finish();
+ exit(1);
+ }
+
+ diag_printer->finish();
return 0;
}
diff --git a/tools/mcld/include/alone/Config/Config.h.in b/tools/mcld/include/alone/Config/Config.h.in
new file mode 100644
index 0000000..edb8721
--- /dev/null
+++ b/tools/mcld/include/alone/Config/Config.h.in
@@ -0,0 +1,14 @@
+#ifndef ALONE_CONFIG_CONFIG_H
+#define ALONE_CONFIG_CONFIG_H
+
+#define PROVIDE_@PROVIDE_ALONE_TARGET@_CODEGEN
+#define DEFAULT_@DEFAULT_ALONE_TARGET@_CODEGEN
+
+#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
new file mode 100644
index 0000000..17f8baa
--- /dev/null
+++ b/tools/mcld/include/alone/Linker.h
@@ -0,0 +1,84 @@
+//===- 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 <mcld/Support/MemoryAreaFactory.h>
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/MC/MCLDDriver.h>
+#include <mcld/MC/InputTree.h>
+
+namespace alone {
+
+class MemoryFactory;
+class LinkerConfig;
+
+class Linker {
+public:
+ enum ErrorCode {
+ kSuccess,
+ kDoubleConfig,
+ kCreateBackend,
+ kDelegateLDInfo,
+ kOpenNameSpec,
+ kOpenObjectFile,
+ kNotConfig,
+ kNotSetUpOutput,
+ kOpenOutput,
+ kReadSections,
+ kReadSymbols,
+ kAddAdditionalSymbols,
+ kMaxErrorCode,
+ };
+
+ static const char *GetErrorString(enum ErrorCode pErrCode);
+
+private:
+ mcld::TargetLDBackend *mBackend;
+ mcld::MCLDDriver *mDriver;
+ mcld::MCLDInfo *mLDInfo;
+ mcld::InputTree::iterator mRoot;
+ MemoryFactory *mMemAreaFactory;
+
+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);
+
+ enum ErrorCode openFile(const mcld::sys::fs::Path& pPath,
+ enum ErrorCode pCode,
+ mcld::Input& pInput);
+
+ void advanceRoot();
+};
+
+} // 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
new file mode 100644
index 0000000..9af994e
--- /dev/null
+++ b/tools/mcld/include/alone/Support/Initialization.h
@@ -0,0 +1,23 @@
+//===- 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
new file mode 100644
index 0000000..37689d2
--- /dev/null
+++ b/tools/mcld/include/alone/Support/LinkerConfig.h
@@ -0,0 +1,78 @@
+//===- 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/MC/MCLDInfo.h>
+#include <mcld/MC/MCLDFile.h>
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/LD/DiagnosticLineInfo.h>
+#include <mcld/LD/DiagnosticPrinter.h>
+
+namespace alone {
+
+class LinkerConfig {
+private:
+ //===----------------------------------------------------------------------===//
+ // Available Configurations
+ //===----------------------------------------------------------------------===//
+ std::string mTriple;
+
+private:
+ //===----------------------------------------------------------------------===//
+ // These are generated by LinkerConfig during initialize().
+ //===----------------------------------------------------------------------===//
+ const mcld::Target *mTarget;
+ bool initializeTarget();
+
+ mcld::MCLDInfo *mLDInfo;
+ bool initializeLDInfo();
+
+ mcld::DiagnosticLineInfo *mDiagLineInfo;
+ mcld::DiagnosticPrinter *mDiagPrinter;
+ bool initializeDiagnostic();
+public:
+ //===----------------------------------------------------------------------===//
+ // Getters
+ //===----------------------------------------------------------------------===//
+ inline const std::string &getTriple() const
+ { return mTriple; }
+
+ inline const mcld::Target *getTarget() const
+ { return mTarget; }
+
+ inline mcld::MCLDInfo* getLDInfo()
+ { return mLDInfo; }
+
+ inline const mcld::MCLDInfo* getLDInfo() const
+ { return mLDInfo; }
+
+ inline void setSOName(const std::string &pSOName)
+ { mLDInfo->output().setSOName(pSOName); }
+
+ inline void setDyld(const std::string &pDyld)
+ { mLDInfo->options().setDyld(pDyld); }
+
+ void setSysRoot(const std::string &pSysRoot);
+
+ void addWrap(const std::string &pWrapSymbol);
+
+ 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/MemoryFactory.h b/tools/mcld/include/alone/Support/MemoryFactory.h
new file mode 100644
index 0000000..2247d2c
--- /dev/null
+++ b/tools/mcld/include/alone/Support/MemoryFactory.h
@@ -0,0 +1,40 @@
+//===- MemoryFactory.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ALONE_SUPPORT_MEMORY_FACTORY_H
+#define ALONE_SUPPORT_MEMORY_FACTORY_H
+
+#include <mcld/Support/FileHandle.h>
+#include <mcld/Support/MemoryAreaFactory.h>
+
+namespace mcld {
+class MemoryArea;
+} // end namespace mcld
+
+namespace alone {
+
+class MemoryFactory : public mcld::MemoryAreaFactory
+{
+public:
+ MemoryFactory();
+
+ ~MemoryFactory() { }
+
+ using mcld::MemoryAreaFactory::produce;
+
+ mcld::MemoryArea* produce(void *pMemBuffer, size_t pSize)
+ { return mcld::MemoryAreaFactory::create(pMemBuffer, pSize); }
+
+ mcld::MemoryArea* produce(int pFD)
+ { return mcld::MemoryAreaFactory::create(pFD, mcld::FileHandle::Unknown); }
+};
+
+} // end namespace alone
+
+#endif // ALONE_SUPPORT_MEMORY_FACTORY_H
diff --git a/tools/mcld/include/alone/Support/TargetLinkerConfigs.h b/tools/mcld/include/alone/Support/TargetLinkerConfigs.h
new file mode 100644
index 0000000..229a9bd
--- /dev/null
+++ b/tools/mcld/include/alone/Support/TargetLinkerConfigs.h
@@ -0,0 +1,78 @@
+//===- 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
+{ };
+
+} // 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
new file mode 100644
index 0000000..0d112ba
--- /dev/null
+++ b/tools/mcld/lib/Core/Linker.cpp
@@ -0,0 +1,353 @@
+//===- 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/MemoryFactory.h"
+
+#include <llvm/Support/ELF.h>
+
+#include <mcld/MC/MCLinker.h>
+#include <mcld/MC/InputTree.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/Target/TargetLDBackend.h>
+#include <mcld/Support/Path.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/FileHandle.h>
+
+using namespace alone;
+
+const char* Linker::GetErrorString(enum Linker::ErrorCode pErrCode)
+{
+ static const char* ErrorString[] = {
+ /* kSuccess */
+ "Successfully compiled.",
+ /* kDoubleConfig */
+ "Configure Linker twice.",
+ /* kCreateBackend */
+ "Cannot create backend.",
+ /* kDelegateLDInfo */
+ "Cannot get linker information",
+ /* kOpenNameSpec */
+ "Cannot open -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()
+ : mBackend(NULL), mDriver(NULL), mMemAreaFactory(NULL), mLDInfo(NULL) {
+}
+
+Linker::Linker(const LinkerConfig& pConfig)
+ : mBackend(NULL), mDriver(NULL), mMemAreaFactory(NULL), mLDInfo(NULL) {
+
+ 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()
+{
+ if (NULL != mDriver)
+ delete mDriver;
+ if (NULL != mBackend)
+ delete mBackend;
+ if (NULL != mMemAreaFactory)
+ delete mMemAreaFactory;
+}
+
+enum Linker::ErrorCode Linker::extractFiles(const LinkerConfig& pConfig)
+{
+ mLDInfo = const_cast<mcld::MCLDInfo*>(pConfig.getLDInfo());
+ if (NULL == mLDInfo)
+ return kDelegateLDInfo;
+
+ mRoot = mLDInfo->inputs().root();
+ return kSuccess;
+}
+
+enum Linker::ErrorCode Linker::config(const LinkerConfig& pConfig)
+{
+ if (NULL != mLDInfo)
+ return kDoubleConfig;
+
+ extractFiles(pConfig);
+
+ mBackend = pConfig.getTarget()->createLDBackend(pConfig.getTriple());
+ if (NULL == mBackend)
+ return kCreateBackend;
+
+ mDriver = new mcld::MCLDDriver(*mLDInfo, *mBackend);
+
+ mMemAreaFactory = new MemoryFactory();
+
+ mDriver->initMCLinker();
+
+ return kSuccess;
+}
+
+void Linker::advanceRoot()
+{
+ if (mRoot.isRoot())
+ --mRoot;
+ else
+ ++mRoot;
+}
+
+enum Linker::ErrorCode
+Linker::openFile(const mcld::sys::fs::Path& pPath, enum Linker::ErrorCode pCode, mcld::Input& pInput)
+{
+ mcld::MemoryArea *input_memory = mMemAreaFactory->produce(pPath,
+ mcld::FileHandle::ReadOnly);
+
+ if (input_memory->handler()->isGood())
+ pInput.setMemArea(input_memory);
+ else
+ return pCode;
+
+ mcld::LDContext *input_context = mLDInfo->contextFactory().produce(pPath);
+ pInput.setContext(input_context);
+ return kSuccess;
+}
+
+enum Linker::ErrorCode Linker::addNameSpec(const std::string &pNameSpec)
+{
+ mcld::sys::fs::Path* path = NULL;
+ // find out the real path of the namespec.
+ if (mLDInfo->attrFactory().constraint().isSharedSystem()) {
+ // In the system with shared object support, we can find both archive
+ // and shared object.
+
+ if (mLDInfo->attrFactory().last().isStatic()) {
+ // with --static, we must search an archive.
+ path = mLDInfo->options().directories().find(pNameSpec, mcld::Input::Archive);
+ }
+ else {
+ // otherwise, with --Bdynamic, we can find either an archive or a
+ // shared object.
+ path = mLDInfo->options().directories().find(pNameSpec, mcld::Input::DynObj);
+ }
+ }
+ else {
+ // In the system without shared object support, we only look for an
+ // archive.
+ path = mLDInfo->options().directories().find(pNameSpec, mcld::Input::Archive);
+ }
+
+ mcld::Input* input = mLDInfo->inputFactory().produce(pNameSpec, *path,
+ mcld::Input::Unknown);
+ mLDInfo->inputs().insert<mcld::InputTree::Positional>(mRoot, *input);
+
+ advanceRoot();
+
+ return openFile(*path, kOpenNameSpec, *input);
+}
+
+/// addObject - Add a object file by the filename.
+enum Linker::ErrorCode Linker::addObject(const std::string &pObjectPath)
+{
+ mcld::Input* input = mLDInfo->inputFactory().produce(pObjectPath,
+ pObjectPath,
+ mcld::Input::Unknown);
+
+ mLDInfo->inputs().insert<mcld::InputTree::Positional>(mRoot, *input);
+
+ advanceRoot();
+
+ return openFile(pObjectPath, kOpenObjectFile, *input);
+}
+
+/// 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 = mLDInfo->inputFactory().produce("memory object",
+ "NAN",
+ mcld::Input::Unknown);
+
+ mLDInfo->inputs().insert<mcld::InputTree::Positional>(mRoot, *input);
+
+ advanceRoot();
+
+ mcld::MemoryArea *input_memory = mMemAreaFactory->produce(pMemory, pSize);
+ input->setMemArea(input_memory);
+
+ mcld::LDContext *input_context = mLDInfo->contextFactory().produce();
+ input->setContext(input_context);
+
+ return kSuccess;
+}
+
+enum Linker::ErrorCode Linker::addCode(void* pMemory, size_t pSize)
+{
+ mcld::Input* input = mLDInfo->inputFactory().produce("code object",
+ "NAN",
+ mcld::Input::External);
+
+ mLDInfo->inputs().insert<mcld::InputTree::Positional>(mRoot, *input);
+
+ advanceRoot();
+
+ mcld::MemoryArea *input_memory = mMemAreaFactory->produce(pMemory, pSize);
+ input->setMemArea(input_memory);
+
+ mcld::LDContext *input_context = mLDInfo->contextFactory().produce();
+ input->setContext(input_context);
+
+ // FIXME: So far, MCLinker must set up output before add input files.
+ // set up LDContext
+ if (mDriver->hasInitLinker())
+ return kNotConfig;
+
+ if (!mLDInfo->output().hasContext())
+ return kNotSetUpOutput;
+
+ // create NULL section
+ mcld::LDSection& null = mDriver->getLinker()->createSectHdr("",
+ mcld::LDFileFormat::Null,
+ llvm::ELF::SHT_NULL,
+ 0);
+
+ null.setSize(0);
+ null.setOffset(0);
+ null.setIndex(0);
+ null.setInfo(0);
+ null.setAlign(0);
+
+ input_context->getSectionTable().push_back(&null);
+
+ // create .text section
+ mcld::LDSection& text = mDriver->getLinker()->createSectHdr(".text",
+ mcld::LDFileFormat::Regular,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR);
+
+ text.setSize(pSize);
+ text.setOffset(0x0);
+ text.setIndex(1);
+ text.setInfo(0);
+ text.setAlign(1);
+
+ input_context->getSectionTable().push_back(&text);
+
+ return kSuccess;
+}
+
+enum Linker::ErrorCode Linker::setOutput(const std::string &pPath)
+{
+ if (mLDInfo->output().hasContext())
+ return kDoubleConfig;
+
+ // ----- initialize output file ----- //
+
+ mcld::FileHandle::Permission perm = 0755;
+
+ mcld::MemoryArea* out_area = mMemAreaFactory->produce(
+ pPath,
+ mcld::FileHandle::ReadWrite | mcld::FileHandle::Truncate,
+ perm);
+
+ if (!out_area->handler()->isGood())
+ return kOpenOutput;
+
+ // FIXME: decide output type by command line option.
+ mLDInfo->output().setType(mcld::Output::DynObj);
+ mLDInfo->output().setMemArea(out_area);
+ mLDInfo->output().setContext(mLDInfo->contextFactory().produce(pPath));
+
+ // FIXME: We must initialize MCLinker before setOutput, and initialize
+ // standard sections here. This is because we have to build the section
+ // map before input files using it.
+ if (!mDriver->hasInitLinker())
+ return kNotConfig;
+
+ mDriver->initStdSections();
+
+ return kSuccess;
+}
+
+enum Linker::ErrorCode Linker::setOutput(int pFileHandler)
+{
+ if (mLDInfo->output().hasContext())
+ return kDoubleConfig;
+
+ // ----- initialize output file ----- //
+ mcld::MemoryArea* out_area = mMemAreaFactory->produce(pFileHandler);
+
+ mLDInfo->output().setType(mcld::Output::DynObj);
+ mLDInfo->output().setMemArea(out_area);
+ mLDInfo->output().setContext(mLDInfo->contextFactory().produce());
+
+ // FIXME: We must initialize MCLinker before setOutput, and initialize
+ // standard sections here. This is because we have to build the section
+ // map before input files using it.
+ if (!mDriver->hasInitLinker())
+ return kNotConfig;
+ mDriver->initStdSections();
+
+ return kSuccess;
+}
+
+enum Linker::ErrorCode Linker::link()
+{
+ mDriver->normalize();
+
+ if (!mDriver->readSections() ||
+ !mDriver->mergeSections())
+ return kReadSections;
+
+ if (!mDriver->readSymbolTables())
+ return kReadSymbols;
+
+ if (!mDriver->addStandardSymbols() ||
+ !mDriver->addTargetSymbols())
+ return kAddAdditionalSymbols;
+
+ mDriver->readRelocations();
+ mDriver->prelayout();
+ mDriver->layout();
+ mDriver->postlayout();
+ mDriver->finalizeSymbolValue();
+ mDriver->relocation();
+ mDriver->emitOutput();
+ mDriver->postProcessing();
+
+ return kSuccess;
+}
+
diff --git a/tools/mcld/lib/Support/Initialization.cpp b/tools/mcld/lib/Support/Initialization.cpp
new file mode 100644
index 0000000..83803f7
--- /dev/null
+++ b/tools/mcld/lib/Support/Initialization.cpp
@@ -0,0 +1,79 @@
+//===- Initialization.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+
+#include "alone/Config/Config.h"
+#include "alone/Support/Initialization.h"
+
+#include <mcld/Support/TargetSelect.h>
+#include <mcld/Support/TargetRegistry.h>
+
+#include <llvm/Support/TargetSelect.h>
+#include <llvm/Support/ErrorHandling.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();
+ LLVMInitializeARMTargetMC();
+ LLVMInitializeARMTargetInfo();
+ LLVMInitializeARMTarget();
+ LLVMInitializeARMLDTargetInfo();
+ LLVMInitializeARMLDTarget();
+ LLVMInitializeARMLDBackend();
+ LLVMInitializeARMDiagnosticLineInfo();
+#endif
+
+#if defined(PROVIDE_MIPS_CODEGEN)
+ LLVMInitializeMipsAsmPrinter();
+ LLVMInitializeMipsTargetMC();
+ LLVMInitializeMipsTargetInfo();
+ LLVMInitializeMipsTarget();
+ LLVMInitializeMipsLDTargetInfo();
+ LLVMInitializeMipsLDTarget();
+ LLVMInitializeMipsLDBackend();
+ LLVMInitializeMipsDiagnosticLineInfo();
+#endif
+
+#if defined(PROVIDE_X86_CODEGEN)
+ LLVMInitializeX86AsmPrinter();
+ LLVMInitializeX86TargetMC();
+ LLVMInitializeX86TargetInfo();
+ LLVMInitializeX86Target();
+ LLVMInitializeX86LDTargetInfo();
+ LLVMInitializeX86LDTarget();
+ LLVMInitializeX86LDBackend();
+ LLVMInitializeX86DiagnosticLineInfo();
+#endif
+
+ is_initialized = true;
+
+ return;
+}
+
diff --git a/tools/mcld/lib/Support/LinkerConfig.cpp b/tools/mcld/lib/Support/LinkerConfig.cpp
new file mode 100644
index 0000000..8da9bbe
--- /dev/null
+++ b/tools/mcld/lib/Support/LinkerConfig.cpp
@@ -0,0 +1,128 @@
+//===- 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 <llvm/Support/Signals.h>
+
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLDDirectory.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), mTarget(NULL), mLDInfo(NULL), mDiagLineInfo(NULL),
+ mDiagPrinter(NULL) {
+
+ initializeTarget();
+ initializeLDInfo();
+ initializeDiagnostic();
+}
+
+LinkerConfig::~LinkerConfig()
+{
+ if (NULL != mLDInfo)
+ delete mLDInfo;
+
+ if (0 != mDiagPrinter->getNumErrors()) {
+ // If we reached here, we are failing ungracefully. Run the interrupt handlers
+ // to make sure any special cleanups get done, in particular that we remove
+ // files registered with RemoveFileOnSignal.
+ llvm::sys::RunInterruptHandlers();
+ }
+ mDiagPrinter->finish();
+
+ 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 != mLDInfo) {
+ ALOGE("Cannot initialize mcld::MCLDInfo for given triple '%s!\n",
+ mTriple.c_str());
+ return false;
+ }
+
+ mLDInfo = new mcld::MCLDInfo(getTriple(), 1, 32);
+ return true;
+}
+
+bool LinkerConfig::initializeDiagnostic()
+{
+ // Set up MsgHandler
+ mDiagLineInfo = mTarget->createDiagnosticLineInfo(*mTarget->get(), mTriple);
+
+ mDiagPrinter = new mcld::TextDiagnosticPrinter(mcld::errs(), *mLDInfo);
+
+ mcld::InitializeDiagnosticEngine(*mLDInfo, mDiagLineInfo, mDiagPrinter);
+
+ return true;
+}
+
+void LinkerConfig::setSysRoot(const std::string &pSysRoot)
+{
+ mLDInfo->options().setSysroot(mcld::sys::fs::Path(pSysRoot));
+}
+
+void LinkerConfig::addWrap(const std::string &pWrapSymbol)
+{
+ bool exist = false;
+
+ // add wname -> __wrap_wname
+ mcld::StringEntry<llvm::StringRef>* to_wrap =
+ mLDInfo->scripts().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 =
+ mLDInfo->scripts().renameMap().insert(from_real_str, exist);
+ from_real->setValue(pWrapSymbol);
+
+ if (exist)
+ mcld::warning(mcld::diag::rewrap) << pWrapSymbol << from_real_str;
+}
+
+void LinkerConfig::addSearchDir(const std::string &pDirPath)
+{
+ // SearchDirs will remove the created MCLDDirectory.
+ mcld::MCLDDirectory* sd = new mcld::MCLDDirectory(pDirPath);
+
+ if (sd->isInSysroot())
+ sd->setSysroot(mLDInfo->options().sysroot());
+ if (exists(sd->path()) && is_directory(sd->path())) {
+ mLDInfo->options().directories().add(*sd);
+ }
+ else
+ mcld::warning(mcld::diag::warn_cannot_open_search_dir) << sd->name();
+}
+
diff --git a/tools/mcld/lib/Support/MemoryFactory.cpp b/tools/mcld/lib/Support/MemoryFactory.cpp
new file mode 100644
index 0000000..0d368dc
--- /dev/null
+++ b/tools/mcld/lib/Support/MemoryFactory.cpp
@@ -0,0 +1,17 @@
+//===- MemoryFactory.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "alone/Support/MemoryFactory.h"
+
+using namespace alone;
+
+MemoryFactory::MemoryFactory()
+ : mcld::MemoryAreaFactory(32) {
+}
+
diff --git a/tools/mcld/lib/Support/TargetLinkerConfigs.cpp b/tools/mcld/lib/Support/TargetLinkerConfigs.cpp
new file mode 100644
index 0000000..8854f79
--- /dev/null
+++ b/tools/mcld/lib/Support/TargetLinkerConfigs.cpp
@@ -0,0 +1,121 @@
+//===- 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"
+
+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 constraints of attributes
+ getLDInfo()->attrFactory().constraint().enableWholeArchive();
+ getLDInfo()->attrFactory().constraint().disableAsNeeded();
+ getLDInfo()->attrFactory().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ getLDInfo()->attrFactory().predefined().setWholeArchive();
+ getLDInfo()->attrFactory().predefined().setDynamic();
+
+ // set up target dependent options
+ if (getLDInfo()->options().sysroot().empty())
+ getLDInfo()->options().setSysroot(gDefaultSysroot);
+
+ if (!getLDInfo()->options().hasDyld())
+ getLDInfo()->options().setDyld(gDefaultDyld);
+
+ // set up default search path
+ addSearchDir("=/lib");
+ addSearchDir("=/usr/lib");
+
+ return;
+}
+#endif // defined(PROVIDE_ARM_CODEGEN)
+
+//===----------------------------------------------------------------------===//
+// Mips
+//===----------------------------------------------------------------------===//
+#if defined(PROVIDE_MIPS_CODEGEN)
+MipsLinkerConfig::MipsLinkerConfig()
+ : LinkerConfig(DEFAULT_MIPS_TRIPLE_STRING) {
+
+ // set up target-dependent constraints of attibutes
+ getLDInfo()->attrFactory().constraint().enableWholeArchive();
+ getLDInfo()->attrFactory().constraint().disableAsNeeded();
+ getLDInfo()->attrFactory().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ getLDInfo()->attrFactory().predefined().setWholeArchive();
+ getLDInfo()->attrFactory().predefined().setDynamic();
+
+ // set up target dependent options
+ if (getLDInfo()->options().sysroot().empty())
+ getLDInfo()->options().setSysroot(gDefaultSysroot);
+
+ if (!getLDInfo()->options().hasDyld())
+ getLDInfo()->options().setDyld(gDefaultDyld);
+
+ // set up default search path
+ addSearchDir("=/lib");
+ addSearchDir("=/usr/lib");
+
+ return;
+}
+#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 constraints of attibutes
+ getLDInfo()->attrFactory().constraint().enableWholeArchive();
+ getLDInfo()->attrFactory().constraint().disableAsNeeded();
+ getLDInfo()->attrFactory().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ getLDInfo()->attrFactory().predefined().setWholeArchive();
+ getLDInfo()->attrFactory().predefined().setDynamic();
+
+ // set up target dependent options
+ if (getLDInfo()->options().sysroot().empty())
+ getLDInfo()->options().setSysroot(gDefaultSysroot);
+
+ if (!getLDInfo()->options().hasDyld())
+ getLDInfo()->options().setDyld(gDefaultDyld);
+
+ // set up default search path
+ addSearchDir("=/lib");
+ addSearchDir("=/usr/lib");
+
+ return;
+}
+
+X86_32LinkerConfig::X86_32LinkerConfig()
+ : X86FamilyLinkerConfigBase(DEFAULT_X86_TRIPLE_STRING) {
+}
+
+X86_64LinkerConfig::X86_64LinkerConfig()
+ : X86FamilyLinkerConfigBase(DEFAULT_X86_64_TRIPLE_STRING) {
+}
+#endif // defined(PROVIDE_X86_CODEGEN)
diff --git a/tools/mcld/main.cpp b/tools/mcld/main.cpp
new file mode 100644
index 0000000..37610b8
--- /dev/null
+++ b/tools/mcld/main.cpp
@@ -0,0 +1,313 @@
+//===- mcld.cpp -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <stdlib.h>
+#include <string>
+
+#include <llvm/ADT/SmallString.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 <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 alone;
+
+//===----------------------------------------------------------------------===//
+// Compiler Options
+//===----------------------------------------------------------------------===//
+#ifdef TARGET_BUILD
+const std::string OptTargetTripe(DEFAULT_TARGET_TRIPLE_STRING);
+#else
+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"));
+
+llvm::cl::alias OptTargetTripleC("C", llvm::cl::NotHidden,
+ llvm::cl::desc("Alias for -mtriple"),
+ llvm::cl::aliasopt(OptTargetTriple));
+#endif
+
+//===----------------------------------------------------------------------===//
+// 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)
+//===----------------------------------------------------------------------===//
+// General Options
+//===----------------------------------------------------------------------===//
+static llvm::cl::opt<std::string>
+OptOutputFilename("o",
+ llvm::cl::desc("Output filename"),
+ llvm::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 llvm::cl::list<std::string>
+OptSearchDirList("L",
+ llvm::cl::ZeroOrMore,
+ llvm::cl::desc("Add path searchdir to the list of paths that ld will "
+ "search for archive libraries and ld control scripts."),
+ llvm::cl::value_desc("searchdir"),
+ llvm::cl::Prefix);
+
+static llvm::cl::opt<std::string>
+OptSOName("soname",
+ llvm::cl::desc("Set internal name of shared library"),
+ llvm::cl::value_desc("name"));
+
+
+static llvm::cl::opt<bool>
+OptShared("shared",
+ llvm::cl::desc("Create a shared library."),
+ llvm::cl::init(false));
+
+static llvm::cl::opt<std::string>
+OptDyld("dynamic-linker",
+ llvm::cl::desc("Set the name of the dynamic linker."),
+ llvm::cl::value_desc("Program"));
+
+//===----------------------------------------------------------------------===//
+// Inputs
+//===----------------------------------------------------------------------===//
+static llvm::cl::list<std::string>
+OptInputObjectFiles(llvm::cl::Positional,
+ llvm::cl::desc("[input object files]"),
+ llvm::cl::ZeroOrMore);
+
+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);
+
+//===----------------------------------------------------------------------===//
+// 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"));
+
+//===----------------------------------------------------------------------===//
+// Helper Functions
+//===----------------------------------------------------------------------===//
+// Override "mcld -version"
+void MCLDVersionPrinter() {
+ llvm::raw_ostream &os = llvm::outs();
+ os << "mcld (The MCLinker Project, http://mclinker.googlecode.com/):\n"
+ << " Default target: " << DEFAULT_TARGET_TRIPLE_STRING << "\n";
+
+ os << "\n";
+
+ os << "LLVM (http://llvm.org/):\n";
+ return;
+}
+
+#define DEFAULT_OUTPUT_PATH "a.out"
+static inline
+std::string DetermineOutputFilename(const std::string pOutputPath)
+{
+ if (!pOutputPath.empty()) {
+ return pOutputPath;
+ }
+
+ // 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;
+ }
+
+ // 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();
+}
+
+static inline
+bool ConfigLinker(Linker &pLinker, const std::string &pOutputFilename)
+{
+ LinkerConfig* config = NULL;
+
+#ifdef TARGET_BUILD
+ config = new (std::nothrow) DefaultLinkerConfig();
+#else
+ config = new (std::nothrow) LinkerConfig(OptTargetTriple);
+#endif
+ if (config == NULL) {
+ llvm::errs() << "Out of memory when create the linker configuration!\n";
+ return false;
+ }
+
+ // Setup the configuration accroding to the value of command line options.
+ // 1. set up soname
+ if (!OptSOName.empty())
+ config->setSOName(OptSOName);
+ 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, wEnd = OptWrapList.end();
+ for (wrap = OptWrapList.begin(); wrap != wEnd; ++wrap)
+ config->addWrap(*wrap);
+
+ // 5. if given, set up search directories
+ llvm::cl::list<std::string>::iterator sdir, sdirEnd = OptSearchDirList.end();
+ for (sdir = OptSearchDirList.begin(); sdir != sdirEnd; ++sdir)
+ config->addSearchDir(*sdir);
+
+ 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: In MCLinker, we have to set up output before setting up inputs.
+ // This constraint is wired, and we should break this constraint.
+ 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 fileIt = OptInputObjectFiles.begin();
+ llvm::cl::list<std::string>::iterator libIt = OptNameSpecList.begin();
+
+ llvm::cl::list<std::string>::iterator fileBegin = OptInputObjectFiles.begin();
+ llvm::cl::list<std::string>::iterator libBegin = OptNameSpecList.begin();
+ llvm::cl::list<std::string>::iterator fileEnd = OptInputObjectFiles.end();
+ llvm::cl::list<std::string>::iterator libEnd = OptNameSpecList.end();
+
+ unsigned libPos = 0, filePos = 0;
+ while (true) {
+ if (libIt != libEnd)
+ libPos = OptNameSpecList.getPosition(libIt - libBegin);
+ else
+ libPos = 0;
+
+ if (fileIt != fileEnd)
+ filePos = OptInputObjectFiles.getPosition(fileIt - fileBegin);
+ else
+ filePos = 0;
+
+ if ( filePos != 0 && (libPos == 0 || filePos < libPos) ) {
+ result = pLinker.addObject(*fileIt);
+ if (Linker::kSuccess != result) {
+ llvm::errs() << "Failed to open the input file! (detail: "
+ << *fileIt << ": "
+ << Linker::GetErrorString(result) << ")\n";
+ return false;
+ }
+ ++fileIt;
+ }
+ else if ( libPos != 0 && (filePos == 0 || libPos < filePos) ) {
+ result = pLinker.addNameSpec(*libIt);
+ if (Linker::kSuccess != result) {
+ llvm::errs() << "Failed to open the namespec! (detail: "
+ << *libIt << ": "
+ << Linker::GetErrorString(result) << ")\n";
+ return false;
+ }
+ ++libIt;
+ }
+
+ else
+ break; // we're done with the list
+ }
+
+ return true;
+}
+
+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 bce4b24..fdf2bd1 100644
--- a/unittests/BinTreeTest.cpp
+++ b/unittests/BinTreeTest.cpp
@@ -9,7 +9,7 @@
#include "BinTreeTest.h"
#include "mcld/ADT/TypeTraits.h"
-#include "mcld/MC/MCLDInputTree.h"
+#include "mcld/MC/InputTree.h"
#include <string>
using namespace mcld;
diff --git a/unittests/FileHandleTest.cpp b/unittests/FileHandleTest.cpp
new file mode 100644
index 0000000..993b07c
--- /dev/null
+++ b/unittests/FileHandleTest.cpp
@@ -0,0 +1,102 @@
+//===- implTest.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/Path.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "FileHandleTest.h"
+
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+FileHandleTest::FileHandleTest()
+{
+ // create testee. modify it if need
+ m_pTestee = new FileHandle();
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+FileHandleTest::~FileHandleTest()
+{
+ delete m_pTestee;
+}
+
+// SetUp() will be called immediately before each test.
+void FileHandleTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void FileHandleTest::TearDown()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// Testcases
+#include <iostream>
+using namespace std;
+
+TEST_F(FileHandleTest, open_close) {
+ mcld::sys::fs::Path path(TOPDIR);
+ path.append("unittests/test.txt");
+ ASSERT_TRUE(m_pTestee->open(path, FileHandle::ReadOnly));
+ ASSERT_TRUE(m_pTestee->isOpened());
+ ASSERT_TRUE(m_pTestee->isGood());
+
+ ASSERT_EQ(27, m_pTestee->size());
+
+ ASSERT_TRUE(m_pTestee->close());
+ ASSERT_FALSE(m_pTestee->isOpened());
+ ASSERT_TRUE(m_pTestee->isGood());
+
+ ASSERT_EQ(0, m_pTestee->size());
+}
+
+TEST_F(FileHandleTest, delegate_close) {
+ mcld::sys::fs::Path path(TOPDIR);
+ path.append("unittests/test.txt");
+
+ int fd = ::open(path.native().c_str(), O_RDONLY);
+
+ ASSERT_TRUE(m_pTestee->delegate(fd, FileHandle::ReadOnly));
+ ASSERT_TRUE(m_pTestee->isOpened());
+ ASSERT_TRUE(m_pTestee->isGood());
+
+ ASSERT_EQ(27, m_pTestee->size());
+
+ ASSERT_TRUE(m_pTestee->close());
+ ASSERT_FALSE(m_pTestee->isOpened());
+ ASSERT_TRUE(m_pTestee->isGood());
+
+ ASSERT_EQ(0, m_pTestee->size());
+
+ int close_result = ::close(fd);
+ int close_err = errno;
+ ASSERT_EQ(-1, close_result);
+ ASSERT_EQ(EBADF, close_err);
+}
+
+TEST_F(FileHandleTest, fail_close) {
+ mcld::sys::fs::Path path(TOPDIR);
+ path.append("unittests/test.txt");
+ ASSERT_TRUE(m_pTestee->open(path, FileHandle::ReadOnly));
+ ASSERT_TRUE(m_pTestee->isOpened());
+ ASSERT_TRUE(m_pTestee->isGood());
+
+ ASSERT_EQ(27, m_pTestee->size());
+
+ int close_result = ::close(m_pTestee->handler());
+ ASSERT_EQ(0, close_result);
+
+ ASSERT_FALSE(m_pTestee->close());
+ ASSERT_FALSE(m_pTestee->isOpened());
+ ASSERT_FALSE(m_pTestee->isGood());
+}
diff --git a/unittests/FileHandleTest.h b/unittests/FileHandleTest.h
new file mode 100644
index 0000000..88e2653
--- /dev/null
+++ b/unittests/FileHandleTest.h
@@ -0,0 +1,50 @@
+//===- headerTest.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_FILEHANDLE_TEST_H
+#define MCLD_FILEHANDLE_TEST_H
+
+#include <gtest.h>
+
+namespace mcld
+{
+class FileHandle;
+
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+/** \class FileHandleTest
+ * \brief
+ *
+ * \see FileHandle
+ */
+class FileHandleTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ FileHandleTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~FileHandleTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ mcld::FileHandle* m_pTestee;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/InputTreeTest.cpp b/unittests/InputTreeTest.cpp
index 060eaad..0013601 100644
--- a/unittests/InputTreeTest.cpp
+++ b/unittests/InputTreeTest.cpp
@@ -6,7 +6,7 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/MC/MCLDInputTree.h"
+#include "mcld/MC/InputTree.h"
#include "mcld/MC/MCLDInfo.h"
#include <InputTreeTest.h>
diff --git a/unittests/LEB128Test.cpp b/unittests/LEB128Test.cpp
index 1f1467f..bd1aec2 100644
--- a/unittests/LEB128Test.cpp
+++ b/unittests/LEB128Test.cpp
@@ -456,7 +456,7 @@
}
TEST_F( LEB128Test, Random_Regression_Test) {
- leb128::ByteType buffer[5];
+ leb128::ByteType buffer[9];
for (int i = 0; i < 20; i++) {
long int value = random();
diff --git a/unittests/MCFragmentRefTest.cpp b/unittests/MCFragmentRefTest.cpp
index 556fbdd..3da3463 100644
--- a/unittests/MCFragmentRefTest.cpp
+++ b/unittests/MCFragmentRefTest.cpp
@@ -6,10 +6,10 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-
#include "mcld/MC/MCFragmentRef.h"
#include "mcld/MC/MCRegionFragment.h"
#include "mcld/Support/MemoryAreaFactory.h"
+#include "mcld/Support/FileHandle.h"
#include "mcld/Support/Path.h"
#include "MCFragmentRefTest.h"
@@ -45,7 +45,7 @@
Path path(TOPDIR);
path.append("unittests/test3.txt");
MemoryAreaFactory* areaFactory = new MemoryAreaFactory(1);
- MemoryArea* area = areaFactory->produce(path, MemoryArea::ReadWrite);
+ MemoryArea* area = areaFactory->produce(path, FileHandle::ReadWrite);
MemoryRegion* region = area->request(0, 4096);
MCRegionFragment *frag = new MCRegionFragment(*region);
diff --git a/unittests/MemoryAreaTest.cpp b/unittests/MemoryAreaTest.cpp
index a2e631a..0499a0d 100644
--- a/unittests/MemoryAreaTest.cpp
+++ b/unittests/MemoryAreaTest.cpp
@@ -6,13 +6,12 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-
-
-#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 <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>
@@ -50,12 +49,15 @@
{
Path path(TOPDIR);
path.append("unittests/test3.txt");
+
MemoryAreaFactory *AreaFactory = new MemoryAreaFactory(1);
- MemoryArea* area = AreaFactory->produce(path, O_RDONLY);
+ 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]);
- delete AreaFactory;
+ area->release(region);
+ AreaFactory->destruct(area);
+ //delete AreaFactory;;
}
TEST_F( MemoryAreaTest, write_by_malloc )
@@ -63,23 +65,27 @@
Path path(TOPDIR);
path.append("unittests/test2.txt");
MemoryAreaFactory *AreaFactory = new MemoryAreaFactory(1);
- MemoryArea* area = AreaFactory->produce(path, O_RDWR);
- ASSERT_TRUE(area->isMapped());
- ASSERT_TRUE(area->isGood());
+ 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->sync();
- area->unmap();
- area->map(path, O_RDONLY);
- ASSERT_TRUE(area->isMapped());
- ASSERT_TRUE(area->isGood());
+ 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]);
- delete AreaFactory;
+ area->release(region);
+ AreaFactory->destruct(area);
+ //delete AreaFactory;;
}
TEST_F( MemoryAreaTest, read_one_page )
@@ -87,13 +93,15 @@
Path path(TOPDIR) ;
path.append("unittests/test3.txt") ;
MemoryAreaFactory *AreaFactory = new MemoryAreaFactory(1) ;
- MemoryArea* area = AreaFactory->produce(path, O_RDWR) ;
- ASSERT_TRUE(area->isMapped()) ;
- ASSERT_TRUE(area->isGood()) ;
- MemoryRegion* region = area->request(0, 4096) ;
+ 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]);
- delete AreaFactory ;
+ area->release(region);
+ AreaFactory->destruct(area);
+ //delete AreaFactory; ;
}
TEST_F( MemoryAreaTest, write_one_page )
@@ -101,22 +109,27 @@
Path path(TOPDIR) ;
path.append("unittests/test2.txt") ;
MemoryAreaFactory *AreaFactory = new MemoryAreaFactory(1) ;
- MemoryArea* area = AreaFactory->produce(path, O_RDWR) ;
- ASSERT_TRUE(area->isMapped()) ;
- ASSERT_TRUE(area->isGood()) ;
+ 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' ;
- area->sync() ;
- area->unmap() ;
- area->map(path, O_RDONLY) ;
- region = area->request(4000, 4) ;
+ 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->sync() ;
- delete AreaFactory ;
+ area->clear() ;
+ AreaFactory->destruct(area);
+ //delete AreaFactory; ;
}
TEST_F( MemoryAreaTest, write_sync )
@@ -124,25 +137,29 @@
Path path(TOPDIR) ;
path.append("unittests/test2.txt") ;
MemoryAreaFactory *AreaFactory = new MemoryAreaFactory(1) ;
- MemoryArea* area = AreaFactory->produce(path, O_RDWR) ;
- ASSERT_TRUE(area->isMapped()) ;
- ASSERT_TRUE(area->isGood()) ;
+ 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->sync() ;
- area->unmap();
- area->map(path, O_RDWR) ;
+ 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->sync();
- delete AreaFactory ;
+ area->release(region1);
+ area->clear();
+ AreaFactory->destruct(area);
+ //delete AreaFactory; ;
}
diff --git a/unittests/NamePoolTest.cpp b/unittests/NamePoolTest.cpp
new file mode 100644
index 0000000..614ee6a
--- /dev/null
+++ b/unittests/NamePoolTest.cpp
@@ -0,0 +1,268 @@
+//===- NamePoolTest.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "NamePoolTest.h"
+#include <mcld/LD/NamePool.h>
+#include <mcld/LD/Resolver.h>
+#include <mcld/LD/StaticResolver.h>
+#include <mcld/LD/ResolveInfo.h>
+#include <mcld/LD/LDSymbol.h>
+#include <llvm/ADT/StringRef.h>
+#include <string>
+#include <cstdio>
+
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+NamePoolTest::NamePoolTest()
+{
+ // create testee. modify it if need
+ StaticResolver resolver;
+ m_pTestee = new NamePool(resolver, 10);
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+NamePoolTest::~NamePoolTest()
+{
+ delete m_pTestee;
+}
+
+// SetUp() will be called immediately before each test.
+void NamePoolTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void NamePoolTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+
+
+TEST_F( NamePoolTest, insertString ) {
+ const char *s1 = "Hello MCLinker";
+ llvm::StringRef result1 = m_pTestee->insertString(s1);
+ EXPECT_NE(s1, result1.data());
+ EXPECT_STREQ(s1, result1.data());
+}
+
+TEST_F( NamePoolTest, insertSameString ) {
+ const char *s1 = "Hello MCLinker";
+ std::string s2(s1);
+ llvm::StringRef result1 = m_pTestee->insertString(s1);
+ llvm::StringRef result2 = m_pTestee->insertString(s2.c_str());
+ EXPECT_STREQ(s1, result1.data());
+ EXPECT_STREQ(s2.c_str(), result2.data());
+ EXPECT_EQ(result1.data(), result2.data());
+}
+
+TEST_F( NamePoolTest, insert_local_defined_Symbol ) {
+ const char *name = "Hello MCLinker";
+ bool isDyn = false;
+ ResolveInfo::Type type = ResolveInfo::Function;
+ ResolveInfo::Desc desc = ResolveInfo::Define;
+ ResolveInfo::Binding binding = ResolveInfo::Local;
+ uint64_t value = 0;
+ uint64_t size = 0;
+ ResolveInfo::Visibility other = ResolveInfo::Default;
+ Resolver::Result result1;
+ m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ desc,
+ binding,
+ size,
+ other,
+ NULL,
+ result1);
+
+ EXPECT_NE(name, result1.info->name());
+ EXPECT_STREQ(name, result1.info->name());
+ EXPECT_EQ(isDyn, result1.info->isDyn());
+ EXPECT_EQ(type, result1.info->type());
+ EXPECT_EQ(desc, result1.info->desc());
+ EXPECT_EQ(binding, result1.info->binding());
+ EXPECT_EQ(size, result1.info->size());
+ EXPECT_EQ(other, result1.info->visibility());
+
+ Resolver::Result result2;
+ m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ desc,
+ binding,
+ size,
+ other,
+ NULL,
+ result2);
+
+ EXPECT_NE(name, result1.info->name());
+ EXPECT_STREQ(name, result1.info->name());
+ EXPECT_EQ(isDyn, result1.info->isDyn());
+ EXPECT_EQ(type, result1.info->type());
+ EXPECT_EQ(desc, result1.info->desc());
+ EXPECT_EQ(binding, result1.info->binding());
+ EXPECT_EQ(size, result1.info->size());
+ EXPECT_EQ(other, result1.info->visibility());
+
+ EXPECT_NE(result1.existent, result2.existent);
+}
+
+TEST_F( NamePoolTest, insert_global_reference_Symbol ) {
+ const char *name = "Hello MCLinker";
+ bool isDyn = false;
+ ResolveInfo::Type type = ResolveInfo::NoType;
+ ResolveInfo::Desc desc = ResolveInfo::Undefined;
+ ResolveInfo::Binding binding = ResolveInfo::Global;
+ uint64_t size = 0;
+ ResolveInfo::Visibility other = ResolveInfo::Default;
+ Resolver::Result result1;
+ m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ desc,
+ binding,
+ size,
+ other,
+ NULL,
+ result1);
+
+ EXPECT_NE(name, result1.info->name());
+ EXPECT_STREQ(name, result1.info->name());
+ EXPECT_EQ(isDyn, result1.info->isDyn());
+ EXPECT_EQ(type, result1.info->type());
+ EXPECT_EQ(desc, result1.info->desc());
+ EXPECT_EQ(binding, result1.info->binding());
+ EXPECT_EQ(size, result1.info->size());
+ EXPECT_EQ(other, result1.info->visibility());
+
+ Resolver::Result result2;
+ m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ desc,
+ binding,
+ size,
+ other,
+ NULL,
+ result2);
+
+ EXPECT_EQ(result1.info, result2.info);
+
+ Resolver::Result result3;
+ m_pTestee->insertSymbol("Different Symbol",
+ isDyn,
+ type,
+ desc,
+ binding,
+ size,
+ other,
+ NULL,
+ result3);
+
+
+ EXPECT_NE(result1.info, result3.info);
+}
+
+
+TEST_F( NamePoolTest, insertSymbol_after_insert_same_string ) {
+ const char *name = "Hello MCLinker";
+ bool isDyn = false;
+ LDSymbol::Type type = LDSymbol::Defined;
+ LDSymbol::Binding binding = LDSymbol::Global;
+ const llvm::MCSectionData *section = 0;
+ uint64_t value = 0;
+ uint64_t size = 0;
+ uint8_t other = 0;
+
+ const char *result1 = m_pTestee->insertString(name);
+ LDSymbol *sym = m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ binding,
+ section,
+ value,
+ size,
+ other);
+
+ EXPECT_STREQ(name, sym->name());
+ EXPECT_EQ(result1, sym->name());
+
+ char s[16];
+ strcpy(s, result1);
+ const char *result2 = m_pTestee->insertString(result1);
+ const char *result3 = m_pTestee->insertString(s);
+
+ EXPECT_EQ(result1, result2);
+ EXPECT_EQ(result1, result3);
+}
+
+
+TEST_F( NamePoolTest, insert_16384_weak_reference_symbols ) {
+ char name[16];
+ bool isDyn = false;
+ LDSymbol::Type type = LDSymbol::Reference;
+ LDSymbol::Binding binding = LDSymbol::Weak;
+ const llvm::MCSectionData *section = 0;
+ uint64_t value = 0;
+ uint64_t size = 0;
+ uint8_t other = 0;
+ strcpy(name, "Hello MCLinker");
+ LDSymbol *syms[128][128];
+ for(int i=0; i<128 ;++i) {
+ name[0] = i;
+ for(int j=0; j<128 ;++j) {
+ name[1] = j;
+ syms[i][j] = m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ binding,
+ section,
+ value,
+ size,
+ other);
+
+ ASSERT_STREQ(name, syms[i][j]->name());
+ }
+ }
+ for(int i=127; i>=0 ;--i) {
+ name[0] = i;
+ for(int j=0; j<128 ;++j) {
+ name[1] = j;
+ LDSymbol *sym = m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ binding,
+ section,
+ value,
+ size,
+ other);
+ ASSERT_EQ(sym, syms[i][j]);
+ }
+ }
+ for(int i=0; i<128 ;++i) {
+ name[0] = i;
+ for(int j=0; j<128 ;++j) {
+ name[1] = j;
+ LDSymbol *sym = m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ binding,
+ section,
+ value,
+ size,
+ other);
+ ASSERT_EQ(sym, syms[i][j]);
+ }
+ }
+}
diff --git a/unittests/StrSymPoolTest.h b/unittests/NamePoolTest.h
similarity index 73%
rename from unittests/StrSymPoolTest.h
rename to unittests/NamePoolTest.h
index 041fafa..12103e0 100644
--- a/unittests/StrSymPoolTest.h
+++ b/unittests/NamePoolTest.h
@@ -1,4 +1,4 @@
-//===- StrSymPoolTest.h ---------------------------------------------------===//
+//===- NamePoolTest.h ---------------------------------------------------===//
//
// The MCLinker Project
//
@@ -13,26 +13,26 @@
namespace mcld
{
-class StrSymPool;
+class NamePool;
} // namespace for mcld
namespace mcldtest
{
-/** \class StrSymPoolTest
+/** \class NamePoolTest
* \brief
*
- * \see StrSymPool
+ * \see NamePool
*/
-class StrSymPoolTest : public ::testing::Test
+class NamePoolTest : public ::testing::Test
{
public:
// Constructor can do set-up work for all test here.
- StrSymPoolTest();
+ NamePoolTest();
// Destructor can do clean-up work that doesn't throw exceptions here.
- virtual ~StrSymPoolTest();
+ virtual ~NamePoolTest();
// SetUp() will be called immediately before each test.
virtual void SetUp();
@@ -41,7 +41,7 @@
virtual void TearDown();
protected:
- mcld::StrSymPool* m_pTestee;
+ mcld::NamePool* m_pTestee;
};
} // namespace of mcldtest
diff --git a/unittests/StaticResolverTest.cpp b/unittests/StaticResolverTest.cpp
index f9dfdf4..0e1e5c9 100644
--- a/unittests/StaticResolverTest.cpp
+++ b/unittests/StaticResolverTest.cpp
@@ -6,12 +6,22 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include <mcld/Support/TargetSelect.h>
#include <mcld/LD/StaticResolver.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/LD/ResolveInfoFactory.h>
+#include <mcld/LD/DiagnosticPrinter.h>
+#include <mcld/LD/DiagnosticLineInfo.h>
+#include <mcld/LD/TextDiagnosticPrinter.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/MC/MCLDInfo.h>
#include "StaticResolverTest.h"
#include <iostream>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/FileSystem.h>
+#include <mcld/LD/DiagnosticLineInfo.h>
+#include <mcld/LD/TextDiagnosticPrinter.h>
using namespace std;
using namespace mcld;
@@ -23,6 +33,13 @@
// create testee. modify it if need
m_pResolver = new StaticResolver();
m_pFactory = new ResolveInfoFactory();
+ mcld::InitializeAllDiagnostics();
+
+ m_pLDInfo = new MCLDInfo("arm-none-linux-gnueabi", 10, 10);
+ m_pLineInfo = new DiagnosticLineInfo();
+ m_pPrinter = new mcld::DiagnosticPrinter(); //llvm::errs(), *m_pLDInfo);
+ mcld::InitializeDiagnosticEngine(*m_pLDInfo, m_pLineInfo, m_pPrinter);
+
}
// Destructor can do clean-up work that doesn't throw exceptions here.
@@ -30,6 +47,7 @@
{
delete m_pResolver;
delete m_pFactory;
+ delete m_pLDInfo;
}
// SetUp() will be called immediately before each test.
@@ -55,10 +73,9 @@
ASSERT_TRUE( mcld::ResolveInfo::define_flag == new_sym->info());
ASSERT_TRUE( mcld::ResolveInfo::define_flag == old_sym->info());
bool override = true;
- unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
- ASSERT_EQ( Resolver::Abort, result);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_TRUE(result);
ASSERT_FALSE( override );
- ASSERT_STREQ( "multiple definitions of `abc'.", m_pResolver->mesg().c_str() );
}
TEST_F( StaticResolverTest, DynDefAfterDynUndef ) {
@@ -82,8 +99,8 @@
ASSERT_EQ( mcld::ResolveInfo::Define, old_sym->desc());
bool override = false;
- unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
- ASSERT_EQ( Resolver::Success, result);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_TRUE(result);
ASSERT_FALSE( override );
ASSERT_EQ(1, old_sym->size());
}
@@ -109,8 +126,8 @@
ASSERT_EQ( mcld::ResolveInfo::Define, old_sym->desc());
bool override = false;
- unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
- ASSERT_EQ( Resolver::Success, result);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_TRUE(result);
ASSERT_FALSE( override );
ASSERT_EQ(1, old_sym->size());
}
@@ -136,8 +153,8 @@
ASSERT_EQ( mcld::ResolveInfo::Undefined, old_sym->desc());
bool override = false;
- unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
- ASSERT_EQ( Resolver::Success, result);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_TRUE(result);
ASSERT_FALSE( override );
ASSERT_EQ(1, old_sym->size());
}
@@ -158,8 +175,8 @@
ASSERT_TRUE( mcld::ResolveInfo::global_flag == new_sym->info());
ASSERT_TRUE( mcld::ResolveInfo::weak_flag == old_sym->info());
bool override = false;
- unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
- ASSERT_EQ( Resolver::Success, result);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_TRUE(result);
ASSERT_TRUE( override );
ASSERT_EQ(0, old_sym->size());
}
@@ -187,8 +204,8 @@
ASSERT_EQ( mcld::ResolveInfo::Define, new_sym->desc());
bool override = false;
- unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
- ASSERT_EQ( Resolver::Success, result);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_TRUE(result);
ASSERT_FALSE( override );
ASSERT_EQ(1, old_sym->size());
}
@@ -209,8 +226,8 @@
ASSERT_TRUE( mcld::ResolveInfo::common_flag == new_sym->info());
ASSERT_TRUE( mcld::ResolveInfo::common_flag == old_sym->info());
bool override = true;
- unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
- ASSERT_EQ( Resolver::Success, result);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_TRUE(result);
ASSERT_FALSE( override );
ASSERT_EQ(999, old_sym->size());
}
@@ -234,8 +251,8 @@
ASSERT_TRUE( (ResolveInfo::weak_flag | ResolveInfo::common_flag) == old_sym->info());
bool override = false;
- unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
- ASSERT_EQ( Resolver::Success, result);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_TRUE(result);
ASSERT_TRUE( override );
ASSERT_EQ(999, old_sym->size());
}
@@ -258,13 +275,10 @@
ASSERT_TRUE( ResolveInfo::common_flag == old_sym->info());
bool override = false;
- unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
- ASSERT_EQ(Resolver::Warning, result);
+ bool result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_TRUE(result);
ASSERT_TRUE( override );
ASSERT_EQ(999, old_sym->size());
-
- ASSERT_STREQ("definition of 'abc' is overriding common.", m_pResolver->mesg().c_str() );
-
}
TEST_F( StaticResolverTest, SetUpDesc)
diff --git a/unittests/StaticResolverTest.h b/unittests/StaticResolverTest.h
index 8b8ba31..e4ffa50 100644
--- a/unittests/StaticResolverTest.h
+++ b/unittests/StaticResolverTest.h
@@ -10,6 +10,7 @@
#define STATICRESOLVER_TEST_H
#include <gtest.h>
+#include <mcld/MC/MCLDInfo.h>
namespace mcld
{
@@ -29,21 +30,24 @@
class StaticResolverTest : public ::testing::Test
{
public:
- // Constructor can do set-up work for all test here.
- StaticResolverTest();
+ // Constructor can do set-up work for all test here.
+ StaticResolverTest();
- // Destructor can do clean-up work that doesn't throw exceptions here.
- virtual ~StaticResolverTest();
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~StaticResolverTest();
- // SetUp() will be called immediately before each test.
- virtual void SetUp();
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
- // TearDown() will be called immediately after each test.
- virtual void TearDown();
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
protected:
- mcld::StaticResolver* m_pResolver;
- mcld::ResolveInfoFactory* m_pFactory;
+ mcld::StaticResolver* m_pResolver;
+ mcld::ResolveInfoFactory* m_pFactory;
+ mcld::MCLDInfo* m_pLDInfo;
+ mcld::DiagnosticLineInfo* m_pLineInfo;
+ mcld::DiagnosticPrinter* m_pPrinter;
};
} // namespace of mcldtest
diff --git a/unittests/StrSymPoolTest.cpp b/unittests/StrSymPoolTest.cpp
deleted file mode 100644
index a4ef558..0000000
--- a/unittests/StrSymPoolTest.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-//===- StrSymPoolTest.cpp -------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include "mcld/LD/StrSymPool.h"
-#include "StrSymPoolTest.h"
-#include <string>
-#include <cstdio>
-
-using namespace mcld;
-using namespace mcldtest;
-
-
-// Constructor can do set-up work for all test here.
-StrSymPoolTest::StrSymPoolTest()
-{
- // create testee. modify it if need
- Resolver resolver;
- m_pTestee = new StrSymPool(1, 1, resolver);
-}
-
-// Destructor can do clean-up work that doesn't throw exceptions here.
-StrSymPoolTest::~StrSymPoolTest()
-{
- delete m_pTestee;
-}
-
-// SetUp() will be called immediately before each test.
-void StrSymPoolTest::SetUp()
-{
-}
-
-// TearDown() will be called immediately after each test.
-void StrSymPoolTest::TearDown()
-{
-}
-
-//==========================================================================//
-// Testcases
-//
-
-
-TEST_F( StrSymPoolTest, insertString ) {
- const char *s1 = "Hello MCLinker";
- const char *result1 = m_pTestee->insertString(s1);
- EXPECT_NE(s1, result1);
- EXPECT_STREQ(s1, result1);
-}
-
-TEST_F( StrSymPoolTest, insertSameString ) {
- const char *s1 = "Hello MCLinker";
- std::string s2(s1);
- const char *result1 = m_pTestee->insertString(s1);
- const char *result2 = m_pTestee->insertString(s2.c_str());
- EXPECT_STREQ(s1, result1);
- EXPECT_STREQ(s2.c_str(), result2);
- EXPECT_EQ(result1, result2);
-}
-
-TEST_F( StrSymPoolTest, insert_local_defined_Symbol ) {
- const char *name = "Hello MCLinker";
- bool isDyn = false;
- LDSymbol::Type type = LDSymbol::Defined;
- LDSymbol::Binding binding = LDSymbol::Local;
- const llvm::MCSectionData *section = 0;
- uint64_t value = 0;
- uint64_t size = 0;
- uint8_t other = 0;
-
- LDSymbol *sym = m_pTestee->insertSymbol(name,
- isDyn,
- type,
- binding,
- section,
- value,
- size,
- other);
- EXPECT_NE(name, sym->name());
- EXPECT_STREQ(name, sym->name());
- EXPECT_EQ(isDyn, sym->isDyn());
- EXPECT_EQ(type, sym->type());
- EXPECT_EQ(binding, sym->binding());
- EXPECT_EQ(section, sym->section());
- EXPECT_EQ(value, sym->value());
- EXPECT_EQ(size, sym->size());
- EXPECT_EQ(other, sym->other());
-
- LDSymbol *sym2 = m_pTestee->insertSymbol(name,
- isDyn,
- type,
- binding,
- section,
- value,
- size,
- other);
- EXPECT_NE(name, sym2->name());
- EXPECT_STREQ(name, sym2->name());
- EXPECT_EQ(isDyn, sym2->isDyn());
- EXPECT_EQ(type, sym2->type());
- EXPECT_EQ(binding, sym2->binding());
- EXPECT_EQ(section, sym2->section());
- EXPECT_EQ(value, sym2->value());
- EXPECT_EQ(size, sym2->size());
- EXPECT_EQ(other, sym2->other());
-
-
- EXPECT_NE(sym, sym2);
-}
-
-TEST_F( StrSymPoolTest, insert_global_reference_Symbol ) {
- const char *name = "Hello MCLinker";
- bool isDyn = false;
- LDSymbol::Type type = LDSymbol::Reference;
- LDSymbol::Binding binding = LDSymbol::Global;
- const llvm::MCSectionData *section = 0;
- uint64_t value = 0;
- uint64_t size = 0;
- uint8_t other = 0;
-
- LDSymbol *sym = m_pTestee->insertSymbol(name,
- isDyn,
- type,
- binding,
- section,
- value,
- size,
- other);
- EXPECT_NE(name, sym->name());
- EXPECT_STREQ(name, sym->name());
- EXPECT_EQ(isDyn, sym->isDyn());
- EXPECT_EQ(type, sym->type());
- EXPECT_EQ(binding, sym->binding());
- EXPECT_EQ(section, sym->section());
- EXPECT_EQ(value, sym->value());
- EXPECT_EQ(size, sym->size());
- EXPECT_EQ(other, sym->other());
-
-
- LDSymbol *sym2 = m_pTestee->insertSymbol(name,
- isDyn,
- type,
- binding,
- section,
- value,
- size,
- other);
-
-
- EXPECT_EQ(sym, sym2);
-
-
- LDSymbol *sym3 = m_pTestee->insertSymbol("Different symbol",
- isDyn,
- type,
- binding,
- section,
- value,
- size,
- other);
-
- EXPECT_NE(sym, sym3);
-}
-
-
-TEST_F( StrSymPoolTest, insertSymbol_after_insert_same_string ) {
- const char *name = "Hello MCLinker";
- bool isDyn = false;
- LDSymbol::Type type = LDSymbol::Defined;
- LDSymbol::Binding binding = LDSymbol::Global;
- const llvm::MCSectionData *section = 0;
- uint64_t value = 0;
- uint64_t size = 0;
- uint8_t other = 0;
-
- const char *result1 = m_pTestee->insertString(name);
- LDSymbol *sym = m_pTestee->insertSymbol(name,
- isDyn,
- type,
- binding,
- section,
- value,
- size,
- other);
-
- EXPECT_STREQ(name, sym->name());
- EXPECT_EQ(result1, sym->name());
-
- char s[16];
- strcpy(s, result1);
- const char *result2 = m_pTestee->insertString(result1);
- const char *result3 = m_pTestee->insertString(s);
-
- EXPECT_EQ(result1, result2);
- EXPECT_EQ(result1, result3);
-}
-
-
-TEST_F( StrSymPoolTest, insert_16384_weak_reference_symbols ) {
- char name[16];
- bool isDyn = false;
- LDSymbol::Type type = LDSymbol::Reference;
- LDSymbol::Binding binding = LDSymbol::Weak;
- const llvm::MCSectionData *section = 0;
- uint64_t value = 0;
- uint64_t size = 0;
- uint8_t other = 0;
- strcpy(name, "Hello MCLinker");
- LDSymbol *syms[128][128];
- for(int i=0; i<128 ;++i) {
- name[0] = i;
- for(int j=0; j<128 ;++j) {
- name[1] = j;
- syms[i][j] = m_pTestee->insertSymbol(name,
- isDyn,
- type,
- binding,
- section,
- value,
- size,
- other);
-
- ASSERT_STREQ(name, syms[i][j]->name());
- }
- }
- for(int i=127; i>=0 ;--i) {
- name[0] = i;
- for(int j=0; j<128 ;++j) {
- name[1] = j;
- LDSymbol *sym = m_pTestee->insertSymbol(name,
- isDyn,
- type,
- binding,
- section,
- value,
- size,
- other);
- ASSERT_EQ(sym, syms[i][j]);
- }
- }
- for(int i=0; i<128 ;++i) {
- name[0] = i;
- for(int j=0; j<128 ;++j) {
- name[1] = j;
- LDSymbol *sym = m_pTestee->insertSymbol(name,
- isDyn,
- type,
- binding,
- section,
- value,
- size,
- other);
- ASSERT_EQ(sym, syms[i][j]);
- }
- }
-}
diff --git a/unittests/UniqueGCFactoryBaseTest.cpp b/unittests/UniqueGCFactoryBaseTest.cpp
index 08f82ba..328e924 100644
--- a/unittests/UniqueGCFactoryBaseTest.cpp
+++ b/unittests/UniqueGCFactoryBaseTest.cpp
@@ -6,8 +6,11 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/MC/ContextFactory.h"
-#include "mcld/Support/MemoryAreaFactory.h"
+#include <mcld/MC/ContextFactory.h>
+#include <mcld/Support/MemoryAreaFactory.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/TargetSelect.h>
+#include <mcld/Support/Path.h>
#include "UniqueGCFactoryBaseTest.h"
using namespace mcld;
@@ -17,6 +20,12 @@
// Constructor can do set-up work for all test here.
UniqueGCFactoryBaseTest::UniqueGCFactoryBaseTest()
{
+ InitializeAllDiagnostics();
+
+ m_pLDInfo = new MCLDInfo("arm-none-linux-gnueabi", 10, 10);
+ m_pLineInfo = new DiagnosticLineInfo();
+ m_pPrinter = new mcld::DiagnosticPrinter(); //llvm::errs(), *m_pLDInfo);
+ mcld::InitializeDiagnosticEngine(*m_pLDInfo, m_pLineInfo, m_pPrinter);
}
// Destructor can do clean-up work that doesn't throw exceptions here.
@@ -67,12 +76,18 @@
TEST_F( UniqueGCFactoryBaseTest, iterator )
{
+ sys::fs::Path path1(TOPDIR), path2(TOPDIR);
+ path1.append("unittests/test1.txt");
+ path2.append("unittests/test2.txt");
+
MemoryAreaFactory* memFactory = new MemoryAreaFactory(10);
- MemoryArea* area1 = memFactory->produce("/home/luba", O_RDONLY);
- MemoryArea* area2 = memFactory->produce("/home/jush", O_RDONLY);
+ MemoryArea* area1 = memFactory->produce(path1, FileHandle::ReadOnly);
+ MemoryArea* area2 = memFactory->produce(path2, FileHandle::ReadOnly);
ASSERT_NE( area1, area2);
- MemoryArea* area3 = memFactory->produce("/home/jush/../luba", O_RDONLY);
- ASSERT_EQ( area1, area3);
+
+ MemoryArea* area3 = memFactory->produce(path1, FileHandle::ReadOnly);
+
+ ASSERT_EQ(area1, area3);
ASSERT_FALSE( memFactory->empty());
ASSERT_EQ( 2, memFactory->size());
MemoryAreaFactory::iterator aIter = memFactory->begin();
diff --git a/unittests/UniqueGCFactoryBaseTest.h b/unittests/UniqueGCFactoryBaseTest.h
index a1558e7..525c8c4 100644
--- a/unittests/UniqueGCFactoryBaseTest.h
+++ b/unittests/UniqueGCFactoryBaseTest.h
@@ -9,7 +9,10 @@
#ifndef UNIQUE_GCFACTORYBASE_TEST_H
#define UNIQUE_GCFACTORYBASE_TEST_H
-#include "mcld/Support/UniqueGCFactory.h"
+#include <mcld/Support/UniqueGCFactory.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/LD/DiagnosticPrinter.h>
+#include <mcld/LD/DiagnosticLineInfo.h>
#include <gtest.h>
namespace mcldtest
@@ -34,6 +37,11 @@
// TearDown() will be called immediately after each test.
virtual void TearDown();
+
+private:
+ mcld::MCLDInfo* m_pLDInfo;
+ mcld::DiagnosticLineInfo* m_pLineInfo;
+ mcld::DiagnosticPrinter* m_pPrinter;
};
} // namespace of mcldtest