summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hines <srhines@google.com>2013-03-04 19:51:03 -0800
committerStephen Hines <srhines@google.com>2013-03-04 20:01:30 -0800
commit6f75755c9204b1d8817ae5a65a2f7e5af0ec3f70 (patch)
tree35a64dc0a0ad870f64fae2c88f4357d88270def8
parent86036a3bd999904d071826b2f0a84023e28aeebc (diff)
downloadmclinker-tools_r22.2.tar.gz
Change-Id: Ibae073aefc7838fce46875a6bf6ce7b7e18eced8 Date: Mon Mar 4 22:29:06 2013 +0100
-rw-r--r--include/mcld/ADT/BinTree.h8
-rw-r--r--include/mcld/ADT/SizeTraits.h45
-rw-r--r--include/mcld/ADT/TreeAllocator.h4
-rw-r--r--include/mcld/ADT/TreeBase.h2
-rw-r--r--include/mcld/Config/Config.h.in83
-rw-r--r--include/mcld/Fragment/FGNode.h91
-rw-r--r--include/mcld/Fragment/FragmentGraph.h177
-rw-r--r--include/mcld/Fragment/FragmentLinker.h113
-rw-r--r--include/mcld/Fragment/FragmentLinker.tcc68
-rw-r--r--include/mcld/Fragment/Relocation.h12
-rw-r--r--include/mcld/GeneralOptions.h90
-rw-r--r--include/mcld/IRBuilder.h116
-rw-r--r--include/mcld/LD/BinaryWriter.h39
-rw-r--r--include/mcld/LD/DiagCommonKinds.inc7
-rw-r--r--include/mcld/LD/DynObjWriter.h44
-rw-r--r--include/mcld/LD/ELFBinaryWriter.h46
-rw-r--r--include/mcld/LD/ELFDynObjWriter.h47
-rw-r--r--include/mcld/LD/ELFExecWriter.h47
-rw-r--r--include/mcld/LD/ELFFileFormat.h14
-rw-r--r--include/mcld/LD/ELFObjectWriter.h94
-rw-r--r--include/mcld/LD/ELFReader.h142
-rw-r--r--include/mcld/LD/ELFReaderIf.h132
-rw-r--r--include/mcld/LD/ELFWriter.h124
-rw-r--r--include/mcld/LD/EhFrame.h29
-rw-r--r--include/mcld/LD/EhFrameHdr.h3
-rw-r--r--include/mcld/LD/ExecWriter.h44
-rw-r--r--include/mcld/LD/LDSymbol.h3
-rw-r--r--include/mcld/LD/LDWriter.h39
-rw-r--r--include/mcld/LD/NamePool.h15
-rw-r--r--include/mcld/LD/ObjectWriter.h3
-rw-r--r--include/mcld/LD/Relocator.h27
-rw-r--r--include/mcld/LD/StubFactory.h4
-rw-r--r--include/mcld/Linker.h13
-rw-r--r--include/mcld/LinkerConfig.h30
-rw-r--r--include/mcld/MC/SearchDirs.h2
-rw-r--r--include/mcld/MC/SymbolCategory.h50
-rw-r--r--include/mcld/Object/ObjectBuilder.h8
-rw-r--r--include/mcld/Object/ObjectLinker.h42
-rw-r--r--include/mcld/Support/FileHandle.h6
-rw-r--r--include/mcld/Support/MemoryArea.h2
-rw-r--r--include/mcld/Support/PathCache.h2
-rw-r--r--include/mcld/Target/ELFDynamic.h37
-rw-r--r--include/mcld/Target/ELFDynamic.tcc28
-rw-r--r--include/mcld/Target/GNUInfo.h27
-rw-r--r--include/mcld/Target/GNULDBackend.h162
-rw-r--r--include/mcld/Target/TargetLDBackend.h57
-rw-r--r--lib/CodeGen/MCLDTargetMachine.cpp4
-rw-r--r--lib/CodeGen/MCLinker.cpp1
-rw-r--r--lib/Core/GeneralOptions.cpp13
-rw-r--r--lib/Core/IRBuilder.cpp208
-rw-r--r--lib/Core/Linker.cpp86
-rw-r--r--lib/Core/LinkerConfig.cpp6
-rw-r--r--lib/Fragment/Android.mk1
-rw-r--r--lib/Fragment/FGNode.cpp40
-rw-r--r--lib/Fragment/FragmentGraph.cpp412
-rw-r--r--lib/Fragment/FragmentLinker.cpp253
-rw-r--r--lib/Fragment/Relocation.cpp5
-rw-r--r--lib/LD/Android.mk10
-rw-r--r--lib/LD/Archive.cpp5
-rw-r--r--lib/LD/BinaryWriter.cpp24
-rw-r--r--lib/LD/DiagnosticEngine.cpp3
-rw-r--r--lib/LD/DiagnosticInfos.cpp7
-rw-r--r--lib/LD/DynObjWriter.cpp16
-rw-r--r--lib/LD/ELFBinaryReader.cpp15
-rw-r--r--lib/LD/ELFBinaryWriter.cpp110
-rw-r--r--lib/LD/ELFDynObjFileFormat.cpp19
-rw-r--r--lib/LD/ELFDynObjReader.cpp2
-rw-r--r--lib/LD/ELFDynObjWriter.cpp144
-rw-r--r--lib/LD/ELFExecFileFormat.cpp9
-rw-r--r--lib/LD/ELFExecWriter.cpp144
-rw-r--r--lib/LD/ELFFileFormat.cpp3
-rw-r--r--lib/LD/ELFObjectReader.cpp3
-rw-r--r--lib/LD/ELFObjectWriter.cpp701
-rw-r--r--lib/LD/ELFReader.cpp685
-rw-r--r--lib/LD/ELFReaderIf.cpp164
-rw-r--r--lib/LD/ELFWriter.cpp600
-rw-r--r--lib/LD/EhFrame.cpp46
-rw-r--r--lib/LD/EhFrameHdr.cpp6
-rw-r--r--lib/LD/ExecWriter.cpp16
-rw-r--r--lib/LD/GNUArchiveReader.cpp4
-rw-r--r--lib/LD/LDSymbol.cpp15
-rw-r--r--lib/LD/LDWriter.cpp15
-rw-r--r--lib/LD/NamePool.cpp32
-rw-r--r--lib/LD/ObjectWriter.cpp4
-rw-r--r--lib/LD/RelocationFactory.cpp10
-rw-r--r--lib/LD/Relocator.cpp (renamed from lib/LD/LDObjectWriter.cpp)16
-rw-r--r--lib/LD/ResolveInfo.cpp1
-rw-r--r--lib/LD/StubFactory.cpp9
-rw-r--r--lib/MC/MCLDInput.cpp3
-rw-r--r--lib/MC/SearchDirs.cpp11
-rw-r--r--lib/MC/SymbolCategory.cpp237
-rw-r--r--lib/Object/ObjectBuilder.cpp30
-rw-r--r--lib/Object/ObjectLinker.cpp238
-rw-r--r--lib/Support/Directory.cpp15
-rw-r--r--lib/Support/FileHandle.cpp16
-rw-r--r--lib/Support/FileSystem.cpp1
-rw-r--r--lib/Support/MemoryArea.cpp35
-rw-r--r--lib/Support/Path.cpp1
-rw-r--r--lib/Support/SystemUtils.cpp1
-rw-r--r--lib/Support/UniqueGCFactory.cpp15
-rw-r--r--lib/Support/Unix/PathV3.inc4
-rw-r--r--lib/Support/raw_ostream.cpp1
-rw-r--r--lib/Target/ARM/ARMELFArchiveReader.cpp14
-rw-r--r--lib/Target/ARM/ARMELFArchiveReader.h29
-rw-r--r--lib/Target/ARM/ARMGNUInfo.h5
-rw-r--r--lib/Target/ARM/ARMLDBackend.cpp253
-rw-r--r--lib/Target/ARM/ARMLDBackend.h60
-rw-r--r--lib/Target/ARM/ARMRelocator.cpp7
-rw-r--r--lib/Target/ARM/ARMRelocator.h2
-rw-r--r--lib/Target/DarwinLDBackend.cpp15
-rw-r--r--lib/Target/ELFDynamic.cpp61
-rw-r--r--lib/Target/ELFEmulation.cpp15
-rw-r--r--lib/Target/GNULDBackend.cpp1114
-rw-r--r--lib/Target/Hexagon/Hexagon.h32
-rw-r--r--lib/Target/Hexagon/HexagonDiagnostic.cpp37
-rw-r--r--lib/Target/Hexagon/HexagonELFDynamic.cpp37
-rw-r--r--lib/Target/Hexagon/HexagonELFDynamic.h32
-rw-r--r--lib/Target/Hexagon/HexagonELFMCLinker.cpp23
-rw-r--r--lib/Target/Hexagon/HexagonELFMCLinker.h38
-rw-r--r--lib/Target/Hexagon/HexagonEmulation.cpp65
-rw-r--r--lib/Target/Hexagon/HexagonGNUInfo.h33
-rw-r--r--lib/Target/Hexagon/HexagonGOT.cpp48
-rw-r--r--lib/Target/Hexagon/HexagonGOT.h55
-rw-r--r--lib/Target/Hexagon/HexagonLDBackend.cpp270
-rw-r--r--lib/Target/Hexagon/HexagonLDBackend.h149
-rw-r--r--lib/Target/Hexagon/HexagonMCLinker.cpp53
-rw-r--r--lib/Target/Hexagon/HexagonPLT.cpp97
-rw-r--r--lib/Target/Hexagon/HexagonPLT.h84
-rw-r--r--lib/Target/Hexagon/HexagonRelocationFunctions.h113
-rw-r--r--lib/Target/Hexagon/HexagonRelocator.cpp259
-rw-r--r--lib/Target/Hexagon/HexagonRelocator.h66
-rw-r--r--lib/Target/Hexagon/HexagonTargetMachine.cpp29
-rw-r--r--lib/Target/Hexagon/HexagonTargetMachine.h28
-rw-r--r--lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp22
-rw-r--r--lib/Target/Mips/MipsGNUInfo.h26
-rw-r--r--lib/Target/Mips/MipsLDBackend.cpp274
-rw-r--r--lib/Target/Mips/MipsLDBackend.h42
-rw-r--r--lib/Target/Mips/MipsRelocationFunctions.h104
-rw-r--r--lib/Target/Mips/MipsRelocator.cpp8
-rw-r--r--lib/Target/Mips/MipsRelocator.h2
-rw-r--r--lib/Target/OutputRelocSection.cpp2
-rw-r--r--lib/Target/X86/TargetInfo/X86TargetInfo.cpp6
-rw-r--r--lib/Target/X86/X86.h3
-rw-r--r--lib/Target/X86/X86Diagnostic.cpp3
-rw-r--r--lib/Target/X86/X86Emulation.cpp15
-rw-r--r--lib/Target/X86/X86GNUInfo.h25
-rw-r--r--lib/Target/X86/X86GOT.cpp47
-rw-r--r--lib/Target/X86/X86GOT.h50
-rw-r--r--lib/Target/X86/X86GOTPLT.cpp63
-rw-r--r--lib/Target/X86/X86GOTPLT.h37
-rw-r--r--lib/Target/X86/X86LDBackend.cpp1006
-rw-r--r--lib/Target/X86/X86LDBackend.h200
-rw-r--r--lib/Target/X86/X86MCLinker.cpp9
-rw-r--r--lib/Target/X86/X86PLT.cpp182
-rw-r--r--lib/Target/X86/X86PLT.h111
-rw-r--r--lib/Target/X86/X86RelocationFunctions.h179
-rw-r--r--lib/Target/X86/X86Relocator.cpp496
-rw-r--r--lib/Target/X86/X86Relocator.h79
-rw-r--r--lib/Target/X86/X86TargetMachine.cpp3
-rw-r--r--tools/llvm-mcld/llvm-mcld.cpp249
-rw-r--r--tools/mcld/main.cpp6
-rw-r--r--unittests/ELFReaderTest.cpp162
-rw-r--r--unittests/ELFReaderTest.h56
-rw-r--r--unittests/FileHandleTest.cpp7
-rw-r--r--unittests/LinkerTest.cpp42
-rw-r--r--unittests/SymbolCategoryTest.cpp8
-rw-r--r--unittests/test8
-rw-r--r--unittests/test_x86_64.obin0 -> 1496 bytes
168 files changed, 8854 insertions, 4454 deletions
diff --git a/include/mcld/ADT/BinTree.h b/include/mcld/ADT/BinTree.h
index f015ac8..76de607 100644
--- a/include/mcld/ADT/BinTree.h
+++ b/include/mcld/ADT/BinTree.h
@@ -12,8 +12,9 @@
#include <gtest.h>
#endif
-#include "mcld/ADT/Uncopyable.h"
-#include "mcld/ADT/TreeAllocator.h"
+#include <mcld/ADT/Uncopyable.h>
+#include <mcld/ADT/TreeBase.h>
+#include <mcld/ADT/TreeAllocator.h>
#include <cstddef>
#include <iterator>
@@ -21,8 +22,7 @@
#include <queue>
#include <stack>
-namespace mcld
-{
+namespace mcld {
template<class DataType>
class BinaryTree;
diff --git a/include/mcld/ADT/SizeTraits.h b/include/mcld/ADT/SizeTraits.h
index c8822cf..dbd5d7b 100644
--- a/include/mcld/ADT/SizeTraits.h
+++ b/include/mcld/ADT/SizeTraits.h
@@ -13,6 +13,7 @@
#endif
#include <llvm/Support/DataTypes.h>
+#include <llvm/Support/ELF.h>
namespace mcld
{
@@ -40,6 +41,50 @@ public:
typedef int64_t SWord;
};
+// FIXME: move this to mcld internal ELF header file?
+template<size_t SIZE>
+class ELFSizeTraits;
+
+template<>
+class ELFSizeTraits<32>
+{
+public:
+ typedef llvm::ELF::Elf32_Addr Addr; // Program address
+ typedef llvm::ELF::Elf32_Off Off; // File offset
+ typedef llvm::ELF::Elf32_Half Half;
+ typedef llvm::ELF::Elf32_Word Word;
+ typedef llvm::ELF::Elf32_Sword Sword;
+
+ typedef llvm::ELF::Elf32_Ehdr Ehdr;
+ typedef llvm::ELF::Elf32_Shdr Shdr;
+ typedef llvm::ELF::Elf32_Sym Sym;
+ typedef llvm::ELF::Elf32_Rel Rel;
+ typedef llvm::ELF::Elf32_Rela Rela;
+ typedef llvm::ELF::Elf32_Phdr Phdr;
+ typedef llvm::ELF::Elf32_Dyn Dyn;
+};
+
+template<>
+class ELFSizeTraits<64>
+{
+public:
+ typedef llvm::ELF::Elf64_Addr Addr;
+ typedef llvm::ELF::Elf64_Off Off;
+ typedef llvm::ELF::Elf64_Half Half;
+ typedef llvm::ELF::Elf64_Word Word;
+ typedef llvm::ELF::Elf64_Sword Sword;
+ typedef llvm::ELF::Elf64_Xword Xword;
+ typedef llvm::ELF::Elf64_Sxword Sxword;
+
+ typedef llvm::ELF::Elf64_Ehdr Ehdr;
+ typedef llvm::ELF::Elf64_Shdr Shdr;
+ typedef llvm::ELF::Elf64_Sym Sym;
+ typedef llvm::ELF::Elf64_Rel Rel;
+ typedef llvm::ELF::Elf64_Rela Rela;
+ typedef llvm::ELF::Elf64_Phdr Phdr;
+ typedef llvm::ELF::Elf64_Dyn Dyn;
+};
+
/// alignAddress - helper function to align an address with given alignment
/// constraint
///
diff --git a/include/mcld/ADT/TreeAllocator.h b/include/mcld/ADT/TreeAllocator.h
index 899896c..10de761 100644
--- a/include/mcld/ADT/TreeAllocator.h
+++ b/include/mcld/ADT/TreeAllocator.h
@@ -13,10 +13,8 @@
#endif
#include <set>
#include "mcld/Support/GCFactory.h"
-#include "mcld/ADT/TreeBase.h"
-namespace mcld
-{
+namespace mcld {
/** \class NodeFactory
* \brief NodeFactory manages the creation and destruction of mcld::Node.
diff --git a/include/mcld/ADT/TreeBase.h b/include/mcld/ADT/TreeBase.h
index 6fb3bf6..13eb474 100644
--- a/include/mcld/ADT/TreeBase.h
+++ b/include/mcld/ADT/TreeBase.h
@@ -11,6 +11,8 @@
#include "mcld/ADT/TypeTraits.h"
#include <cstddef>
+#include <cassert>
+#include <iterator>
namespace mcld {
diff --git a/include/mcld/Config/Config.h.in b/include/mcld/Config/Config.h.in
index 7b55240..1967ca1 100644
--- a/include/mcld/Config/Config.h.in
+++ b/include/mcld/Config/Config.h.in
@@ -1,3 +1,6 @@
+/* include/mcld/Config/Config.h.in. Generated from configure.ac by autoheader. */
+
+
//===- Config.h.in --------------------------------------------------------===//
//
// The MCLinker Project
@@ -9,8 +12,84 @@
#ifndef MCLD_CONFIG_H
#define MCLD_CONFIG_H
-#define @MCLD_ON_PLATFORM@ 1
-#define MCLD_VERSION "@MCLD_VERSION@"
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if you have POSIX threads libraries and header files. */
+#undef HAVE_PTHREAD
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if this is Unixish platform */
+#undef MCLD_ON_UNIX
+
+/* Define if this is Win32ish platform */
+#undef MCLD_ON_WIN32
+
+/* MCLINKER version */
+#undef MCLD_VERSION
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+#undef PTHREAD_CREATE_JOINABLE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define for standalone Android linker */
+#undef TARGET_BUILD
+
+/* Version number of package */
+#undef VERSION
+
+
#define MCLD_REGION_CHUNK_SIZE 32
#define MCLD_NUM_OF_INPUTS 32
#define MCLD_SECTIONS_PER_INPUT 16
diff --git a/include/mcld/Fragment/FGNode.h b/include/mcld/Fragment/FGNode.h
new file mode 100644
index 0000000..0afee0e
--- /dev/null
+++ b/include/mcld/Fragment/FGNode.h
@@ -0,0 +1,91 @@
+//===- FGNode.h -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_FGNODE_H
+#define MCLD_FGNODE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/DataTypes.h>
+
+#include <vector>
+
+namespace mcld
+{
+
+class Relocation;
+class ResolveInfo;
+class Fragment;
+
+/** \class FGNode
+ * \brief FGNode is a node for FragmentGraph
+ */
+class FGNode
+{
+public:
+ typedef ResolveInfo* Slot;
+ typedef Relocation* Signal;
+
+ typedef std::vector<Fragment*> FragmentListType;
+ typedef FragmentListType::iterator frag_iterator;
+ typedef FragmentListType::const_iterator const_frag_iterator;
+
+ typedef std::vector<Slot> SlotListType;
+ typedef SlotListType::iterator slot_iterator;
+ typedef SlotListType::const_iterator const_slot_iterator;
+
+ typedef std::vector<Signal> SignalListType;
+ typedef SignalListType::iterator signal_iterator;
+ typedef SignalListType::const_iterator const_signal_iterator;
+
+public:
+ FGNode();
+ explicit FGNode(uint32_t pIndex);
+
+ void addFragment(Fragment* pFrag);
+ void addSignal(Signal pSignal);
+ void addSlot(Slot pSlot);
+
+ /// ----- observers ----- ///
+ uint32_t getIndex() const
+ { return m_Index; }
+
+ slot_iterator slot_begin () { return m_Slots.begin(); }
+ const_slot_iterator slot_begin () const { return m_Slots.begin(); }
+ slot_iterator slot_end () { return m_Slots.end(); }
+ const_slot_iterator slot_end () const { return m_Slots.end(); }
+
+ signal_iterator signal_begin () { return m_Signals.begin(); }
+ const_signal_iterator signal_begin () const { return m_Signals.begin(); }
+ signal_iterator signal_end () { return m_Signals.end(); }
+ const_signal_iterator signal_end () const { return m_Signals.end(); }
+
+ frag_iterator frag_begin () { return m_Fragments.begin(); }
+ const_frag_iterator frag_begin () const { return m_Fragments.begin(); }
+ frag_iterator frag_end () { return m_Fragments.end(); }
+ const_frag_iterator frag_end () const { return m_Fragments.end(); }
+
+private:
+ FragmentListType m_Fragments;
+
+ /// m_Signals - a list of relocations describes the possible fan-out of this
+ /// node
+ SignalListType m_Signals;
+
+ /// m_Slots - a list of symbols describes the possible fan-in of this node
+ SlotListType m_Slots;
+
+ /// m_Index - the index in the reachability matrix
+ uint32_t m_Index;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Fragment/FragmentGraph.h b/include/mcld/Fragment/FragmentGraph.h
new file mode 100644
index 0000000..96d438f
--- /dev/null
+++ b/include/mcld/Fragment/FragmentGraph.h
@@ -0,0 +1,177 @@
+//===- FragmentGraph.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_FRAGMENTGRAPH_H
+#define MCLD_FRAGMENTGRAPH_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <vector>
+
+#include <mcld/ADT/HashTable.h>
+#include <mcld/ADT/HashEntry.h>
+#include <mcld/Config/Config.h>
+#include <mcld/Fragment/FGNode.h>
+#include <mcld/Fragment/FGEdge.h>
+#include <mcld/Support/GCFactory.h>
+
+#include <llvm/Support/DataTypes.h>
+
+namespace mcld
+{
+class Module;
+class ResolveInfo;
+class Relocation;
+class LinkerConfig;
+
+/** \class FragmentGraph
+ * \brief FragmentGraph describes the references between fragments.
+ */
+class FragmentGraph
+{
+public:
+ typedef FGNode::Slot Slot;
+ typedef FGNode::Signal Signal;
+
+ typedef GCFactory<FGNode, MCLD_SECTIONS_PER_INPUT> NodeFactoryType;
+ typedef NodeFactoryType::iterator node_iterator;
+ typedef NodeFactoryType::const_iterator const_node_iterator;
+
+ typedef std::vector<FGEdge> EdgeListType;
+ typedef EdgeListType::iterator edge_iterator;
+ typedef EdgeListType::const_iterator const_edge_iterator;
+
+
+public:
+ FragmentGraph();
+ ~FragmentGraph();
+
+ /// construct - construct the whole graph from input Fragments, relocations
+ /// and symbols
+ bool construct(const LinkerConfig& pConfig, Module& pModule);
+
+ /// connect - connect two nodes
+ bool connect(Signal pSignal, Slot pSlot);
+ bool connect(FGNode& pFrom, Slot pSlot);
+
+ /// getEdges - given a node, get the list of edges which are the fan-out of
+ /// this node
+ /// @param pEdges - the edge list which contains the found edges
+ /// @return false - the given node
+ bool getEdges(FGNode& pNode, EdgeListType& pEdges);
+
+ /// ----- observers -----///
+ /// getNode - given a fragment, finde the node which the fragment is belong to
+ FGNode* getNode(const Fragment& pFrag);
+ const FGNode* getNode(const Fragment& pFrag) const;
+
+ FGNode* getNode(const ResolveInfo& pSym);
+ const FGNode* getNode(const ResolveInfo& pSym) const;
+
+private:
+ typedef std::vector<Relocation*> RelocationListType;
+ typedef RelocationListType::iterator reloc_iterator;
+ typedef RelocationListType::const_iterator const_reloc_iterator;
+
+ struct PtrCompare
+ {
+ bool operator()(const void* X, const void* Y) const
+ { return (X==Y); }
+ };
+
+ struct PtrHash
+ {
+ size_t operator()(const void* pKey) const
+ {
+ return (unsigned((uintptr_t)pKey) >> 4) ^
+ (unsigned((uintptr_t)pKey) >> 9);
+ }
+ };
+
+ /// HashTable for Fragment* to Node*
+ typedef HashEntry<const Fragment*, FGNode*, PtrCompare> FragHashEntryType;
+ typedef HashTable<FragHashEntryType,
+ PtrHash,
+ EntryFactory<FragHashEntryType> > FragHashTableType;
+
+ /// HashTable for ResolveInfo* to Node*
+ typedef HashEntry<const ResolveInfo*, FGNode*, PtrCompare> SymHashEntryType;
+ typedef HashTable<SymHashEntryType,
+ PtrHash,
+ EntryFactory<SymHashEntryType> > SymHashTableType;
+
+ /** \class ReachMatrix
+ * \brief ReachMatrix is the reachability matrix which describes the relation
+ * of Nodes in FragmentGraph
+ */
+ class ReachMatrix
+ {
+ public:
+ typedef std::vector<uint32_t> MatrixDataType;
+
+ public:
+ ReachMatrix(size_t pSize);
+ ~ReachMatrix();
+ uint32_t& at(uint32_t pX, uint32_t pY);
+ uint32_t at(uint32_t pX, uint32_t pY) const;
+
+ uint32_t getN() const
+ { return m_N; }
+
+ void print();
+
+ private:
+ // m_Data - the contents of the matrix. Here we use a one dimensional array
+ // to represent the two dimensional matrix
+ MatrixDataType m_Data;
+
+ // m_N - this is an m_N x m_N matrix
+ size_t m_N;
+ };
+
+private:
+ FGNode* producePseudoNode();
+ FGNode* produceRegularNode();
+ void destroyPseudoNode();
+ void destroyRegularNode();
+
+ void initMatrix();
+
+ bool createRegularNodes(Module& pModule);
+ bool setNodeSlots(Module& pModule);
+ bool createPseudoNodes(Module& pModule);
+
+ bool createRegularEdges(Module& pModule);
+ bool createPseudoEdges(Module& pModule);
+
+private:
+ NodeFactoryType* m_pPseudoNodeFactory;
+ NodeFactoryType* m_pRegularNodeFactory;
+
+ /// m_pFragNodeMap - HashTable to map the fragment to the node it belongs to
+ FragHashTableType* m_pFragNodeMap;
+
+ /// m_pSymNodeMap - HashTable to map the ResolveInfo to the node. The node is
+ /// the pseudo node which the contains it's fan-out is to the ResolveInfo
+ SymHashTableType* m_pSymNodeMap;
+
+ ReachMatrix* m_pMatrix;
+
+ /// m_NumOfPNodes - number of pseudo nodes
+ size_t m_NumOfPNodes;
+ /// m_NumOfRNodes - number of regular nodes
+ size_t m_NumOfRNodes;
+ /// m_NumOfEdges - number of edges
+ size_t m_NumOfEdges;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Fragment/FragmentLinker.h b/include/mcld/Fragment/FragmentLinker.h
index 17e80bd..45ef85d 100644
--- a/include/mcld/Fragment/FragmentLinker.h
+++ b/include/mcld/Fragment/FragmentLinker.h
@@ -30,14 +30,7 @@ namespace mcld {
class Module;
class TargetLDBackend;
class LinkerConfig;
-class LDSection;
-class LDSectionFactory;
-class SectionData;
-class Output;
-class EhFrame;
-class EhFrameHdr;
class MemoryArea;
-class RelocData;
/** \class FragmentLinker
* \brief FragmentLinker provides a pass to link object files.
@@ -45,56 +38,12 @@ class RelocData;
class FragmentLinker
{
public:
- enum DefinePolicy
- {
- Force,
- AsRefered
- };
-
- enum ResolvePolicy
- {
- Unresolve,
- Resolve
- };
-
-public:
FragmentLinker(const LinkerConfig& pConfig,
Module& pModule,
TargetLDBackend& pBackend);
~FragmentLinker();
- // ----- about symbols ----- //
- /// defineSymbol - add a symbol
- /// defineSymbol define a output symbol
- ///
- /// @tparam POLICY idicate how to define the symbol.
- /// - Force
- /// - Define the symbol forcefully. If the symbol has existed, override
- /// it. Otherwise, define it.
- /// - AsRefered
- /// - If the symbol has existed, override it. Otherwise, return NULL
- /// immediately.
- ///
- /// @tparam RESOLVE indicate whether to resolve the symbol or not.
- /// - Unresolve
- /// - Do not resolve the symbol, and override the symbol immediately.
- /// - Resolve
- /// - Resolve the defined symbol.
- ///
- /// @return If the output symbol has existed, return it. Otherwise, create
- /// a new symbol and return the new one.
- template<DefinePolicy POLICY, ResolvePolicy RESOLVE>
- LDSymbol* defineSymbol(const llvm::StringRef& pName,
- bool pIsDyn,
- ResolveInfo::Type pType,
- ResolveInfo::Desc pDesc,
- ResolveInfo::Binding pBinding,
- ResolveInfo::SizeType pSize,
- LDSymbol::ValueType pValue,
- FragmentRef* pFragmentRef,
- ResolveInfo::Visibility pVisibility = ResolveInfo::Default);
-
bool finalizeSymbols();
/// applyRelocations - apply all relocation enties.
@@ -104,67 +53,7 @@ public:
/// data to output file.
void syncRelocationResult(MemoryArea& pOutput);
- // ----- capacity ----- //
- const LinkerConfig& getLDInfo() const { return m_Config; }
-
- // ----- output attribute ----- //
- /// isOutputPIC - return whether the output is position-independent
- bool isOutputPIC() const;
-
- /// isStaticLink - return whether we're doing static link
- bool isStaticLink() const;
-
private:
- LDSymbol* defineSymbolForcefully(const llvm::StringRef& pName,
- bool pIsDyn,
- ResolveInfo::Type pType,
- ResolveInfo::Desc pDesc,
- ResolveInfo::Binding pBinding,
- ResolveInfo::SizeType pSize,
- LDSymbol::ValueType pValue,
- FragmentRef* pFragmentRef,
- ResolveInfo::Visibility pVisibility);
-
- LDSymbol* defineAndResolveSymbolForcefully(const llvm::StringRef& pName,
- bool pIsDyn,
- ResolveInfo::Type pType,
- ResolveInfo::Desc pDesc,
- ResolveInfo::Binding pBinding,
- ResolveInfo::SizeType pSize,
- LDSymbol::ValueType pValue,
- FragmentRef* pFragmentRef,
- ResolveInfo::Visibility pVisibility);
-
- LDSymbol* defineSymbolAsRefered(const llvm::StringRef& pName,
- bool pIsDyn,
- ResolveInfo::Type pType,
- ResolveInfo::Desc pDesc,
- ResolveInfo::Binding pBinding,
- ResolveInfo::SizeType pSize,
- LDSymbol::ValueType pValue,
- FragmentRef* pFragmentRef,
- ResolveInfo::Visibility pVisibility);
-
- LDSymbol* defineAndResolveSymbolAsRefered(const llvm::StringRef& pName,
- bool pIsDyn,
- ResolveInfo::Type pType,
- ResolveInfo::Desc pDesc,
- ResolveInfo::Binding pBinding,
- ResolveInfo::SizeType pSize,
- LDSymbol::ValueType pValue,
- FragmentRef* pFragmentRef,
- ResolveInfo::Visibility pVisibility);
-
- bool shouldForceLocal(const ResolveInfo& pInfo) const;
-
- /// checkIsOutputPIC - return whether the output is position-independent,
- /// called by isOutputPIC()
- bool checkIsOutputPIC() const;
-
- /// checkIsStaticLink - return whether we're doing static link, called by
- /// isStaticLink()
- bool checkIsStaticLink() const;
-
/// normalSyncRelocationResult - sync relocation result when producing shared
/// objects or executables
void normalSyncRelocationResult(MemoryArea& pOutput);
@@ -183,8 +72,6 @@ private:
TargetLDBackend& m_Backend;
};
-#include "FragmentLinker.tcc"
-
} // namespace of mcld
#endif
diff --git a/include/mcld/Fragment/FragmentLinker.tcc b/include/mcld/Fragment/FragmentLinker.tcc
deleted file mode 100644
index cc3fad6..0000000
--- a/include/mcld/Fragment/FragmentLinker.tcc
+++ /dev/null
@@ -1,68 +0,0 @@
-//===- FragmentLinker.tcc --------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-// defineSymbol - define a new symbol
-template<FragmentLinker::DefinePolicy POLICY,
- FragmentLinker::ResolvePolicy RESOLVE>
-LDSymbol* FragmentLinker::defineSymbol(const llvm::StringRef& pName,
- bool pIsDyn,
- ResolveInfo::Type pType,
- ResolveInfo::Desc pDesc,
- ResolveInfo::Binding pBinding,
- ResolveInfo::SizeType pSize,
- LDSymbol::ValueType pValue,
- FragmentRef* pFragmentRef,
- ResolveInfo::Visibility pVisibility)
-{
- // These if/return should be optimized by compiler.
- // This function is defined for clarity.
- if (FragmentLinker::Force == POLICY && FragmentLinker::Unresolve == RESOLVE)
- return defineSymbolForcefully(pName,
- pIsDyn,
- pType,
- pDesc,
- pBinding,
- pSize,
- pValue,
- pFragmentRef,
- pVisibility);
-
- if (FragmentLinker::AsRefered == POLICY && FragmentLinker::Unresolve == RESOLVE)
- return defineSymbolAsRefered(pName,
- pIsDyn,
- pType,
- pDesc,
- pBinding,
- pSize,
- pValue,
- pFragmentRef,
- pVisibility);
-
- if (FragmentLinker::Force == POLICY && FragmentLinker::Resolve == RESOLVE)
- return defineAndResolveSymbolForcefully(pName,
- pIsDyn,
- pType,
- pDesc,
- pBinding,
- pSize,
- pValue,
- pFragmentRef,
- pVisibility);
-
- if (FragmentLinker::AsRefered == POLICY && FragmentLinker::Resolve == RESOLVE)
- return defineAndResolveSymbolAsRefered(pName,
- pIsDyn,
- pType,
- pDesc,
- pBinding,
- pSize,
- pValue,
- pFragmentRef,
- pVisibility);
-}
-
diff --git a/include/mcld/Fragment/Relocation.h b/include/mcld/Fragment/Relocation.h
index 37b32f6..e8c57e4 100644
--- a/include/mcld/Fragment/Relocation.h
+++ b/include/mcld/Fragment/Relocation.h
@@ -32,9 +32,10 @@ friend class Chunk<Relocation, MCLD_RELOCATIONS_PER_INPUT>;
public:
typedef uint64_t Address; // FIXME: use SizeTrait<T>::Address instead
- typedef uint64_t DWord; // FIXME: use SizeTrait<T>::Word instead
- typedef int64_t SWord; // FIXME: use SizeTrait<T>::SWord instead
- typedef uint8_t Type;
+ typedef uint64_t DWord; // FIXME: use SizeTrait<T>::Word instead
+ typedef int64_t SWord; // FIXME: use SizeTrait<T>::SWord instead
+ typedef uint8_t Type;
+ typedef uint32_t Size;
private:
Relocation();
@@ -80,6 +81,9 @@ public:
/// place - P value - address of the place being relocated
Address place() const;
+ /// size - the size of the relocation in bit
+ Size size(Relocator& pRelocator) const;
+
/// symbol info - binding, type
const ResolveInfo* symInfo() const { return m_pSymInfo; }
ResolveInfo* symInfo() { return m_pSymInfo; }
@@ -105,8 +109,6 @@ public:
void setSymInfo(ResolveInfo* pSym);
- size_t size() const;
-
private:
/// m_Type - the type of the relocation entries
Type m_Type;
diff --git a/include/mcld/GeneralOptions.h b/include/mcld/GeneralOptions.h
index 1468704..9d31097 100644
--- a/include/mcld/GeneralOptions.h
+++ b/include/mcld/GeneralOptions.h
@@ -30,6 +30,28 @@ class Input;
class GeneralOptions
{
public:
+ enum StripSymbolMode {
+ KeepAllSymbols,
+ StripTemporaries,
+ StripLocals,
+ StripAllSymbols
+ };
+
+ enum HashStyle {
+ SystemV = 0x1,
+ GNU = 0x2,
+ Both = 0x3
+ };
+
+ typedef std::vector<std::string> RpathList;
+ typedef RpathList::iterator rpath_iterator;
+ typedef RpathList::const_iterator const_rpath_iterator;
+
+ typedef std::vector<std::string> AuxiliaryList;
+ typedef AuxiliaryList::iterator aux_iterator;
+ typedef AuxiliaryList::const_iterator const_aux_iterator;
+
+public:
GeneralOptions();
~GeneralOptions();
@@ -43,6 +65,8 @@ public:
void setSysroot(const sys::fs::Path &pPath);
+ bool hasSysroot() const;
+
/// search directory
SearchDirs& directories()
{ return m_SearchDirs; }
@@ -98,12 +122,6 @@ public:
const std::string& soname() const
{ return m_SOName; }
- void setAllowShlibUndefined(bool pEnabled = true)
- { m_bAllowShlibUndefined = pEnabled; }
-
- bool isAllowShlibUndefined() const
- { return m_bAllowShlibUndefined; }
-
void setVerbose(int8_t pVerbose = -1)
{ m_Verbose = pVerbose; }
@@ -201,7 +219,7 @@ public:
void setNMagic(bool pMagic = true)
{ m_bNMagic = pMagic; }
- bool nnagic() const
+ bool nmagic() const
{ return m_bNMagic; }
// -N, --omagic
@@ -250,6 +268,56 @@ public:
bool isFatalWarnings() const
{ return m_bFatalWarnings; }
+ StripSymbolMode getStripSymbolMode() const
+ { return m_StripSymbols; }
+
+ void setStripSymbols(StripSymbolMode pMode)
+ { m_StripSymbols = pMode; }
+
+ void setNewDTags(bool pEnable = true)
+ { m_bNewDTags = pEnable; }
+
+ bool hasNewDTags() const
+ { return m_bNewDTags; }
+
+ void setNoStdlib(bool pEnable = true)
+ { m_bNoStdlib = pEnable; }
+
+ bool nostdlib() const
+ { return m_bNoStdlib; }
+
+ unsigned int getHashStyle() const { return m_HashStyle; }
+
+ void setHashStyle(unsigned int pStyle)
+ { m_HashStyle = pStyle; }
+
+ // ----- link-in rpath ----- //
+ const RpathList& getRpathList() const { return m_RpathList; }
+ RpathList& getRpathList() { return m_RpathList; }
+
+ const_rpath_iterator rpath_begin() const { return m_RpathList.begin(); }
+ rpath_iterator rpath_begin() { return m_RpathList.begin(); }
+ const_rpath_iterator rpath_end () const { return m_RpathList.end(); }
+ rpath_iterator rpath_end () { return m_RpathList.end(); }
+
+ // ----- filter and auxiliary filter ----- //
+ void setFilter(const std::string& pFilter)
+ { m_Filter = pFilter; }
+
+ const std::string& filter() const
+ { return m_Filter; }
+
+ bool hasFilter() const
+ { return !m_Filter.empty(); }
+
+ const AuxiliaryList& getAuxiliaryList() const { return m_AuxiliaryList; }
+ AuxiliaryList& getAuxiliaryList() { return m_AuxiliaryList; }
+
+ const_aux_iterator aux_begin() const { return m_AuxiliaryList.begin(); }
+ aux_iterator aux_begin() { return m_AuxiliaryList.begin(); }
+ const_aux_iterator aux_end () const { return m_AuxiliaryList.end(); }
+ aux_iterator aux_end () { return m_AuxiliaryList.end(); }
+
private:
enum status {
YES,
@@ -289,7 +357,6 @@ private:
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
bool m_bNMagic : 1; // -n, --nmagic
bool m_bOMagic : 1; // -N, --omagic
@@ -299,6 +366,13 @@ private:
bool m_bBinaryInput : 1; // -b [input-format], --format=[input-format]
bool m_bDefineCommon : 1; // -d, -dc, -dp
bool m_bFatalWarnings : 1; // --fatal-warnings
+ bool m_bNewDTags: 1; // --enable-new-dtags
+ bool m_bNoStdlib: 1; // -nostdlib
+ StripSymbolMode m_StripSymbols;
+ RpathList m_RpathList;
+ unsigned int m_HashStyle;
+ std::string m_Filter;
+ AuxiliaryList m_AuxiliaryList;
};
} // namespace of mcld
diff --git a/include/mcld/IRBuilder.h b/include/mcld/IRBuilder.h
index 3de292f..e189ce8 100644
--- a/include/mcld/IRBuilder.h
+++ b/include/mcld/IRBuilder.h
@@ -25,6 +25,7 @@
#include <mcld/Fragment/Relocation.h>
#include <mcld/Fragment/RegionFragment.h>
#include <mcld/Fragment/FillFragment.h>
+#include <mcld/Fragment/FragmentRef.h>
#include <mcld/Support/Path.h>
#include <mcld/Support/FileHandle.h>
@@ -53,6 +54,16 @@ public:
COFF
};
+ enum SymbolDefinePolicy {
+ Force,
+ AsReferred
+ };
+
+ enum SymbolResolvePolicy {
+ Unresolve,
+ Resolve
+ };
+
public:
IRBuilder(Module& pModule, const LinkerConfig& pConfig);
@@ -361,15 +372,19 @@ public:
/// @return Total size of the inserted fragments.
static uint64_t AppendEhFrame(EhFrame::CIE& pCIE, EhFrame& pEhFrame);
- /// AddSymbol - To add a symbol to the input file and module. The symbol is
- /// resolved immediately.
+ /// AddSymbol - To add a symbol to the input file.
+ /// This function create a new symbol and insert it into the input file. If
+ /// mcld::Module has another symbol with the same name, then this function
+ /// resolves these two symbols and keeps one in mcld::Module by their
+ /// attributes.
///
/// This is a general method for all kinds of symbol.
///
/// @param [in, out] pInput The input file. Either a relocatable or dynamic
/// object
/// @param [in] pName The name of the symbol
- /// @param [in] pType What the symbol refers to
+ /// @param [in] pType What the symbol refers to. May be a object,
+ /// function, no-type and so on. @see ResolveInfo
/// @param [in] pDesc { Undefined, Define, Common, Indirect }
/// @param [in] pBind { Global, Weak, Local, Absolute }
/// @param [in] pSize The size of the symbol. Bigger common symbols
@@ -381,6 +396,9 @@ public:
/// @param [in] pSection Absolute, undefined, common symbols do not have
/// pSection. Keep their pSection be NULL.
/// @oaram [in] pVis The visibility of the symbol
+ ///
+ /// @return The added symbol. If the insertion fails due to the resoluction,
+ /// return NULL.
LDSymbol* AddSymbol(Input& pInput,
const std::string& pName,
ResolveInfo::Type pType,
@@ -391,6 +409,51 @@ public:
LDSection* pSection = NULL,
ResolveInfo::Visibility pVis = ResolveInfo::Default);
+ /// AddSymbol - To add a symbol in mcld::Module
+ /// This function create a new symbol and insert it into mcld::Module.
+ ///
+ /// @tparam POLICY idicate the condition to define or not to define the
+ /// symbol.
+ /// - AsRefered
+ /// - Define a symbol only if mcld::Module contains a symbol with
+ /// identical name. If mcld::Module does not have any symbol with
+ /// the same name, this function returns NULL.
+ ///
+ /// - Force
+ /// - Define a symbol no matter mcld::Module has a symbol with identical
+ /// name or not.
+ ///
+ /// @tparam RESOLVE indicate the method to define a symbol. If we must define
+ /// a symbol in mcld::Module, then how to define it.
+ ///
+ /// - Resolve
+ /// - Follow the symbol resolution rule to bind the symbol references.
+ /// Resolution of the symbols with idential name depends on their
+ /// attributes.
+ ///
+ /// - Unresolve
+ /// - Forcefully override the symbol in mcld::Module. With this
+ /// argument, AddSymbol function turns a blind eye to symbol
+ /// resolution rules.
+ ///
+ /// @param [in] pName The name of the symbol
+ /// @param [in] pType The type of the symbol
+ /// @param [in] pDesc The description of the symbol, Could be one of
+ /// { Undefined, Define, Common, Indirect }
+ /// @param [in] pBinding The binding of the symbol. Could be one of
+ /// { Global, Weak, Local, Absolute }
+ ///
+ /// @return The symbol kept in mcld::Module.
+ template<SymbolDefinePolicy POLICY, SymbolResolvePolicy RESOLVE>
+ LDSymbol* AddSymbol(const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize = 0,
+ LDSymbol::ValueType pValue = 0x0,
+ FragmentRef* pFragmentRef = FragmentRef::Null(),
+ ResolveInfo::Visibility pVisibility = ResolveInfo::Default);
+
/// AddRelocation - To add a relocation entry
///
/// @param [in] pSection The relocation section. pSection's link should point to
@@ -415,7 +478,8 @@ private:
FragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility);
- LDSymbol* addSymbolFromDynObj(const std::string& pName,
+ LDSymbol* addSymbolFromDynObj(Input& pInput,
+ const std::string& pName,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBinding,
@@ -430,6 +494,50 @@ private:
InputBuilder m_InputBuilder;
};
+template<> LDSymbol*
+IRBuilder::AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
+ const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ FragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+
+template<> LDSymbol*
+IRBuilder::AddSymbol<IRBuilder::AsReferred, IRBuilder::Unresolve>(
+ const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ FragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+
+template<> LDSymbol*
+IRBuilder::AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
+ const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ FragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+
+template<> LDSymbol*
+IRBuilder::AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ FragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+
} // end of namespace mcld
#endif
diff --git a/include/mcld/LD/BinaryWriter.h b/include/mcld/LD/BinaryWriter.h
deleted file mode 100644
index d8133c4..0000000
--- a/include/mcld/LD/BinaryWriter.h
+++ /dev/null
@@ -1,39 +0,0 @@
-//===- BinaryWriter.h -----------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_BINARY_WRITER_INTERFACE_H
-#define MCLD_BINARY_WRITER_INTERFACE_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-#include <llvm/Support/system_error.h>
-
-namespace mcld {
-
-class Module;
-class MemoryArea;
-class GNULDBackend;
-
-/** \class BinaryWriter
- * \brief BinaryWriter provides a common interface for Binary file writers.
- */
-class BinaryWriter
-{
-protected:
- BinaryWriter(GNULDBackend& pBackend);
-
-public:
- virtual ~BinaryWriter();
-
- virtual llvm::error_code writeBinary(Module& pModule, MemoryArea& pOutput) = 0;
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/LD/DiagCommonKinds.inc b/include/mcld/LD/DiagCommonKinds.inc
index 08850e7..ae54fe4 100644
--- a/include/mcld/LD/DiagCommonKinds.inc
+++ b/include/mcld/LD/DiagCommonKinds.inc
@@ -24,9 +24,8 @@ DIAG(err_unsupported_Bdynamic, DiagnosticEngine::Error, "Target does not support
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_open_file, DiagnosticEngine::Error, "cannot open file `%0': %1.", "cannot open file `%0': %1.")
+DIAG(err_cannot_close_file, DiagnosticEngine::Error, "cannot close file `%0': %1.", "cannot close file `%0': %1.")
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.")
@@ -46,3 +45,5 @@ DIAG(fatal_unwritable_output, DiagnosticEngine::Fatal, "unable to write output f
DIAG(warn_unsupported_option, DiagnosticEngine::Warning, "Option `%0' is not implemented yet!", "Option `%0' is not implemented yet!")
DIAG(warn_shared_textrel, DiagnosticEngine::Warning, "Add DT_TEXTREL in a shared object!", "Add DT_TEXTREL in a shared object.")
DIAG(fatal_illegal_codegen_type, DiagnosticEngine::Fatal, "illegal output format of output %0", "illegal output format of output %0")
+DIAG(err_nmagic_not_static, DiagnosticEngine::Error, "cannot mix -nmagic option with -shared", "cannot mix -nmagic option with -shared")
+DIAG(err_omagic_not_static, DiagnosticEngine::Error, "cannot mix -omagic option with -shared", "cannot mix -omagic option with -shared")
diff --git a/include/mcld/LD/DynObjWriter.h b/include/mcld/LD/DynObjWriter.h
deleted file mode 100644
index 89d9765..0000000
--- a/include/mcld/LD/DynObjWriter.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//===- DynObjWriter.h -----------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_DYNAMIC_SHARED_OBJECT_WRITER_H
-#define MCLD_DYNAMIC_SHARED_OBJECT_WRITER_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-#include <mcld/LD/LDWriter.h>
-#include <llvm/Support/system_error.h>
-
-namespace mcld {
-
-class Module;
-class MemoryArea;
-class TargetLDBackend;
-
-/** \class DynObjWriter
- * \brief DynObjWriter provides an common interface for different object
- * formats.
- */
-class DynObjWriter : public LDWriter
-{
-protected:
- // force to have a TargetLDBackend
- DynObjWriter(TargetLDBackend& pLDBackend)
- { }
-
-public:
- virtual ~DynObjWriter() { }
-
- virtual llvm::error_code writeDynObj(Module& pModule,
- MemoryArea& pOutput) = 0;
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/LD/ELFBinaryWriter.h b/include/mcld/LD/ELFBinaryWriter.h
deleted file mode 100644
index 593b54b..0000000
--- a/include/mcld/LD/ELFBinaryWriter.h
+++ /dev/null
@@ -1,46 +0,0 @@
-//===- ELFBinaryWriter.h --------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_ELF_BINARY_WRITER_H
-#define MCLD_ELF_BINARY_WRITER_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-#include <llvm/Support/system_error.h>
-#include <mcld/LD/BinaryWriter.h>
-#include <mcld/LD/ELFWriter.h>
-
-namespace mcld {
-
-class Module;
-class LinkerConfig;
-class MemoryArea;
-class GNULDBackend;
-
-/** \class ELFBinaryWriter
- * \brief ELFBinaryWriter writes the target-independent parts of Binary files.
- * ELFBinaryWriter reads a MCLDFile and writes into raw_ostream
- *
- */
-class ELFBinaryWriter : public BinaryWriter, protected ELFWriter
-{
-public:
- ELFBinaryWriter(GNULDBackend& pBackend, const LinkerConfig& pConfig);
-
- ~ELFBinaryWriter();
-
- llvm::error_code writeBinary(Module& pModule, MemoryArea& pOutput);
-
-private:
- const LinkerConfig& m_Config;
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/LD/ELFDynObjWriter.h b/include/mcld/LD/ELFDynObjWriter.h
deleted file mode 100644
index 774943e..0000000
--- a/include/mcld/LD/ELFDynObjWriter.h
+++ /dev/null
@@ -1,47 +0,0 @@
-//===- ELFDynObjWriter.h --------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_ELF_DYNAMIC_SHARED_OBJECT_WRITER_H
-#define MCLD_ELF_DYNAMIC_SHARED_OBJECT_WRITER_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-#include <mcld/LD/DynObjWriter.h>
-#include <mcld/LD/ELFWriter.h>
-
-namespace mcld {
-
-class Module;
-class LinkerConfig;
-class MemoryArea;
-class GNULDBackend;
-
-/** \class ELFDynObjWriter
- * \brief ELFDynObjWriter writes the dynamic sections.
- */
-class ELFDynObjWriter : public DynObjWriter, private ELFWriter
-{
-public:
- typedef ELFWriter::FileOffset FileOffset;
-
-public:
- ELFDynObjWriter(GNULDBackend& pBackend,
- const LinkerConfig& pConfig);
-
- ~ELFDynObjWriter();
-
- llvm::error_code writeDynObj(Module& pModule, MemoryArea& pOutput);
-
-private:
- const LinkerConfig& m_Config;
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/LD/ELFExecWriter.h b/include/mcld/LD/ELFExecWriter.h
deleted file mode 100644
index ca69235..0000000
--- a/include/mcld/LD/ELFExecWriter.h
+++ /dev/null
@@ -1,47 +0,0 @@
-//===- 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 <mcld/LD/ExecWriter.h>
-#include <mcld/LD/ELFWriter.h>
-
-namespace mcld {
-
-class Module;
-class LinkerConfig;
-class MemoryArea;
-class GNULDBackend;
-
-/** \class ELFDynObjWriter
- * \brief ELFDynObjWriter writes the dynamic sections.
- */
-class ELFExecWriter : public ExecWriter, private ELFWriter
-{
-public:
- typedef ELFWriter::FileOffset FileOffset;
-
-public:
- ELFExecWriter(GNULDBackend& pBackend,
- const LinkerConfig& pConfig);
-
- ~ELFExecWriter();
-
- llvm::error_code writeExecutable(Module& pModule, MemoryArea& pOutput);
-
-private:
- const LinkerConfig& m_Config;
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/LD/ELFFileFormat.h b/include/mcld/LD/ELFFileFormat.h
index e52a813..5ed8997 100644
--- a/include/mcld/LD/ELFFileFormat.h
+++ b/include/mcld/LD/ELFFileFormat.h
@@ -180,6 +180,9 @@ public:
bool hasDataRelRoLocal() const
{ return (NULL != f_pDataRelRoLocal) && (0 != f_pDataRelRoLocal->size()); }
+ bool hasGNUHashTab() const
+ { return (NULL != f_pGNUHashTab) && (0 != f_pGNUHashTab->size()); }
+
// ----- access functions ----- //
/// @ref Special Sections, Ch. 4.17, System V ABI, 4th edition.
LDSection& getNULLSection() {
@@ -634,6 +637,16 @@ public:
return *f_pDataRelRoLocal;
}
+ LDSection& getGNUHashTab() {
+ assert(NULL != f_pGNUHashTab);
+ return *f_pGNUHashTab;
+ }
+
+ const LDSection& getGNUHashTab() const {
+ assert(NULL != f_pGNUHashTab);
+ return *f_pGNUHashTab;
+ }
+
protected:
// variable name : ELF
/// @ref Special Sections, Ch. 4.17, System V ABI, 4th edition.
@@ -688,6 +701,7 @@ protected:
LDSection* f_pStack; // .stack
LDSection* f_pStackNote; // .note.GNU-stack
LDSection* f_pDataRelRoLocal; // .data.rel.ro.local
+ LDSection* f_pGNUHashTab; // .gnu.hash
};
} // namespace of mcld
diff --git a/include/mcld/LD/ELFObjectWriter.h b/include/mcld/LD/ELFObjectWriter.h
index 28bbba8..ec4311e 100644
--- a/include/mcld/LD/ELFObjectWriter.h
+++ b/include/mcld/LD/ELFObjectWriter.h
@@ -12,7 +12,7 @@
#include <gtest.h>
#endif
#include <mcld/LD/ObjectWriter.h>
-#include <mcld/LD/ELFWriter.h>
+#include <cassert>
#include <llvm/Support/system_error.h>
@@ -20,17 +20,27 @@ namespace mcld {
class Module;
class LinkerConfig;
-class MemoryArea;
class GNULDBackend;
+class FragmentLinker;
+class Relocation;
+class LDSection;
+class SectionData;
+class RelocData;
+class Output;
+class MemoryRegion;
+class MemoryArea;
/** \class ELFObjectWriter
* \brief ELFObjectWriter writes the target-independent parts of object files.
* ELFObjectWriter reads a MCLDFile and writes into raw_ostream
*
*/
-class ELFObjectWriter : public ObjectWriter, protected ELFWriter
+class ELFObjectWriter : public ObjectWriter
{
public:
+ typedef uint64_t FileOffset;
+
+public:
ELFObjectWriter(GNULDBackend& pBackend,
const LinkerConfig& pConfig);
@@ -39,9 +49,87 @@ public:
llvm::error_code writeObject(Module& pModule, MemoryArea& pOutput);
private:
+ void writeSection(MemoryArea& pOutput, LDSection *section);
+
+ GNULDBackend& target() { return m_Backend; }
+
+ const GNULDBackend& target() const { return m_Backend; }
+
+ // writeELFHeader - emit ElfXX_Ehdr
+ template<size_t SIZE>
+ void writeELFHeader(const LinkerConfig& pConfig,
+ const Module& pModule,
+ MemoryArea& pOutput) const;
+
+ uint64_t getEntryPoint(const LinkerConfig& pConfig,
+ const Module& pModule) const;
+
+ // emitSectionHeader - emit ElfXX_Shdr
+ template<size_t SIZE>
+ void emitSectionHeader(const Module& pModule,
+ const LinkerConfig& pConfig,
+ MemoryArea& pOutput) const;
+
+ // emitProgramHeader - emit ElfXX_Phdr
+ template<size_t SIZE>
+ void emitProgramHeader(MemoryArea& pOutput) const;
+
+ // emitShStrTab - emit .shstrtab
+ void emitShStrTab(const LDSection& pShStrTab,
+ const Module& pModule,
+ MemoryArea& pOutput);
+
+ void emitSectionData(const LDSection& pSection,
+ MemoryRegion& pRegion) const;
+
+ void emitRelocation(const LinkerConfig& pConfig,
+ const LDSection& pSection,
+ MemoryRegion& pRegion) const;
+
+ // emitRel - emit ElfXX_Rel
+ template<size_t SIZE>
+ void emitRel(const LinkerConfig& pConfig,
+ const RelocData& pRelocData,
+ MemoryRegion& pRegion) const;
+
+ // emitRela - emit ElfXX_Rela
+ template<size_t SIZE>
+ void emitRela(const LinkerConfig& pConfig,
+ const RelocData& pRelocData,
+ MemoryRegion& pRegion) const;
+
+ // getSectEntrySize - compute ElfXX_Shdr::sh_entsize
+ template<size_t SIZE>
+ uint64_t getSectEntrySize(const LDSection& pSection) const;
+
+ // getSectLink - compute ElfXX_Shdr::sh_link
+ uint64_t getSectLink(const LDSection& pSection,
+ const LinkerConfig& pConfig) const;
+
+ // getSectInfo - compute ElfXX_Shdr::sh_info
+ uint64_t getSectInfo(const LDSection& pSection) const;
+
+ template<size_t SIZE>
+ uint64_t getLastStartOffset(const Module& pModule) const
+ {
+ assert(0 && "Call invalid ELFObjectWriter::getLastStartOffset");
+ return 0;
+ }
+
+ void emitSectionData(const SectionData& pSD, MemoryRegion& pRegion) const;
+
+private:
+ GNULDBackend& m_Backend;
+
const LinkerConfig& m_Config;
};
+template<>
+uint64_t ELFObjectWriter::getLastStartOffset<32>(const Module& pModule) const;
+
+template<>
+uint64_t ELFObjectWriter::getLastStartOffset<64>(const Module& pModule) const;
+
} // namespace of mcld
#endif
diff --git a/include/mcld/LD/ELFReader.h b/include/mcld/LD/ELFReader.h
index 146a00a..b42b272 100644
--- a/include/mcld/LD/ELFReader.h
+++ b/include/mcld/LD/ELFReader.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MCLD_ELF_READER_INTERFACE_H
-#define MCLD_ELF_READER_INTERFACE_H
+#ifndef MCLD_ELF_READER_H
+#define MCLD_ELF_READER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -16,139 +16,105 @@
#include <llvm/Support/ELF.h>
#include <llvm/Support/Host.h>
-#include <mcld/Module.h>
-#include <mcld/LinkerConfig.h>
-#include <mcld/MC/MCLDInput.h>
+#include <mcld/LD/ELFReaderIf.h>
#include <mcld/LD/ResolveInfo.h>
-#include <mcld/LD/LDContext.h>
#include <mcld/Target/GNULDBackend.h>
#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MemoryArea.h>
-#include <mcld/Support/MsgHandling.h>
namespace mcld {
-class Module;
+//class Module;
class IRBuilder;
-class FragmentRef;
class SectionData;
class LDSection;
-/** \class ELFReaderIF
- * \brief ELFReaderIF provides common interface for all kind of ELF readers.
+/** \class ELFReader
+ * \brief ELFReader is a template scaffolding for partial specification.
+ */
+template<size_t BIT, bool LITTLEENDIAN>
+class ELFReader
+{ };
+
+/** \class ELFReader<32, true>
+ * \brief ELFReader<32, true> is a 32-bit, little endian ELFReader.
*/
-class ELFReaderIF
+template<>
+class ELFReader<32, true> : public ELFReaderIF
{
public:
- ELFReaderIF(GNULDBackend& pBackend)
- : m_Backend(pBackend)
- { }
+ typedef llvm::ELF::Elf32_Ehdr ELFHeader;
+ typedef llvm::ELF::Elf32_Shdr SectionHeader;
+ typedef llvm::ELF::Elf32_Sym Symbol;
+ typedef llvm::ELF::Elf32_Rel Rel;
+ typedef llvm::ELF::Elf32_Rela Rela;
+
+public:
+ ELFReader(GNULDBackend& pBackend);
- virtual ~ELFReaderIF() { }
+ ~ELFReader();
/// ELFHeaderSize - return the size of the ELFHeader
- virtual size_t getELFHeaderSize() const = 0;
+ size_t getELFHeaderSize() const
+ { return sizeof(ELFHeader); }
/// isELF - is this a ELF file
- virtual bool isELF(void* pELFHeader) const = 0;
+ bool isELF(void* pELFHeader) const;
/// isMyEndian - is this ELF file in the same endian to me?
- virtual bool isMyEndian(void* pELFHeader) const = 0;
+ bool isMyEndian(void* pELFHeader) const;
/// isMyMachine - is this ELF file generated for the same machine.
- virtual bool isMyMachine(void* pELFHeader) const = 0;
+ bool isMyMachine(void* pELFHeader) const;
/// fileType - the file type of this file
- virtual Input::Type fileType(void* pELFHeader) const = 0;
-
- /// target - the target backend
- const GNULDBackend& target() const { return m_Backend; }
- GNULDBackend& target() { return m_Backend; }
-
+ Input::Type fileType(void* pELFHeader) const;
/// readSectionHeaders - read ELF section header table and create LDSections
- virtual bool readSectionHeaders(Input& pInput, void* pELFHeader) const = 0;
+ bool readSectionHeaders(Input& pInput, void* pELFHeader) const;
/// readRegularSection - read a regular section and create fragments.
- virtual bool readRegularSection(Input& pInput, SectionData& pSD) const = 0;
+ bool readRegularSection(Input& pInput, SectionData& pSD) const;
/// readSymbols - read ELF symbols and create LDSymbol
- virtual bool readSymbols(Input& pInput,
- IRBuilder& pBuilder,
- const MemoryRegion& pRegion,
- const char* StrTab) const = 0;
+ bool readSymbols(Input& pInput,
+ IRBuilder& pBuilder,
+ const MemoryRegion& pRegion,
+ const char* StrTab) const;
/// readSignature - read a symbol from the given Input and index in symtab
/// This is used to get the signature of a group section.
- virtual ResolveInfo* readSignature(Input& pInput,
- LDSection& pSymTab,
- uint32_t pSymIdx) const = 0;
+ ResolveInfo* readSignature(Input& pInput,
+ LDSection& pSymTab,
+ uint32_t pSymIdx) const;
/// readRela - read ELF rela and create Relocation
- virtual bool readRela(Input& pInput,
- LDSection& pSection,
- const MemoryRegion& pRegion) const = 0;
+ bool readRela(Input& pInput,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const;
/// readRel - read ELF rel and create Relocation
- virtual bool readRel(Input& pInput,
- LDSection& pSection,
- const MemoryRegion& pRegion) const = 0;
+ bool readRel(Input& pInput,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) 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 {
- LDSection* section;
- uint32_t sh_link;
- uint32_t sh_info;
- };
-
- typedef std::vector<LinkInfo> LinkInfoList;
-
-protected:
- ResolveInfo::Type getSymType(uint8_t pInfo, uint16_t pShndx) const;
-
- ResolveInfo::Desc getSymDesc(uint16_t pShndx, const Input& pInput) const;
-
- ResolveInfo::Binding getSymBinding(uint8_t pBinding,
- uint16_t pShndx,
- uint8_t pVisibility) const;
-
- uint64_t getSymValue(uint64_t pValue,
- uint16_t pShndx,
- const Input& pInput) const;
-
- FragmentRef* getSymFragmentRef(Input& pInput,
- uint16_t pShndx,
- uint32_t pOffset) const;
-
- ResolveInfo::Visibility getSymVisibility(uint8_t pVis) const;
-
-protected:
- GNULDBackend& m_Backend;
+ bool readDynamic(Input& pInput) const;
};
-/** \class ELFReader
- * \brief ELFReader is a template scaffolding for partial specification.
- */
-template<size_t BIT, bool LITTLEENDIAN>
-class ELFReader
-{ };
-/** \class ELFReader<32, true>
- * \brief ELFReader<32, true> is a 32-bit, little endian ELFReader.
+/** \class ELFReader<64, true>
+ * \brief ELFReader<64, true> is a 64-bit, little endian ELFReader.
*/
template<>
-class ELFReader<32, true> : public ELFReaderIF
+class ELFReader<64, true> : public ELFReaderIF
{
public:
- typedef llvm::ELF::Elf32_Ehdr ELFHeader;
- typedef llvm::ELF::Elf32_Shdr SectionHeader;
- typedef llvm::ELF::Elf32_Sym Symbol;
- typedef llvm::ELF::Elf32_Rel Rel;
- typedef llvm::ELF::Elf32_Rela Rela;
+ typedef llvm::ELF::Elf64_Ehdr ELFHeader;
+ typedef llvm::ELF::Elf64_Shdr SectionHeader;
+ typedef llvm::ELF::Elf64_Sym Symbol;
+ typedef llvm::ELF::Elf64_Rel Rel;
+ typedef llvm::ELF::Elf64_Rela Rela;
public:
ELFReader(GNULDBackend& pBackend);
diff --git a/include/mcld/LD/ELFReaderIf.h b/include/mcld/LD/ELFReaderIf.h
new file mode 100644
index 0000000..245b542
--- /dev/null
+++ b/include/mcld/LD/ELFReaderIf.h
@@ -0,0 +1,132 @@
+//===- ELFReader.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_READER_INTERFACE_H
+#define MCLD_ELF_READER_INTERFACE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/Host.h>
+
+#include <mcld/Module.h>
+#include <mcld/LinkerConfig.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/Support/MsgHandling.h>
+
+namespace mcld {
+
+class Module;
+class IRBuilder;
+class FragmentRef;
+class SectionData;
+class LDSection;
+
+/** \class ELFReaderIF
+ * \brief ELFReaderIF provides common interface for all kind of ELF readers.
+ */
+class ELFReaderIF
+{
+public:
+ ELFReaderIF(GNULDBackend& pBackend)
+ : m_Backend(pBackend)
+ { }
+
+ virtual ~ELFReaderIF() { }
+
+ /// ELFHeaderSize - return the size of the ELFHeader
+ virtual size_t getELFHeaderSize() const = 0;
+
+ /// isELF - is this a ELF file
+ virtual bool isELF(void* pELFHeader) const = 0;
+
+ /// isMyEndian - is this ELF file in the same endian to me?
+ virtual bool isMyEndian(void* pELFHeader) const = 0;
+
+ /// isMyMachine - is this ELF file generated for the same machine.
+ virtual bool isMyMachine(void* pELFHeader) const = 0;
+
+ /// fileType - the file type of this file
+ virtual Input::Type fileType(void* pELFHeader) const = 0;
+
+ /// target - the target backend
+ const GNULDBackend& target() const { return m_Backend; }
+ GNULDBackend& target() { return m_Backend; }
+
+
+ /// readSectionHeaders - read ELF section header table and create LDSections
+ virtual bool readSectionHeaders(Input& pInput, void* pELFHeader) const = 0;
+
+ /// readRegularSection - read a regular section and create fragments.
+ virtual bool readRegularSection(Input& pInput, SectionData& pSD) const = 0;
+
+ /// readSymbols - read ELF symbols and create LDSymbol
+ virtual bool readSymbols(Input& pInput,
+ IRBuilder& pBuilder,
+ const MemoryRegion& pRegion,
+ const char* StrTab) const = 0;
+
+ /// readSignature - read a symbol from the given Input and index in symtab
+ /// This is used to get the signature of a group section.
+ virtual ResolveInfo* readSignature(Input& pInput,
+ LDSection& pSymTab,
+ uint32_t pSymIdx) const = 0;
+
+ /// readRela - read ELF rela and create Relocation
+ virtual bool readRela(Input& pInput,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const = 0;
+
+ /// readRel - read ELF rel and create Relocation
+ virtual bool readRel(Input& pInput,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const = 0;
+
+ /// 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 {
+ LDSection* section;
+ uint32_t sh_link;
+ uint32_t sh_info;
+ };
+
+ typedef std::vector<LinkInfo> LinkInfoList;
+
+protected:
+ ResolveInfo::Type getSymType(uint8_t pInfo, uint16_t pShndx) const;
+
+ ResolveInfo::Desc getSymDesc(uint16_t pShndx, const Input& pInput) const;
+
+ ResolveInfo::Binding getSymBinding(uint8_t pBinding,
+ uint16_t pShndx,
+ uint8_t pVisibility) const;
+
+ uint64_t getSymValue(uint64_t pValue,
+ uint16_t pShndx,
+ const Input& pInput) const;
+
+ FragmentRef* getSymFragmentRef(Input& pInput,
+ uint16_t pShndx,
+ uint32_t pOffset) const;
+
+ ResolveInfo::Visibility getSymVisibility(uint8_t pVis) const;
+
+protected:
+ GNULDBackend& m_Backend;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFWriter.h b/include/mcld/LD/ELFWriter.h
deleted file mode 100644
index b0c4d81..0000000
--- a/include/mcld/LD/ELFWriter.h
+++ /dev/null
@@ -1,124 +0,0 @@
-//===- ELFWriter.h --------------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_ELF_WRITER_H
-#define MCLD_ELF_WRITER_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-
-#include <llvm/Support/ELF.h>
-
-namespace mcld {
-
-class Module;
-class FragmentLinker;
-class LinkerConfig;
-class GNULDBackend;
-class Relocation;
-class LDSection;
-class SectionData;
-class RelocData;
-class Output;
-class MemoryRegion;
-class MemoryArea;
-
-/** \class ELFWriter
- * \brief ELFWriter provides basic functions to write ELF sections, symbols,
- * and so on.
- */
-class ELFWriter
-{
-public:
- typedef uint64_t FileOffset;
-
-protected:
- ELFWriter(GNULDBackend& pBackend)
- : f_Backend(pBackend) {
- }
-
-public:
- virtual ~ELFWriter() { }
-
- GNULDBackend& target()
- { return f_Backend; }
-
- const GNULDBackend& target() const
- { return f_Backend; }
-
- virtual void writeELF32Header(const LinkerConfig& pConfig,
- const Module& pModule,
- MemoryArea& pOutput) const;
-
- virtual void writeELF64Header(const LinkerConfig& pConfig,
- const Module& pModule,
- MemoryArea& pOutput) const;
-
- virtual uint64_t getEntryPoint(const LinkerConfig& pConfig,
- const Module& pModule) const;
-
-protected:
- void emitELF32SectionHeader(const Module& pModule,
- const LinkerConfig& pConfig,
- MemoryArea& pOutput) const;
-
- void emitELF64SectionHeader(const Module& pModule,
- const LinkerConfig& pConfig,
- MemoryArea& pOutput) const;
-
- void emitELF32ProgramHeader(MemoryArea& pOutput) const;
-
- void emitELF64ProgramHeader(MemoryArea& pOutput) const;
-
- // emitShStrTab - emit .shstrtab
- void emitELFShStrTab(const LDSection& pShStrTab, const Module& pModule,
- MemoryArea& pOutput);
-
- void emitSectionData(const LDSection& pSection,
- MemoryRegion& pRegion) const;
-
- void emitRelocation(const LinkerConfig& pConfig,
- const LDSection& pSection,
- MemoryRegion& pRegion) const;
-
- void emitRel(const LinkerConfig& pConfig,
- const RelocData& pRelocData,
- MemoryRegion& pRegion) const;
-
- void emitRela(const LinkerConfig& pConfig,
- const RelocData& pRelocData,
- MemoryRegion& pRegion) const;
-
-private:
- // getSectEntrySize - compute ElfXX_Shdr::sh_entsize
- uint64_t getELF32SectEntrySize(const LDSection& pSection) const;
-
- // getSectEntrySize - compute ElfXX_Shdr::sh_entsize
- uint64_t getELF64SectEntrySize(const LDSection& pSection) const;
-
- // getSectEntrySize - compute ElfXX_Shdr::sh_link
- uint64_t getSectLink(const LDSection& pSection,
- const LinkerConfig& pConfig) const;
-
- // getSectEntrySize - compute ElfXX_Shdr::sh_info
- uint64_t getSectInfo(const LDSection& pSection) const;
-
- uint64_t getELF32LastStartOffset(const Module& pModule) const;
-
- uint64_t getELF64LastStartOffset(const Module& pModule) const;
-
- void emitSectionData(const SectionData& pSD, MemoryRegion& pRegion) const;
-
-protected:
- GNULDBackend& f_Backend;
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/LD/EhFrame.h b/include/mcld/LD/EhFrame.h
index dc360a2..695f72b 100644
--- a/include/mcld/LD/EhFrame.h
+++ b/include/mcld/LD/EhFrame.h
@@ -12,8 +12,11 @@
#include <gtest.h>
#endif
-#include <vector>
+#include <mcld/Config/Config.h>
#include <mcld/Fragment/RegionFragment.h>
+#include <mcld/Support/Allocators.h>
+
+#include <vector>
namespace mcld {
@@ -25,6 +28,17 @@ class SectionData;
*/
class EhFrame
{
+private:
+ friend class Chunk<EhFrame, MCLD_SECTIONS_PER_INPUT>;
+
+ EhFrame();
+ explicit EhFrame(LDSection& pSection);
+
+ ~EhFrame();
+
+ EhFrame(const EhFrame&); // DO NOT IMPLEMENT
+ EhFrame& operator=(const EhFrame&); // DO NOT IMPLEMENT
+
public:
/** \class CIE
* \brief Common Information Entry.
@@ -56,6 +70,7 @@ public:
const CIE& getCIE() const { return m_CIE; }
uint32_t getDataStart() const { return m_DataStart; }
+
private:
const CIE& m_CIE;
uint32_t m_DataStart;
@@ -74,15 +89,17 @@ public:
typedef FDEList::const_iterator const_fde_iterator;
public:
- EhFrame(LDSection& pSection);
+ static EhFrame* Create(LDSection& pSection);
- ~EhFrame();
+ static void Destroy(EhFrame*& pSection);
+
+ static void Clear();
/// merge - move all data from pOther to this object.
EhFrame& merge(EhFrame& pOther);
- const LDSection& getSection() const { return m_Section; }
- LDSection& getSection() { return m_Section; }
+ const LDSection& getSection() const;
+ LDSection& getSection();
const SectionData& getSectionData() const { return *m_pSectionData; }
SectionData& getSectionData() { return *m_pSectionData; }
@@ -125,7 +142,7 @@ public:
size_t numOfFDEs() const { return m_FDEs.size(); }
private:
- LDSection& m_Section;
+ LDSection* m_pSection;
SectionData* m_pSectionData;
CIEList m_CIEs;
diff --git a/include/mcld/LD/EhFrameHdr.h b/include/mcld/LD/EhFrameHdr.h
index 3a5971d..e9d8702 100644
--- a/include/mcld/LD/EhFrameHdr.h
+++ b/include/mcld/LD/EhFrameHdr.h
@@ -70,6 +70,9 @@ private:
template<>
void EhFrameHdr::emitOutput<32>(MemoryArea& pOutput);
+template<>
+void EhFrameHdr::emitOutput<64>(MemoryArea& pOutput);
+
} // namespace of mcld
#endif
diff --git a/include/mcld/LD/ExecWriter.h b/include/mcld/LD/ExecWriter.h
deleted file mode 100644
index e0ea325..0000000
--- a/include/mcld/LD/ExecWriter.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//===- 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/LD/LDWriter.h>
-#include <llvm/Support/system_error.h>
-
-namespace mcld {
-
-class Module;
-class MemoryArea;
-class TargetLDBackend;
-
-/** \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(Module& pModule,
- MemoryArea& pOutput) = 0;
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/include/mcld/LD/LDSymbol.h b/include/mcld/LD/LDSymbol.h
index 326c82f..b40213c 100644
--- a/include/mcld/LD/LDSymbol.h
+++ b/include/mcld/LD/LDSymbol.h
@@ -19,6 +19,8 @@
#include <mcld/LD/ResolveInfo.h>
#include <mcld/Support/Allocators.h>
+#include <llvm/Support/ManagedStatic.h>
+
namespace mcld {
class FragmentRef;
@@ -127,6 +129,7 @@ public:
private:
friend class Chunk<LDSymbol, MCLD_SYMBOLS_PER_INPUT>;
+ template<class T> friend void* llvm::object_creator();
LDSymbol();
LDSymbol(const LDSymbol& pCopy);
diff --git a/include/mcld/LD/LDWriter.h b/include/mcld/LD/LDWriter.h
deleted file mode 100644
index b7dd14c..0000000
--- a/include/mcld/LD/LDWriter.h
+++ /dev/null
@@ -1,39 +0,0 @@
-//===- LDWriter.h ---------------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// LDWriter provides an interface used by MCLinker,
-// which writes the result of linking into a .so file or a executable.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_WRITER_INTERFACE_H
-#define MCLD_WRITER_INTERFACE_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-
-namespace mcld {
-
-/** \class LDWriter
- * \brief LDWriter provides the basic interfaces for all writers.
- * (ObjectWriter, DynObjWriter, and EXEObjWriter)
- */
-class LDWriter
-{
-protected:
- LDWriter() { }
-
-public:
- virtual ~LDWriter() { }
-
-};
-
-} //end namespace
-
-#endif
-
diff --git a/include/mcld/LD/NamePool.h b/include/mcld/LD/NamePool.h
index 12b4b91..fa0bb10 100644
--- a/include/mcld/LD/NamePool.h
+++ b/include/mcld/LD/NamePool.h
@@ -12,15 +12,17 @@
#include <gtest.h>
#endif
-#include <utility>
-
-#include <llvm/ADT/StringRef.h>
-
+#include <mcld/Config/Config.h>
#include <mcld/ADT/HashTable.h>
#include <mcld/ADT/StringHash.h>
#include <mcld/ADT/Uncopyable.h>
#include <mcld/LD/Resolver.h>
#include <mcld/LD/ResolveInfo.h>
+#include <mcld/Support/GCFactory.h>
+
+#include <utility>
+
+#include <llvm/ADT/StringRef.h>
namespace mcld {
@@ -97,9 +99,12 @@ public:
size_type capacity() const;
private:
+ typedef GCFactory<ResolveInfo*, 128> FreeInfoSet;
+
+private:
Resolver* m_pResolver;
Table m_Table;
-
+ FreeInfoSet m_FreeInfoSet;
};
} // namespace of mcld
diff --git a/include/mcld/LD/ObjectWriter.h b/include/mcld/LD/ObjectWriter.h
index a84e0d3..c1dcac6 100644
--- a/include/mcld/LD/ObjectWriter.h
+++ b/include/mcld/LD/ObjectWriter.h
@@ -17,7 +17,6 @@ namespace mcld {
class Module;
class MemoryArea;
-class GNULDBackend;
/** \class ObjectWriter
* \brief ObjectWriter provides a common interface for object file writers.
@@ -25,7 +24,7 @@ class GNULDBackend;
class ObjectWriter
{
protected:
- ObjectWriter(GNULDBackend& pBackend);
+ ObjectWriter();
public:
virtual ~ObjectWriter();
diff --git a/include/mcld/LD/Relocator.h b/include/mcld/LD/Relocator.h
index 6fd431e..8589894 100644
--- a/include/mcld/LD/Relocator.h
+++ b/include/mcld/LD/Relocator.h
@@ -26,10 +26,11 @@ class TargetLDBackend;
class Relocator
{
public:
- typedef Relocation::Type Type;
+ typedef Relocation::Type Type;
typedef Relocation::Address Address;
- typedef Relocation::DWord DWord;
- typedef Relocation::SWord SWord;
+ typedef Relocation::DWord DWord;
+ typedef Relocation::SWord SWord;
+ typedef Relocation::Size Size;
public:
enum Result {
@@ -41,33 +42,21 @@ public:
};
public:
- virtual ~Relocator() {}
+ virtual ~Relocator() = 0;
/// apply - general apply function
virtual Result applyRelocation(Relocation& pRelocation) = 0;
- void setFragmentLinker(const FragmentLinker& pLinker)
- { m_pLinker = &pLinker; }
-
// ------ observers -----//
- const FragmentLinker& getFragmentLinker() const
- {
- assert(NULL != m_pLinker);
- return *m_pLinker;
- }
-
- bool hasFragmentLinker() const
- { return (NULL != m_pLinker); }
-
virtual TargetLDBackend& getTarget() = 0;
virtual const TargetLDBackend& getTarget() const = 0;
+ /// getName - get the name of a relocation
virtual const char* getName(Type pType) const = 0;
-private:
- const FragmentLinker* m_pLinker;
-
+ /// getSize - get the size of a relocation in bit
+ virtual Size getSize(Type pType) const = 0;
};
} // namespace of mcld
diff --git a/include/mcld/LD/StubFactory.h b/include/mcld/LD/StubFactory.h
index b38a96f..8548e5a 100644
--- a/include/mcld/LD/StubFactory.h
+++ b/include/mcld/LD/StubFactory.h
@@ -20,7 +20,7 @@ namespace mcld {
class Stub;
class Relocation;
class BranchIslandFactory;
-class FragmentLinker;
+class IRBuilder;
/** \class StubFactory
* \brief the clone factory of Stub
@@ -37,7 +37,7 @@ public:
/// create - create a stub if needed, otherwise return NULL
Stub* create(Relocation& pReloc,
uint64_t pTargetSymValue,
- FragmentLinker& pLinker,
+ IRBuilder& pBuilder,
BranchIslandFactory& pBRIslandFactory);
private:
diff --git a/include/mcld/Linker.h b/include/mcld/Linker.h
index 891372c..d5fc438 100644
--- a/include/mcld/Linker.h
+++ b/include/mcld/Linker.h
@@ -38,14 +38,26 @@ public:
~Linker();
+ /// config - To set up target-dependent options in pConfig.
bool config(LinkerConfig& pConfig);
+ /// resolve - To read participatory input files and build up mcld::Module
+ bool resolve(Module& pModule, IRBuilder& pBuilder);
+
+ /// layout - To serialize the final result of the output mcld::Module
+ bool layout();
+
+ /// link - A convenient way to resolve and to layout the output mcld::Module.
bool link(Module& pModule, IRBuilder& pBuilder);
+ /// emit - To emit output mcld::Module to a output MemoryArea
bool emit(MemoryArea& pOutput);
+ /// emit - To open a file for output in pPath and to emit output mcld::Module
+ /// to the file.
bool emit(const std::string& pPath);
+ /// emit - To emit output mcld::Module in the pFileDescriptor.
bool emit(int pFileDescriptor);
bool reset();
@@ -61,7 +73,6 @@ private:
private:
LinkerConfig* m_pConfig;
- Module* m_pModule;
IRBuilder* m_pIRBuilder;
const Target* m_pTarget;
diff --git a/include/mcld/LinkerConfig.h b/include/mcld/LinkerConfig.h
index 9e70ecf..f0c2c87 100644
--- a/include/mcld/LinkerConfig.h
+++ b/include/mcld/LinkerConfig.h
@@ -44,6 +44,28 @@ public:
Binary
};
+ /** \enum CodePosition
+ * CodePosition indicates the ability of the generated output to be
+ * loaded at different addresses. If the output can be loaded at different
+ * addresses, we say the output is position independent. Shared libraries
+ * and position-independent executable programs (PIE) are in this category.
+ * ::Independent indicates the output is position independent.
+ * If a executable program can not be loaded at arbitrary addresses, but it
+ * can call outside functions, we say the program is dynamic dependent on
+ * the address to be loaded. ::DynamicDependent indicates the output is not
+ * only a executable program, but also dynamic dependent. In general,
+ * executable programs are dynamic dependent.
+ * If a executable program can not be loaded at different addresses, and
+ * only call inner functions, then we say the program is static dependent on
+ * its loaded address. ::StaticDependent is used to indicate this kind of
+ * output.
+ */
+ enum CodePosition {
+ Independent, ///< Position Independent
+ DynamicDependent, ///< Can call outside libraries
+ StaticDependent ///< Can not call outside libraries
+ };
+
public:
LinkerConfig();
@@ -70,6 +92,13 @@ public:
void setCodeGenType(CodeGenType pType) { m_CodeGenType = pType; }
+ CodePosition codePosition() const { return m_CodePosition; }
+ void setCodePosition(CodePosition pPosition) { m_CodePosition = pPosition; }
+
+ bool isCodeIndep() const { return (Independent == m_CodePosition); }
+ bool isCodeDynamic() const { return (DynamicDependent == m_CodePosition); }
+ bool isCodeStatic() const { return (StaticDependent == m_CodePosition); }
+
static const char* version();
private:
@@ -81,6 +110,7 @@ private:
AttributeOption m_Attribute;
CodeGenType m_CodeGenType;
+ CodePosition m_CodePosition;
};
} // namespace of mcld
diff --git a/include/mcld/MC/SearchDirs.h b/include/mcld/MC/SearchDirs.h
index 13cc12f..0c0c657 100644
--- a/include/mcld/MC/SearchDirs.h
+++ b/include/mcld/MC/SearchDirs.h
@@ -65,6 +65,8 @@ public:
iterator end () { return m_DirList.end(); }
// ----- modifiers ----- //
+ bool insert(const char* pDirectory);
+
bool insert(const std::string& pDirectory);
bool insert(const sys::fs::Path& pDirectory);
diff --git a/include/mcld/MC/SymbolCategory.h b/include/mcld/MC/SymbolCategory.h
index 3aa16c5..700fba2 100644
--- a/include/mcld/MC/SymbolCategory.h
+++ b/include/mcld/MC/SymbolCategory.h
@@ -11,7 +11,7 @@
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
-#include <mcld/ADT/TypeTraits.h>
+#include <cstddef>
#include <vector>
namespace mcld
@@ -45,7 +45,7 @@ public:
SymbolCategory& changeCommonsToGlobal();
- SymbolCategory& changeLocalToTLS(const LDSymbol& pSymbol);
+ SymbolCategory& changeLocalToDynamic(const LDSymbol& pSymbol);
// ----- access ----- //
LDSymbol& at(size_t pPosition)
@@ -63,18 +63,30 @@ public:
// ----- observers ----- //
size_t numOfSymbols() const;
+ size_t numOfFiles() const;
+
size_t numOfLocals() const;
+ size_t numOfLocalDyns() const;
+
size_t numOfCommons() const;
+ size_t numOfDynamics() const;
+
size_t numOfRegulars() const;
bool empty() const;
+ bool emptyFiles() const;
+
bool emptyLocals() const;
+ bool emptyLocalDyns() const;
+
bool emptyCommons() const;
+ bool emptyDynamics() const;
+
bool emptyRegulars() const;
// ----- iterators ----- //
@@ -83,21 +95,31 @@ public:
const_iterator begin() const;
const_iterator end() const;
+ iterator fileBegin();
+ iterator fileEnd();
+ const_iterator fileBegin() const;
+ const_iterator fileEnd() const;
+
iterator localBegin();
iterator localEnd();
const_iterator localBegin() const;
const_iterator localEnd() const;
- iterator tlsBegin();
- iterator tlsEnd();
- const_iterator tlsBegin() const;
- const_iterator tlsEnd() const;
+ iterator localDynBegin();
+ iterator localDynEnd();
+ const_iterator localDynBegin() const;
+ const_iterator localDynEnd() const;
iterator commonBegin();
iterator commonEnd();
const_iterator commonBegin() const;
const_iterator commonEnd() const;
+ iterator dynamicBegin();
+ iterator dynamicEnd();
+ const_iterator dynamicBegin() const;
+ const_iterator dynamicEnd() const;
+
iterator regularBegin();
iterator regularEnd();
const_iterator regularBegin() const;
@@ -110,10 +132,10 @@ private:
enum Type {
File,
Local,
- TLS,
+ LocalDyn,
Common,
- Weak,
- Global
+ Dynamic,
+ Regular
};
public:
@@ -147,18 +169,20 @@ private:
{ return (NULL == next); }
static Type categorize(const ResolveInfo& pInfo);
-
};
private:
+ SymbolCategory& add(LDSymbol& pSymbol, Category::Type pTarget);
+
+private:
OutputSymbols m_OutputSymbols;
Category* m_pFile;
Category* m_pLocal;
- Category* m_pTLS;
+ Category* m_pLocalDyn;
Category* m_pCommon;
- Category* m_pWeak;
- Category* m_pGlobal;
+ Category* m_pDynamic;
+ Category* m_pRegular;
};
} // namespace of mcld
diff --git a/include/mcld/Object/ObjectBuilder.h b/include/mcld/Object/ObjectBuilder.h
index bfa4c6b..79f81a5 100644
--- a/include/mcld/Object/ObjectBuilder.h
+++ b/include/mcld/Object/ObjectBuilder.h
@@ -65,12 +65,16 @@ public:
///
/// @see SectionMap
/// @param [in] pInputSection The merged input section.
- /// @return If the corresponding output sections is not defined, return false.
- bool MergeSection(LDSection& pInputSection);
+ /// @return The merged output section. If the corresponding output sections
+ /// is not defined, return NULL.
+ LDSection* MergeSection(LDSection& pInputSection);
/// MoveSectionData - move the fragment of pFrom to pTo section data.
static bool MoveSectionData(SectionData& pFrom, SectionData& pTo);
+ /// UpdateSectionAlign - update alignment for input section
+ static void UpdateSectionAlign(LDSection& pTo, const LDSection& pFrom);
+
/// @}
/// @name Fragment Methods
/// @{
diff --git a/include/mcld/Object/ObjectLinker.h b/include/mcld/Object/ObjectLinker.h
index 515bc58..999764f 100644
--- a/include/mcld/Object/ObjectLinker.h
+++ b/include/mcld/Object/ObjectLinker.h
@@ -44,12 +44,12 @@ class ObjectLinker
{
public:
ObjectLinker(const LinkerConfig& pConfig,
- Module& pModule,
- IRBuilder& pBuilder,
TargetLDBackend& pLDBackend);
~ObjectLinker();
+ void setup(Module& pModule, IRBuilder& pBuilder);
+
/// initFragmentLinker - initialize FragmentLinker
/// Connect all components in FragmentLinker
bool initFragmentLinker();
@@ -72,6 +72,10 @@ public:
/// mergeSections - put allinput sections into output sections
bool mergeSections();
+ /// allocateCommonSymobols - allocate fragments for common symbols to the
+ /// corresponding sections
+ bool allocateCommonSymbols();
+
/// addStandardSymbols - shared object and executable files need some
/// standard symbols
/// @return if there are some input symbols with the same name to the
@@ -84,9 +88,18 @@ public:
/// target symbols, return false
bool addTargetSymbols();
+ /// addScriptSymbols - define symbols from the command line option or linker
+ /// scripts.
+ /// @return if there are some existing symbols with identical name to the
+ /// script symbols, return false.
+ bool addScriptSymbols();
+
/// scanRelocations - scan all relocation entries by output symbols.
bool scanRelocations();
+ /// initStubs - initialize stub-related stuff.
+ bool initStubs();
+
/// prelayout - help backend to do some modification before layout
bool prelayout();
@@ -140,25 +153,15 @@ public:
const BinaryReader* getBinaryReader () const { return m_pBinaryReader; }
BinaryReader* getBinaryReader () { return m_pBinaryReader; }
- const ObjectWriter* getObjectWriter () const { return m_pObjectWriter; }
- ObjectWriter* getObjectWriter () { return m_pObjectWriter; }
-
- const DynObjWriter* getDynObjWriter () const { return m_pDynObjWriter; }
- DynObjWriter* getDynObjWriter () { return m_pDynObjWriter; }
-
- const ExecWriter* getExecWriter () const { return m_pExecWriter; }
- ExecWriter* getExecWriter () { return m_pExecWriter; }
-
- const BinaryWriter* getBinaryWriter () const { return m_pBinaryWriter; }
- BinaryWriter* getBinaryWriter () { return m_pBinaryWriter; }
+ const ObjectWriter* getWriter () const { return m_pWriter; }
+ ObjectWriter* getWriter () { return m_pWriter; }
private:
const LinkerConfig& m_Config;
- Module& m_Module;
-
- IRBuilder& m_Builder;
-
FragmentLinker* m_pLinker;
+ Module* m_pModule;
+ IRBuilder* m_pBuilder;
+
TargetLDBackend &m_LDBackend;
// ----- readers and writers ----- //
@@ -167,10 +170,7 @@ private:
ArchiveReader* m_pArchiveReader;
GroupReader* m_pGroupReader;
BinaryReader* m_pBinaryReader;
- ObjectWriter* m_pObjectWriter;
- DynObjWriter* m_pDynObjWriter;
- ExecWriter* m_pExecWriter;
- BinaryWriter* m_pBinaryWriter;
+ ObjectWriter* m_pWriter;
};
} // end namespace mcld
diff --git a/include/mcld/Support/FileHandle.h b/include/mcld/Support/FileHandle.h
index 3b4fe81..ce43e0f 100644
--- a/include/mcld/Support/FileHandle.h
+++ b/include/mcld/Support/FileHandle.h
@@ -35,6 +35,7 @@ public:
BadBit = 1L << 0, // error due to the inappropriate operation
EOFBit = 1L << 1, // reached End-Of-File
FailBit = 1L << 2, // internal logic fail
+ DeputedBit = 1L << 3, // the file descriptor is delegated
IOStateEnd = 1L << 16
};
@@ -120,14 +121,15 @@ public:
bool isFailed() const;
+ bool isOwned() const;
+
bool isReadable() const;
bool isWritable() const;
bool isReadWrite() const;
- int error() const
- { return errno; }
+ int error() const { return errno; }
private:
sys::fs::Path m_Path;
diff --git a/include/mcld/Support/MemoryArea.h b/include/mcld/Support/MemoryArea.h
index a735f62..74297f3 100644
--- a/include/mcld/Support/MemoryArea.h
+++ b/include/mcld/Support/MemoryArea.h
@@ -110,7 +110,7 @@ private:
size_t m_Length;
};
- typedef std::map<Key, Space*, Key::Compare> SpaceMapType;
+ typedef std::multimap<Key, Space*, Key::Compare> SpaceMapType;
private:
SpaceMapType m_SpaceMap;
diff --git a/include/mcld/Support/PathCache.h b/include/mcld/Support/PathCache.h
index 89ec513..8da59e5 100644
--- a/include/mcld/Support/PathCache.h
+++ b/include/mcld/Support/PathCache.h
@@ -24,7 +24,7 @@ namespace fs {
namespace {
typedef HashEntry<llvm::StringRef,
- mcld::sys::fs::Path*,
+ mcld::sys::fs::Path,
StringCompare<llvm::StringRef> > HashEntryType;
} // anonymous namespace
diff --git a/include/mcld/Target/ELFDynamic.h b/include/mcld/Target/ELFDynamic.h
index 7102226..62f534d 100644
--- a/include/mcld/Target/ELFDynamic.h
+++ b/include/mcld/Target/ELFDynamic.h
@@ -88,6 +88,43 @@ private:
Pair m_Pair;
};
+template<>
+class Entry<64, true> : public EntryIF
+{
+public:
+ typedef llvm::ELF::Elf64_Dyn Pair;
+ typedef llvm::ELF::Elf64_Sym Symbol;
+ typedef llvm::ELF::Elf64_Rel Rel;
+ typedef llvm::ELF::Elf64_Rela Rela;
+
+public:
+ inline Entry();
+
+ inline ~Entry();
+
+ Entry* clone() const
+ { return new Entry(); }
+
+ size_t size() const
+ { return sizeof(Pair); }
+
+ size_t symbolSize() const
+ { return sizeof(Symbol); }
+
+ size_t relSize() const
+ { return sizeof(Rel); }
+
+ size_t relaSize() const
+ { return sizeof(Rela); }
+
+ inline void setValue(uint64_t pTag, uint64_t pValue);
+
+ inline size_t emit(uint8_t* pAddress) const;
+
+private:
+ Pair m_Pair;
+};
+
#include "ELFDynamic.tcc"
} // namespace of elf_dynamic
diff --git a/include/mcld/Target/ELFDynamic.tcc b/include/mcld/Target/ELFDynamic.tcc
index 8b04651..5d67be4 100644
--- a/include/mcld/Target/ELFDynamic.tcc
+++ b/include/mcld/Target/ELFDynamic.tcc
@@ -7,6 +7,8 @@
//
//===----------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
+/// 32-bit dynamic entry
Entry<32, true>::Entry()
{
m_Pair.d_tag = 0;
@@ -31,3 +33,29 @@ size_t Entry<32, true>::emit(uint8_t* pAddress) const
return sizeof(Pair);
}
+//===----------------------------------------------------------------------===//
+/// 64-bit dynamic entry
+Entry<64, true>::Entry()
+{
+ m_Pair.d_tag = 0;
+ m_Pair.d_un.d_val = 0;
+}
+
+Entry<64, true>::~Entry()
+{
+}
+
+void Entry<64, true>::setValue(uint64_t pTag, uint64_t pValue)
+{
+ m_Pair.d_tag = pTag;
+ m_Pair.d_un.d_val = pValue;
+}
+
+size_t Entry<64, true>::emit(uint8_t* pAddress) const
+{
+ memcpy(reinterpret_cast<void*>(pAddress),
+ reinterpret_cast<const void*>(&m_Pair),
+ sizeof(Pair));
+ return sizeof(Pair);
+}
+
diff --git a/include/mcld/Target/GNUInfo.h b/include/mcld/Target/GNUInfo.h
index f918431..86a29ba 100644
--- a/include/mcld/Target/GNUInfo.h
+++ b/include/mcld/Target/GNUInfo.h
@@ -38,6 +38,33 @@ public:
/// ABIVersion - the value of e_ident[EI_ABIVRESION]
uint8_t ABIVersion() const { return 0x0; }
+ /// defaultTextSegmentAddr - target should specify its own default start address
+ /// of the text segment. esp. for exec.
+ virtual uint64_t defaultTextSegmentAddr() const { return 0x0; }
+
+ /// flags - the value of ElfXX_Ehdr::e_flags
+ virtual uint64_t flags() const = 0;
+
+ /// entry - the symbol name of the entry point
+ virtual const char* entry() const { return "_start"; }
+
+ /// 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"; }
+
+ /// 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; }
+
+ /// 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
+ virtual uint64_t commonPageSize() const { return 0x1000; }
+
+ /// 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 { return 0x1000; }
+
private:
const llvm::Triple& m_Triple;
};
diff --git a/include/mcld/Target/GNULDBackend.h b/include/mcld/Target/GNULDBackend.h
index d20b8ac..dfcbd85 100644
--- a/include/mcld/Target/GNULDBackend.h
+++ b/include/mcld/Target/GNULDBackend.h
@@ -23,10 +23,7 @@
#include <mcld/LD/ELFObjectReader.h>
#include <mcld/LD/ELFDynObjReader.h>
#include <mcld/LD/ELFBinaryReader.h>
-#include <mcld/LD/ELFDynObjWriter.h>
-#include <mcld/LD/ELFExecWriter.h>
#include <mcld/LD/ELFObjectWriter.h>
-#include <mcld/LD/ELFBinaryWriter.h>
#include <mcld/LD/ELFSegment.h>
#include <mcld/LD/ELFSegmentFactory.h>
#include <mcld/Target/ELFDynamic.h>
@@ -41,7 +38,6 @@ class Module;
class LinkerConfig;
class IRBuilder;
class Layout;
-class EhFrame;
class EhFrameHdr;
class BranchIslandFactory;
class StubFactory;
@@ -64,10 +60,7 @@ public:
ELFObjectReader* createObjectReader(IRBuilder& pBuilder);
ELFDynObjReader* createDynObjReader(IRBuilder& pBuilder);
ELFBinaryReader* createBinaryReader(IRBuilder& pBuilder);
- ELFObjectWriter* createObjectWriter();
- ELFDynObjWriter* createDynObjWriter();
- ELFExecWriter* createExecWriter();
- ELFBinaryWriter* createBinaryWriter();
+ ELFObjectWriter* createWriter();
// ----- output sections ----- //
/// initStdSections - initialize standard sections of the output file.
@@ -81,26 +74,26 @@ public:
/// 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. FragmentLinker must finalize its value
+ /// undefined symbol in input objects. ObjectLinker 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(FragmentLinker& pLinker, Module& pModule);
+ bool initStandardSymbols(IRBuilder& pBuilder, Module& pModule);
/// 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(FragmentLinker& pLinker) {
- return (finalizeStandardSymbols(pLinker) &&
- finalizeTargetSymbols(pLinker));
+ bool finalizeSymbols() {
+ return (finalizeStandardSymbols() &&
+ finalizeTargetSymbols());
}
/// finalizeStandardSymbols - set the value of standard symbols
- virtual bool finalizeStandardSymbols(FragmentLinker& pLinker);
+ virtual bool finalizeStandardSymbols();
/// finalizeTargetSymbols - set the value of target symbols
- virtual bool finalizeTargetSymbols(FragmentLinker& pLinker) = 0;
+ virtual bool finalizeTargetSymbols() = 0;
/// finalizeTLSSymbol - set the value of a TLS symbol
virtual bool finalizeTLSSymbol(LDSymbol& pSymbol);
@@ -110,56 +103,41 @@ public:
const GNUInfo& getInfo() const { return *m_pInfo; }
GNUInfo& getInfo() { return *m_pInfo; }
- /// flags - the value of ElfXX_Ehdr::e_flags
- virtual uint64_t flags() const = 0;
+ bool hasTextRel() const { return m_bHasTextRel; }
- /// entry - the symbol name of the entry point
- 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; }
-
- bool hasTextRel() const
- { return m_bHasTextRel; }
-
- bool hasStaticTLS() const
- { return m_bHasStaticTLS; }
+ bool hasStaticTLS() const { return m_bHasStaticTLS; }
/// segmentStartAddr - this function returns the start address of the segment
- uint64_t segmentStartAddr(const FragmentLinker& pLinker) const;
+ uint64_t segmentStartAddr() const;
/// partialScanRelocation - When doing partial linking, fix the relocation
/// offset after section merge
void partialScanRelocation(Relocation& pReloc,
- FragmentLinker& pLinker,
Module& pModule,
const LDSection& pSection);
/// sizeNamePools - compute the size of regular name pools
/// In ELF executable files, regular name pools are .symtab, .strtab.,
/// .dynsym, .dynstr, and .hash
- virtual void sizeNamePools(const Module& pModule, bool pIsStaticLink);
+ virtual void sizeNamePools(Module& pModule, bool pIsStaticLink);
/// emitSectionData - emit target-dependent section data
virtual uint64_t emitSectionData(const LDSection& pSection,
MemoryRegion& pRegion) const = 0;
/// emitRegNamePools - emit regular name pools - .symtab, .strtab
- virtual void emitRegNamePools(const Module& pModule,
- MemoryArea& pOutput);
+ virtual void emitRegNamePools(const Module& pModule, MemoryArea& pOutput);
/// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash
- virtual void emitDynNamePools(const Module& pModule,
- MemoryArea& pOutput);
+ virtual void emitDynNamePools(Module& pModule, MemoryArea& pOutput);
+
+ /// emitELFHashTab - emit .hash
+ virtual void emitELFHashTab(const Module::SymbolTable& pSymtab,
+ MemoryArea& pOutput);
+
+ /// emitGNUHashTab - emit .gnu.hash
+ virtual void emitGNUHashTab(Module::SymbolTable& pSymtab,
+ MemoryArea& pOutput);
/// sizeInterp - compute the size of program interpreter's name
/// In ELF executables, this is the length of dynamic linker's path name
@@ -191,48 +169,44 @@ public:
/// 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(); }
+ size_t numOfSegments() const { return m_ELFSegmentTable.size(); }
/// elfSegmentTable - return the reference of the elf segment table
- ELFSegmentFactory& elfSegmentTable()
- { return m_ELFSegmentTable; }
+ ELFSegmentFactory& elfSegmentTable() { return m_ELFSegmentTable; }
/// elfSegmentTable - return the reference of the elf segment table
- const ELFSegmentFactory& elfSegmentTable() const
- { return m_ELFSegmentTable; }
+ const ELFSegmentFactory& elfSegmentTable() const { 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;
+ /// commonPageSize - the common page size of the target machine
+ uint64_t commonPageSize() 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;
+ /// abiPageSize - the abi page size of the target machine
+ uint64_t abiPageSize() 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; }
+ size_t getSymbolIdx(const LDSymbol* pSymbol) const;
/// allocateCommonSymbols - allocate common symbols in the corresponding
/// sections.
/// Different concrete target backend may overlap this function.
virtual bool allocateCommonSymbols(Module& pModule);
+ /// updateSectionFlags - update pTo's flags when merging pFrom
+ /// update the output section flags based on input section flags.
+ virtual bool updateSectionFlags(LDSection& pTo, const LDSection& pFrom);
+
/// isSymbolPreemtible - whether the symbol can be preemted by other
/// link unit
/// @ref Google gold linker, symtab.h:551
bool isSymbolPreemptible(const ResolveInfo& pSym) const;
+ virtual ResolveInfo::Desc getSymDesc(uint16_t pShndx) const {
+ return ResolveInfo::Define;
+ }
+
/// symbolNeedsDynRel - return whether the symbol needs a dynamic relocation
/// @ref Google gold linker, symtab.h:645
- bool symbolNeedsDynRel(const FragmentLinker& pLinker,
- const ResolveInfo& pSym,
+ bool symbolNeedsDynRel(const ResolveInfo& pSym,
bool pSymHasPLT,
bool isAbsReloc) const;
@@ -270,10 +244,17 @@ protected:
uint64_t getSymbolShndx(const LDSymbol& pSymbol) const;
+ /// isTemporary - Whether pSymbol is a local label.
+ virtual bool isTemporary(const LDSymbol& pSymbol) const;
+
/// getHashBucketCount - calculate hash bucket count.
/// @ref Google gold linker, dynobj.cc:791
static unsigned getHashBucketCount(unsigned pNumOfSymbols, bool pIsGNUStyle);
+ /// getGNUHashMaskbitslog2 - calculate the number of mask bits in log2
+ /// @ref binutils gold, dynobj.cc:1165
+ unsigned getGNUHashMaskbitslog2(unsigned pNumOfSymbols) const;
+
/// isDynamicSymbol
/// @ref Google gold linker: symtab.cc:311
bool isDynamicSymbol(const LDSymbol& pSymbol);
@@ -284,18 +265,15 @@ protected:
/// symbolNeedsPLT - return whether the symbol needs a PLT entry
/// @ref Google gold linker, symtab.h:596
- bool symbolNeedsPLT(const FragmentLinker& pLinker,
- const ResolveInfo& pSym) const;
+ bool symbolNeedsPLT(const ResolveInfo& pSym) const;
/// symbolNeedsCopyReloc - return whether the symbol needs a copy relocation
- bool symbolNeedsCopyReloc(const FragmentLinker& pLinker,
- const Relocation& pReloc,
+ bool symbolNeedsCopyReloc(const Relocation& pReloc,
const ResolveInfo& pSym) const;
/// symbolHasFinalValue - return true if the symbol's value can be decided at
/// link time
- bool symbolFinalValueIsKnown(const FragmentLinker& pLinker,
- const ResolveInfo& pSym) const;
+ bool symbolFinalValueIsKnown(const ResolveInfo& pSym) const;
/// emitSymbol32 - emit an ELF32 symbol
void emitSymbol32(llvm::ELF::Elf32_Sym& pSym32,
@@ -314,21 +292,19 @@ protected:
/// checkAndSetHasTextRel - check pSection flag to set HasTextRel
void checkAndSetHasTextRel(const LDSection& pSection);
- void setHasStaticTLS(bool pVal = true)
- { m_bHasStaticTLS = pVal; }
+ void setHasStaticTLS(bool pVal = true) { m_bHasStaticTLS = pVal; }
private:
/// createProgramHdrs - base on output sections to create the program headers
- void createProgramHdrs(Module& pModule, const FragmentLinker& pLinker);
+ void createProgramHdrs(Module& pModule);
/// doCreateProgramHdrs - backend can implement this function to create the
/// target-dependent segments
- virtual void doCreateProgramHdrs(Module& pModule,
- const FragmentLinker& pLinker) = 0;
+ virtual void doCreateProgramHdrs(Module& pModule) = 0;
/// setupProgramHdrs - set up the attributes of segments
/// (i.e., offset, addresses, file/mem size, flag, and alignment)
- void setupProgramHdrs(const FragmentLinker& pLinker);
+ void setupProgramHdrs();
/// getSegmentFlag - give a section flag and return the corresponding segment
/// flag
@@ -343,7 +319,7 @@ private:
}
/// setupGNUStackInfo - setup the section flag of .note.GNU-stack in output
- void setupGNUStackInfo(Module& pModule, FragmentLinker& pLinker);
+ void setupGNUStackInfo(Module& pModule);
/// setupRelro - setup the offset constraint of PT_RELRO
void setupRelro(Module& pModule);
@@ -356,28 +332,27 @@ private:
uint64_t pStartOffset = -1U);
/// setOutputSectionOffset - helper function to set output sections' address.
- void setOutputSectionAddress(FragmentLinker& pLinker,
- Module& pModule,
+ void setOutputSectionAddress(Module& pModule,
Module::iterator pSectBegin,
Module::iterator pSectEnd);
/// layout - layout method
- void layout(Module& pModule, FragmentLinker& pLinker);
+ void layout(Module& pModule);
/// preLayout - Backend can do any needed modification before layout
- void preLayout(Module& pModule, FragmentLinker& pLinker);
+ void preLayout(Module& pModule, IRBuilder& pBuilder);
/// postLayout -Backend can do any needed modification after layout
- void postLayout(Module& pModule, FragmentLinker& pLinker);
+ void postLayout(Module& pModule, IRBuilder& pBuilder);
/// preLayout - Backend can do any needed modification before layout
- virtual void doPreLayout(FragmentLinker& pLinker) = 0;
+ virtual void doPreLayout(IRBuilder& pBuilder) = 0;
/// postLayout -Backend can do any needed modification after layout
- virtual void doPostLayout(Module& pModule, FragmentLinker& pLinker) = 0;
+ virtual void doPostLayout(Module& pModule, IRBuilder& pLinker) = 0;
/// postProcessing - Backend can do any needed modification in the final stage
- void postProcessing(FragmentLinker& pLinker, MemoryArea& pOutput);
+ void postProcessing(MemoryArea& pOutput);
/// dynamic - the dynamic section of the target machine.
virtual ELFDynamic& dynamic() = 0;
@@ -386,7 +361,7 @@ private:
virtual const ELFDynamic& dynamic() const = 0;
/// relax - the relaxation pass
- bool relax(Module& pModule, FragmentLinker& pLinker);
+ bool relax(Module& pModule, IRBuilder& pBuilder);
/// mayRelax - Backends should override this function if they need relaxation
virtual bool mayRelax() { return false; }
@@ -395,7 +370,7 @@ private:
/// implementation. Return true if the output (e.g., .text) is "relaxed"
/// (i.e. layout is changed), and set pFinished to true if everything is fit,
/// otherwise set it to false.
- virtual bool doRelax(Module& pModule, FragmentLinker& pLinker, bool& pFinished)
+ virtual bool doRelax(Module& pModule, IRBuilder& pBuilder, bool& pFinished)
{ return false; }
/// getRelEntrySize - the size in BYTE of rel type relocation
@@ -450,6 +425,14 @@ protected:
{ return (X==Y); }
};
+ // for gnu style hash table
+ struct DynsymCompare
+ {
+ bool needGNUHash(const LDSymbol& X) const;
+
+ bool operator()(const LDSymbol* X, const LDSymbol* Y) const;
+ };
+
struct SymPtrHash
{
size_t operator()(const LDSymbol* pKey) const
@@ -488,9 +471,6 @@ protected:
// map the LDSymbol to its index in the output symbol table
HashTableType* m_pSymIndexMap;
- /// m_pEhFrame - section .eh_frame
- EhFrame* m_pEhFrame;
-
// section .eh_frame_hdr
EhFrameHdr* m_pEhFrameHdr;
diff --git a/include/mcld/Target/TargetLDBackend.h b/include/mcld/Target/TargetLDBackend.h
index 10cf280..1690004 100644
--- a/include/mcld/Target/TargetLDBackend.h
+++ b/include/mcld/Target/TargetLDBackend.h
@@ -16,7 +16,6 @@ namespace mcld {
class Module;
class LinkerConfig;
class IRBuilder;
-class FragmentLinker;
class Relocation;
class RelocationFactory;
class Relocator;
@@ -56,13 +55,13 @@ public:
virtual ~TargetLDBackend();
// ----- target dependent ----- //
- virtual void initTargetSegments(FragmentLinker& pLinker) { }
+ virtual void initTargetSegments(IRBuilder& pBuilder) { }
virtual void initTargetSections(Module& pModule, ObjectBuilder& pBuilder) { }
- virtual void initTargetSymbols(FragmentLinker& pLinker) { }
- virtual void initTargetRelocation(FragmentLinker& pLinker) { }
- virtual bool initStandardSymbols(FragmentLinker& pLinker, Module& pModule) = 0;
+ virtual void initTargetSymbols(IRBuilder& pBuilder, Module& pModule) { }
+ virtual void initTargetRelocation(IRBuilder& pBuilder) { }
+ virtual bool initStandardSymbols(IRBuilder& pBuilder, Module& pModule) = 0;
- virtual bool initRelocator(const FragmentLinker& pLinker) = 0;
+ virtual bool initRelocator() = 0;
virtual Relocator* getRelocator() = 0;
@@ -74,9 +73,9 @@ public:
/// @param pInputSym - the input LDSymbol of relocation target symbol
/// @param pSection - the section of relocation applying target
virtual void scanRelocation(Relocation& pReloc,
- FragmentLinker& pLinker,
+ IRBuilder& pBuilder,
Module& pModule,
- const LDSection& pSection) = 0;
+ LDSection& pSection) = 0;
/// partialScanRelocation - When doing partial linking, backend can do any
/// modification to relocation to fix the relocation offset after section
@@ -85,7 +84,6 @@ public:
/// @param pInputSym - the input LDSymbol of relocation target symbol
/// @param pSection - the section of relocation applying target
virtual void partialScanRelocation(Relocation& pReloc,
- FragmentLinker& pLinker,
Module& pModule,
const LDSection& pSection) = 0;
@@ -94,31 +92,21 @@ public:
virtual ObjectReader* createObjectReader(IRBuilder&) = 0;
virtual DynObjReader* createDynObjReader(IRBuilder&) = 0;
virtual BinaryReader* createBinaryReader(IRBuilder&) = 0;
- virtual ObjectWriter* createObjectWriter() = 0;
- virtual DynObjWriter* createDynObjWriter() = 0;
- virtual ExecWriter* createExecWriter() = 0;
- virtual BinaryWriter* createBinaryWriter() = 0;
+ virtual ObjectWriter* createWriter() = 0;
virtual bool initStdSections(ObjectBuilder& pBuilder) = 0;
/// layout - layout method
- virtual void layout(Module& pModule, FragmentLinker& pLinker) = 0;
+ virtual void layout(Module& pModule) = 0;
/// preLayout - Backend can do any needed modification before layout
- virtual void preLayout(Module& pModule, FragmentLinker& pLinker) = 0;
+ virtual void preLayout(Module& pModule, IRBuilder& pBuilder) = 0;
- /// postLayout -Backend can do any needed modification after layout
- virtual void postLayout(Module& pModule, FragmentLinker& pLinker) = 0;
+ /// postLayout - Backend can do any needed modification after layout
+ virtual void postLayout(Module& pModule, IRBuilder& pBuilder) = 0;
/// postProcessing - Backend can do any needed modification in the final stage
- virtual void postProcessing(FragmentLinker& pLinker,
- MemoryArea& pOutput) = 0;
-
- /// the common page size of the target machine
- virtual uint64_t commonPageSize() const = 0;
-
- /// the abi page size of the target machine
- virtual uint64_t abiPageSize() const = 0;
+ virtual void postProcessing(MemoryArea& pOutput) = 0;
/// section start offset in the output file
virtual size_t sectionStartOffset() const = 0;
@@ -129,14 +117,13 @@ public:
/// sizeNamePools - compute the size of regular name pools
/// In ELF executable files, regular name pools are .symtab, .strtab.,
/// .dynsym, .dynstr, and .hash
- virtual void
- sizeNamePools(const Module& pModule, bool pIsStaticLink) = 0;
+ virtual void sizeNamePools(Module& pModule, bool pIsStaticLink) = 0;
/// finalizeSymbol - Linker checks pSymbol.reserved() if it's not zero,
/// then it will ask backend to finalize the symbol value.
/// @return ture - if backend set the symbol value sucessfully
/// @return false - if backend do not recognize the symbol
- virtual bool finalizeSymbols(FragmentLinker& pLinker) = 0;
+ virtual bool finalizeSymbols() = 0;
/// finalizeTLSSymbol - Linker asks backend to set the symbol value when it
/// meets a TLS symbol
@@ -150,13 +137,17 @@ public:
virtual bool mergeSection(Module& pModule, LDSection& pInputSection)
{ return true; }
+ /// updateSectionFlags - update pTo's flags when merging pFrom
+ /// update the output section flags based on input section flags.
+ /// FIXME: (Luba) I know ELF need to merge flags, but I'm not sure if
+ /// MachO and COFF also need this.
+ virtual bool updateSectionFlags(LDSection& pTo, const LDSection& pFrom)
+ { return true; }
+
/// readSection - read a target dependent section
virtual bool readSection(Input& pInput, SectionData& pSD)
{ 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() = 0;
@@ -164,13 +155,13 @@ public:
// ----- relaxation ----- //
virtual bool initBRIslandFactory() = 0;
virtual bool initStubFactory() = 0;
- virtual bool initTargetStubs(FragmentLinker& pLinker) { return true; }
+ virtual bool initTargetStubs() { return true; }
virtual BranchIslandFactory* getBRIslandFactory() = 0;
virtual StubFactory* getStubFactory() = 0;
/// relax - the relaxation pass
- virtual bool relax(Module& pModule, FragmentLinker& pLinker) = 0;
+ virtual bool relax(Module& pModule, IRBuilder& pBuilder) = 0;
/// mayRelax - return true if the backend needs to do relaxation
virtual bool mayRelax() = 0;
diff --git a/lib/CodeGen/MCLDTargetMachine.cpp b/lib/CodeGen/MCLDTargetMachine.cpp
index 785ef1f..57da5b5 100644
--- a/lib/CodeGen/MCLDTargetMachine.cpp
+++ b/lib/CodeGen/MCLDTargetMachine.cpp
@@ -214,8 +214,6 @@ bool mcld::MCLDTargetMachine::addPassesToEmitFile(PassManagerBase &pPM,
pOutput.formatted_os(),
Context))
return true;
-
- pPM.add(createGCInfoDeleter()); // not in addPassesToMC
break;
}
case CGFT_OBJFile: {
@@ -227,8 +225,6 @@ bool mcld::MCLDTargetMachine::addPassesToEmitFile(PassManagerBase &pPM,
pOutput.mem_os(),
Context))
return true;
-
- pPM.add(createGCInfoDeleter()); // not in addPassesToMC
break;
}
case CGFT_EXEFile: {
diff --git a/lib/CodeGen/MCLinker.cpp b/lib/CodeGen/MCLinker.cpp
index 6b7196b..3613a03 100644
--- a/lib/CodeGen/MCLinker.cpp
+++ b/lib/CodeGen/MCLinker.cpp
@@ -382,6 +382,7 @@ void MCLinker::initializeInputTree(IRBuilder& pBuilder)
std::vector<InputAction*>::iterator action, actionEnd = actions.end();
for (action = actions.begin(); action != actionEnd; ++action) {
(*action)->activate(pBuilder.getInputBuilder());
+ delete *action;
}
if (pBuilder.getInputBuilder().isInGroup())
diff --git a/lib/Core/GeneralOptions.cpp b/lib/Core/GeneralOptions.cpp
index d762237..f29ab1d 100644
--- a/lib/Core/GeneralOptions.cpp
+++ b/lib/Core/GeneralOptions.cpp
@@ -41,7 +41,6 @@ GeneralOptions::GeneralOptions()
m_Bgroup(false),
m_bPIE(false),
m_bColor(true),
- m_bAllowShlibUndefined(true),
m_bCreateEhFrameHdr(false),
m_bNMagic(false),
m_bOMagic(false),
@@ -50,8 +49,11 @@ GeneralOptions::GeneralOptions()
m_bWarnSharedTextrel(false),
m_bBinaryInput(false),
m_bDefineCommon(false),
- m_bFatalWarnings(false)
-{
+ m_bFatalWarnings(false),
+ m_bNewDTags(false),
+ m_bNoStdlib(false),
+ m_StripSymbols(KeepAllSymbols),
+ m_HashStyle(SystemV) {
}
GeneralOptions::~GeneralOptions()
@@ -82,6 +84,11 @@ void GeneralOptions::setSysroot(const mcld::sys::fs::Path &pSysroot)
m_SearchDirs.setSysRoot(pSysroot);
}
+bool GeneralOptions::hasSysroot() const
+{
+ return !sysroot().empty();
+}
+
void GeneralOptions::setSOName(const std::string& pName)
{
size_t pos = pName.find_last_of(sys::fs::separator);
diff --git a/lib/Core/IRBuilder.cpp b/lib/Core/IRBuilder.cpp
index 5472db0..549aa8d 100644
--- a/lib/Core/IRBuilder.cpp
+++ b/lib/Core/IRBuilder.cpp
@@ -83,7 +83,7 @@ LDFileFormat::Kind GetELFSectionKind(uint32_t pType, const char* pName)
return LDFileFormat::MetaData;
}
-bool shouldForceLocal(const ResolveInfo& pInfo, const LinkerConfig& pConfig)
+bool ShouldForceLocal(const ResolveInfo& pInfo, const LinkerConfig& pConfig)
{
// forced local symbol matches all rules:
// 1. We are not doing incremental linking.
@@ -333,7 +333,7 @@ EhFrame* IRBuilder::CreateEhFrame(LDSection& pSection)
{
assert(!pSection.hasEhFrame() && "pSection already has eh_frame.");
- EhFrame* eh_frame = new EhFrame(pSection);
+ EhFrame* eh_frame = EhFrame::Create(pSection);
pSection.setEhFrame(eh_frame);
return eh_frame;
}
@@ -471,13 +471,14 @@ LDSymbol* IRBuilder::AddSymbol(Input& pInput,
return input_sym;
}
case Input::DynObj: {
- return addSymbolFromDynObj(name, pType, pDesc, pBind, pSize, pValue, pVis);
+ return addSymbolFromDynObj(pInput, name, pType, pDesc, pBind, pSize, pValue, pVis);
}
default: {
return NULL;
break;
}
}
+ return NULL;
}
LDSymbol* IRBuilder::addSymbolFromObject(const std::string& pName,
@@ -564,7 +565,7 @@ LDSymbol* IRBuilder::addSymbolFromObject(const std::string& pName,
// No matter the symbol is already in the output or not, add it if it
// should be forcefully set local.
- if (shouldForceLocal(*resolved_result.info, m_Config))
+ if (ShouldForceLocal(*resolved_result.info, m_Config))
m_Module.getSymbolTable().forceLocal(*output_sym);
else {
// the symbol should not be forcefully local.
@@ -572,8 +573,8 @@ LDSymbol* IRBuilder::addSymbolFromObject(const std::string& pName,
}
}
else if (resolved_result.overriden) {
- if (!shouldForceLocal(old_info, m_Config) ||
- !shouldForceLocal(*resolved_result.info, m_Config)) {
+ if (!ShouldForceLocal(old_info, m_Config) ||
+ !ShouldForceLocal(*resolved_result.info, m_Config)) {
// If the old info and the new info are both forcefully local, then
// we should keep the output_sym in forcefully local category. Else,
// we should re-sort the output_sym
@@ -585,7 +586,8 @@ LDSymbol* IRBuilder::addSymbolFromObject(const std::string& pName,
return input_sym;
}
-LDSymbol* IRBuilder::addSymbolFromDynObj(const std::string& pName,
+LDSymbol* IRBuilder::addSymbolFromDynObj(Input& pInput,
+ const std::string& pName,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBinding,
@@ -619,6 +621,9 @@ LDSymbol* IRBuilder::addSymbolFromDynObj(const std::string& pName,
// the return ResolveInfo should not NULL
assert(NULL != resolved_result.info);
+ if (resolved_result.overriden || !resolved_result.existent)
+ pInput.setNeeded();
+
// create a LDSymbol for the input file.
LDSymbol* input_sym = LDSymbol::Create(*resolved_result.info);
input_sym->setFragmentRef(FragmentRef::Null());
@@ -638,7 +643,7 @@ LDSymbol* IRBuilder::addSymbolFromDynObj(const std::string& pName,
// After symbol resolution, visibility is changed to the most restrict one.
// If we are not doing incremental linking, then any symbol with hidden
// or internal visibility is forcefully set as a local symbol.
- if (shouldForceLocal(*resolved_result.info, m_Config)) {
+ if (ShouldForceLocal(*resolved_result.info, m_Config)) {
m_Module.getSymbolTable().forceLocal(*output_sym);
}
}
@@ -674,3 +679,190 @@ Relocation* IRBuilder::AddRelocation(LDSection& pSection,
return relocation;
}
+/// AddSymbol - define an output symbol and override it immediately
+template<> LDSymbol*
+IRBuilder::AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
+ const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ FragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility)
+{
+ ResolveInfo* info = m_Module.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_Module.getNamePool().insertSymbol(pName, false, pType, pDesc,
+ pBinding, pSize, pVisibility,
+ NULL, result);
+ assert(!result.existent);
+
+ // create a output LDSymbol
+ output_sym = LDSymbol::Create(*result.info);
+ result.info->setSymPtr(output_sym);
+
+ if (ShouldForceLocal(*result.info, m_Config))
+ m_Module.getSymbolTable().forceLocal(*output_sym);
+ else
+ m_Module.getSymbolTable().add(*output_sym);
+ }
+ else {
+ // the symbol is already in the pool, override it
+ ResolveInfo old_info;
+ old_info.override(*info);
+
+ info->setRegular();
+ info->setType(pType);
+ info->setDesc(pDesc);
+ info->setBinding(pBinding);
+ info->setVisibility(pVisibility);
+ info->setIsSymbol(true);
+ info->setSize(pSize);
+
+ output_sym = info->outSymbol();
+ if (NULL != output_sym)
+ m_Module.getSymbolTable().arrange(*output_sym, old_info);
+ else {
+ // create a output LDSymbol
+ output_sym = LDSymbol::Create(*info);
+ info->setSymPtr(output_sym);
+
+ m_Module.getSymbolTable().add(*output_sym);
+ }
+ }
+
+ if (NULL != output_sym) {
+ output_sym->setFragmentRef(pFragmentRef);
+ output_sym->setValue(pValue);
+ }
+
+ return output_sym;
+}
+
+/// AddSymbol - define an output symbol and override it immediately
+template<> LDSymbol*
+IRBuilder::AddSymbol<IRBuilder::AsReferred, IRBuilder::Unresolve>(
+ const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ FragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility)
+{
+ ResolveInfo* info = m_Module.getNamePool().findInfo(pName);
+
+ if (NULL == info || !(info->isUndef() || info->isDyn())) {
+ // only undefined symbol and dynamic symbol can make a reference.
+ return NULL;
+ }
+
+ // the symbol is already in the pool, override it
+ ResolveInfo old_info;
+ old_info.override(*info);
+
+ info->setRegular();
+ info->setType(pType);
+ info->setDesc(pDesc);
+ info->setBinding(pBinding);
+ info->setVisibility(pVisibility);
+ info->setIsSymbol(true);
+ info->setSize(pSize);
+
+ LDSymbol* output_sym = info->outSymbol();
+ if (NULL != output_sym) {
+ output_sym->setFragmentRef(pFragmentRef);
+ output_sym->setValue(pValue);
+ m_Module.getSymbolTable().arrange(*output_sym, old_info);
+ }
+ else {
+ // create a output LDSymbol
+ output_sym = LDSymbol::Create(*info);
+ info->setSymPtr(output_sym);
+
+ m_Module.getSymbolTable().add(*output_sym);
+ }
+
+ return output_sym;
+}
+
+/// AddSymbol - define an output symbol and resolve it
+/// immediately
+template<> LDSymbol*
+IRBuilder::AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
+ const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ FragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility)
+{
+ // Result is <info, existent, override>
+ Resolver::Result result;
+ ResolveInfo old_info;
+ m_Module.getNamePool().insertSymbol(pName, false, pType, pDesc, pBinding,
+ pSize, pVisibility,
+ &old_info, result);
+
+ LDSymbol* output_sym = result.info->outSymbol();
+ bool has_output_sym = (NULL != output_sym);
+
+ if (!result.existent || !has_output_sym) {
+ output_sym = LDSymbol::Create(*result.info);
+ result.info->setSymPtr(output_sym);
+ }
+
+ if (result.overriden || !has_output_sym) {
+ output_sym->setFragmentRef(pFragmentRef);
+ output_sym->setValue(pValue);
+ }
+
+ // After symbol resolution, the visibility is changed to the most restrict.
+ // arrange the output position
+ if (ShouldForceLocal(*result.info, m_Config))
+ m_Module.getSymbolTable().forceLocal(*output_sym);
+ else if (has_output_sym)
+ m_Module.getSymbolTable().arrange(*output_sym, old_info);
+ else
+ m_Module.getSymbolTable().add(*output_sym);
+
+ return output_sym;
+}
+
+/// defineSymbol - define an output symbol and resolve it immediately.
+template<> LDSymbol*
+IRBuilder::AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ FragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility)
+{
+ ResolveInfo* info = m_Module.getNamePool().findInfo(pName);
+
+ if (NULL == info || !(info->isUndef() || info->isDyn())) {
+ // only undefined symbol and dynamic symbol can make a reference.
+ return NULL;
+ }
+
+ return AddSymbol<Force, Resolve>(pName,
+ pType,
+ pDesc,
+ pBinding,
+ pSize,
+ pValue,
+ pFragmentRef,
+ pVisibility);
+}
+
diff --git a/lib/Core/Linker.cpp b/lib/Core/Linker.cpp
index 9f6449e..d0c9b2e 100644
--- a/lib/Core/Linker.cpp
+++ b/lib/Core/Linker.cpp
@@ -32,7 +32,7 @@
using namespace mcld;
Linker::Linker()
- : m_pConfig(NULL), m_pModule(NULL), m_pIRBuilder(NULL),
+ : m_pConfig(NULL), m_pIRBuilder(NULL),
m_pTarget(NULL), m_pBackend(NULL), m_pObjLinker(NULL) {
}
@@ -51,6 +51,9 @@ bool Linker::config(LinkerConfig& pConfig)
if (!initBackend())
return false;
+ m_pObjLinker = new ObjectLinker(*m_pConfig,
+ *m_pBackend);
+
if (!initEmulator())
return false;
@@ -62,13 +65,19 @@ bool Linker::config(LinkerConfig& pConfig)
bool Linker::link(Module& pModule, IRBuilder& pBuilder)
{
+ if (!resolve(pModule, pBuilder))
+ return false;
+
+ return layout();
+}
+
+bool Linker::resolve(Module& pModule, IRBuilder& pBuilder)
+{
assert(NULL != m_pConfig);
m_pIRBuilder = &pBuilder;
- m_pObjLinker = new ObjectLinker(*m_pConfig,
- pModule,
- *m_pIRBuilder,
- *m_pBackend);
+ assert(m_pObjLinker!=NULL);
+ m_pObjLinker->setup(pModule, pBuilder);
// 2. - initialize FragmentLinker
if (!m_pObjLinker->initFragmentLinker())
@@ -78,7 +87,13 @@ bool Linker::link(Module& pModule, IRBuilder& pBuilder)
if (!m_pObjLinker->initStdSections())
return false;
+ if (!Diagnose())
+ return false;
+
// 4. - normalize the input tree
+ // read out sections and symbol/string tables (from the files) and
+ // set them in Module. When reading out the symbol, resolve their symbols
+ // immediately and set their ResolveInfo (i.e., Symbol Resolution).
m_pObjLinker->normalize();
if (m_pConfig->options().trace()) {
@@ -112,39 +127,80 @@ bool Linker::link(Module& pModule, IRBuilder& pBuilder)
}
}
- // 5. - check if we can do static linking and if we use split-stack.
+ // 5. - set up code position
+ if (LinkerConfig::DynObj == m_pConfig->codeGenType() ||
+ m_pConfig->options().isPIE()) {
+ m_pConfig->setCodePosition(LinkerConfig::Independent);
+ }
+ else if (pModule.getLibraryList().empty()) {
+ // If the output is dependent on its loaded address, and it does not need
+ // to call outside functions, then we can treat the output static dependent
+ // and perform better optimizations.
+ m_pConfig->setCodePosition(LinkerConfig::StaticDependent);
+ }
+ else {
+ m_pConfig->setCodePosition(LinkerConfig::DynamicDependent);
+ }
+
if (!m_pObjLinker->linkable())
return Diagnose();
// 6. - read all relocation entries from input files
+ // For all relocation sections of each input file (in the tree),
+ // read out reloc entry info from the object file and accordingly
+ // initiate their reloc entries in SectOrRelocData of LDSection.
m_pObjLinker->readRelocations();
// 7. - merge all sections
+ // Push sections into Module's SectionTable.
+ // Merge sections that have the same name.
+ // Maintain them as fragments in the section.
if (!m_pObjLinker->mergeSections())
return false;
- // 8. - add standard symbols and target-dependent symbols
+ // 8. - allocateCommonSymbols
+ // Allocate fragments for common symbols to the corresponding sections.
+ if (!m_pObjLinker->allocateCommonSymbols())
+ return false;
+ return true;
+}
+
+bool Linker::layout()
+{
+ assert(NULL != m_pConfig && NULL != m_pObjLinker);
+
+ // 9. - add standard symbols, target-dependent symbols and script symbols
// m_pObjLinker->addUndefSymbols();
if (!m_pObjLinker->addStandardSymbols() ||
- !m_pObjLinker->addTargetSymbols())
+ !m_pObjLinker->addTargetSymbols() ||
+ !m_pObjLinker->addScriptSymbols())
return false;
- // 9. - scan all relocation entries by output symbols.
+ // 10. - scan all relocation entries by output symbols.
+ // reserve GOT space for layout.
+ // the space info is needed by pre-layout to compute the section size
m_pObjLinker->scanRelocations();
- // 10.a - pre-layout
+ // 11.a - init relaxation stuff.
+ m_pObjLinker->initStubs();
+
+ // 11.b - pre-layout
m_pObjLinker->prelayout();
- // 10.b - linear layout
+ // 11.c - linear layout
+ // Decide which sections will be left in. Sort the sections according to
+ // a given order. Then, create program header accordingly.
+ // Finally, set the offset for sections (@ref LDSection)
+ // according to the new order.
m_pObjLinker->layout();
- // 10.c - post-layout (create segment, instruction relaxing)
+ // 11.d - post-layout (create segment, instruction relaxing)
m_pObjLinker->postlayout();
- // 11. - finalize symbol value
+ // 12. - finalize symbol value
m_pObjLinker->finalizeSymbolValue();
- // 12. - apply relocations
+ // 13. - apply relocations
m_pObjLinker->relocation();
if (!Diagnose())
@@ -202,7 +258,6 @@ bool Linker::emit(int pFileDescriptor)
bool Linker::reset()
{
m_pConfig = NULL;
- m_pModule = NULL;
m_pIRBuilder = NULL;
m_pTarget = NULL;
@@ -210,6 +265,7 @@ bool Linker::reset()
// RelocData before deleting target backend.
RelocData::Clear();
SectionData::Clear();
+ EhFrame::Clear();
delete m_pBackend;
m_pBackend = NULL;
diff --git a/lib/Core/LinkerConfig.cpp b/lib/Core/LinkerConfig.cpp
index cbdb7a7..63609fa 100644
--- a/lib/Core/LinkerConfig.cpp
+++ b/lib/Core/LinkerConfig.cpp
@@ -22,7 +22,8 @@ LinkerConfig::LinkerConfig()
m_Targets(),
m_Bitcode(),
m_Attribute(),
- m_CodeGenType(Unknown)
+ m_CodeGenType(Unknown),
+ m_CodePosition(DynamicDependent)
{
// FIXME: is here the right place to hold this?
InitializeDiagnosticEngine(*this);
@@ -34,7 +35,8 @@ LinkerConfig::LinkerConfig(const std::string& pTripleString)
m_Targets(pTripleString),
m_Bitcode(),
m_Attribute(),
- m_CodeGenType(Unknown)
+ m_CodeGenType(Unknown),
+ m_CodePosition(DynamicDependent)
{
// FIXME: is here the right place to hold this?
InitializeDiagnosticEngine(*this);
diff --git a/lib/Fragment/Android.mk b/lib/Fragment/Android.mk
index 0da2051..6e875a8 100644
--- a/lib/Fragment/Android.mk
+++ b/lib/Fragment/Android.mk
@@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir)
mcld_fragment_SRC_FILES := \
AlignFragment.cpp \
+ FGNode.cpp \
FillFragment.cpp \
Fragment.cpp \
FragmentLinker.cpp \
diff --git a/lib/Fragment/FGNode.cpp b/lib/Fragment/FGNode.cpp
new file mode 100644
index 0000000..92706ba
--- /dev/null
+++ b/lib/Fragment/FGNode.cpp
@@ -0,0 +1,40 @@
+//===- FGNode.cpp ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Fragment/FGNode.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// FGNode
+//===----------------------------------------------------------------------===//
+FGNode::FGNode()
+ : m_Index(0x0)
+{
+}
+
+FGNode::FGNode(uint32_t pIndex)
+ : m_Index(pIndex)
+{
+}
+
+void FGNode::addFragment(Fragment* pFrag)
+{
+ m_Fragments.push_back(pFrag);
+}
+
+void FGNode::addSignal(Signal pSignal)
+{
+ m_Signals.push_back(pSignal);
+}
+
+void FGNode::addSlot(Slot pSlot)
+{
+ m_Slots.push_back(pSlot);
+}
+
diff --git a/lib/Fragment/FragmentGraph.cpp b/lib/Fragment/FragmentGraph.cpp
new file mode 100644
index 0000000..3140447
--- /dev/null
+++ b/lib/Fragment/FragmentGraph.cpp
@@ -0,0 +1,412 @@
+//===- FragmentGraph.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Fragment/FragmentGraph.h>
+#include <mcld/Fragment/Fragment.h>
+#include <mcld/Fragment/Relocation.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/LDSymbol.h>
+#include <mcld/LD/SectionData.h>
+#include <mcld/LD/RelocData.h>
+#include <mcld/LinkerConfig.h>
+#include <mcld/Module.h>
+#include <mcld/Support/MsgHandling.h>
+
+#include <llvm/Support/Casting.h>
+#include <llvm/Support/ELF.h>
+
+#include <iostream>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// non-member functions
+//===----------------------------------------------------------------------===//
+static int get_state(Fragment::Type pKind)
+{
+ switch(pKind) {
+ case Fragment::Alignment:
+ return 0;
+ case Fragment::Fillment:
+ case Fragment::Region:
+ return 1;
+ case Fragment::Null:
+ return 2;
+ default:
+ unreachable(diag::unexpected_frag_type) << pKind;
+ }
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// ReachMatrix
+//===----------------------------------------------------------------------===//
+FragmentGraph::ReachMatrix::ReachMatrix(size_t pSize)
+{
+ assert(pSize != 0);
+ m_Data.assign(pSize * pSize, 0x0);
+ m_N = pSize;
+}
+
+uint32_t& FragmentGraph::ReachMatrix::at(uint32_t pX, uint32_t pY)
+{
+ return m_Data[pX * m_N + pY];
+}
+
+uint32_t FragmentGraph::ReachMatrix::at(uint32_t pX, uint32_t pY) const
+{
+ return m_Data[pX * m_N + pY];
+}
+
+//===----------------------------------------------------------------------===//
+// FragmentGraph
+//===----------------------------------------------------------------------===//
+FragmentGraph::FragmentGraph()
+ : m_pMatrix(NULL), m_NumOfPNodes(0x0), m_NumOfRNodes(0x0), m_NumOfEdges(0x0)
+{
+ m_pPseudoNodeFactory = new NodeFactoryType();
+ m_pRegularNodeFactory = new NodeFactoryType();
+ m_pFragNodeMap = new FragHashTableType(256);
+ m_pSymNodeMap = new SymHashTableType(256);
+}
+
+FragmentGraph::~FragmentGraph()
+{
+ delete m_pPseudoNodeFactory;
+ delete m_pRegularNodeFactory;
+ delete m_pFragNodeMap;
+}
+
+FGNode* FragmentGraph::getNode(const Fragment& pFrag)
+{
+ FragHashTableType::iterator entry = m_pFragNodeMap->find(&pFrag);
+ if (entry == m_pFragNodeMap->end())
+ return NULL;
+ return entry.getEntry()->value();
+}
+
+const FGNode* FragmentGraph::getNode(const Fragment& pFrag) const
+{
+ FragHashTableType::iterator entry = m_pFragNodeMap->find(&pFrag);
+ if (entry == m_pFragNodeMap->end())
+ return NULL;
+ return entry.getEntry()->value();
+}
+
+FGNode* FragmentGraph::getNode(const ResolveInfo& pSym)
+{
+ SymHashTableType::iterator entry = m_pSymNodeMap->find(&pSym);
+ if (entry == m_pSymNodeMap->end())
+ return NULL;
+ return entry.getEntry()->value();
+}
+
+const FGNode* FragmentGraph::getNode(const ResolveInfo& pSym) const
+{
+ SymHashTableType::iterator entry = m_pSymNodeMap->find(&pSym);
+ if (entry == m_pSymNodeMap->end())
+ return NULL;
+ return entry.getEntry()->value();
+}
+
+FGNode* FragmentGraph::producePseudoNode()
+{
+ FGNode* result = m_pPseudoNodeFactory->allocate();
+ new (result) FGNode(m_NumOfPNodes + m_NumOfRNodes);
+ ++m_NumOfPNodes;
+ return result;
+}
+
+FGNode* FragmentGraph::produceRegularNode()
+{
+ FGNode* result = m_pRegularNodeFactory->allocate();
+ new (result) FGNode(m_NumOfPNodes + m_NumOfRNodes);
+ ++m_NumOfRNodes;
+ return result;
+}
+
+bool FragmentGraph::setNodeSlots(Module& pModule)
+{
+ // symbols are the slots of nodes, push the symbols into the corresponding
+ // nodes.
+
+ // Traverse all defined symbols, including global and local symbols, to add
+ // symbols into the corresponding nodes
+ Module::SymbolTable& sym_tab = pModule.getSymbolTable();
+ SymbolCategory::iterator sym_it, sym_end = sym_tab.end();
+ for (sym_it = sym_tab.begin(); sym_it != sym_end; ++sym_it) {
+ // only the defined symbols with FragmnentRef can form a slot. The defined
+ // symbol with no FragmentRef such as ABS symbol should be skipped
+ LDSymbol* sym = *sym_it;
+ if (!sym->resolveInfo()->isDefine() ||
+ !sym->hasFragRef())
+ continue;
+
+ // FIXME: judge by getNode() is NULL or not
+ LDFileFormat::Kind sect_kind =
+ sym->fragRef()->frag()->getParent()->getSection().kind();
+ if (sect_kind != LDFileFormat::Regular &&
+ sect_kind != LDFileFormat::BSS)
+ continue;
+
+ FGNode* node = getNode(*sym->fragRef()->frag());
+ assert(NULL != node);
+ node->addSlot(sym->resolveInfo());
+ }
+
+ return true;
+}
+
+bool FragmentGraph::createRegularEdges(Module& pModule)
+{
+ // The reference between nodes are presented by the relocations. Set the
+ // reachability matrix to present the connection
+
+ // Traverse all input relocations to set connection
+ Module::obj_iterator input, inEnd = pModule.obj_end();
+ for (input = pModule.obj_begin(); input != inEnd; ++input) {
+ LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
+ for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
+ // bypass the discarded relocations
+ // 1. its section kind is changed to Ignore. (The target section is a
+ // discarded group section.)
+ // 2. it has no reloc data. (All symbols in the input relocs are in the
+ // discarded group sections)
+ if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData())
+ continue;
+ RelocData::iterator reloc_it, rEnd = (*rs)->getRelocData()->end();
+ for (reloc_it = (*rs)->getRelocData()->begin(); reloc_it != rEnd;
+ ++reloc_it) {
+ Relocation* reloc = llvm::cast<Relocation>(reloc_it);
+ ResolveInfo* sym = reloc->symInfo();
+ // only the target symbols defined in the input fragments can make the
+ // connection
+ if (NULL == sym)
+ continue;
+ if (!sym->isDefine() || !sym->outSymbol()->hasFragRef())
+ continue;
+
+ // only the relocation target places which defined in the concerned
+ // sections can make the connection
+ // FIXME: judge by getNode() is NULL or not
+ LDFileFormat::Kind sect_kind =
+ reloc->targetRef().frag()->getParent()->getSection().kind();
+ if (sect_kind != LDFileFormat::Regular &&
+ sect_kind != LDFileFormat::BSS)
+ continue;
+
+ // only the target symbols defined in the concerned sections can make
+ // the connection
+ // FIXME: judge by getNode() is NULL or not
+ sect_kind =
+ sym->outSymbol()->fragRef()->frag()->getParent()->getSection().kind();
+ if (sect_kind != LDFileFormat::Regular &&
+ sect_kind != LDFileFormat::BSS)
+ continue;
+
+ connect(reloc, sym);
+ }
+ }
+ }
+ return true;
+}
+
+bool FragmentGraph::createPseudoEdges(Module& pModule)
+{
+ // the pseudo edges are the edges from pseudo nodes to regular nodes, which
+ // present the reference from out-side world when building shared library
+
+ // Traverse all pseudo relocations in the pseudo nodes to set the connection
+ node_iterator node_it, node_end = m_pPseudoNodeFactory->end();
+ for (node_it = m_pPseudoNodeFactory->begin(); node_it != node_end; ++node_it) {
+ FGNode& node = *node_it;
+ FGNode::signal_iterator sig_it, sig_end = node.signal_end();
+ for (sig_it = node.signal_begin(); sig_it != sig_end; ++sig_it) {
+ connect(node, (*sig_it)->symInfo());
+ }
+ }
+ return true;
+}
+
+bool FragmentGraph::connect(Signal pSignal, Slot pSlot)
+{
+ FGNode* from = getNode(*pSignal->targetRef().frag());
+ assert(NULL != from);
+
+ FGNode* to = getNode(*pSlot->outSymbol()->fragRef()->frag());
+ assert(NULL != to);
+
+ // maintain edge counter
+ if (0 == m_pMatrix->at(from->getIndex(), to->getIndex()))
+ ++m_NumOfEdges;
+ ++m_pMatrix->at(from->getIndex(), to->getIndex());
+ return true;
+}
+
+bool FragmentGraph::connect(FGNode& pFrom, Slot pSlot)
+{
+ FGNode* to = getNode(*pSlot->outSymbol()->fragRef()->frag());
+ assert(NULL != to);
+
+ // maintain edge counter
+ if (0 == m_pMatrix->at(pFrom.getIndex(), to->getIndex()))
+ ++m_NumOfEdges;
+ ++m_pMatrix->at(pFrom.getIndex(), to->getIndex());
+ return true;
+}
+
+bool FragmentGraph::createPseudoNodes(Module& pModule)
+{
+ // when generating shared library, we need to create pseudo node for every
+ // global defined symbols to present the fan-in of a regular node.
+
+ // Traverse all global defined symbols to build the pseudo nodes.
+ Module::SymbolTable& sym_tab = pModule.getSymbolTable();
+ SymbolCategory::iterator sym_it, sym_end = sym_tab.dynamicEnd();
+ for (sym_it = sym_tab.dynamicBegin(); sym_it != sym_end; ++sym_it) {
+ ResolveInfo* sym = (*sym_it)->resolveInfo();
+ if (!sym->isDefine() || !sym->outSymbol()->hasFragRef())
+ continue;
+ FGNode* node = producePseudoNode();
+ // create the pseudo relocation to present the fan-out of the pseudo node
+ Relocation* reloc = Relocation::Create();
+ reloc->setSymInfo(sym);
+
+ // set the signal of the pseudo node
+ node->addSignal(reloc);
+
+ // maintain the map for symbol to pseudo node
+ SymHashTableType::entry_type* entry = 0;
+ bool exist = false;
+ entry = m_pSymNodeMap->insert(sym, exist);
+ entry->setValue(node);
+
+ }
+ return true;
+}
+
+bool FragmentGraph::createRegularNodes(Module& pModule)
+{
+ // Traverse all sections to build the Nodes. We build nodes only for Regular,
+ // and BSS
+ Module::iterator sect_it, sect_end = pModule.end();
+ for (sect_it = pModule.begin(); sect_it != sect_end; ++sect_it) {
+ LDSection* section = *sect_it;
+ SectionData* sect_data = NULL;
+
+ if (LDFileFormat::Regular != section->kind() &&
+ LDFileFormat::BSS != section->kind())
+ continue;
+
+ sect_data = section->getSectionData();
+ if (NULL == sect_data)
+ continue;
+
+ // Traverse all fragments in the sections, create Nodes and push the
+ // fragments into Nodes. Each Region or Fillment fragment belongs to a
+ // unique Node. The corresponding Align fragments and Null fragments belong
+ // to the same Node as the Region or Fillment fragment.
+ SectionData::iterator frag_it = sect_data->begin();
+ SectionData::iterator frag_end = sect_data->end();
+ if (frag_it == frag_end)
+ continue;
+
+ int cur_stat = 0;
+ int last_stat = 0;
+ // FIXME:
+ // To prevent some cases that we add the redundant NULL or Align fragments
+ // and lead a Region/Fillment fragment has more than one NULL or Align
+ // fragment. We should put all of them into the same Node.
+ static int stat_matrix[3][3] = {{0, 1, 1},
+ {0, 1, 1},
+ {0, 0, 0}};
+
+ FragHashTableType::entry_type* entry = 0;
+ bool exist = false;
+
+ FGNode* node = produceRegularNode();
+ Fragment* frag = NULL;
+
+ frag = &(*frag_it);
+ cur_stat = get_state(frag->getKind());
+
+ node->addFragment(frag);
+ // maintain the fragment to Node map
+ entry = m_pFragNodeMap->insert(frag, exist);
+ entry->setValue(node);
+ ++frag_it;
+
+ while (frag_it != frag_end) {
+ last_stat = cur_stat;
+ frag = &(*frag_it);
+
+ cur_stat = get_state(frag->getKind());
+
+ if (stat_matrix[cur_stat][last_stat]) {
+ node = produceRegularNode();
+ }
+ node->addFragment(frag);
+ // maintain the fragment to Node map
+ entry = m_pFragNodeMap->insert(frag, exist);
+ entry->setValue(node);
+
+ ++frag_it;
+ }
+ }
+ return true;
+}
+
+void FragmentGraph::initMatrix()
+{
+ m_pMatrix = new ReachMatrix(m_NumOfPNodes + m_NumOfRNodes);
+}
+
+bool FragmentGraph::getEdges(FGNode& pNode, EdgeListType& pEdges)
+{
+ // Traverse all regular nodes to find the connection to pNode
+ node_iterator it, itEnd = m_pRegularNodeFactory->end();
+ for (it = m_pRegularNodeFactory->begin(); it != itEnd; ++it) {
+ FGNode& node_to = *it;
+ uint32_t weight = m_pMatrix->at(pNode.getIndex(), node_to.getIndex());
+ if (weight > 0) {
+ // build an Edge
+ pEdges.push_back(FGEdge(pNode, node_to, weight));
+ }
+ }
+
+ return true;
+}
+
+bool FragmentGraph::construct(const LinkerConfig& pConfig, Module& pModule)
+{
+ // create nodes - traverse all fragments to create the regular nodes, and
+ // then traverse all global defined symbols to create pseudo nodes
+ if (!createRegularNodes(pModule))
+ return false;
+ if (!createPseudoNodes(pModule))
+ return false;
+
+ // after all nodes created, we know the number of the nodes and then can
+ // create the reachability matrix
+ initMatrix();
+
+ // set slots - traverse all symbols to set the slots of regular nodes
+ if(!setNodeSlots(pModule))
+ return false;
+
+ // connect edges - traverse all relocations to set the edges
+ if(!createRegularEdges(pModule))
+ return false;
+ if(!createPseudoEdges(pModule))
+ return false;
+
+ return true;
+}
+
diff --git a/lib/Fragment/FragmentLinker.cpp b/lib/Fragment/FragmentLinker.cpp
index 0398834..dae7b00 100644
--- a/lib/Fragment/FragmentLinker.cpp
+++ b/lib/Fragment/FragmentLinker.cpp
@@ -52,194 +52,6 @@ FragmentLinker::~FragmentLinker()
{
}
-//===----------------------------------------------------------------------===//
-// Symbol Operations
-//===----------------------------------------------------------------------===//
-/// defineSymbolForcefully - define an output symbol and override it immediately
-LDSymbol* FragmentLinker::defineSymbolForcefully(const llvm::StringRef& pName,
- bool pIsDyn,
- ResolveInfo::Type pType,
- ResolveInfo::Desc pDesc,
- ResolveInfo::Binding pBinding,
- ResolveInfo::SizeType pSize,
- LDSymbol::ValueType pValue,
- FragmentRef* pFragmentRef,
- ResolveInfo::Visibility pVisibility)
-{
- ResolveInfo* info = m_Module.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_Module.getNamePool().insertSymbol(pName, pIsDyn, pType, pDesc,
- pBinding, pSize, pVisibility,
- NULL, result);
- assert(!result.existent);
-
- // create a output LDSymbol
- output_sym = LDSymbol::Create(*result.info);
- result.info->setSymPtr(output_sym);
-
- if (shouldForceLocal(*result.info))
- m_Module.getSymbolTable().forceLocal(*output_sym);
- else
- m_Module.getSymbolTable().add(*output_sym);
- }
- else {
- // the symbol is already in the pool, override it
- ResolveInfo old_info;
- old_info.override(*info);
-
- info->setSource(pIsDyn);
- info->setType(pType);
- info->setDesc(pDesc);
- info->setBinding(pBinding);
- info->setVisibility(pVisibility);
- info->setIsSymbol(true);
- info->setSize(pSize);
-
- output_sym = info->outSymbol();
- if (NULL != output_sym)
- m_Module.getSymbolTable().arrange(*output_sym, old_info);
- else {
- // create a output LDSymbol
- output_sym = LDSymbol::Create(*info);
- info->setSymPtr(output_sym);
-
- m_Module.getSymbolTable().add(*output_sym);
- }
- }
-
- if (NULL != output_sym) {
- output_sym->setFragmentRef(pFragmentRef);
- output_sym->setValue(pValue);
- }
-
- return output_sym;
-}
-
-/// defineSymbolAsRefered - define an output symbol and override it immediately
-LDSymbol* FragmentLinker::defineSymbolAsRefered(const llvm::StringRef& pName,
- bool pIsDyn,
- ResolveInfo::Type pType,
- ResolveInfo::Desc pDesc,
- ResolveInfo::Binding pBinding,
- ResolveInfo::SizeType pSize,
- LDSymbol::ValueType pValue,
- FragmentRef* pFragmentRef,
- ResolveInfo::Visibility pVisibility)
-{
- ResolveInfo* info = m_Module.getNamePool().findInfo(pName);
-
- if (NULL == info || !(info->isUndef() || info->isDyn())) {
- // only undefined symbol and dynamic symbol can make a reference.
- return NULL;
- }
-
- // the symbol is already in the pool, override it
- ResolveInfo old_info;
- old_info.override(*info);
-
- info->setSource(pIsDyn);
- info->setType(pType);
- info->setDesc(pDesc);
- info->setBinding(pBinding);
- info->setVisibility(pVisibility);
- info->setIsSymbol(true);
- info->setSize(pSize);
-
- LDSymbol* output_sym = info->outSymbol();
- if (NULL != output_sym) {
- output_sym->setFragmentRef(pFragmentRef);
- output_sym->setValue(pValue);
- m_Module.getSymbolTable().arrange(*output_sym, old_info);
- }
- else {
- // create a output LDSymbol
- output_sym = LDSymbol::Create(*info);
- info->setSymPtr(output_sym);
-
- m_Module.getSymbolTable().add(*output_sym);
- }
-
- return output_sym;
-}
-
-/// defineAndResolveSymbolForcefully - define an output symbol and resolve it
-/// immediately
-LDSymbol* FragmentLinker::defineAndResolveSymbolForcefully(const llvm::StringRef& pName,
- bool pIsDyn,
- ResolveInfo::Type pType,
- ResolveInfo::Desc pDesc,
- ResolveInfo::Binding pBinding,
- ResolveInfo::SizeType pSize,
- LDSymbol::ValueType pValue,
- FragmentRef* pFragmentRef,
- ResolveInfo::Visibility pVisibility)
-{
- // Result is <info, existent, override>
- Resolver::Result result;
- ResolveInfo old_info;
- m_Module.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);
-
- if (!result.existent || !has_output_sym) {
- output_sym = LDSymbol::Create(*result.info);
- result.info->setSymPtr(output_sym);
- }
-
- if (result.overriden || !has_output_sym) {
- output_sym->setFragmentRef(pFragmentRef);
- output_sym->setValue(pValue);
- }
-
- // After symbol resolution, the visibility is changed to the most restrict.
- // arrange the output position
- if (shouldForceLocal(*result.info))
- m_Module.getSymbolTable().forceLocal(*output_sym);
- else if (has_output_sym)
- m_Module.getSymbolTable().arrange(*output_sym, old_info);
- else
- m_Module.getSymbolTable().add(*output_sym);
-
- return output_sym;
-}
-
-/// defineAndResolveSymbolAsRefered - define an output symbol and resolve it
-/// immediately.
-LDSymbol* FragmentLinker::defineAndResolveSymbolAsRefered(const llvm::StringRef& pName,
- bool pIsDyn,
- ResolveInfo::Type pType,
- ResolveInfo::Desc pDesc,
- ResolveInfo::Binding pBinding,
- ResolveInfo::SizeType pSize,
- LDSymbol::ValueType pValue,
- FragmentRef* pFragmentRef,
- ResolveInfo::Visibility pVisibility)
-{
- ResolveInfo* info = m_Module.getNamePool().findInfo(pName);
-
- if (NULL == info || !(info->isUndef() || info->isDyn())) {
- // only undefined symbol and dynamic symbol can make a reference.
- return NULL;
- }
-
- return defineAndResolveSymbolForcefully(pName,
- pIsDyn,
- pType,
- pDesc,
- pBinding,
- pSize,
- pValue,
- pFragmentRef,
- pVisibility);
-}
-
bool FragmentLinker::finalizeSymbols()
{
Module::sym_iterator symbol, symEnd = m_Module.sym_end();
@@ -270,24 +82,7 @@ bool FragmentLinker::finalizeSymbols()
}
}
- // finialize target-dependent symbols
- return m_Backend.finalizeSymbols(*this);
-}
-
-bool FragmentLinker::shouldForceLocal(const ResolveInfo& pInfo) const
-{
- // forced local symbol matches all rules:
- // 1. We are not doing incremental linking.
- // 2. The symbol is with Hidden or Internal visibility.
- // 3. The symbol should be global or weak. Otherwise, local symbol is local.
- // 4. The symbol is defined or common
- if (LinkerConfig::Object != m_Config.codeGenType() &&
- (pInfo.visibility() == ResolveInfo::Hidden ||
- pInfo.visibility() == ResolveInfo::Internal) &&
- (pInfo.isGlobal() || pInfo.isWeak()) &&
- (pInfo.isDefine() || pInfo.isCommon()))
- return true;
- return false;
+ return true;
}
//===----------------------------------------------------------------------===//
@@ -426,15 +221,25 @@ void FragmentLinker::partialSyncRelocationResult(MemoryArea& pOutput)
void FragmentLinker::writeRelocationResult(Relocation& pReloc, uint8_t* pOutput)
{
// get output file offset
- size_t out_offset = pReloc.targetRef().frag()->getParent()->getSection().offset() +
- pReloc.targetRef().getOutputOffset();
+ size_t out_offset =
+ pReloc.targetRef().frag()->getParent()->getSection().offset() +
+ pReloc.targetRef().getOutputOffset();
uint8_t* target_addr = pOutput + out_offset;
// byte swapping if target and host has different endian, and then write back
if(llvm::sys::isLittleEndianHost() != m_Config.targets().isLittleEndian()) {
uint64_t tmp_data = 0;
- switch(m_Config.targets().bitclass()) {
+ switch(pReloc.size(*m_Backend.getRelocator())) {
+ case 8u:
+ std::memcpy(target_addr, &pReloc.target(), 1);
+ break;
+
+ case 16u:
+ tmp_data = mcld::bswap16(pReloc.target());
+ std::memcpy(target_addr, &tmp_data, 2);
+ break;
+
case 32u:
tmp_data = mcld::bswap32(pReloc.target());
std::memcpy(target_addr, &tmp_data, 4);
@@ -450,33 +255,7 @@ void FragmentLinker::writeRelocationResult(Relocation& pReloc, uint8_t* pOutput)
}
}
else
- std::memcpy(target_addr, &pReloc.target(), m_Config.targets().bitclass()/8);
-}
-
-/// isOutputPIC - return whether the output is position-independent
-bool FragmentLinker::isOutputPIC() const
-{
- return checkIsOutputPIC();
-}
-
-/// isStaticLink - return whether we're doing static link
-bool FragmentLinker::isStaticLink() const
-{
- return checkIsStaticLink();
-}
-
-bool FragmentLinker::checkIsOutputPIC() const
-{
- if (LinkerConfig::DynObj == m_Config.codeGenType() ||
- m_Config.options().isPIE())
- return true;
- return false;
-}
-
-bool FragmentLinker::checkIsStaticLink() const
-{
- if (m_Module.getLibraryList().empty() && !isOutputPIC())
- return true;
- return false;
+ std::memcpy(target_addr, &pReloc.target(),
+ pReloc.size(*m_Backend.getRelocator())/8);
}
diff --git a/lib/Fragment/Relocation.cpp b/lib/Fragment/Relocation.cpp
index 293b1c9..fd042ea 100644
--- a/lib/Fragment/Relocation.cpp
+++ b/lib/Fragment/Relocation.cpp
@@ -143,10 +143,9 @@ void Relocation::setSymInfo(ResolveInfo* pSym)
m_pSymInfo = pSym;
}
-size_t Relocation::size() const
+Relocation::Size Relocation::size(Relocator& pRelocator) const
{
- // TODO: the size of Relocation fragment is handled by backend
- return 0;
+ return pRelocator.getSize(m_Type);
}
void Relocation::updateAddend()
diff --git a/lib/LD/Android.mk b/lib/LD/Android.mk
index 53c1f10..edba1b0 100644
--- a/lib/LD/Android.mk
+++ b/lib/LD/Android.mk
@@ -7,7 +7,6 @@ LOCAL_PATH:= $(call my-dir)
mcld_ld_SRC_FILES := \
Archive.cpp \
ArchiveReader.cpp \
- BinaryWriter.cpp \
BranchIsland.cpp \
BranchIslandFactory.cpp \
DWARFLineInfo.cpp \
@@ -17,27 +16,24 @@ mcld_ld_SRC_FILES := \
DiagnosticLineInfo.cpp \
DiagnosticPrinter.cpp \
DynObjReader.cpp \
- DynObjWriter.cpp \
ELFBinaryReader.cpp \
- ELFBinaryWriter.cpp \
ELFSegment.cpp \
ELFSegmentFactory.cpp \
EhFrame.cpp \
EhFrameHdr.cpp \
EhFrameReader.cpp \
- ExecWriter.cpp \
GroupReader.cpp \
LDContext.cpp \
LDFileFormat.cpp \
LDReader.cpp \
LDSection.cpp \
LDSymbol.cpp \
- LDWriter.cpp \
MsgHandler.cpp \
NamePool.cpp \
ObjectWriter.cpp \
RelocData.cpp \
RelocationFactory.cpp \
+ Relocator.cpp \
ResolveInfo.cpp \
Resolver.cpp \
SectionData.cpp \
@@ -80,14 +76,12 @@ mcld_ld_variant_SRC_FILES := \
GNUArchiveReader.cpp \
ELFDynObjFileFormat.cpp \
ELFDynObjReader.cpp \
- ELFDynObjWriter.cpp \
ELFExecFileFormat.cpp \
- ELFExecWriter.cpp \
ELFFileFormat.cpp \
ELFObjectReader.cpp \
ELFObjectWriter.cpp \
ELFReader.cpp \
- ELFWriter.cpp
+ ELFReaderIf.cpp
# For the host
# =====================================================
diff --git a/lib/LD/Archive.cpp b/lib/LD/Archive.cpp
index be82922..ee2edea 100644
--- a/lib/LD/Archive.cpp
+++ b/lib/LD/Archive.cpp
@@ -129,7 +129,10 @@ bool Archive::addArchiveMember(const llvm::StringRef& pName,
ArchiveMemberEntryType* entry = m_ArchiveMemberMap.insert(pName, exist);
if (!exist) {
ArchiveMember& ar = entry->value();
- ar.file = *pLastPos;
+ if (pLastPos == m_pInputTree->root())
+ ar.file = &m_ArchiveFile;
+ else
+ ar.file = *pLastPos;
ar.lastPos = pLastPos;
ar.move = pMove;
}
diff --git a/lib/LD/BinaryWriter.cpp b/lib/LD/BinaryWriter.cpp
deleted file mode 100644
index 00dd169..0000000
--- a/lib/LD/BinaryWriter.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-//===- BinaryWriter.cpp ---------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/LD/BinaryWriter.h>
-#include <mcld/MC/MCLDInput.h>
-#include <mcld/Target/GNULDBackend.h>
-
-using namespace mcld;
-
-//==========================
-// BinaryWriter
-BinaryWriter::BinaryWriter(GNULDBackend& pBackend)
-{
-}
-
-BinaryWriter::~BinaryWriter()
-{
-}
-
diff --git a/lib/LD/DiagnosticEngine.cpp b/lib/LD/DiagnosticEngine.cpp
index c2e52d7..ac51080 100644
--- a/lib/LD/DiagnosticEngine.cpp
+++ b/lib/LD/DiagnosticEngine.cpp
@@ -30,6 +30,9 @@ DiagnosticEngine::~DiagnosticEngine()
delete m_pPrinter;
delete m_pInfoMap;
+
+ // FIXME: design the destructive relation of LineInfo.
+ delete m_pLineInfo;
}
void DiagnosticEngine::reset(const LinkerConfig& pConfig)
diff --git a/lib/LD/DiagnosticInfos.cpp b/lib/LD/DiagnosticInfos.cpp
index 130fd9a..280e178 100644
--- a/lib/LD/DiagnosticInfos.cpp
+++ b/lib/LD/DiagnosticInfos.cpp
@@ -130,12 +130,17 @@ bool DiagnosticInfos::process(DiagnosticEngine& pEngine) const
severity = DiagnosticEngine::Ignore;
break;
case LinkerConfig::DynObj:
- if (m_Config.options().isNoUndefined() || !m_Config.options().isAllowShlibUndefined())
+ if (m_Config.options().isNoUndefined())
severity = DiagnosticEngine::Error;
else
severity = DiagnosticEngine::Ignore;
break;
case LinkerConfig::Exec:
+ if (m_Config.options().isNoUndefined() || m_Config.isCodeStatic())
+ severity = DiagnosticEngine::Error;
+ else
+ severity = DiagnosticEngine::Ignore;
+ break;
default:
severity = DiagnosticEngine::Error;
break;
diff --git a/lib/LD/DynObjWriter.cpp b/lib/LD/DynObjWriter.cpp
deleted file mode 100644
index 6f031ff..0000000
--- a/lib/LD/DynObjWriter.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-//===- DynObjWriter.cpp ---------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include "mcld/LD/DynObjWriter.h"
-#include "mcld/Target/TargetLDBackend.h"
-#include "mcld/MC/MCLDInput.h"
-
-using namespace mcld;
-
-//==========================
-// DynObjWriter
diff --git a/lib/LD/ELFBinaryReader.cpp b/lib/LD/ELFBinaryReader.cpp
index c291544..f818286 100644
--- a/lib/LD/ELFBinaryReader.cpp
+++ b/lib/LD/ELFBinaryReader.cpp
@@ -16,6 +16,8 @@
#include <llvm/Support/ELF.h>
+#include <cctype>
+
using namespace mcld;
//===----------------------------------------------------------------------===//
@@ -83,9 +85,16 @@ bool ELFBinaryReader::readBinary(Input& pInput)
0x0,
data_sect);
+ std::string mangled_name = pInput.path().filename().string();
+ for (std::string::iterator it = mangled_name.begin(),
+ ie = mangled_name.end(); it != ie; ++it) {
+ if (isalnum(*it) == 0)
+ *it = '_';
+ }
+
// symbol: _start
m_Builder.AddSymbol(pInput,
- "_binary_" + pInput.path().filename().string() + "_start",
+ "_binary_" + mangled_name + "_start",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
@@ -95,7 +104,7 @@ bool ELFBinaryReader::readBinary(Input& pInput)
// symbol: _end
m_Builder.AddSymbol(pInput,
- "_binary_" + pInput.path().filename().string() + "_end",
+ "_binary_" + mangled_name + "_end",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
@@ -105,7 +114,7 @@ bool ELFBinaryReader::readBinary(Input& pInput)
// symbol: _size
m_Builder.AddSymbol(pInput,
- "_binary_" + pInput.path().filename().string() + "_size",
+ "_binary_" + mangled_name + "_size",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
diff --git a/lib/LD/ELFBinaryWriter.cpp b/lib/LD/ELFBinaryWriter.cpp
deleted file mode 100644
index 28ef553..0000000
--- a/lib/LD/ELFBinaryWriter.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-//===- ELFBinaryWriter.cpp ------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/LD/ELFBinaryWriter.h>
-
-#include <mcld/Module.h>
-#include <mcld/Target/GNULDBackend.h>
-#include <mcld/Fragment/FragmentLinker.h>
-#include <mcld/Support/MemoryArea.h>
-#include <mcld/LD/ELFSegmentFactory.h>
-#include <mcld/LD/ELFSegment.h>
-
-#include <llvm/Support/system_error.h>
-using namespace llvm;
-using namespace mcld;
-
-//===----------------------------------------------------------------------===//
-// ELFBinaryWriter
-//===----------------------------------------------------------------------===//
-ELFBinaryWriter::ELFBinaryWriter(GNULDBackend& pBackend,
- const LinkerConfig& pConfig)
- : BinaryWriter(pBackend), ELFWriter(pBackend), m_Config(pConfig) {
-}
-
-ELFBinaryWriter::~ELFBinaryWriter()
-{
-}
-
-llvm::error_code ELFBinaryWriter::writeBinary(Module& pModule,
- MemoryArea& pOutput)
-{
- // Write out regular ELF sections
- for (ELFSegmentFactory::iterator seg = target().elfSegmentTable().begin(),
- segEnd = target().elfSegmentTable().end(); seg != segEnd; ++seg) {
- if (llvm::ELF::PT_LOAD != (*seg).type())
- continue;
-
- for (ELFSegment::sect_iterator sect = (*seg).begin(),
- sectEnd = (*seg).end(); sect != sectEnd; ++sect) {
- MemoryRegion* region = NULL;
- // request output region
- switch((*sect)->kind()) {
- case LDFileFormat::Note:
- if ((*sect)->getSectionData() == NULL)
- continue;
- // Fall through
- case LDFileFormat::Regular:
- case LDFileFormat::Relocation:
- case LDFileFormat::Target:
- case LDFileFormat::Debug:
- case LDFileFormat::GCCExceptTable:
- case LDFileFormat::EhFrame: {
- region = pOutput.request((*sect)->offset(), (*sect)->size());
- if (NULL == region) {
- llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section `") +
- llvm::Twine((*sect)->name()) +
- llvm::Twine("'.\n"));
- }
- break;
- }
- case LDFileFormat::Null:
- case LDFileFormat::NamePool:
- case LDFileFormat::BSS:
- case LDFileFormat::MetaData:
- case LDFileFormat::Version:
- case LDFileFormat::EhFrameHdr:
- case LDFileFormat::StackNote:
- // 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::Note:
- case LDFileFormat::EhFrame: {
- // FIXME: if optimization of exception handling sections is enabled,
- // then we should emit these sections by the other way.
- emitSectionData(**sect, *region);
- break;
- }
- case LDFileFormat::Relocation:
- emitRelocation(m_Config, **sect, *region);
- break;
- case LDFileFormat::Target:
- target().emitSectionData(**sect, *region);
- break;
- default:
- continue;
- }
- } // end of section for loop
- } // end of segment for loop
- return llvm::make_error_code(llvm::errc::success);
-}
-
diff --git a/lib/LD/ELFDynObjFileFormat.cpp b/lib/LD/ELFDynObjFileFormat.cpp
index 9ccf967..e89f48b 100644
--- a/lib/LD/ELFDynObjFileFormat.cpp
+++ b/lib/LD/ELFDynObjFileFormat.cpp
@@ -52,12 +52,12 @@ void ELFDynObjFileFormat::initObjectFormat(ObjectBuilder& pBuilder,
llvm::ELF::SHT_RELA,
llvm::ELF::SHF_ALLOC,
pBitClass / 8);
- f_pRelDyn = pBuilder.CreateSection(".rel.dyn",
+ f_pRelDyn = pBuilder.CreateSection(".rel.dyn",
LDFileFormat::Relocation,
llvm::ELF::SHT_REL,
llvm::ELF::SHF_ALLOC,
pBitClass / 8);
- f_pRelPlt = pBuilder.CreateSection(".rel.plt",
+ f_pRelPlt = pBuilder.CreateSection(".rel.plt",
LDFileFormat::Relocation,
llvm::ELF::SHT_REL,
llvm::ELF::SHF_ALLOC,
@@ -77,10 +77,15 @@ void ELFDynObjFileFormat::initObjectFormat(ObjectBuilder& pBuilder,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
pBitClass / 8);
- f_pEhFrameHdr = pBuilder.CreateSection(".eh_frame_hdr",
- LDFileFormat::EhFrameHdr,
- llvm::ELF::SHT_PROGBITS,
- llvm::ELF::SHF_ALLOC,
- 0x4);
+ f_pEhFrameHdr = pBuilder.CreateSection(".eh_frame_hdr",
+ LDFileFormat::EhFrameHdr,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x4);
+ f_pGNUHashTab = pBuilder.CreateSection(".gnu.hash",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_GNU_HASH,
+ llvm::ELF::SHF_ALLOC,
+ pBitClass / 8);
}
diff --git a/lib/LD/ELFDynObjReader.cpp b/lib/LD/ELFDynObjReader.cpp
index e52e863..4f8c7ba 100644
--- a/lib/LD/ELFDynObjReader.cpp
+++ b/lib/LD/ELFDynObjReader.cpp
@@ -34,6 +34,8 @@ ELFDynObjReader::ELFDynObjReader(GNULDBackend& pBackend,
m_Builder(pBuilder) {
if (pConfig.targets().is32Bits() && pConfig.targets().isLittleEndian())
m_pELFReader = new ELFReader<32, true>(pBackend);
+ else if (pConfig.targets().is64Bits() && pConfig.targets().isLittleEndian())
+ m_pELFReader = new ELFReader<64, true>(pBackend);
}
ELFDynObjReader::~ELFDynObjReader()
diff --git a/lib/LD/ELFDynObjWriter.cpp b/lib/LD/ELFDynObjWriter.cpp
deleted file mode 100644
index 2e903ce..0000000
--- a/lib/LD/ELFDynObjWriter.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-//===- ELFDynObjWriter.cpp ------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/LD/ELFDynObjWriter.h>
-
-#include <mcld/Module.h>
-#include <mcld/LinkerConfig.h>
-#include <mcld/LD/LDSymbol.h>
-#include <mcld/Target/GNULDBackend.h>
-#include <mcld/MC/MCLDInput.h>
-#include <mcld/Support/MemoryArea.h>
-
-#include <llvm/Support/ELF.h>
-
-#include <vector>
-
-using namespace llvm;
-using namespace mcld;
-
-//===----------------------------------------------------------------------===//
-// ELFDynObjWriter
-//===----------------------------------------------------------------------===//
-ELFDynObjWriter::ELFDynObjWriter(GNULDBackend& pBackend,
- const LinkerConfig& pConfig)
- : DynObjWriter(pBackend), ELFWriter(pBackend),
- m_Config(pConfig) {
-
-}
-
-ELFDynObjWriter::~ELFDynObjWriter()
-{
-}
-
-llvm::error_code ELFDynObjWriter::writeDynObj(Module& pModule,
- MemoryArea& pOutput)
-{
- target().emitInterp(pOutput);
-
- // Write out name pool sections: .dynsym, .dynstr, .hash
- target().emitDynNamePools(pModule, pOutput);
-
- // Write out name pool sections: .symtab, .strtab
- target().emitRegNamePools(pModule, pOutput);
-
- // Write out regular ELF sections
- Module::iterator sect, sectEnd = pModule.end();
- for (sect = pModule.begin(); sect != sectEnd; ++sect) {
- MemoryRegion* region = NULL;
- // request output region
- switch((*sect)->kind()) {
- case LDFileFormat::Note:
- if ((*sect)->getSectionData() == NULL)
- continue;
- // Fall through
- case LDFileFormat::Regular:
- case LDFileFormat::Relocation:
- case LDFileFormat::Target:
- case LDFileFormat::Debug:
- case LDFileFormat::GCCExceptTable:
- case LDFileFormat::EhFrame: {
- region = pOutput.request((*sect)->offset(), (*sect)->size());
- if (NULL == region) {
- llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section ") +
- llvm::Twine((*sect)->name()) +
- llvm::Twine(".\n"));
- }
- break;
- }
- case LDFileFormat::Null:
- case LDFileFormat::NamePool:
- case LDFileFormat::BSS:
- case LDFileFormat::MetaData:
- case LDFileFormat::Version:
- case LDFileFormat::EhFrameHdr:
- case LDFileFormat::StackNote:
- // 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::Note:
- case LDFileFormat::EhFrame: {
- // FIXME: if optimization of exception handling sections is enabled,
- // then we should emit these sections by the other way.
- emitSectionData(**sect, *region);
- break;
- }
- case LDFileFormat::Relocation:
- emitRelocation(m_Config, **sect, *region);
- break;
- case LDFileFormat::Target:
- target().emitSectionData(**sect, *region);
- break;
- default:
- continue;
- }
-
- } // end of for loop
-
- emitELFShStrTab(target().getOutputFormat()->getShStrTab(),
- pModule,
- pOutput);
-
- if (m_Config.targets().is32Bits()) {
- // Write out ELF header
- // Write out section header table
- writeELF32Header(m_Config, pModule, pOutput);
-
- emitELF32ProgramHeader(pOutput);
-
- emitELF32SectionHeader(pModule, m_Config, pOutput);
- }
- else if (m_Config.targets().is64Bits()) {
- // Write out ELF header
- // Write out section header table
- writeELF64Header(m_Config, pModule, pOutput);
-
- emitELF64ProgramHeader(pOutput);
-
- emitELF64SectionHeader(pModule, m_Config, pOutput);
- }
- else
- return make_error_code(errc::not_supported);
- pOutput.clear();
- return llvm::make_error_code(llvm::errc::success);
-}
-
diff --git a/lib/LD/ELFExecFileFormat.cpp b/lib/LD/ELFExecFileFormat.cpp
index a05c058..6a81f72 100644
--- a/lib/LD/ELFExecFileFormat.cpp
+++ b/lib/LD/ELFExecFileFormat.cpp
@@ -53,12 +53,12 @@ void ELFExecFileFormat::initObjectFormat(ObjectBuilder& pBuilder,
llvm::ELF::SHT_RELA,
llvm::ELF::SHF_ALLOC,
pBitClass / 8);
- f_pRelDyn = pBuilder.CreateSection(".rel.dyn",
+ f_pRelDyn = pBuilder.CreateSection(".rel.dyn",
LDFileFormat::Relocation,
llvm::ELF::SHT_REL,
llvm::ELF::SHF_ALLOC,
pBitClass / 8);
- f_pRelPlt = pBuilder.CreateSection(".rel.plt",
+ f_pRelPlt = pBuilder.CreateSection(".rel.plt",
LDFileFormat::Relocation,
llvm::ELF::SHT_REL,
llvm::ELF::SHF_ALLOC,
@@ -83,4 +83,9 @@ void ELFExecFileFormat::initObjectFormat(ObjectBuilder& pBuilder,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC,
0x4);
+ f_pGNUHashTab = pBuilder.CreateSection(".gnu.hash",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_GNU_HASH,
+ llvm::ELF::SHF_ALLOC,
+ pBitClass / 8);
}
diff --git a/lib/LD/ELFExecWriter.cpp b/lib/LD/ELFExecWriter.cpp
deleted file mode 100644
index a9af584..0000000
--- a/lib/LD/ELFExecWriter.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-//===- 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/Module.h>
-#include <mcld/LinkerConfig.h>
-#include <mcld/LD/LDSymbol.h>
-#include <mcld/Target/GNULDBackend.h>
-#include <mcld/Support/MemoryArea.h>
-
-#include <llvm/Support/ELF.h>
-#include <vector>
-
-using namespace llvm;
-using namespace mcld;
-
-
-//===----------------------------------------------------------------------===//
-// ELFExecWriter
-//===----------------------------------------------------------------------===//
-ELFExecWriter::ELFExecWriter(GNULDBackend& pBackend,
- const LinkerConfig& pConfig)
- : ExecWriter(pBackend), ELFWriter(pBackend),
- m_Config(pConfig) {
-
-}
-
-ELFExecWriter::~ELFExecWriter()
-{
-}
-
-llvm::error_code ELFExecWriter::writeExecutable(Module& pModule,
- MemoryArea& pOutput)
-{
- // write out the interpreter section: .interp
- target().emitInterp(pOutput);
-
- // Write out name pool sections: .dynsym, .dynstr, .hash
- target().emitDynNamePools(pModule, pOutput);
-
- // Write out name pool sections: .symtab, .strtab
- target().emitRegNamePools(pModule, pOutput);
-
- // Write out regular ELF sections
- Module::iterator sect, sectEnd = pModule.end();
- for (sect = pModule.begin(); sect != sectEnd; ++sect) {
- MemoryRegion* region = NULL;
- // request output region
- switch((*sect)->kind()) {
- case LDFileFormat::Note:
- if ((*sect)->getSectionData() == NULL)
- continue;
- // Fall through
- case LDFileFormat::Regular:
- case LDFileFormat::Relocation:
- case LDFileFormat::Target:
- case LDFileFormat::Debug:
- case LDFileFormat::GCCExceptTable:
- case LDFileFormat::EhFrame: {
- region = pOutput.request((*sect)->offset(), (*sect)->size());
- if (NULL == region) {
- llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section `") +
- llvm::Twine((*sect)->name()) +
- llvm::Twine("'.\n"));
- }
- break;
- }
- case LDFileFormat::Null:
- case LDFileFormat::NamePool:
- case LDFileFormat::BSS:
- case LDFileFormat::MetaData:
- case LDFileFormat::Version:
- case LDFileFormat::EhFrameHdr:
- case LDFileFormat::StackNote:
- // 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::Note:
- case LDFileFormat::EhFrame: {
- // FIXME: if optimization of exception handling sections is enabled,
- // then we should emit these sections by the other way.
- emitSectionData(**sect, *region);
- break;
- }
- case LDFileFormat::Relocation:
- emitRelocation(m_Config, **sect, *region);
- break;
- case LDFileFormat::Target:
- target().emitSectionData(**sect, *region);
- break;
- default:
- continue;
- }
- } // end of for loop
-
- emitELFShStrTab(target().getOutputFormat()->getShStrTab(),
- pModule,
- pOutput);
-
- if (m_Config.targets().is32Bits()) {
- // Write out ELF header
- // Write out section header table
- writeELF32Header(m_Config, pModule, pOutput);
-
- emitELF32ProgramHeader(pOutput);
-
- emitELF32SectionHeader(pModule, m_Config, pOutput);
- }
- else if (m_Config.targets().is64Bits()) {
- // Write out ELF header
- // Write out section header table
- writeELF64Header(m_Config, pModule, pOutput);
-
- emitELF64ProgramHeader(pOutput);
-
- emitELF64SectionHeader(pModule, m_Config, pOutput);
- }
- else
- return make_error_code(errc::not_supported);
-
- pOutput.clear();
- return llvm::make_error_code(llvm::errc::success);
-}
-
diff --git a/lib/LD/ELFFileFormat.cpp b/lib/LD/ELFFileFormat.cpp
index b4792b5..067f48c 100644
--- a/lib/LD/ELFFileFormat.cpp
+++ b/lib/LD/ELFFileFormat.cpp
@@ -59,7 +59,8 @@ ELFFileFormat::ELFFileFormat()
f_pStabStr(NULL),
f_pStack(NULL),
f_pStackNote(NULL),
- f_pDataRelRoLocal(NULL) {
+ f_pDataRelRoLocal(NULL),
+ f_pGNUHashTab(NULL) {
}
diff --git a/lib/LD/ELFObjectReader.cpp b/lib/LD/ELFObjectReader.cpp
index a87b5b8..b26bb1f 100644
--- a/lib/LD/ELFObjectReader.cpp
+++ b/lib/LD/ELFObjectReader.cpp
@@ -42,6 +42,9 @@ ELFObjectReader::ELFObjectReader(GNULDBackend& pBackend,
if (pConfig.targets().is32Bits() && pConfig.targets().isLittleEndian()) {
m_pELFReader = new ELFReader<32, true>(pBackend);
}
+ else if (pConfig.targets().is64Bits() && pConfig.targets().isLittleEndian()) {
+ m_pELFReader = new ELFReader<64, true>(pBackend);
+ }
m_pEhFrameReader = new EhFrameReader();
}
diff --git a/lib/LD/ELFObjectWriter.cpp b/lib/LD/ELFObjectWriter.cpp
index e9b7b99..f31b9fb 100644
--- a/lib/LD/ELFObjectWriter.cpp
+++ b/lib/LD/ELFObjectWriter.cpp
@@ -12,10 +12,29 @@
#include <mcld/LinkerConfig.h>
#include <mcld/Target/GNULDBackend.h>
#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/ADT/SizeTraits.h>
+#include <mcld/Fragment/FragmentLinker.h>
+#include <mcld/Fragment/AlignFragment.h>
+#include <mcld/Fragment/FillFragment.h>
+#include <mcld/Fragment/RegionFragment.h>
+#include <mcld/Fragment/Stub.h>
+#include <mcld/Fragment/NullFragment.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/SectionData.h>
+#include <mcld/LD/ELFSegment.h>
+#include <mcld/LD/ELFSegmentFactory.h>
+#include <mcld/LD/RelocData.h>
+#include <mcld/LD/EhFrame.h>
+#include <llvm/Support/ErrorHandling.h>
#include <llvm/Support/system_error.h>
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/Casting.h>
using namespace llvm;
+using namespace llvm::ELF;
using namespace mcld;
//===----------------------------------------------------------------------===//
@@ -23,112 +42,622 @@ using namespace mcld;
//===----------------------------------------------------------------------===//
ELFObjectWriter::ELFObjectWriter(GNULDBackend& pBackend,
const LinkerConfig& pConfig)
- : ObjectWriter(pBackend), ELFWriter(pBackend),
- m_Config(pConfig) {
+ : ObjectWriter(), m_Backend(pBackend), m_Config(pConfig)
+{
}
ELFObjectWriter::~ELFObjectWriter()
{
}
+void ELFObjectWriter::writeSection(MemoryArea& pOutput, LDSection *section)
+{
+ MemoryRegion* region;
+ // Request output region
+ switch (section->kind()) {
+ case LDFileFormat::Note:
+ if (section->getSectionData() == NULL)
+ return;
+ // Fall through
+ case LDFileFormat::Regular:
+ case LDFileFormat::Relocation:
+ case LDFileFormat::Target:
+ case LDFileFormat::Debug:
+ case LDFileFormat::GCCExceptTable:
+ case LDFileFormat::EhFrame: {
+ region = pOutput.request(section->offset(), section->size());
+ if (NULL == region) {
+ llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section `") +
+ llvm::Twine(section->name()) +
+ llvm::Twine("'.\n"));
+ }
+ break;
+ }
+ case LDFileFormat::Null:
+ case LDFileFormat::NamePool:
+ case LDFileFormat::BSS:
+ case LDFileFormat::MetaData:
+ case LDFileFormat::Version:
+ case LDFileFormat::EhFrameHdr:
+ case LDFileFormat::StackNote:
+ // Ignore these sections
+ return;
+ default:
+ llvm::errs() << "WARNING: unsupported section kind: "
+ << section->kind()
+ << " of section "
+ << section->name()
+ << ".\n";
+ return;
+ }
+
+ // Write out sections with data
+ switch(section->kind()) {
+ case LDFileFormat::GCCExceptTable:
+ case LDFileFormat::EhFrame:
+ case LDFileFormat::Regular:
+ case LDFileFormat::Debug:
+ case LDFileFormat::Note:
+ // FIXME: if optimization of exception handling sections is enabled,
+ // then we should emit these sections by the other way.
+ emitSectionData(*section, *region);
+ break;
+ case LDFileFormat::Relocation:
+ emitRelocation(m_Config, *section, *region);
+ break;
+ case LDFileFormat::Target:
+ target().emitSectionData(*section, *region);
+ break;
+ default:
+ llvm_unreachable("invalid section kind");
+ }
+}
+
llvm::error_code ELFObjectWriter::writeObject(Module& pModule,
MemoryArea& pOutput)
{
- // Write out name pool sections: .symtab, .strtab
- target().emitRegNamePools(pModule, pOutput);
-
- // Write out regular ELF sections
- Module::iterator sect, sectEnd = pModule.end();
- for (sect = pModule.begin(); sect != sectEnd; ++sect) {
- MemoryRegion* region = NULL;
- // request output region
- switch((*sect)->kind()) {
- case LDFileFormat::Note:
- if ((*sect)->getSectionData() == NULL)
- continue;
- // Fall through
- case LDFileFormat::Regular:
- case LDFileFormat::Relocation:
- case LDFileFormat::Target:
- case LDFileFormat::Debug:
- case LDFileFormat::GCCExceptTable:
- case LDFileFormat::EhFrame: {
- region = pOutput.request((*sect)->offset(), (*sect)->size());
- if (NULL == region) {
- llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section `") +
- llvm::Twine((*sect)->name()) +
- llvm::Twine("'.\n"));
- }
- break;
- }
- case LDFileFormat::Null:
- case LDFileFormat::NamePool:
- case LDFileFormat::BSS:
- case LDFileFormat::MetaData:
- case LDFileFormat::Version:
- case LDFileFormat::EhFrameHdr:
- case LDFileFormat::StackNote:
- // ignore these sections
- continue;
- default: {
- llvm::errs() << "WARNING: unsupported section kind: "
- << (*sect)->kind()
- << " of section "
- << (*sect)->name()
- << ".\n";
- continue;
+ bool is_dynobj = m_Config.codeGenType() == LinkerConfig::DynObj;
+ bool is_exec = m_Config.codeGenType() == LinkerConfig::Exec;
+ bool is_binary = m_Config.codeGenType() == LinkerConfig::Binary;
+ bool is_object = m_Config.codeGenType() == LinkerConfig::Object;
+
+ assert(is_dynobj || is_exec || is_binary || is_object);
+
+ if (is_dynobj || is_exec) {
+ // Write out the interpreter section: .interp
+ target().emitInterp(pOutput);
+
+ // Write out name pool sections: .dynsym, .dynstr, .hash
+ target().emitDynNamePools(pModule, pOutput);
+ }
+
+ if (is_object || is_dynobj || is_exec) {
+ // Write out name pool sections: .symtab, .strtab
+ target().emitRegNamePools(pModule, pOutput);
+ }
+
+ if (is_binary) {
+ // Iterate over the loadable segments and write the corresponding sections
+ ELFSegmentFactory::iterator seg, segEnd = target().elfSegmentTable().end();
+
+ for (seg = target().elfSegmentTable().begin(); seg != segEnd; ++seg) {
+ if (llvm::ELF::PT_LOAD == (*seg).type()) {
+ ELFSegment::sect_iterator sect, sectEnd = (*seg).end();
+ for (sect = (*seg).begin(); sect != sectEnd; ++sect)
+ writeSection(pOutput, *sect);
}
}
+ } else {
+ // Write out regular ELF sections
+ Module::iterator sect, sectEnd = pModule.end();
+ for (sect = pModule.begin(); sect != sectEnd; ++sect)
+ writeSection(pOutput, *sect);
- // write out sections with data
- switch((*sect)->kind()) {
- case LDFileFormat::Regular:
- case LDFileFormat::Debug:
- case LDFileFormat::GCCExceptTable:
- case LDFileFormat::Note:
- case LDFileFormat::EhFrame: {
- // FIXME: if optimization of exception handling sections is enabled,
- // then we should emit these sections by the other way.
- emitSectionData(**sect, *region);
- break;
+ emitShStrTab(target().getOutputFormat()->getShStrTab(), pModule, pOutput);
+
+ if (m_Config.targets().is32Bits()) {
+ // Write out ELF header
+ // Write out section header table
+ writeELFHeader<32>(m_Config, pModule, pOutput);
+ if (is_dynobj || is_exec)
+ emitProgramHeader<32>(pOutput);
+
+ emitSectionHeader<32>(pModule, m_Config, pOutput);
+ }
+ else if (m_Config.targets().is64Bits()) {
+ // Write out ELF header
+ // Write out section header table
+ writeELFHeader<64>(m_Config, pModule, pOutput);
+ if (is_dynobj || is_exec)
+ emitProgramHeader<64>(pOutput);
+
+ emitSectionHeader<64>(pModule, m_Config, pOutput);
+ }
+ else
+ return make_error_code(errc::not_supported);
+ }
+
+ pOutput.clear();
+ return llvm::make_error_code(llvm::errc::success);
+}
+
+// writeELFHeader - emit ElfXX_Ehdr
+template<size_t SIZE>
+void ELFObjectWriter::writeELFHeader(const LinkerConfig& pConfig,
+ const Module& pModule,
+ MemoryArea& pOutput) const
+{
+ typedef typename ELFSizeTraits<SIZE>::Ehdr ElfXX_Ehdr;
+ typedef typename ELFSizeTraits<SIZE>::Shdr ElfXX_Shdr;
+ typedef typename ELFSizeTraits<SIZE>::Phdr ElfXX_Phdr;
+
+ // ELF header must start from 0x0
+ MemoryRegion *region = pOutput.request(0, sizeof(ElfXX_Ehdr));
+ ElfXX_Ehdr* header = (ElfXX_Ehdr*)region->start();
+
+ memcpy(header->e_ident, ElfMagic, EI_MAG3+1);
+
+ header->e_ident[EI_CLASS] = (SIZE == 32) ? ELFCLASS32 : ELFCLASS64;
+ header->e_ident[EI_DATA] = pConfig.targets().isLittleEndian()?
+ ELFDATA2LSB : ELFDATA2MSB;
+ header->e_ident[EI_VERSION] = target().getInfo().ELFVersion();
+ header->e_ident[EI_OSABI] = target().getInfo().OSABI();
+ header->e_ident[EI_ABIVERSION] = target().getInfo().ABIVersion();
+
+ // FIXME: add processor-specific and core file types.
+ switch(pConfig.codeGenType()) {
+ case LinkerConfig::Object:
+ header->e_type = ET_REL;
+ break;
+ case LinkerConfig::DynObj:
+ header->e_type = ET_DYN;
+ break;
+ case LinkerConfig::Exec:
+ header->e_type = ET_EXEC;
+ break;
+ default:
+ llvm::errs() << "unspported output file type: " << pConfig.codeGenType() << ".\n";
+ header->e_type = ET_NONE;
+ }
+ header->e_machine = target().getInfo().machine();
+ header->e_version = header->e_ident[EI_VERSION];
+ header->e_entry = getEntryPoint(pConfig, pModule);
+
+ if (LinkerConfig::Object != pConfig.codeGenType())
+ header->e_phoff = sizeof(ElfXX_Ehdr);
+ else
+ header->e_phoff = 0x0;
+
+ header->e_shoff = getLastStartOffset<SIZE>(pModule);
+ header->e_flags = target().getInfo().flags();
+ header->e_ehsize = sizeof(ElfXX_Ehdr);
+ header->e_phentsize = sizeof(ElfXX_Phdr);
+ header->e_phnum = target().numOfSegments();
+ header->e_shentsize = sizeof(ElfXX_Shdr);
+ header->e_shnum = pModule.size();
+ header->e_shstrndx = pModule.getSection(".shstrtab")->index();
+}
+
+/// getEntryPoint
+uint64_t ELFObjectWriter::getEntryPoint(const LinkerConfig& pConfig,
+ const Module& pModule) const
+{
+ llvm::StringRef entry_name;
+ if (pConfig.options().hasEntry())
+ entry_name = pConfig.options().entry();
+ else
+ entry_name = target().getInfo().entry();
+
+ uint64_t result = 0x0;
+
+ bool issue_warning = (pConfig.options().hasEntry() &&
+ LinkerConfig::Object != pConfig.codeGenType() &&
+ LinkerConfig::DynObj != pConfig.codeGenType());
+
+ const LDSymbol* entry_symbol = pModule.getNamePool().findSymbol(entry_name);
+
+ // found the symbol
+ if (NULL != entry_symbol) {
+ if (entry_symbol->desc() != ResolveInfo::Define && issue_warning) {
+ llvm::errs() << "WARNING: entry symbol '"
+ << entry_symbol->name()
+ << "' exists but is not defined.\n";
+ }
+ result = entry_symbol->value();
+ }
+ // not in the symbol pool
+ else {
+ // We should parse entry as a number.
+ // @ref GNU ld manual, Options -e. e.g., -e 0x1000.
+ char* endptr;
+ result = strtoull(entry_name.data(), &endptr, 0);
+ if (*endptr != '\0') {
+ if (issue_warning) {
+ llvm::errs() << "cannot find entry symbol '"
+ << entry_name.data()
+ << "'.\n";
}
- case LDFileFormat::Relocation:
- emitRelocation(m_Config, **sect, *region);
- break;
- case LDFileFormat::Target:
- target().emitSectionData(**sect, *region);
- break;
- default:
- continue;
+ result = 0x0;
}
- } // end of for loop
+ }
+ return result;
+}
- emitELFShStrTab(target().getOutputFormat()->getShStrTab(),
- pModule,
- pOutput);
+// emitSectionHeader - emit ElfXX_Shdr
+template<size_t SIZE>
+void ELFObjectWriter::emitSectionHeader(const Module& pModule,
+ const LinkerConfig& pConfig,
+ MemoryArea& pOutput) const
+{
+ typedef typename ELFSizeTraits<SIZE>::Shdr ElfXX_Shdr;
- if (m_Config.targets().is32Bits()) {
- // Write out ELF header
- // Write out section header table
- writeELF32Header(m_Config,
- pModule,
- pOutput);
+ // emit section header
+ unsigned int sectNum = pModule.size();
+ unsigned int header_size = sizeof(ElfXX_Shdr) * sectNum;
+ MemoryRegion* region = pOutput.request(getLastStartOffset<SIZE>(pModule),
+ header_size);
+ ElfXX_Shdr* shdr = (ElfXX_Shdr*)region->start();
- emitELF32SectionHeader(pModule, m_Config, pOutput);
+ // Iterate the SectionTable in LDContext
+ unsigned int sectIdx = 0;
+ unsigned int shstridx = 0; // NULL section has empty name
+ for (; sectIdx < sectNum; ++sectIdx) {
+ const LDSection *ld_sect = pModule.getSectionTable().at(sectIdx);
+ shdr[sectIdx].sh_name = shstridx;
+ shdr[sectIdx].sh_type = ld_sect->type();
+ shdr[sectIdx].sh_flags = ld_sect->flag();
+ shdr[sectIdx].sh_addr = ld_sect->addr();
+ shdr[sectIdx].sh_offset = ld_sect->offset();
+ shdr[sectIdx].sh_size = ld_sect->size();
+ shdr[sectIdx].sh_addralign = ld_sect->align();
+ shdr[sectIdx].sh_entsize = getSectEntrySize<SIZE>(*ld_sect);
+ shdr[sectIdx].sh_link = getSectLink(*ld_sect, pConfig);
+ shdr[sectIdx].sh_info = getSectInfo(*ld_sect);
+
+ // adjust strshidx
+ shstridx += ld_sect->name().size() + 1;
}
- else if (m_Config.targets().is64Bits()) {
- // Write out ELF header
- // Write out section header table
- writeELF64Header(m_Config,
- pModule,
- pOutput);
+}
+
+// emitProgramHeader - emit ElfXX_Phdr
+template<size_t SIZE>
+void ELFObjectWriter::emitProgramHeader(MemoryArea& pOutput) const
+{
+ typedef typename ELFSizeTraits<SIZE>::Ehdr ElfXX_Ehdr;
+ typedef typename ELFSizeTraits<SIZE>::Phdr ElfXX_Phdr;
+
+ uint64_t start_offset, phdr_size;
- emitELF64SectionHeader(pModule, m_Config, pOutput);
+ start_offset = sizeof(ElfXX_Ehdr);
+ phdr_size = sizeof(ElfXX_Phdr);
+ // Program header must start directly after ELF header
+ MemoryRegion *region = pOutput.request(start_offset,
+ target().numOfSegments() * phdr_size);
+
+ ElfXX_Phdr* phdr = (ElfXX_Phdr*)region->start();
+
+ // Iterate the elf segment table in GNULDBackend
+ size_t index = 0;
+ ELFSegmentFactory::const_iterator seg = target().elfSegmentTable().begin(),
+ segEnd = target().elfSegmentTable().end();
+ for (; seg != segEnd; ++seg, ++index) {
+ phdr[index].p_type = (*seg).type();
+ phdr[index].p_flags = (*seg).flag();
+ phdr[index].p_offset = (*seg).offset();
+ phdr[index].p_vaddr = (*seg).vaddr();
+ phdr[index].p_paddr = (*seg).paddr();
+ phdr[index].p_filesz = (*seg).filesz();
+ phdr[index].p_memsz = (*seg).memsz();
+ phdr[index].p_align = (*seg).align();
}
- else
- return make_error_code(errc::not_supported);
+}
- pOutput.clear();
- return llvm::make_error_code(llvm::errc::success);
+/// emitShStrTab - emit section string table
+void
+ELFObjectWriter::emitShStrTab(const LDSection& pShStrTab,
+ const Module& pModule,
+ MemoryArea& pOutput)
+{
+ // write out data
+ MemoryRegion* region = pOutput.request(pShStrTab.offset(), pShStrTab.size());
+ unsigned char* data = region->start();
+ size_t shstrsize = 0;
+ Module::const_iterator section, sectEnd = pModule.end();
+ for (section = pModule.begin(); section != sectEnd; ++section) {
+ strcpy((char*)(data + shstrsize), (*section)->name().data());
+ shstrsize += (*section)->name().size() + 1;
+ }
+}
+
+/// emitSectionData
+void
+ELFObjectWriter::emitSectionData(const LDSection& pSection,
+ MemoryRegion& pRegion) const
+{
+ const SectionData* sd = NULL;
+ switch (pSection.kind()) {
+ case LDFileFormat::Relocation:
+ assert(pSection.hasRelocData());
+ return;
+ case LDFileFormat::EhFrame:
+ assert(pSection.hasEhFrame());
+ sd = &pSection.getEhFrame()->getSectionData();
+ break;
+ default:
+ assert(pSection.hasSectionData());
+ sd = pSection.getSectionData();
+ break;
+ }
+ emitSectionData(*sd, pRegion);
+}
+
+/// emitRelocation
+void ELFObjectWriter::emitRelocation(const LinkerConfig& pConfig,
+ const LDSection& pSection,
+ MemoryRegion& pRegion) const
+{
+ const RelocData* sect_data = pSection.getRelocData();
+ assert(NULL != sect_data && "SectionData is NULL in emitRelocation!");
+
+ if (pSection.type() == SHT_REL) {
+ if (pConfig.targets().is32Bits())
+ emitRel<32>(pConfig, *sect_data, pRegion);
+ else if (pConfig.targets().is64Bits())
+ emitRel<64>(pConfig, *sect_data, pRegion);
+ else {
+ fatal(diag::unsupported_bitclass) << pConfig.targets().triple().str()
+ << pConfig.targets().bitclass();
+ }
+ } else if (pSection.type() == SHT_RELA) {
+ if (pConfig.targets().is32Bits())
+ emitRela<32>(pConfig, *sect_data, pRegion);
+ else if (pConfig.targets().is64Bits())
+ emitRela<64>(pConfig, *sect_data, pRegion);
+ else {
+ fatal(diag::unsupported_bitclass) << pConfig.targets().triple().str()
+ << pConfig.targets().bitclass();
+ }
+ } else
+ llvm::report_fatal_error("unsupported relocation section type!");
+}
+
+
+// emitRel - emit ElfXX_Rel
+template<size_t SIZE>
+void ELFObjectWriter::emitRel(const LinkerConfig& pConfig,
+ const RelocData& pRelocData,
+ MemoryRegion& pRegion) const
+{
+ typedef typename ELFSizeTraits<SIZE>::Rel ElfXX_Rel;
+ typedef typename ELFSizeTraits<SIZE>::Addr ElfXX_Addr;
+ typedef typename ELFSizeTraits<SIZE>::Word ElfXX_Word;
+
+ ElfXX_Rel* rel = reinterpret_cast<ElfXX_Rel*>(pRegion.start());
+
+ const Relocation* relocation = 0;
+ const FragmentRef* frag_ref = 0;
+
+ for (RelocData::const_iterator it = pRelocData.begin(),
+ ie = pRelocData.end(); it != ie; ++it, ++rel) {
+
+ relocation = &(llvm::cast<Relocation>(*it));
+ frag_ref = &(relocation->targetRef());
+
+ if(LinkerConfig::DynObj == pConfig.codeGenType() ||
+ LinkerConfig::Exec == pConfig.codeGenType()) {
+ rel->r_offset = static_cast<ElfXX_Addr>(
+ frag_ref->frag()->getParent()->getSection().addr() +
+ frag_ref->getOutputOffset());
+ }
+ else {
+ rel->r_offset = static_cast<ElfXX_Addr>(frag_ref->getOutputOffset());
+ }
+ ElfXX_Word Index;
+ if( relocation->symInfo() == NULL )
+ Index = 0;
+ else
+ Index = static_cast<ElfXX_Word>(
+ target().getSymbolIdx(relocation->symInfo()->outSymbol()));
+
+ rel->setSymbolAndType(Index, relocation->type());
+ }
+}
+
+// emitRela - emit ElfXX_Rela
+template<size_t SIZE>
+void ELFObjectWriter::emitRela(const LinkerConfig& pConfig,
+ const RelocData& pRelocData,
+ MemoryRegion& pRegion) const
+{
+ typedef typename ELFSizeTraits<SIZE>::Rela ElfXX_Rela;
+ typedef typename ELFSizeTraits<SIZE>::Addr ElfXX_Addr;
+ typedef typename ELFSizeTraits<SIZE>::Word ElfXX_Word;
+
+ ElfXX_Rela* rel = reinterpret_cast<ElfXX_Rela*>(pRegion.start());
+
+ const Relocation* relocation = 0;
+ const FragmentRef* frag_ref = 0;
+
+ for (RelocData::const_iterator it = pRelocData.begin(),
+ ie = pRelocData.end(); it != ie; ++it, ++rel) {
+
+ relocation = &(llvm::cast<Relocation>(*it));
+ frag_ref = &(relocation->targetRef());
+
+ if(LinkerConfig::DynObj == pConfig.codeGenType() ||
+ LinkerConfig::Exec == pConfig.codeGenType()) {
+ rel->r_offset = static_cast<ElfXX_Addr>(
+ frag_ref->frag()->getParent()->getSection().addr() +
+ frag_ref->getOutputOffset());
+ }
+ else {
+ rel->r_offset = static_cast<ElfXX_Addr>(frag_ref->getOutputOffset());
+ }
+
+ ElfXX_Word Index;
+ if( relocation->symInfo() == NULL )
+ Index = 0;
+ else
+ Index = static_cast<ElfXX_Word>(
+ target().getSymbolIdx(relocation->symInfo()->outSymbol()));
+
+ rel->setSymbolAndType(Index, relocation->type());
+ rel->r_addend = relocation->addend();
+ }
+}
+
+
+/// getSectEntrySize - compute ElfXX_Shdr::sh_entsize
+template<size_t SIZE>
+uint64_t ELFObjectWriter::getSectEntrySize(const LDSection& pSection) const
+{
+ typedef typename ELFSizeTraits<SIZE>::Word ElfXX_Word;
+ typedef typename ELFSizeTraits<SIZE>::Sym ElfXX_Sym;
+ typedef typename ELFSizeTraits<SIZE>::Rel ElfXX_Rel;
+ typedef typename ELFSizeTraits<SIZE>::Rela ElfXX_Rela;
+ typedef typename ELFSizeTraits<SIZE>::Dyn ElfXX_Dyn;
+
+ if (llvm::ELF::SHT_DYNSYM == pSection.type() ||
+ llvm::ELF::SHT_SYMTAB == pSection.type())
+ return sizeof(ElfXX_Sym);
+ if (llvm::ELF::SHT_REL == pSection.type())
+ return sizeof(ElfXX_Rel);
+ if (llvm::ELF::SHT_RELA == pSection.type())
+ return sizeof(ElfXX_Rela);
+ if (llvm::ELF::SHT_HASH == pSection.type() ||
+ llvm::ELF::SHT_GNU_HASH == pSection.type())
+ return sizeof(ElfXX_Word);
+ if (llvm::ELF::SHT_DYNAMIC == pSection.type())
+ return sizeof(ElfXX_Dyn);
+ return 0x0;
+}
+
+/// getSectLink - compute ElfXX_Shdr::sh_link
+uint64_t ELFObjectWriter::getSectLink(const LDSection& pSection,
+ const LinkerConfig& pConfig) const
+{
+ if (llvm::ELF::SHT_SYMTAB == pSection.type())
+ return target().getOutputFormat()->getStrTab().index();
+ if (llvm::ELF::SHT_DYNSYM == pSection.type())
+ return target().getOutputFormat()->getDynStrTab().index();
+ if (llvm::ELF::SHT_DYNAMIC == pSection.type())
+ return target().getOutputFormat()->getDynStrTab().index();
+ if (llvm::ELF::SHT_HASH == pSection.type() ||
+ llvm::ELF::SHT_GNU_HASH == pSection.type())
+ return target().getOutputFormat()->getDynSymTab().index();
+ if (llvm::ELF::SHT_REL == pSection.type() ||
+ llvm::ELF::SHT_RELA == pSection.type()) {
+ if (LinkerConfig::Object == pConfig.codeGenType())
+ return target().getOutputFormat()->getSymTab().index();
+ else
+ return target().getOutputFormat()->getDynSymTab().index();
+ }
+ // FIXME: currently we link ARM_EXIDX section to output text section here
+ if (llvm::ELF::SHT_ARM_EXIDX == pSection.type())
+ return target().getOutputFormat()->getText().index();
+ return llvm::ELF::SHN_UNDEF;
+}
+
+/// getSectInfo - compute ElfXX_Shdr::sh_info
+uint64_t ELFObjectWriter::getSectInfo(const LDSection& pSection) const
+{
+ if (llvm::ELF::SHT_SYMTAB == pSection.type() ||
+ llvm::ELF::SHT_DYNSYM == pSection.type())
+ return pSection.getInfo();
+
+ if (llvm::ELF::SHT_REL == pSection.type() ||
+ llvm::ELF::SHT_RELA == pSection.type()) {
+ const LDSection* info_link = pSection.getLink();
+ if (NULL != info_link)
+ return info_link->index();
+ }
+
+ return 0x0;
+}
+
+/// getLastStartOffset
+template<>
+uint64_t ELFObjectWriter::getLastStartOffset<32>(const Module& pModule) const
+{
+ const LDSection* lastSect = pModule.back();
+ assert(lastSect != NULL);
+ return Align<32>(lastSect->offset() + lastSect->size());
+}
+
+/// getLastStartOffset
+template<>
+uint64_t ELFObjectWriter::getLastStartOffset<64>(const Module& pModule) const
+{
+ const LDSection* lastSect = pModule.back();
+ assert(lastSect != NULL);
+ return Align<64>(lastSect->offset() + lastSect->size());
+}
+
+/// emitSectionData
+void ELFObjectWriter::emitSectionData(const SectionData& pSD,
+ MemoryRegion& pRegion) const
+{
+ SectionData::const_iterator fragIter, fragEnd = pSD.end();
+ size_t cur_offset = 0;
+ for (fragIter = pSD.begin(); fragIter != fragEnd; ++fragIter) {
+ size_t size = fragIter->size();
+ switch(fragIter->getKind()) {
+ case Fragment::Region: {
+ const RegionFragment& region_frag = llvm::cast<RegionFragment>(*fragIter);
+ const uint8_t* from = region_frag.getRegion().start();
+ memcpy(pRegion.getBuffer(cur_offset), from, size);
+ break;
+ }
+ case Fragment::Alignment: {
+ // TODO: emit values with different sizes (> 1 byte), and emit nops
+ const AlignFragment& align_frag = llvm::cast<AlignFragment>(*fragIter);
+ uint64_t count = size / align_frag.getValueSize();
+ switch (align_frag.getValueSize()) {
+ case 1u:
+ std::memset(pRegion.getBuffer(cur_offset),
+ align_frag.getValue(),
+ count);
+ break;
+ default:
+ llvm::report_fatal_error("unsupported value size for align fragment emission yet.\n");
+ break;
+ }
+ break;
+ }
+ case Fragment::Fillment: {
+ const FillFragment& fill_frag = llvm::cast<FillFragment>(*fragIter);
+ if (0 == size ||
+ 0 == fill_frag.getValueSize() ||
+ 0 == fill_frag.size()) {
+ // ignore virtual fillment
+ break;
+ }
+
+ uint64_t num_tiles = fill_frag.size() / fill_frag.getValueSize();
+ for (uint64_t i = 0; i != num_tiles; ++i) {
+ std::memset(pRegion.getBuffer(cur_offset),
+ fill_frag.getValue(),
+ fill_frag.getValueSize());
+ }
+ break;
+ }
+ case Fragment::Stub: {
+ const Stub& stub_frag = llvm::cast<Stub>(*fragIter);
+ memcpy(pRegion.getBuffer(cur_offset), stub_frag.getContent(), size);
+ break;
+ }
+ case Fragment::Null: {
+ assert(0x0 == size);
+ break;
+ }
+ case Fragment::Target:
+ llvm::report_fatal_error("Target fragment should not be in a regular section.\n");
+ break;
+ default:
+ llvm::report_fatal_error("invalid fragment should not be in a regular section.\n");
+ break;
+ }
+ cur_offset += size;
+ }
}
diff --git a/lib/LD/ELFReader.cpp b/lib/LD/ELFReader.cpp
index 84ad17b..4057ac8 100644
--- a/lib/LD/ELFReader.cpp
+++ b/lib/LD/ELFReader.cpp
@@ -13,7 +13,6 @@
#include <mcld/LD/EhFrame.h>
#include <mcld/LD/SectionData.h>
#include <mcld/Target/GNULDBackend.h>
-#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Object/ObjectBuilder.h>
@@ -25,138 +24,9 @@
#include <llvm/Support/ELF.h>
#include <llvm/Support/Host.h>
-using namespace mcld;
-
-//===----------------------------------------------------------------------===//
-// ELFReaderIF
-//===----------------------------------------------------------------------===//
-/// getSymType
-ResolveInfo::Type ELFReaderIF::getSymType(uint8_t pInfo, uint16_t pShndx) const
-{
- ResolveInfo::Type result = static_cast<ResolveInfo::Type>(pInfo & 0xF);
- if (llvm::ELF::SHN_ABS == pShndx && ResolveInfo::Section == result) {
- // In Mips, __gp_disp is a special section symbol. Its name comes from
- // .strtab, not .shstrtab. However, it is unique. Only it is also a ABS
- // symbol. So here is a tricky to identify __gp_disp and convert it to
- // Object symbol.
- return ResolveInfo::Object;
- }
-
- return result;
-}
-
-/// getSymDesc
-ResolveInfo::Desc ELFReaderIF::getSymDesc(uint16_t pShndx, const Input& pInput) const
-{
- if (pShndx == llvm::ELF::SHN_UNDEF)
- return ResolveInfo::Undefined;
-
- if (pShndx < llvm::ELF::SHN_LORESERVE) {
- // an ELF symbol defined in a section which we are not including
- // must be treated as an Undefined.
- // @ref Google gold linker: symtab.cc: 1086
- if (NULL == pInput.context()->getSection(pShndx) ||
- LDFileFormat::Ignore == pInput.context()->getSection(pShndx)->kind())
- return ResolveInfo::Undefined;
- return ResolveInfo::Define;
- }
-
- if (pShndx == llvm::ELF::SHN_ABS)
- return ResolveInfo::Define;
-
- if (pShndx == llvm::ELF::SHN_COMMON)
- return ResolveInfo::Common;
-
- // FIXME: ELF weak alias should be ResolveInfo::Indirect
- return ResolveInfo::NoneDesc;
-}
-
-/// getSymBinding
-ResolveInfo::Binding
-ELFReaderIF::getSymBinding(uint8_t pBinding, uint16_t pShndx, uint8_t pVis) const
-{
-
- // TODO:
- // if --just-symbols option is enabled, the symbol must covert to Absolute
-
- switch(pBinding) {
- case llvm::ELF::STB_LOCAL:
- return ResolveInfo::Local;
- case llvm::ELF::STB_GLOBAL:
- return ResolveInfo::Global;
- case llvm::ELF::STB_WEAK:
- return ResolveInfo::Weak;
- }
-
- if (pShndx == llvm::ELF::SHN_ABS)
- return ResolveInfo::Absolute;
-
- return ResolveInfo::NoneBinding;
-}
-
-/// getSymFragmentRef
-FragmentRef*
-ELFReaderIF::getSymFragmentRef(Input& pInput,
- uint16_t pShndx,
- uint32_t pOffset) const
-{
-
- if (Input::DynObj == pInput.type())
- return FragmentRef::Null();
-
- if (pShndx == llvm::ELF::SHN_UNDEF)
- return FragmentRef::Null();
-
- if (pShndx >= llvm::ELF::SHN_LORESERVE) // including ABS and COMMON
- return FragmentRef::Null();
+#include <iostream>
- LDSection* sect_hdr = pInput.context()->getSection(pShndx);
-
- if (NULL == sect_hdr)
- unreachable(diag::unreachable_invalid_section_idx) << pShndx
- << pInput.path().native();
-
- if (LDFileFormat::Ignore == sect_hdr->kind())
- return FragmentRef::Null();
-
- if (LDFileFormat::Group == sect_hdr->kind())
- return FragmentRef::Null();
-
- return FragmentRef::Create(*sect_hdr, pOffset);
-}
-
-/// getSymVisibility
-ResolveInfo::Visibility
-ELFReaderIF::getSymVisibility(uint8_t pVis) const
-{
- return static_cast<ResolveInfo::Visibility>(pVis);
-}
-
-/// getSymValue - get the section offset of the symbol.
-uint64_t ELFReaderIF::getSymValue(uint64_t pValue,
- uint16_t pShndx,
- const Input& pInput) const
-{
- if (Input::Object == pInput.type()) {
- // In relocatable files, st_value holds alignment constraints for a symbol
- // whose section index is SHN_COMMON
- if (pShndx == llvm::ELF::SHN_COMMON || pShndx == llvm::ELF::SHN_ABS) {
- return pValue;
- }
-
- // In relocatable files, st_value holds a section offset for a defined symbol.
- // TODO:
- // if --just-symbols option are enabled, convert the value from section offset
- // to virtual address by adding input section's virtual address.
- // The section's virtual address in relocatable files is normally zero, but
- // people can use link script to change it.
- return pValue;
- }
-
- // In executable and shared object files, st_value holds a virtual address.
- // the virtual address is useless during linking.
- return 0x0;
-}
+using namespace mcld;
//===----------------------------------------------------------------------===//
// ELFReader<32, true>
@@ -413,8 +283,8 @@ ELFReader<32, true>::readSectionHeaders(Input& pInput, void* pELFHeader) const
uint32_t shoff = 0x0;
uint16_t shentsize = 0x0;
- uint16_t shnum = 0x0;
- uint16_t shstrtab = 0x0;
+ uint32_t shnum = 0x0;
+ uint32_t shstrtab = 0x0;
if (llvm::sys::isLittleEndianHost()) {
shoff = ehdr->e_shoff;
@@ -433,11 +303,8 @@ ELFReader<32, true>::readSectionHeaders(Input& pInput, void* pELFHeader) const
if (0x0 == shoff)
return true;
- MemoryRegion* shdr_region = pInput.memArea()->request(
- pInput.fileOffset() + shoff, shnum*shentsize);
- llvm::ELF::Elf32_Shdr* shdrTab =
- reinterpret_cast<llvm::ELF::Elf32_Shdr*>(shdr_region->start());
-
+ llvm::ELF::Elf32_Shdr *shdr = NULL;
+ MemoryRegion* shdr_region = NULL;
uint32_t sh_name = 0x0;
uint32_t sh_type = 0x0;
uint32_t sh_flags = 0x0;
@@ -447,8 +314,37 @@ ELFReader<32, true>::readSectionHeaders(Input& pInput, void* pELFHeader) const
uint32_t sh_info = 0x0;
uint32_t sh_addralign = 0x0;
+ // if shnum and shstrtab overflow, the actual values are in the 1st shdr
+ if (shnum == llvm::ELF::SHN_UNDEF || shstrtab == llvm::ELF::SHN_XINDEX) {
+ shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff,
+ shentsize);
+ shdr = reinterpret_cast<llvm::ELF::Elf32_Shdr*>(shdr_region->start());
+
+ if (llvm::sys::isLittleEndianHost()) {
+ sh_size = shdr->sh_size;
+ sh_link = shdr->sh_link;
+ }
+ else {
+ sh_size = mcld::bswap32(shdr->sh_size);
+ sh_link = mcld::bswap32(shdr->sh_link);
+ }
+ pInput.memArea()->release(shdr_region);
+
+ if (shnum == llvm::ELF::SHN_UNDEF)
+ shnum = sh_size;
+ if (shstrtab == llvm::ELF::SHN_XINDEX)
+ shstrtab = sh_link;
+
+ shoff += shentsize;
+ }
+
+ shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff,
+ shnum * shentsize);
+ llvm::ELF::Elf32_Shdr * shdrTab =
+ reinterpret_cast<llvm::ELF::Elf32_Shdr*>(shdr_region->start());
+
// get .shstrtab first
- llvm::ELF::Elf32_Shdr* shdr = &shdrTab[shstrtab];
+ shdr = &shdrTab[shstrtab];
if (llvm::sys::isLittleEndianHost()) {
sh_offset = shdr->sh_offset;
sh_size = shdr->sh_size;
@@ -641,3 +537,512 @@ bool ELFReader<32, true>::readDynamic(Input& pInput) const
return true;
}
+//===----------------------------------------------------------------------===//
+// ELFReader<64, true>
+//===----------------------------------------------------------------------===//
+/// constructor
+ELFReader<64, true>::ELFReader(GNULDBackend& pBackend)
+ : ELFReaderIF(pBackend) {
+}
+
+/// destructor
+ELFReader<64, true>::~ELFReader()
+{
+}
+
+/// isELF - is this a ELF file
+bool ELFReader<64, true>::isELF(void* pELFHeader) const
+{
+ llvm::ELF::Elf64_Ehdr* hdr =
+ reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(pELFHeader);
+ if (0 == memcmp(llvm::ELF::ElfMagic, hdr, 4))
+ return true;
+ return false;
+}
+
+/// readRegularSection - read a regular section and create fragments.
+bool
+ELFReader<64, true>::readRegularSection(Input& pInput, SectionData& pSD) const
+{
+ uint64_t offset = pInput.fileOffset() + pSD.getSection().offset();
+ uint64_t size = pSD.getSection().size();
+
+ Fragment* frag = IRBuilder::CreateRegion(pInput, offset, size);
+ ObjectBuilder::AppendFragment(*frag, pSD);
+ return true;
+}
+
+/// readSymbols - read ELF symbols and create LDSymbol
+bool ELFReader<64, true>::readSymbols(Input& pInput,
+ IRBuilder& pBuilder,
+ const MemoryRegion& pRegion,
+ const char* pStrTab) const
+{
+ // get number of symbols
+ size_t entsize = pRegion.size()/sizeof(llvm::ELF::Elf64_Sym);
+ const llvm::ELF::Elf64_Sym* symtab =
+ reinterpret_cast<const llvm::ELF::Elf64_Sym*>(pRegion.start());
+
+ uint32_t st_name = 0x0;
+ uint64_t st_value = 0x0;
+ uint64_t st_size = 0x0;
+ uint8_t st_info = 0x0;
+ uint8_t st_other = 0x0;
+ uint16_t st_shndx = 0x0;
+
+ // skip the first NULL symbol
+ pInput.context()->addSymbol(LDSymbol::Null());
+
+ for (size_t idx = 1; idx < entsize; ++idx) {
+ st_info = symtab[idx].st_info;
+ st_other = symtab[idx].st_other;
+
+ if (llvm::sys::isLittleEndianHost()) {
+ st_name = symtab[idx].st_name;
+ st_value = symtab[idx].st_value;
+ st_size = symtab[idx].st_size;
+ st_shndx = symtab[idx].st_shndx;
+ }
+ else {
+ st_name = mcld::bswap32(symtab[idx].st_name);
+ st_value = mcld::bswap64(symtab[idx].st_value);
+ st_size = mcld::bswap64(symtab[idx].st_size);
+ st_shndx = mcld::bswap16(symtab[idx].st_shndx);
+ }
+
+ // If the section should not be included, set the st_shndx SHN_UNDEF
+ // - A section in interrelated groups are not included.
+ if (pInput.type() == Input::Object &&
+ st_shndx < llvm::ELF::SHN_LORESERVE &&
+ st_shndx != llvm::ELF::SHN_UNDEF) {
+ if (NULL == pInput.context()->getSection(st_shndx))
+ st_shndx = llvm::ELF::SHN_UNDEF;
+ }
+
+ // get ld_type
+ ResolveInfo::Type ld_type = getSymType(st_info, st_shndx);
+
+ // get ld_desc
+ ResolveInfo::Desc ld_desc = getSymDesc(st_shndx, pInput);
+
+ // get ld_binding
+ ResolveInfo::Binding ld_binding = getSymBinding((st_info >> 4), st_shndx, st_other);
+
+ // get ld_value - ld_value must be section relative.
+ uint64_t ld_value = getSymValue(st_value, st_shndx, pInput);
+
+ // get ld_vis
+ ResolveInfo::Visibility ld_vis = getSymVisibility(st_other);
+
+ // get section
+ LDSection* section = NULL;
+ if (st_shndx < llvm::ELF::SHN_LORESERVE) // including ABS and COMMON
+ section = pInput.context()->getSection(st_shndx);
+
+ // get ld_name
+ std::string ld_name;
+ if (ResolveInfo::Section == ld_type) {
+ // Section symbol's st_name is the section index.
+ assert(NULL != section && "get a invalid section");
+ ld_name = section->name();
+ }
+ else {
+ ld_name = std::string(pStrTab + st_name);
+ }
+
+ pBuilder.AddSymbol(pInput,
+ ld_name,
+ ld_type,
+ ld_desc,
+ ld_binding,
+ st_size,
+ ld_value,
+ section, ld_vis);
+ } // end of for loop
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// ELFReader::read relocations - read ELF rela and rel, and create Relocation
+//===----------------------------------------------------------------------===//
+/// ELFReader::readRela - read ELF rela and create Relocation
+bool ELFReader<64, true>::readRela(Input& pInput,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const
+{
+ // get the number of rela
+ size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf64_Rela);
+ const llvm::ELF::Elf64_Rela* relaTab =
+ reinterpret_cast<const llvm::ELF::Elf64_Rela*>(pRegion.start());
+
+ for (size_t idx=0; idx < entsize; ++idx) {
+ uint64_t r_offset = 0x0;
+ uint64_t r_info = 0x0;
+ int64_t r_addend = 0;
+ if (llvm::sys::isLittleEndianHost()) {
+ r_offset = relaTab[idx].r_offset;
+ r_info = relaTab[idx].r_info;
+ r_addend = relaTab[idx].r_addend;
+ }
+ else {
+ r_offset = mcld::bswap64(relaTab[idx].r_offset);
+ r_info = mcld::bswap64(relaTab[idx].r_info);
+ r_addend = mcld::bswap64(relaTab[idx].r_addend);
+ }
+
+ uint32_t r_type = static_cast<uint32_t>(r_info);
+ uint32_t r_sym = (r_info >> 32);
+ LDSymbol* symbol = pInput.context()->getSymbol(r_sym);
+ if (NULL == symbol) {
+ fatal(diag::err_cannot_read_symbol) << r_sym << pInput.path();
+ }
+
+ IRBuilder::AddRelocation(pSection, r_type, *symbol, r_offset, r_addend);
+ } // end of for
+ return true;
+}
+
+/// readRel - read ELF rel and create Relocation
+bool ELFReader<64, true>::readRel(Input& pInput,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const
+{
+ // get the number of rel
+ size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf64_Rel);
+ const llvm::ELF::Elf64_Rel* relTab =
+ reinterpret_cast<const llvm::ELF::Elf64_Rel*>(pRegion.start());
+
+ for (size_t idx=0; idx < entsize; ++idx) {
+ uint64_t r_offset = 0x0;
+ uint64_t r_info = 0x0;
+ if (llvm::sys::isLittleEndianHost()) {
+ r_offset = relTab[idx].r_offset;
+ r_info = relTab[idx].r_info;
+ }
+ else {
+ r_offset = mcld::bswap64(relTab[idx].r_offset);
+ r_info = mcld::bswap64(relTab[idx].r_info);
+ }
+
+ uint32_t r_type = static_cast<uint32_t>(r_info);
+ uint32_t r_sym = (r_info >> 32);
+
+ LDSymbol* symbol = pInput.context()->getSymbol(r_sym);
+ if (NULL == symbol) {
+ fatal(diag::err_cannot_read_symbol) << r_sym << pInput.path();
+ }
+
+ IRBuilder::AddRelocation(pSection, r_type, *symbol, r_offset);
+ } // end of for
+ return true;
+}
+
+/// isMyEndian - is this ELF file in the same endian to me?
+bool ELFReader<64, true>::isMyEndian(void* pELFHeader) const
+{
+ llvm::ELF::Elf64_Ehdr* hdr =
+ reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(pELFHeader);
+
+ return (hdr->e_ident[llvm::ELF::EI_DATA] == llvm::ELF::ELFDATA2LSB);
+}
+
+/// isMyMachine - is this ELF file generated for the same machine.
+bool ELFReader<64, true>::isMyMachine(void* pELFHeader) const
+{
+ llvm::ELF::Elf64_Ehdr* hdr =
+ reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(pELFHeader);
+
+ if (llvm::sys::isLittleEndianHost())
+ return (hdr->e_machine == target().getInfo().machine());
+ return (mcld::bswap16(hdr->e_machine) == target().getInfo().machine());
+}
+
+/// fileType - return the file type
+Input::Type ELFReader<64, true>::fileType(void* pELFHeader) const
+{
+ llvm::ELF::Elf64_Ehdr* hdr =
+ reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(pELFHeader);
+ uint32_t type = 0x0;
+ if (llvm::sys::isLittleEndianHost())
+ type = hdr->e_type;
+ else
+ type = mcld::bswap16(hdr->e_type);
+
+ switch(type) {
+ case llvm::ELF::ET_REL:
+ return Input::Object;
+ case llvm::ELF::ET_EXEC:
+ return Input::Exec;
+ case llvm::ELF::ET_DYN:
+ return Input::DynObj;
+ case llvm::ELF::ET_CORE:
+ return Input::CoreFile;
+ case llvm::ELF::ET_NONE:
+ default:
+ return Input::Unknown;
+ }
+}
+
+/// readSectionHeaders - read ELF section header table and create LDSections
+bool
+ELFReader<64, true>::readSectionHeaders(Input& pInput, void* pELFHeader) const
+{
+ llvm::ELF::Elf64_Ehdr* ehdr =
+ reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(pELFHeader);
+
+ uint64_t shoff = 0x0;
+ uint16_t shentsize = 0x0;
+ uint32_t shnum = 0x0;
+ uint32_t shstrtab = 0x0;
+
+ if (llvm::sys::isLittleEndianHost()) {
+ shoff = ehdr->e_shoff;
+ shentsize = ehdr->e_shentsize;
+ shnum = ehdr->e_shnum;
+ shstrtab = ehdr->e_shstrndx;
+ }
+ else {
+ shoff = mcld::bswap64(ehdr->e_shoff);
+ shentsize = mcld::bswap16(ehdr->e_shentsize);
+ shnum = mcld::bswap16(ehdr->e_shnum);
+ shstrtab = mcld::bswap16(ehdr->e_shstrndx);
+ }
+
+ // If the file has no section header table, e_shoff holds zero.
+ if (0x0 == shoff)
+ return true;
+
+ llvm::ELF::Elf64_Shdr *shdr = NULL;
+ MemoryRegion* shdr_region = NULL;
+ uint32_t sh_name = 0x0;
+ uint32_t sh_type = 0x0;
+ uint64_t sh_flags = 0x0;
+ uint64_t sh_offset = 0x0;
+ uint64_t sh_size = 0x0;
+ uint32_t sh_link = 0x0;
+ uint32_t sh_info = 0x0;
+ uint64_t sh_addralign = 0x0;
+
+ // if shnum and shstrtab overflow, the actual values are in the 1st shdr
+ if (shnum == llvm::ELF::SHN_UNDEF || shstrtab == llvm::ELF::SHN_XINDEX) {
+ shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff,
+ shentsize);
+ shdr = reinterpret_cast<llvm::ELF::Elf64_Shdr*>(shdr_region->start());
+
+ if (llvm::sys::isLittleEndianHost()) {
+ sh_size = shdr->sh_size;
+ sh_link = shdr->sh_link;
+ }
+ else {
+ sh_size = mcld::bswap64(shdr->sh_size);
+ sh_link = mcld::bswap32(shdr->sh_link);
+ }
+ pInput.memArea()->release(shdr_region);
+
+ if (shnum == llvm::ELF::SHN_UNDEF)
+ shnum = sh_size;
+ if (shstrtab == llvm::ELF::SHN_XINDEX)
+ shstrtab = sh_link;
+
+ shoff += shentsize;
+ }
+
+ shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff,
+ shnum * shentsize);
+ llvm::ELF::Elf64_Shdr * shdrTab =
+ reinterpret_cast<llvm::ELF::Elf64_Shdr*>(shdr_region->start());
+
+ // get .shstrtab first
+ shdr = &shdrTab[shstrtab];
+ if (llvm::sys::isLittleEndianHost()) {
+ sh_offset = shdr->sh_offset;
+ sh_size = shdr->sh_size;
+ }
+ else {
+ sh_offset = mcld::bswap64(shdr->sh_offset);
+ sh_size = mcld::bswap64(shdr->sh_size);
+ }
+
+ MemoryRegion* sect_name_region = pInput.memArea()->request(
+ pInput.fileOffset() + sh_offset, sh_size);
+ const char* sect_name =
+ reinterpret_cast<const char*>(sect_name_region->start());
+
+ LinkInfoList link_info_list;
+
+ // create all LDSections, including first NULL section.
+ for (size_t idx = 0; idx < shnum; ++idx) {
+ if (llvm::sys::isLittleEndianHost()) {
+ sh_name = shdrTab[idx].sh_name;
+ sh_type = shdrTab[idx].sh_type;
+ sh_flags = shdrTab[idx].sh_flags;
+ sh_offset = shdrTab[idx].sh_offset;
+ sh_size = shdrTab[idx].sh_size;
+ sh_link = shdrTab[idx].sh_link;
+ sh_info = shdrTab[idx].sh_info;
+ sh_addralign = shdrTab[idx].sh_addralign;
+ }
+ else {
+ sh_name = mcld::bswap32(shdrTab[idx].sh_name);
+ sh_type = mcld::bswap32(shdrTab[idx].sh_type);
+ sh_flags = mcld::bswap64(shdrTab[idx].sh_flags);
+ sh_offset = mcld::bswap64(shdrTab[idx].sh_offset);
+ sh_size = mcld::bswap64(shdrTab[idx].sh_size);
+ sh_link = mcld::bswap32(shdrTab[idx].sh_link);
+ sh_info = mcld::bswap32(shdrTab[idx].sh_info);
+ sh_addralign = mcld::bswap64(shdrTab[idx].sh_addralign);
+ }
+
+ LDSection* section = IRBuilder::CreateELFHeader(pInput,
+ sect_name+sh_name,
+ sh_type,
+ sh_flags,
+ sh_addralign);
+ section->setSize(sh_size);
+ section->setOffset(sh_offset);
+ section->setInfo(sh_info);
+
+ if (sh_link != 0x0 || sh_info != 0x0) {
+ LinkInfo link_info = { section, sh_link, sh_info };
+ link_info_list.push_back(link_info);
+ }
+ } // end of for
+
+ // set up InfoLink
+ LinkInfoList::iterator info, infoEnd = link_info_list.end();
+ for (info = link_info_list.begin(); info != infoEnd; ++info) {
+ if (LDFileFormat::NamePool == info->section->kind() ||
+ LDFileFormat::Group == info->section->kind() ||
+ LDFileFormat::Note == info->section->kind()) {
+ info->section->setLink(pInput.context()->getSection(info->sh_link));
+ continue;
+ }
+ if (LDFileFormat::Relocation == info->section->kind()) {
+ info->section->setLink(pInput.context()->getSection(info->sh_info));
+ continue;
+ }
+ }
+
+ pInput.memArea()->release(shdr_region);
+ pInput.memArea()->release(sect_name_region);
+
+ return true;
+}
+
+/// readSignature - read a symbol from the given Input and index in symtab
+/// This is used to get the signature of a group section.
+ResolveInfo* ELFReader<64, true>::readSignature(Input& pInput,
+ LDSection& pSymTab,
+ uint32_t pSymIdx) const
+{
+ LDSection* symtab = &pSymTab;
+ LDSection* strtab = symtab->getLink();
+ assert(NULL != symtab && NULL != strtab);
+
+ uint64_t offset = pInput.fileOffset() + symtab->offset() +
+ sizeof(llvm::ELF::Elf64_Sym) * pSymIdx;
+ MemoryRegion* symbol_region =
+ pInput.memArea()->request(offset, sizeof(llvm::ELF::Elf64_Sym));
+ llvm::ELF::Elf64_Sym* entry =
+ reinterpret_cast<llvm::ELF::Elf64_Sym*>(symbol_region->start());
+
+ uint32_t st_name = 0x0;
+ uint8_t st_info = 0x0;
+ uint8_t st_other = 0x0;
+ uint16_t st_shndx = 0x0;
+ st_info = entry->st_info;
+ st_other = entry->st_other;
+ if (llvm::sys::isLittleEndianHost()) {
+ st_name = entry->st_name;
+ st_shndx = entry->st_shndx;
+ }
+ else {
+ st_name = mcld::bswap32(entry->st_name);
+ st_shndx = mcld::bswap16(entry->st_shndx);
+ }
+
+ MemoryRegion* strtab_region = pInput.memArea()->request(
+ pInput.fileOffset() + strtab->offset(), strtab->size());
+
+ // get ld_name
+ llvm::StringRef ld_name(
+ reinterpret_cast<char*>(strtab_region->start() + st_name));
+
+ ResolveInfo* result = ResolveInfo::Create(ld_name);
+ result->setSource(pInput.type() == Input::DynObj);
+ result->setType(static_cast<ResolveInfo::Type>(st_info & 0xF));
+ result->setDesc(getSymDesc(st_shndx, pInput));
+ result->setBinding(getSymBinding((st_info >> 4), st_shndx, st_other));
+ result->setVisibility(getSymVisibility(st_other));
+
+ // release regions
+ pInput.memArea()->release(symbol_region);
+ pInput.memArea()->release(strtab_region);
+
+ return result;
+}
+
+/// readDynamic - read ELF .dynamic in input dynobj
+bool ELFReader<64, 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(
+ pInput.fileOffset() + dynamic_sect->offset(), dynamic_sect->size());
+
+ MemoryRegion* dynstr_region = pInput.memArea()->request(
+ pInput.fileOffset() + dynstr_sect->offset(), dynstr_sect->size());
+
+ assert(NULL != dynamic_region && NULL != dynstr_region);
+
+ const llvm::ELF::Elf64_Dyn* dynamic =
+ (llvm::ELF::Elf64_Dyn*) dynamic_region->start();
+ const char* dynstr = (const char*) dynstr_region->start();
+ bool hasSOName = false;
+ size_t numOfEntries = dynamic_sect->size() / sizeof(llvm::ELF::Elf64_Dyn);
+
+ for (size_t idx = 0; idx < numOfEntries; ++idx) {
+
+ llvm::ELF::Elf64_Sxword d_tag = 0x0;
+ llvm::ELF::Elf64_Xword d_val = 0x0;
+
+ if (llvm::sys::isLittleEndianHost()) {
+ d_tag = dynamic[idx].d_tag;
+ d_val = dynamic[idx].d_un.d_val;
+ } else {
+ d_tag = mcld::bswap64(dynamic[idx].d_tag);
+ d_val = mcld::bswap64(dynamic[idx].d_un.d_val);
+ }
+
+ switch (d_tag) {
+ case llvm::ELF::DT_SONAME:
+ assert(d_val < dynstr_sect->size());
+ pInput.setName(sys::fs::Path(dynstr + d_val).filename().native());
+ 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.setName(pInput.path().filename().native());
+
+ pInput.memArea()->release(dynamic_region);
+ pInput.memArea()->release(dynstr_region);
+ return true;
+}
+
diff --git a/lib/LD/ELFReaderIf.cpp b/lib/LD/ELFReaderIf.cpp
new file mode 100644
index 0000000..9625d85
--- /dev/null
+++ b/lib/LD/ELFReaderIf.cpp
@@ -0,0 +1,164 @@
+//===- ELFReader.cpp ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/ELFReaderIf.h>
+
+#include <mcld/IRBuilder.h>
+#include <mcld/Fragment/FillFragment.h>
+#include <mcld/LD/EhFrame.h>
+#include <mcld/LD/SectionData.h>
+#include <mcld/Target/GNULDBackend.h>
+//#include <mcld/Support/MemoryArea.h>
+//#include <mcld/Support/MemoryRegion.h>
+//#include <mcld/Support/MsgHandling.h>
+//#include <mcld/Object/ObjectBuilder.h>
+
+#include <cstring>
+
+#include <llvm/ADT/StringRef.h>
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/Host.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// ELFReaderIF
+//===----------------------------------------------------------------------===//
+/// getSymType
+ResolveInfo::Type ELFReaderIF::getSymType(uint8_t pInfo, uint16_t pShndx) const
+{
+ ResolveInfo::Type result = static_cast<ResolveInfo::Type>(pInfo & 0xF);
+ if (llvm::ELF::SHN_ABS == pShndx && ResolveInfo::Section == result) {
+ // In Mips, __gp_disp is a special section symbol. Its name comes from
+ // .strtab, not .shstrtab. However, it is unique. Only it is also a ABS
+ // symbol. So here is a tricky to identify __gp_disp and convert it to
+ // Object symbol.
+ return ResolveInfo::Object;
+ }
+
+ return result;
+}
+
+/// getSymDesc
+ResolveInfo::Desc ELFReaderIF::getSymDesc(uint16_t pShndx, const Input& pInput) const
+{
+ if (pShndx == llvm::ELF::SHN_UNDEF)
+ return ResolveInfo::Undefined;
+
+ if (pShndx < llvm::ELF::SHN_LORESERVE) {
+ // an ELF symbol defined in a section which we are not including
+ // must be treated as an Undefined.
+ // @ref Google gold linker: symtab.cc: 1086
+ if (NULL == pInput.context()->getSection(pShndx) ||
+ LDFileFormat::Ignore == pInput.context()->getSection(pShndx)->kind())
+ return ResolveInfo::Undefined;
+ return ResolveInfo::Define;
+ }
+
+ if (pShndx == llvm::ELF::SHN_ABS)
+ return ResolveInfo::Define;
+
+ if (pShndx == llvm::ELF::SHN_COMMON)
+ return ResolveInfo::Common;
+
+ if (pShndx >= llvm::ELF::SHN_LOPROC &&
+ pShndx <= llvm::ELF::SHN_HIPROC)
+ return target().getSymDesc(pShndx);
+
+ // FIXME: ELF weak alias should be ResolveInfo::Indirect
+ return ResolveInfo::NoneDesc;
+}
+
+/// getSymBinding
+ResolveInfo::Binding
+ELFReaderIF::getSymBinding(uint8_t pBinding, uint16_t pShndx, uint8_t pVis) const
+{
+
+ // TODO:
+ // if --just-symbols option is enabled, the symbol must covert to Absolute
+
+ switch(pBinding) {
+ case llvm::ELF::STB_LOCAL:
+ return ResolveInfo::Local;
+ case llvm::ELF::STB_GLOBAL:
+ return ResolveInfo::Global;
+ case llvm::ELF::STB_WEAK:
+ return ResolveInfo::Weak;
+ }
+
+ if (pShndx == llvm::ELF::SHN_ABS)
+ return ResolveInfo::Absolute;
+
+ return ResolveInfo::NoneBinding;
+}
+
+/// getSymFragmentRef
+FragmentRef*
+ELFReaderIF::getSymFragmentRef(Input& pInput,
+ uint16_t pShndx,
+ uint32_t pOffset) const
+{
+
+ if (Input::DynObj == pInput.type())
+ return FragmentRef::Null();
+
+ if (pShndx == llvm::ELF::SHN_UNDEF)
+ return FragmentRef::Null();
+
+ if (pShndx >= llvm::ELF::SHN_LORESERVE) // including ABS and COMMON
+ return FragmentRef::Null();
+
+ LDSection* sect_hdr = pInput.context()->getSection(pShndx);
+
+ if (NULL == sect_hdr)
+ unreachable(diag::unreachable_invalid_section_idx) << pShndx
+ << pInput.path().native();
+
+ if (LDFileFormat::Ignore == sect_hdr->kind())
+ return FragmentRef::Null();
+
+ if (LDFileFormat::Group == sect_hdr->kind())
+ return FragmentRef::Null();
+
+ return FragmentRef::Create(*sect_hdr, pOffset);
+}
+
+/// getSymVisibility
+ResolveInfo::Visibility
+ELFReaderIF::getSymVisibility(uint8_t pVis) const
+{
+ return static_cast<ResolveInfo::Visibility>(pVis);
+}
+
+/// getSymValue - get the section offset of the symbol.
+uint64_t ELFReaderIF::getSymValue(uint64_t pValue,
+ uint16_t pShndx,
+ const Input& pInput) const
+{
+ if (Input::Object == pInput.type()) {
+ // In relocatable files, st_value holds alignment constraints for a symbol
+ // whose section index is SHN_COMMON
+ if (pShndx == llvm::ELF::SHN_COMMON || pShndx == llvm::ELF::SHN_ABS) {
+ return pValue;
+ }
+
+ // In relocatable files, st_value holds a section offset for a defined symbol.
+ // TODO:
+ // if --just-symbols option are enabled, convert the value from section offset
+ // to virtual address by adding input section's virtual address.
+ // The section's virtual address in relocatable files is normally zero, but
+ // people can use link script to change it.
+ return pValue;
+ }
+
+ // In executable and shared object files, st_value holds a virtual address.
+ // the virtual address is useless during linking.
+ return 0x0;
+}
+
diff --git a/lib/LD/ELFWriter.cpp b/lib/LD/ELFWriter.cpp
deleted file mode 100644
index a37e654..0000000
--- a/lib/LD/ELFWriter.cpp
+++ /dev/null
@@ -1,600 +0,0 @@
-//===- ELFWriter.cpp ------------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include <cstdlib>
-#include <cstring>
-
-#include <llvm/Support/ELF.h>
-#include <llvm/Support/Casting.h>
-
-#include <mcld/LinkerConfig.h>
-#include <mcld/Module.h>
-#include <mcld/ADT/SizeTraits.h>
-#include <mcld/Fragment/FragmentLinker.h>
-#include <mcld/Fragment/AlignFragment.h>
-#include <mcld/Fragment/FillFragment.h>
-#include <mcld/Fragment/RegionFragment.h>
-#include <mcld/Fragment/Stub.h>
-#include <mcld/Fragment/NullFragment.h>
-#include <mcld/LD/ELFWriter.h>
-#include <mcld/LD/LDSymbol.h>
-#include <mcld/LD/LDSection.h>
-#include <mcld/LD/SectionData.h>
-#include <mcld/LD/ELFSegment.h>
-#include <mcld/LD/ELFSegmentFactory.h>
-#include <mcld/LD/RelocData.h>
-#include <mcld/LD/EhFrame.h>
-#include <mcld/Target/GNULDBackend.h>
-#include <mcld/Support/MemoryArea.h>
-#include <mcld/Support/MemoryRegion.h>
-
-using namespace llvm::ELF;
-using namespace mcld;
-
-/// writeELF32Header - write ELF header
-void ELFWriter::writeELF32Header(const LinkerConfig& pConfig,
- const Module& pModule,
- MemoryArea& pOutput) const
-{
- // ELF header must start from 0x0
- MemoryRegion *region = pOutput.request(0, sizeof(Elf32_Ehdr));
- Elf32_Ehdr* header = (Elf32_Ehdr*)region->start();
-
- memcpy(header->e_ident, ElfMagic, EI_MAG3+1);
-
- header->e_ident[EI_CLASS] = ELFCLASS32;
- header->e_ident[EI_DATA] = pConfig.targets().isLittleEndian()?
- ELFDATA2LSB : ELFDATA2MSB;
- header->e_ident[EI_VERSION] = target().getInfo().ELFVersion();
- header->e_ident[EI_OSABI] = target().getInfo().OSABI();
- header->e_ident[EI_ABIVERSION] = target().getInfo().ABIVersion();
-
- // FIXME: add processor-specific and core file types.
- switch(pConfig.codeGenType()) {
- case LinkerConfig::Object:
- header->e_type = ET_REL;
- break;
- case LinkerConfig::DynObj:
- header->e_type = ET_DYN;
- break;
- case LinkerConfig::Exec:
- header->e_type = ET_EXEC;
- break;
- default:
- llvm::errs() << "unspported output file type: " << pConfig.codeGenType() << ".\n";
- header->e_type = ET_NONE;
- }
- header->e_machine = target().getInfo().machine();
- header->e_version = header->e_ident[EI_VERSION];
- header->e_entry = getEntryPoint(pConfig, pModule);
-
- if (LinkerConfig::Object != pConfig.codeGenType())
- header->e_phoff = sizeof(Elf32_Ehdr);
- else
- header->e_phoff = 0x0;
-
- header->e_shoff = getELF32LastStartOffset(pModule);
- header->e_flags = target().flags();
- header->e_ehsize = sizeof(Elf32_Ehdr);
- header->e_phentsize = sizeof(Elf32_Phdr);
- header->e_phnum = target().numOfSegments();
- header->e_shentsize = sizeof(Elf32_Shdr);
- header->e_shnum = pModule.size();
- header->e_shstrndx = pModule.getSection(".shstrtab")->index();
-}
-
-/// writeELF64Header - write ELF header
-void ELFWriter::writeELF64Header(const LinkerConfig& pConfig,
- const Module& pModule,
- MemoryArea& pOutput) const
-{
- // ELF header must start from 0x0
- MemoryRegion *region = pOutput.request(0, sizeof(Elf64_Ehdr));
- Elf64_Ehdr* header = (Elf64_Ehdr*)region->start();
-
- memcpy(header->e_ident, ElfMagic, EI_MAG3+1);
-
- header->e_ident[EI_CLASS] = ELFCLASS64;
- header->e_ident[EI_DATA] = pConfig.targets().isLittleEndian()?
- ELFDATA2LSB : ELFDATA2MSB;
- header->e_ident[EI_VERSION] = target().getInfo().ELFVersion();
- header->e_ident[EI_OSABI] = target().getInfo().OSABI();
- header->e_ident[EI_ABIVERSION] = target().getInfo().ABIVersion();
-
- // FIXME: add processor-specific and core file types.
- switch(pConfig.codeGenType()) {
- case LinkerConfig::Object:
- header->e_type = ET_REL;
- break;
- case LinkerConfig::DynObj:
- header->e_type = ET_DYN;
- break;
- case LinkerConfig::Exec:
- header->e_type = ET_EXEC;
- break;
- default:
- llvm::errs() << "unspported output file type: " << pConfig.codeGenType() << ".\n";
- header->e_type = ET_NONE;
- }
- header->e_machine = target().getInfo().machine();
- header->e_version = header->e_ident[EI_VERSION];
- header->e_entry = getEntryPoint(pConfig, pModule);
-
- if (LinkerConfig::Object != pConfig.codeGenType())
- header->e_phoff = sizeof(Elf64_Ehdr);
- else
- header->e_phoff = 0x0;
-
- header->e_shoff = getELF64LastStartOffset(pModule);
- header->e_flags = target().flags();
- header->e_ehsize = sizeof(Elf64_Ehdr);
- header->e_phentsize = sizeof(Elf64_Phdr);
- header->e_phnum = target().numOfSegments();
- header->e_shentsize = sizeof(Elf64_Shdr);
- header->e_shnum = pModule.size();
- header->e_shstrndx = pModule.getSection(".shstrtab")->index();
-}
-
-/// getEntryPoint
-uint64_t ELFWriter::getEntryPoint(const LinkerConfig& pConfig,
- const Module& pModule) const
-{
-
- llvm::StringRef entry_name;
- if (pConfig.options().hasEntry())
- entry_name = pConfig.options().entry();
- else
- entry_name = target().entry();
-
- uint64_t result = 0x0;
-
- bool issue_warning = (pConfig.options().hasEntry() &&
- LinkerConfig::Object != pConfig.codeGenType() &&
- LinkerConfig::DynObj != pConfig.codeGenType());
-
- const LDSymbol* entry_symbol = pModule.getNamePool().findSymbol(entry_name);
-
- // found the symbol
- if (NULL != entry_symbol) {
- if (entry_symbol->desc() != ResolveInfo::Define && issue_warning) {
- llvm::errs() << "WARNING: entry symbol '"
- << entry_symbol->name()
- << "' exists but is not defined.\n";
- }
- result = entry_symbol->value();
- }
- // not in the symbol pool
- else {
- // We should parse entry as a number.
- // @ref GNU ld manual, Options -e. e.g., -e 0x1000.
- char* endptr;
- result = strtoull(entry_name.data(), &endptr, 0);
- if (*endptr != '\0') {
- if (issue_warning) {
- llvm::errs() << "cannot find entry symbol '"
- << entry_name.data()
- << "'.\n";
- }
- result = 0x0;
- }
- }
- return result;
-}
-
-/// emitELF32SectionHeader - emit Elf32_Shdr
-void
-ELFWriter::emitELF32SectionHeader(const Module& pModule,
- const LinkerConfig& pConfig,
- MemoryArea& pOutput) const
-{
- // emit section header
- unsigned int sectNum = pModule.size();
- unsigned int header_size = sizeof(Elf32_Shdr) * sectNum;
- MemoryRegion* region = pOutput.request(getELF32LastStartOffset(pModule), header_size);
- Elf32_Shdr* shdr = (Elf32_Shdr*)region->start();
-
- // Iterate the SectionTable in LDContext
- unsigned int sectIdx = 0;
- unsigned int shstridx = 0; // NULL section has empty name
- for (; sectIdx < sectNum; ++sectIdx) {
- const LDSection *ld_sect = pModule.getSectionTable().at(sectIdx);
- shdr[sectIdx].sh_name = shstridx;
- shdr[sectIdx].sh_type = ld_sect->type();
- shdr[sectIdx].sh_flags = ld_sect->flag();
- shdr[sectIdx].sh_addr = ld_sect->addr();
- shdr[sectIdx].sh_offset = ld_sect->offset();
- shdr[sectIdx].sh_size = ld_sect->size();
- shdr[sectIdx].sh_addralign = ld_sect->align();
- shdr[sectIdx].sh_entsize = getELF32SectEntrySize(*ld_sect);
- shdr[sectIdx].sh_link = getSectLink(*ld_sect, pConfig);
- shdr[sectIdx].sh_info = getSectInfo(*ld_sect);
-
- // adjust strshidx
- shstridx += ld_sect->name().size() + 1;
- }
-}
-
-/// emitELF64SectionHeader - emit Elf64_Shdr
-void
-ELFWriter::emitELF64SectionHeader(const Module& pModule,
- const LinkerConfig& pConfig,
- MemoryArea& pOutput) const
-{
- // emit section header
- unsigned int sectNum = pModule.size();
- unsigned int header_size = sizeof(Elf64_Shdr) * sectNum;
- MemoryRegion* region = pOutput.request(getELF64LastStartOffset(pModule),
- header_size);
- Elf64_Shdr* shdr = (Elf64_Shdr*)region->start();
-
- // Iterate the SectionTable in LDContext
- unsigned int sectIdx = 0;
- unsigned int shstridx = 0; // NULL section has empty name
- for (; sectIdx < sectNum; ++sectIdx) {
- const LDSection *ld_sect = pModule.getSectionTable().at(sectIdx);
- shdr[sectIdx].sh_name = shstridx;
- shdr[sectIdx].sh_type = ld_sect->type();
- shdr[sectIdx].sh_flags = ld_sect->flag();
- shdr[sectIdx].sh_addr = ld_sect->addr();
- shdr[sectIdx].sh_offset = ld_sect->offset();
- shdr[sectIdx].sh_size = ld_sect->size();
- shdr[sectIdx].sh_addralign = ld_sect->align();
- shdr[sectIdx].sh_entsize = getELF64SectEntrySize(*ld_sect);
- shdr[sectIdx].sh_link = getSectLink(*ld_sect, pConfig);
- shdr[sectIdx].sh_info = getSectInfo(*ld_sect);
-
- // adjust strshidx
- shstridx += ld_sect->name().size() + 1;
- }
-}
-
-
-/// emitELF32ProgramHeader - emit Elf32_Phdr
-void ELFWriter::emitELF32ProgramHeader(MemoryArea& pOutput) const
-{
- 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.request(start_offset,
- target().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 = target().elfSegmentTable().begin(),
- segEnd = target().elfSegmentTable().end();
- for (; seg != segEnd; ++seg, ++index) {
- phdr[index].p_type = (*seg).type();
- phdr[index].p_flags = (*seg).flag();
- phdr[index].p_offset = (*seg).offset();
- phdr[index].p_vaddr = (*seg).vaddr();
- phdr[index].p_paddr = (*seg).paddr();
- phdr[index].p_filesz = (*seg).filesz();
- phdr[index].p_memsz = (*seg).memsz();
- phdr[index].p_align = (*seg).align();
- }
-}
-
-/// emitELF64ProgramHeader - emit ElfR64Phdr
-void ELFWriter::emitELF64ProgramHeader(MemoryArea& pOutput) const
-{
- 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.request(start_offset,
- target().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 = target().elfSegmentTable().begin(),
- segEnd = target().elfSegmentTable().end();
- for (; seg != segEnd; ++seg, ++index) {
- phdr[index].p_type = (*seg).type();
- phdr[index].p_flags = (*seg).flag();
- phdr[index].p_offset = (*seg).offset();
- phdr[index].p_vaddr = (*seg).vaddr();
- phdr[index].p_paddr = (*seg).paddr();
- phdr[index].p_filesz = (*seg).filesz();
- phdr[index].p_memsz = (*seg).memsz();
- phdr[index].p_align = (*seg).align();
- }
-}
-
-/// emitELFShStrTab - emit section string table
-void
-ELFWriter::emitELFShStrTab(const LDSection& pShStrTab, const Module& pModule,
- MemoryArea& pOutput)
-{
- // write out data
- MemoryRegion* region = pOutput.request(pShStrTab.offset(), pShStrTab.size());
- unsigned char* data = region->start();
- size_t shstrsize = 0;
- Module::const_iterator section, sectEnd = pModule.end();
- for (section = pModule.begin(); section != sectEnd; ++section) {
- strcpy((char*)(data + shstrsize), (*section)->name().data());
- shstrsize += (*section)->name().size() + 1;
- }
-}
-
-/// emitSectionData
-void
-ELFWriter::emitSectionData(const LDSection& pSection,
- MemoryRegion& pRegion) const
-{
- const SectionData* sd = NULL;
- switch (pSection.kind()) {
- case LDFileFormat::Relocation:
- return;
- case LDFileFormat::EhFrame:
- sd = &pSection.getEhFrame()->getSectionData();
- break;
- default:
- sd = pSection.getSectionData();
- break;
- }
- emitSectionData(*sd, pRegion);
-}
-
-/// emitRelocation
-void ELFWriter::emitRelocation(const LinkerConfig& pConfig,
- const LDSection& pSection,
- MemoryRegion& pRegion) const
-{
- const RelocData* sect_data = pSection.getRelocData();
- assert(NULL != sect_data && "SectionData is NULL in emitRelocation!");
-
- if (pSection.type() == SHT_REL)
- emitRel(pConfig, *sect_data, pRegion);
- else if (pSection.type() == SHT_RELA)
- emitRela(pConfig, *sect_data, pRegion);
- else
- llvm::report_fatal_error("unsupported relocation section type!");
-}
-
-
-/// emitRel
-void ELFWriter::emitRel(const LinkerConfig& pConfig,
- const RelocData& pRelocData,
- MemoryRegion& pRegion) const
-{
- Elf32_Rel* rel = reinterpret_cast<Elf32_Rel*>(pRegion.start());
-
- Relocation* relocation = 0;
- FragmentRef* frag_ref = 0;
-
- for (RelocData::const_iterator it = pRelocData.begin(),
- ie = pRelocData.end(); it != ie; ++it, ++rel) {
-
- relocation = &(llvm::cast<Relocation>(*it));
- frag_ref = &(relocation->targetRef());
-
- if(LinkerConfig::DynObj == pConfig.codeGenType() ||
- LinkerConfig::Exec == pConfig.codeGenType()) {
- rel->r_offset = static_cast<Elf32_Addr>(
- frag_ref->frag()->getParent()->getSection().addr() +
- frag_ref->getOutputOffset());
- }
- else {
- rel->r_offset = static_cast<Elf32_Addr>(frag_ref->getOutputOffset());
- }
- Elf32_Word Index;
- if( relocation->symInfo() == NULL )
- Index = 0;
- else
- Index = static_cast<Elf32_Word>(
- f_Backend.getSymbolIdx(relocation->symInfo()->outSymbol()));
-
- rel->setSymbolAndType(Index, relocation->type());
- }
-}
-
-/// emitRela
-void ELFWriter::emitRela(const LinkerConfig& pConfig,
- const RelocData& pRelocData,
- MemoryRegion& pRegion) const
-{
- Elf32_Rela* rel = reinterpret_cast<Elf32_Rela*>(pRegion.start());
-
- Relocation* relocation = 0;
- FragmentRef* frag_ref = 0;
-
- for (RelocData::const_iterator it = pRelocData.begin(),
- ie = pRelocData.end(); it != ie; ++it, ++rel) {
-
- relocation = &(llvm::cast<Relocation>(*it));
- frag_ref = &(relocation->targetRef());
-
- if(LinkerConfig::DynObj == pConfig.codeGenType() ||
- LinkerConfig::Exec == pConfig.codeGenType()) {
- rel->r_offset = static_cast<Elf32_Addr>(
- frag_ref->frag()->getParent()->getSection().addr() +
- frag_ref->getOutputOffset());
- }
- else {
- rel->r_offset = static_cast<Elf32_Addr>(frag_ref->getOutputOffset());
- }
-
- Elf32_Word Index;
- if( relocation->symInfo() == NULL )
- Index = 0;
- else
- Index = static_cast<Elf32_Word>(
- f_Backend.getSymbolIdx(relocation->symInfo()->outSymbol()));
-
- rel->setSymbolAndType(Index, relocation->type());
- rel->r_addend = relocation->addend();
- }
-}
-
-/// getELF32SectEntrySize - compute Elf32_Shdr::sh_entsize
-uint64_t ELFWriter::getELF32SectEntrySize(const LDSection& pSection) const
-{
- if (llvm::ELF::SHT_DYNSYM == pSection.type() ||
- llvm::ELF::SHT_SYMTAB == pSection.type())
- return sizeof(llvm::ELF::Elf32_Sym);
- if (llvm::ELF::SHT_REL == pSection.type())
- return sizeof(llvm::ELF::Elf32_Rel);
- if (llvm::ELF::SHT_RELA == pSection.type())
- return sizeof(llvm::ELF::Elf32_Rela);
- if (llvm::ELF::SHT_HASH == pSection.type())
- return sizeof(llvm::ELF::Elf32_Word);
- if (llvm::ELF::SHT_DYNAMIC == pSection.type())
- return sizeof(llvm::ELF::Elf32_Dyn);
- return 0x0;
-}
-
-/// getELF64SectEntrySize - compute Elf64_Shdr::sh_entsize
-uint64_t ELFWriter::getELF64SectEntrySize(const LDSection& pSection) const
-{
- if (llvm::ELF::SHT_DYNSYM == pSection.type() ||
- llvm::ELF::SHT_SYMTAB == pSection.type())
- return sizeof(llvm::ELF::Elf64_Sym);
- if (llvm::ELF::SHT_REL == pSection.type())
- return sizeof(llvm::ELF::Elf64_Rel);
- if (llvm::ELF::SHT_RELA == pSection.type())
- return sizeof(llvm::ELF::Elf64_Rela);
- if (llvm::ELF::SHT_HASH == pSection.type())
- return sizeof(llvm::ELF::Elf64_Word);
- if (llvm::ELF::SHT_DYNAMIC == pSection.type())
- return sizeof(llvm::ELF::Elf64_Dyn);
- return 0x0;
-}
-
-/// getSectLink - compute ElfXX_Shdr::sh_link
-uint64_t ELFWriter::getSectLink(const LDSection& pSection,
- const LinkerConfig& pConfig) const
-{
- if (llvm::ELF::SHT_SYMTAB == pSection.type())
- return target().getOutputFormat()->getStrTab().index();
- if (llvm::ELF::SHT_DYNSYM == pSection.type())
- return target().getOutputFormat()->getDynStrTab().index();
- if (llvm::ELF::SHT_DYNAMIC == pSection.type())
- return target().getOutputFormat()->getDynStrTab().index();
- if (llvm::ELF::SHT_HASH == pSection.type())
- return target().getOutputFormat()->getDynSymTab().index();
- if (llvm::ELF::SHT_REL == pSection.type() ||
- llvm::ELF::SHT_RELA == pSection.type()) {
- if (LinkerConfig::Object == pConfig.codeGenType())
- return target().getOutputFormat()->getSymTab().index();
- else
- return target().getOutputFormat()->getDynSymTab().index();
- }
- // FIXME: currently we link ARM_EXIDX section to output text section here
- if (llvm::ELF::SHT_ARM_EXIDX == pSection.type())
- return target().getOutputFormat()->getText().index();
- return llvm::ELF::SHN_UNDEF;
-}
-
-/// getSectInfo - compute ElfXX_Shdr::sh_info
-uint64_t ELFWriter::getSectInfo(const LDSection& pSection) const
-{
- if (llvm::ELF::SHT_SYMTAB == pSection.type() ||
- llvm::ELF::SHT_DYNSYM == pSection.type())
- return pSection.getInfo();
-
- if (llvm::ELF::SHT_REL == pSection.type() ||
- llvm::ELF::SHT_RELA == pSection.type()) {
- const LDSection* info_link = pSection.getLink();
- if (NULL != info_link)
- return info_link->index();
- }
-
- return 0x0;
-}
-
-/// getELF32LastStartOffset
-uint64_t ELFWriter::getELF32LastStartOffset(const Module& pModule) const
-{
- const LDSection* lastSect = pModule.back();
- assert(lastSect != NULL);
- return Align<32>(lastSect->offset() + lastSect->size());
-}
-
-/// getELF64LastStartOffset
-uint64_t ELFWriter::getELF64LastStartOffset(const Module& pModule) const
-{
- const LDSection* lastSect = pModule.back();
- assert(lastSect != NULL);
- return Align<64>(lastSect->offset() + lastSect->size());
-}
-
-/// emitSectionData
-void
-ELFWriter::emitSectionData(const SectionData& pSD, MemoryRegion& pRegion) const
-{
- SectionData::const_iterator fragIter, fragEnd = pSD.end();
- size_t cur_offset = 0;
- for (fragIter = pSD.begin(); fragIter != fragEnd; ++fragIter) {
- size_t size = fragIter->size();
- switch(fragIter->getKind()) {
- case Fragment::Region: {
- const RegionFragment& region_frag = llvm::cast<RegionFragment>(*fragIter);
- const uint8_t* from = region_frag.getRegion().start();
- memcpy(pRegion.getBuffer(cur_offset), from, size);
- break;
- }
- case Fragment::Alignment: {
- // TODO: emit values with different sizes (> 1 byte), and emit nops
- AlignFragment& align_frag = llvm::cast<AlignFragment>(*fragIter);
- uint64_t count = size / align_frag.getValueSize();
- switch (align_frag.getValueSize()) {
- case 1u:
- std::memset(pRegion.getBuffer(cur_offset),
- align_frag.getValue(),
- count);
- break;
- default:
- llvm::report_fatal_error("unsupported value size for align fragment emission yet.\n");
- break;
- }
- break;
- }
- case Fragment::Fillment: {
- FillFragment& fill_frag = llvm::cast<FillFragment>(*fragIter);
- if (0 == size ||
- 0 == fill_frag.getValueSize() ||
- 0 == fill_frag.size()) {
- // ignore virtual fillment
- break;
- }
-
- uint64_t num_tiles = fill_frag.size() / fill_frag.getValueSize();
- for (uint64_t i = 0; i != num_tiles; ++i) {
- std::memset(pRegion.getBuffer(cur_offset),
- fill_frag.getValue(),
- fill_frag.getValueSize());
- }
- break;
- }
- case Fragment::Stub: {
- Stub& stub_frag = llvm::cast<Stub>(*fragIter);
- memcpy(pRegion.getBuffer(cur_offset), stub_frag.getContent(), size);
- break;
- }
- case Fragment::Null: {
- assert(0x0 == size);
- break;
- }
- case Fragment::Target:
- llvm::report_fatal_error("Target fragment should not be in a regular section.\n");
- break;
- default:
- llvm::report_fatal_error("invalid fragment should not be in a regular section.\n");
- break;
- }
- cur_offset += size;
- }
-}
-
diff --git a/lib/LD/EhFrame.cpp b/lib/LD/EhFrame.cpp
index df61c24..9d49630 100644
--- a/lib/LD/EhFrame.cpp
+++ b/lib/LD/EhFrame.cpp
@@ -9,11 +9,18 @@
#include <mcld/LD/EhFrame.h>
#include <mcld/LD/LDSection.h>
#include <mcld/LD/SectionData.h>
-#include <mcld/Support/MemoryRegion.h>
#include <mcld/Object/ObjectBuilder.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/GCFactory.h>
+
+#include <llvm/Support/ManagedStatic.h>
using namespace mcld;
+typedef GCFactory<EhFrame, MCLD_SECTIONS_PER_INPUT> EhFrameFactory;
+
+static llvm::ManagedStatic<EhFrameFactory> g_EhFrameFactory;
+
//===----------------------------------------------------------------------===//
// EhFrame::CIE
//===----------------------------------------------------------------------===//
@@ -35,8 +42,12 @@ EhFrame::FDE::FDE(MemoryRegion& pRegion,
//===----------------------------------------------------------------------===//
// EhFrame
//===----------------------------------------------------------------------===//
+EhFrame::EhFrame()
+ : m_pSection(NULL), m_pSectionData(NULL) {
+}
+
EhFrame::EhFrame(LDSection& pSection)
- : m_Section(pSection),
+ : m_pSection(&pSection),
m_pSectionData(NULL) {
m_pSectionData = SectionData::Create(pSection);
}
@@ -47,6 +58,37 @@ EhFrame::~EhFrame()
// will delete the fragments and we do not need to handle with it.
}
+EhFrame* EhFrame::Create(LDSection& pSection)
+{
+ EhFrame* result = g_EhFrameFactory->allocate();
+ new (result) EhFrame(pSection);
+ return result;
+}
+
+void EhFrame::Destroy(EhFrame*& pSection)
+{
+ pSection->~EhFrame();
+ g_EhFrameFactory->deallocate(pSection);
+ pSection = NULL;
+}
+
+void EhFrame::Clear()
+{
+ g_EhFrameFactory->clear();
+}
+
+const LDSection& EhFrame::getSection() const
+{
+ assert(NULL != m_pSection);
+ return *m_pSection;
+}
+
+LDSection& EhFrame::getSection()
+{
+ assert(NULL != m_pSection);
+ return *m_pSection;
+}
+
void EhFrame::addFragment(RegionFragment& pFrag)
{
uint32_t offset = 0;
diff --git a/lib/LD/EhFrameHdr.cpp b/lib/LD/EhFrameHdr.cpp
index 4c0d59c..a00d785 100644
--- a/lib/LD/EhFrameHdr.cpp
+++ b/lib/LD/EhFrameHdr.cpp
@@ -114,6 +114,12 @@ void EhFrameHdr::emitOutput<32>(MemoryArea& pOutput)
pOutput.release(ehframe_region);
}
+/// emitOutput<64> - write out eh_frame_hdr
+template<>
+void EhFrameHdr::emitOutput<64>(MemoryArea& pOutput)
+{
+}
+
//===----------------------------------------------------------------------===//
// EhFrameHdr
//===----------------------------------------------------------------------===//
diff --git a/lib/LD/ExecWriter.cpp b/lib/LD/ExecWriter.cpp
deleted file mode 100644
index d66cd17..0000000
--- a/lib/LD/ExecWriter.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-//===- 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/GNUArchiveReader.cpp b/lib/LD/GNUArchiveReader.cpp
index 82e4fec..6324824 100644
--- a/lib/LD/GNUArchiveReader.cpp
+++ b/lib/LD/GNUArchiveReader.cpp
@@ -89,6 +89,10 @@ bool GNUArchiveReader::isThinArchive(Input& pInput) const
bool GNUArchiveReader::readArchive(Archive& pArchive)
{
+ // bypass the empty archive
+ if (Archive::MAGIC_LEN == pArchive.getARFile().memArea()->handler()->size())
+ return true;
+
if (pArchive.getARFile().attribute()->isWholeArchive())
return includeAllMembers(pArchive);
diff --git a/lib/LD/LDSymbol.cpp b/lib/LD/LDSymbol.cpp
index c6fab43..9002235 100644
--- a/lib/LD/LDSymbol.cpp
+++ b/lib/LD/LDSymbol.cpp
@@ -19,10 +19,10 @@
using namespace mcld;
-static LDSymbol* g_NullSymbol = NULL;
-
typedef GCFactory<LDSymbol, MCLD_SYMBOLS_PER_INPUT> LDSymbolFactory;
+static llvm::ManagedStatic<LDSymbol> g_NullSymbol;
+static llvm::ManagedStatic<NullFragment> g_NullSymbolFragment;
static llvm::ManagedStatic<LDSymbolFactory> g_LDSymbolFactory;
//===----------------------------------------------------------------------===//
@@ -72,14 +72,13 @@ void LDSymbol::Clear()
LDSymbol* LDSymbol::Null()
{
- if (NULL == g_NullSymbol) {
- g_NullSymbol = new LDSymbol();
+ // lazy initialization
+ if (NULL == g_NullSymbol->resolveInfo()) {
g_NullSymbol->setResolveInfo(*ResolveInfo::Null());
- NullFragment* null_frag = new NullFragment();
- g_NullSymbol->setFragmentRef(FragmentRef::Create(*null_frag, 0));
- ResolveInfo::Null()->setSymPtr(g_NullSymbol);
+ g_NullSymbol->setFragmentRef(FragmentRef::Create(*g_NullSymbolFragment, 0));
+ ResolveInfo::Null()->setSymPtr(&*g_NullSymbol);
}
- return g_NullSymbol;
+ return &*g_NullSymbol;
}
void LDSymbol::setFragmentRef(FragmentRef* pFragmentRef)
diff --git a/lib/LD/LDWriter.cpp b/lib/LD/LDWriter.cpp
deleted file mode 100644
index e78f087..0000000
--- a/lib/LD/LDWriter.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-//===- LDWriter.cpp -------------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include "mcld/LD/LDWriter.h"
-
-using namespace mcld;
-
-//==========================
-// LDReader
-
diff --git a/lib/LD/NamePool.cpp b/lib/LD/NamePool.cpp
index 6af1f7d..7fb8688 100644
--- a/lib/LD/NamePool.cpp
+++ b/lib/LD/NamePool.cpp
@@ -22,6 +22,11 @@ NamePool::NamePool(NamePool::size_type pSize)
NamePool::~NamePool()
{
delete m_pResolver;
+
+ FreeInfoSet::iterator info, iEnd = m_FreeInfoSet.end();
+ for (info = m_FreeInfoSet.begin(); info != iEnd; ++info) {
+ ResolveInfo::Destroy(*info);
+ }
}
/// createSymbol - create a symbol
@@ -33,15 +38,16 @@ ResolveInfo* NamePool::createSymbol(const llvm::StringRef& pName,
ResolveInfo::SizeType pSize,
ResolveInfo::Visibility pVisibility)
{
- ResolveInfo* result = ResolveInfo::Create(pName);
- result->setIsSymbol(true);
- result->setSource(pIsDyn);
- result->setType(pType);
- result->setDesc(pDesc);
- result->setBinding(pBinding);
- result->setVisibility(pVisibility);
- result->setSize(pSize);
- return result;
+ ResolveInfo** result = m_FreeInfoSet.allocate();
+ (*result) = ResolveInfo::Create(pName);
+ (*result)->setIsSymbol(true);
+ (*result)->setSource(pIsDyn);
+ (*result)->setType(pType);
+ (*result)->setDesc(pDesc);
+ (*result)->setBinding(pBinding);
+ (*result)->setVisibility(pVisibility);
+ (*result)->setSize(pSize);
+ return *result;
}
/// insertSymbol - insert a symbol and resolve it immediately
@@ -65,7 +71,6 @@ void NamePool::insertSymbol(const llvm::StringRef& pName,
ResolveInfo* old_symbol = m_Table.insert(pName, exist);
ResolveInfo* new_symbol = NULL;
if (exist && old_symbol->isSymbol()) {
- exist = true;
new_symbol = m_Table.getEntryFactory().produce(pName);
}
else {
@@ -82,7 +87,7 @@ void NamePool::insertSymbol(const llvm::StringRef& pName,
new_symbol->setSize(pSize);
if (!exist) {
- // not exit or not a symbol
+ // old_symbol is neither existed nor a symbol.
pResult.info = new_symbol;
pResult.existent = false;
pResult.overriden = true;
@@ -102,8 +107,11 @@ void NamePool::insertSymbol(const llvm::StringRef& pName,
pResult.existent = true;
pResult.overriden = override;
}
- else
+ else {
m_pResolver->resolveAgain(*this, action, *old_symbol, *new_symbol, pResult);
+ }
+
+ m_Table.getEntryFactory().destroy(new_symbol);
return;
}
diff --git a/lib/LD/ObjectWriter.cpp b/lib/LD/ObjectWriter.cpp
index 15691f2..17d04eb 100644
--- a/lib/LD/ObjectWriter.cpp
+++ b/lib/LD/ObjectWriter.cpp
@@ -7,14 +7,12 @@
//
//===----------------------------------------------------------------------===//
#include <mcld/LD/ObjectWriter.h>
-#include <mcld/MC/MCLDInput.h>
-#include <mcld/Target/GNULDBackend.h>
using namespace mcld;
//==========================
// ObjectWriter
-ObjectWriter::ObjectWriter(GNULDBackend& pBackend)
+ObjectWriter::ObjectWriter()
{
}
diff --git a/lib/LD/RelocationFactory.cpp b/lib/LD/RelocationFactory.cpp
index 52bf45c..8a065a8 100644
--- a/lib/LD/RelocationFactory.cpp
+++ b/lib/LD/RelocationFactory.cpp
@@ -71,18 +71,16 @@ Relocation* RelocationFactory::produce(RelocationFactory::Type pType,
pFragRef.memcpy(&target_data, (m_pConfig->targets().bitclass()/8));
}
- Relocation *result = allocate();
+ Relocation* result = allocate();
new (result) Relocation(pType, &pFragRef, pAddend, target_data);
return result;
}
Relocation* RelocationFactory::produceEmptyEntry()
{
- // FIXME: To prevent relocations from double free by both iplist and
- // GCFactory, currently we new relocations directly and let iplist
- // delete them.
-
- return new Relocation(0, 0, 0, 0);
+ Relocation* result = allocate();
+ new (result) Relocation(0, 0, 0, 0);
+ return result;
}
void RelocationFactory::destroy(Relocation* pRelocation)
diff --git a/lib/LD/LDObjectWriter.cpp b/lib/LD/Relocator.cpp
index d08c6a7..d9dfb61 100644
--- a/lib/LD/LDObjectWriter.cpp
+++ b/lib/LD/Relocator.cpp
@@ -1,4 +1,4 @@
-//===- LDObjectWriter.cpp -------------------------------------------------===//
+//===- Relocator.cpp ------------------------------------------------------===//
//
// The MCLinker Project
//
@@ -6,18 +6,14 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/MC/MCObjectWriter.h"
+#include <mcld/LD/Relocator.h>
using namespace mcld;
-//==========================
-// MCObjectWriter
-
-
-MCObjectWriter::MCObjectWriter()
+//===----------------------------------------------------------------------===//
+// Relocator
+//===----------------------------------------------------------------------===//
+Relocator::~Relocator()
{
}
-MCObjectWriter::~MCObjectWriter()
-{
-}
diff --git a/lib/LD/ResolveInfo.cpp b/lib/LD/ResolveInfo.cpp
index 00df6ae..42ee83c 100644
--- a/lib/LD/ResolveInfo.cpp
+++ b/lib/LD/ResolveInfo.cpp
@@ -275,6 +275,7 @@ ResolveInfo* ResolveInfo::Null()
new (g_NullResolveInfo) ResolveInfo();
g_NullResolveInfo->m_Name[0] = '\0';
g_NullResolveInfo->m_BitField = 0x0;
+ g_NullResolveInfo->setBinding(Local);
}
return g_NullResolveInfo;
}
diff --git a/lib/LD/StubFactory.cpp b/lib/LD/StubFactory.cpp
index cbe14b2..0124ec0 100644
--- a/lib/LD/StubFactory.cpp
+++ b/lib/LD/StubFactory.cpp
@@ -7,13 +7,13 @@
//
//===----------------------------------------------------------------------===//
#include <mcld/LD/StubFactory.h>
+#include <mcld/IRBuilder.h>
#include <mcld/LD/BranchIslandFactory.h>
#include <mcld/LD/BranchIsland.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/Fragment/Stub.h>
#include <mcld/Fragment/Relocation.h>
-#include <mcld/Fragment/FragmentLinker.h>
#include <mcld/Fragment/FragmentRef.h>
#include <string>
@@ -39,7 +39,7 @@ void StubFactory::addPrototype(Stub* pPrototype)
/// create - create a stub if needed, otherwise return NULL
Stub* StubFactory::create(Relocation& pReloc,
uint64_t pTargetSymValue,
- FragmentLinker& pLinker,
+ IRBuilder& pBuilder,
BranchIslandFactory& pBRIslandFactory)
{
// find if there is a prototype stub for the input relocation
@@ -74,9 +74,8 @@ Stub* StubFactory::create(Relocation& pReloc,
// create LDSymbol for the stub
LDSymbol* symbol =
- pLinker.defineSymbol<FragmentLinker::Force,
- FragmentLinker::Resolve>(name,
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
+ name,
ResolveInfo::Function,
ResolveInfo::Define,
ResolveInfo::Local,
diff --git a/lib/MC/MCLDInput.cpp b/lib/MC/MCLDInput.cpp
index 1fc6cb5..a10466b 100644
--- a/lib/MC/MCLDInput.cpp
+++ b/lib/MC/MCLDInput.cpp
@@ -9,6 +9,7 @@
#include <mcld/MC/MCLDInput.h>
#include <mcld/MC/Attribute.h>
#include <mcld/LD/LDContext.h>
+#include <mcld/Support/MemoryArea.h>
using namespace mcld;
@@ -70,5 +71,7 @@ Input::~Input()
{
// Attribute is deleted by AttributeFactory
// MemoryArea is deleted by MemoryAreaFactory
+ if (NULL != m_pMemArea)
+ m_pMemArea->clear();
}
diff --git a/lib/MC/SearchDirs.cpp b/lib/MC/SearchDirs.cpp
index 12d08e2..940553e 100644
--- a/lib/MC/SearchDirs.cpp
+++ b/lib/MC/SearchDirs.cpp
@@ -56,7 +56,16 @@ bool SearchDirs::insert(const std::string& pPath)
m_DirList.push_back(dir);
return true;
}
- return false;
+ else {
+ delete dir;
+ return false;
+ }
+ return true;
+}
+
+bool SearchDirs::insert(const char* pPath)
+{
+ return insert(std::string(pPath));
}
bool SearchDirs::insert(const sys::fs::Path& pPath)
diff --git a/lib/MC/SymbolCategory.cpp b/lib/MC/SymbolCategory.cpp
index f01083f..3c3881a 100644
--- a/lib/MC/SymbolCategory.cpp
+++ b/lib/MC/SymbolCategory.cpp
@@ -10,6 +10,7 @@
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/ResolveInfo.h>
#include <algorithm>
+#include <cassert>
using namespace mcld;
@@ -24,33 +25,34 @@ SymbolCategory::Category::categorize(const ResolveInfo& pInfo)
return Category::Local;
if (ResolveInfo::Common == pInfo.desc())
return Category::Common;
- if (ResolveInfo::Weak == pInfo.binding())
- return Category::Weak;
- return Category::Global;
+ if (ResolveInfo::Default == pInfo.visibility() ||
+ ResolveInfo::Protected == pInfo.visibility())
+ return Category::Dynamic;
+ return Category::Regular;
}
//===----------------------------------------------------------------------===//
// SymbolCategory
SymbolCategory::SymbolCategory()
{
- m_pFile = new Category(Category::File);
- m_pLocal = new Category(Category::Local);
- m_pTLS = new Category(Category::TLS);
- m_pCommon = new Category(Category::Common);
- m_pWeak = new Category(Category::Weak);
- m_pGlobal = new Category(Category::Global);
+ m_pFile = new Category(Category::File);
+ m_pLocal = new Category(Category::Local);
+ m_pLocalDyn = new Category(Category::LocalDyn);
+ m_pCommon = new Category(Category::Common);
+ m_pDynamic = new Category(Category::Dynamic);
+ m_pRegular = new Category(Category::Regular);
- m_pFile->next = m_pLocal;
- m_pLocal->next = m_pTLS;
- m_pTLS->next = m_pCommon;
- m_pCommon->next = m_pWeak;
- m_pWeak->next = m_pGlobal;
+ m_pFile->next = m_pLocal;
+ m_pLocal->next = m_pLocalDyn;
+ m_pLocalDyn->next = m_pCommon;
+ m_pCommon->next = m_pDynamic;
+ m_pDynamic->next = m_pRegular;
- m_pGlobal->prev = m_pWeak;
- m_pWeak->prev = m_pCommon;
- m_pCommon->prev = m_pTLS;
- m_pTLS->prev = m_pLocal;
- m_pLocal->prev = m_pFile;
+ m_pRegular->prev = m_pDynamic;
+ m_pDynamic->prev = m_pCommon;
+ m_pCommon->prev = m_pLocalDyn;
+ m_pLocalDyn->prev = m_pLocal;
+ m_pLocal->prev = m_pFile;
}
SymbolCategory::~SymbolCategory()
@@ -63,18 +65,14 @@ SymbolCategory::~SymbolCategory()
}
}
-SymbolCategory& SymbolCategory::add(LDSymbol& pSymbol)
+SymbolCategory& SymbolCategory::add(LDSymbol& pSymbol, Category::Type pTarget)
{
+ Category* current = m_pRegular;
m_OutputSymbols.push_back(&pSymbol);
- assert(NULL != pSymbol.resolveInfo());
- Category::Type target = Category::categorize(*pSymbol.resolveInfo());
-
- Category* current = m_pGlobal;
-
// use non-stable bubble sort to arrange the order of symbols.
while (NULL != current) {
- if (current->type == target) {
+ if (current->type == pTarget) {
current->end++;
break;
}
@@ -91,23 +89,19 @@ SymbolCategory& SymbolCategory::add(LDSymbol& pSymbol)
return *this;
}
-SymbolCategory& SymbolCategory::forceLocal(LDSymbol& pSymbol)
+SymbolCategory& SymbolCategory::add(LDSymbol& pSymbol)
{
- m_OutputSymbols.insert(localEnd(), &pSymbol);
- m_pLocal->end++;
- m_pTLS->begin++;
- m_pTLS->end++;
- m_pCommon->begin++;
- m_pCommon->end++;
- m_pWeak->begin++;
- m_pWeak->end++;
- m_pGlobal->begin++;
- m_pGlobal->end++;
+ assert(NULL != pSymbol.resolveInfo());
+ return add(pSymbol, Category::categorize(*pSymbol.resolveInfo()));
+}
- return *this;
+SymbolCategory& SymbolCategory::forceLocal(LDSymbol& pSymbol)
+{
+ return add(pSymbol, Category::Local);
}
-SymbolCategory& SymbolCategory::arrange(LDSymbol& pSymbol, const ResolveInfo& pSourceInfo)
+SymbolCategory& SymbolCategory::arrange(LDSymbol& pSymbol,
+ const ResolveInfo& pSourceInfo)
{
assert(NULL != pSymbol.resolveInfo());
Category::Type source = Category::categorize(pSourceInfo);
@@ -188,27 +182,30 @@ SymbolCategory& SymbolCategory::arrange(LDSymbol& pSymbol, const ResolveInfo& pS
SymbolCategory& SymbolCategory::changeCommonsToGlobal()
{
- if (emptyCommons())
- return *this;
-
- size_t com_rear = m_pCommon->end - 1;
- size_t com_front = m_pCommon->begin;
- size_t weak_rear = m_pWeak->end - 1;
- size_t weak_size = m_pWeak->end - m_pWeak->begin;
- for (size_t sym = com_rear; sym >= com_front; --sym) {
- std::swap(m_OutputSymbols[weak_rear], m_OutputSymbols[sym]);
- --weak_rear;
+ // Change Common to Dynamic/Regular
+ while (!emptyCommons()) {
+ size_t pos = m_pCommon->end - 1;
+ switch (Category::categorize(*(m_OutputSymbols[pos]->resolveInfo()))) {
+ case Category::Dynamic:
+ m_pCommon->end--;
+ m_pDynamic->begin--;
+ break;
+ case Category::Regular:
+ std::swap(m_OutputSymbols[pos], m_OutputSymbols[m_pDynamic->end - 1]);
+ m_pCommon->end--;
+ m_pDynamic->begin--;
+ m_pDynamic->end--;
+ m_pRegular->begin--;
+ break;
+ default:
+ assert(0);
+ break;
+ }
}
-
- m_pWeak->begin = m_pCommon->begin;
- m_pWeak->end = m_pCommon->begin + weak_size;
- m_pGlobal->begin = m_pWeak->end;
- m_pCommon->begin = m_pCommon->end = m_pWeak->begin;
-
return *this;
}
-SymbolCategory& SymbolCategory::changeLocalToTLS(const LDSymbol& pSymbol)
+SymbolCategory& SymbolCategory::changeLocalToDynamic(const LDSymbol& pSymbol)
{
// find the position of pSymbol from local category
size_t pos = m_pLocal->begin;
@@ -222,10 +219,10 @@ SymbolCategory& SymbolCategory::changeLocalToTLS(const LDSymbol& pSymbol)
if (m_pLocal->end == pos)
return *this;
- // bubble sort downward to TLS
+ // bubble sort downward to LocalDyn
std::swap(m_OutputSymbols[pos], m_OutputSymbols[m_pLocal->end - 1]);
m_pLocal->end--;
- m_pTLS->begin--;
+ m_pLocalDyn->begin--;
return *this;
}
@@ -234,9 +231,19 @@ size_t SymbolCategory::numOfSymbols() const
return m_OutputSymbols.size();
}
+size_t SymbolCategory::numOfFiles() const
+{
+ return m_pFile->size();
+}
+
size_t SymbolCategory::numOfLocals() const
{
- return (m_pFile->size() + m_pLocal->size() + m_pTLS->size());
+ return m_pLocal->size();
+}
+
+size_t SymbolCategory::numOfLocalDyns() const
+{
+ return m_pLocalDyn->size();
}
size_t SymbolCategory::numOfCommons() const
@@ -244,21 +251,34 @@ size_t SymbolCategory::numOfCommons() const
return m_pCommon->size();
}
+size_t SymbolCategory::numOfDynamics() const
+{
+ return m_pDynamic->size();
+}
+
size_t SymbolCategory::numOfRegulars() const
{
- return (m_pWeak->size() + m_pGlobal->size());
+ return m_pRegular->size();
}
bool SymbolCategory::empty() const
{
- return (emptyLocals() &&
- emptyCommons() &&
- emptyRegulars());
+ return m_OutputSymbols.empty();
+}
+
+bool SymbolCategory::emptyFiles() const
+{
+ return m_pFile->empty();
}
bool SymbolCategory::emptyLocals() const
{
- return (m_pFile->empty() && m_pLocal->empty() && m_pTLS->empty());
+ return m_pLocal->empty();
+}
+
+bool SymbolCategory::emptyLocalDyns() const
+{
+ return m_pLocalDyn->empty();
}
bool SymbolCategory::emptyCommons() const
@@ -266,9 +286,14 @@ bool SymbolCategory::emptyCommons() const
return m_pCommon->empty();
}
+bool SymbolCategory::emptyDynamics() const
+{
+ return m_pDynamic->empty();
+}
+
bool SymbolCategory::emptyRegulars() const
{
- return (m_pWeak->empty() && m_pGlobal->empty());
+ return m_pRegular->empty();
}
SymbolCategory::iterator SymbolCategory::begin()
@@ -291,80 +316,126 @@ SymbolCategory::const_iterator SymbolCategory::end() const
return m_OutputSymbols.end();
}
-SymbolCategory::iterator SymbolCategory::localBegin()
+SymbolCategory::iterator SymbolCategory::fileBegin()
{
return m_OutputSymbols.begin();
}
-SymbolCategory::iterator SymbolCategory::localEnd()
+SymbolCategory::iterator SymbolCategory::fileEnd()
{
- iterator iter = m_OutputSymbols.begin();
+ iterator iter = fileBegin();
iter += m_pFile->size();
+ return iter;
+}
+
+SymbolCategory::const_iterator SymbolCategory::fileBegin() const
+{
+ return m_OutputSymbols.begin();
+}
+
+SymbolCategory::const_iterator SymbolCategory::fileEnd() const
+{
+ const_iterator iter = fileBegin();
+ iter += m_pFile->size();
+ return iter;
+}
+
+SymbolCategory::iterator SymbolCategory::localBegin()
+{
+ return fileEnd();
+}
+
+SymbolCategory::iterator SymbolCategory::localEnd()
+{
+ iterator iter = localBegin();
iter += m_pLocal->size();
return iter;
}
SymbolCategory::const_iterator SymbolCategory::localBegin() const
{
- return m_OutputSymbols.begin();
+ return fileEnd();
}
SymbolCategory::const_iterator SymbolCategory::localEnd() const
{
- const_iterator iter = m_OutputSymbols.begin();
- iter += m_pFile->size();
+ const_iterator iter = localBegin();
iter += m_pLocal->size();
return iter;
}
-SymbolCategory::iterator SymbolCategory::tlsBegin()
+SymbolCategory::iterator SymbolCategory::localDynBegin()
{
return localEnd();
}
-SymbolCategory::iterator SymbolCategory::tlsEnd()
+SymbolCategory::iterator SymbolCategory::localDynEnd()
{
- iterator iter = localEnd();
- iter += m_pTLS->size();
+ iterator iter = localDynBegin();
+ iter += m_pLocalDyn->size();
return iter;
}
-SymbolCategory::const_iterator SymbolCategory::tlsBegin() const
+SymbolCategory::const_iterator SymbolCategory::localDynBegin() const
{
return localEnd();
}
-SymbolCategory::const_iterator SymbolCategory::tlsEnd() const
+SymbolCategory::const_iterator SymbolCategory::localDynEnd() const
{
- const_iterator iter = localEnd();
- iter += m_pTLS->size();
+ const_iterator iter = localDynBegin();
+ iter += m_pLocalDyn->size();
return iter;
}
SymbolCategory::iterator SymbolCategory::commonBegin()
{
- return tlsEnd();
+ return localDynEnd();
}
SymbolCategory::iterator SymbolCategory::commonEnd()
{
- iterator iter = tlsEnd();
+ iterator iter = commonBegin();
iter += m_pCommon->size();
return iter;
}
SymbolCategory::const_iterator SymbolCategory::commonBegin() const
{
- return tlsEnd();
+ return localDynEnd();
}
SymbolCategory::const_iterator SymbolCategory::commonEnd() const
{
- const_iterator iter = tlsEnd();
+ const_iterator iter = commonBegin();
iter += m_pCommon->size();
return iter;
}
+SymbolCategory::iterator SymbolCategory::dynamicBegin()
+{
+ return commonEnd();
+}
+
+SymbolCategory::iterator SymbolCategory::dynamicEnd()
+{
+ iterator iter = dynamicBegin();
+ iter += m_pDynamic->size();
+ return iter;
+}
+
+SymbolCategory::const_iterator SymbolCategory::dynamicBegin() const
+{
+ return commonEnd();
+}
+
+SymbolCategory::const_iterator SymbolCategory::dynamicEnd() const
+{
+ const_iterator iter = dynamicBegin();
+ iter += m_pDynamic->size();
+ return iter;
+}
+
SymbolCategory::iterator SymbolCategory::regularBegin()
{
return commonEnd();
diff --git a/lib/Object/ObjectBuilder.cpp b/lib/Object/ObjectBuilder.cpp
index ec09901..d222110 100644
--- a/lib/Object/ObjectBuilder.cpp
+++ b/lib/Object/ObjectBuilder.cpp
@@ -49,7 +49,7 @@ LDSection* ObjectBuilder::CreateSection(const std::string& pName,
}
/// MergeSection - merge the pInput section to the pOutput section
-bool ObjectBuilder::MergeSection(LDSection& pInputSection)
+LDSection* ObjectBuilder::MergeSection(LDSection& pInputSection)
{
const SectionMap::NamePair& pair =
m_Config.scripts().sectionMap().find(pInputSection.name());
@@ -70,7 +70,7 @@ bool ObjectBuilder::MergeSection(LDSection& pInputSection)
case LDFileFormat::Relocation:
case LDFileFormat::NamePool:
/** do nothing **/
- return true;
+ return target;
case LDFileFormat::EhFrame: {
EhFrame* eh_frame = NULL;
if (target->hasEhFrame())
@@ -79,7 +79,8 @@ bool ObjectBuilder::MergeSection(LDSection& pInputSection)
eh_frame = IRBuilder::CreateEhFrame(*target);
eh_frame->merge(*pInputSection.getEhFrame());
- return true;
+ UpdateSectionAlign(*target, pInputSection);
+ return target;
}
default: {
SectionData* data = NULL;
@@ -88,10 +89,14 @@ bool ObjectBuilder::MergeSection(LDSection& pInputSection)
else
data = IRBuilder::CreateSectionData(*target);
- return MoveSectionData(*pInputSection.getSectionData(), *data);
+ if (MoveSectionData(*pInputSection.getSectionData(), *data)) {
+ UpdateSectionAlign(*target, pInputSection);
+ return target;
+ }
+ return NULL;
}
}
- return true;
+ return target;
}
/// MoveSectionData - move the fragments of pTO section data to pTo
@@ -125,20 +130,19 @@ bool ObjectBuilder::MoveSectionData(SectionData& pFrom, SectionData& pTo)
}
to_list.splice(to_list.end(), from_list);
- // append the null fragment
- NullFragment* null = new NullFragment();
- null->setParent(&pTo);
- null->setOffset(offset);
- pTo.getFragmentList().push_back(null);
-
// set up pTo's header
pTo.getSection().setSize(offset);
- if (pFrom.getSection().align() > pTo.getSection().align())
- pTo.getSection().setAlign(pFrom.getSection().align());
return true;
}
+/// UpdateSectionFlags - update alignment for input section
+void ObjectBuilder::UpdateSectionAlign(LDSection& pTo, const LDSection& pFrom)
+{
+ if (pFrom.align() > pTo.align())
+ pTo.setAlign(pFrom.align());
+}
+
/// AppendFragment - To append pFrag to the given SectionData pSD.
uint64_t ObjectBuilder::AppendFragment(Fragment& pFrag,
SectionData& pSD,
diff --git a/lib/Object/ObjectLinker.cpp b/lib/Object/ObjectLinker.cpp
index 1e2ccb4..bbca437 100644
--- a/lib/Object/ObjectLinker.cpp
+++ b/lib/Object/ObjectLinker.cpp
@@ -21,9 +21,6 @@
#include <mcld/LD/GroupReader.h>
#include <mcld/LD/BinaryReader.h>
#include <mcld/LD/ObjectWriter.h>
-#include <mcld/LD/DynObjWriter.h>
-#include <mcld/LD/ExecWriter.h>
-#include <mcld/LD/BinaryWriter.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/LD/RelocData.h>
#include <mcld/Support/RealPath.h>
@@ -35,32 +32,23 @@
#include <llvm/Support/Casting.h>
+
using namespace llvm;
using namespace mcld;
ObjectLinker::ObjectLinker(const LinkerConfig& pConfig,
- Module& pModule,
- IRBuilder& pBuilder,
TargetLDBackend& pLDBackend)
: m_Config(pConfig),
- m_Module(pModule),
- m_Builder(pBuilder),
m_pLinker(NULL),
+ m_pModule(NULL),
+ m_pBuilder(NULL),
m_LDBackend(pLDBackend),
m_pObjectReader(NULL),
m_pDynObjReader(NULL),
m_pArchiveReader(NULL),
m_pGroupReader(NULL),
m_pBinaryReader(NULL),
- m_pObjectWriter(NULL),
- m_pDynObjWriter(NULL),
- m_pExecWriter(NULL),
- m_pBinaryWriter(NULL)
-{
- // set up soname
- if (!m_Config.options().soname().empty()) {
- m_Module.setName(m_Config.options().soname());
- }
+ m_pWriter(NULL) {
}
ObjectLinker::~ObjectLinker()
@@ -71,10 +59,17 @@ ObjectLinker::~ObjectLinker()
delete m_pArchiveReader;
delete m_pGroupReader;
delete m_pBinaryReader;
- delete m_pObjectWriter;
- delete m_pDynObjWriter;
- delete m_pExecWriter;
- delete m_pBinaryWriter;
+ delete m_pWriter;
+}
+
+void ObjectLinker::setup(Module& pModule, IRBuilder& pBuilder)
+{
+ m_pModule = &pModule;
+ m_pBuilder = &pBuilder;
+ // set up soname
+ if (!m_Config.options().soname().empty()) {
+ m_pModule->setName(m_Config.options().soname());
+ }
}
/// initFragmentLinker - initialize FragmentLinker
@@ -83,49 +78,37 @@ bool ObjectLinker::initFragmentLinker()
{
if (NULL == m_pLinker) {
m_pLinker = new FragmentLinker(m_Config,
- m_Module,
+ *m_pModule,
m_LDBackend);
}
// initialize the readers and writers
// Because constructor can not be failed, we initalize all readers and
// writers outside the FragmentLinker constructors.
- m_pObjectReader = m_LDBackend.createObjectReader(m_Builder);
- m_pArchiveReader = m_LDBackend.createArchiveReader(m_Module);
- m_pDynObjReader = m_LDBackend.createDynObjReader(m_Builder);
- m_pGroupReader = new GroupReader(m_Module, *m_pObjectReader,
+ m_pObjectReader = m_LDBackend.createObjectReader(*m_pBuilder);
+ m_pArchiveReader = m_LDBackend.createArchiveReader(*m_pModule);
+ m_pDynObjReader = m_LDBackend.createDynObjReader(*m_pBuilder);
+ m_pGroupReader = new GroupReader(*m_pModule, *m_pObjectReader,
*m_pDynObjReader, *m_pArchiveReader);
- m_pBinaryReader = m_LDBackend.createBinaryReader(m_Builder);
- m_pObjectWriter = m_LDBackend.createObjectWriter();
- m_pDynObjWriter = m_LDBackend.createDynObjWriter();
- m_pExecWriter = m_LDBackend.createExecWriter();
- m_pBinaryWriter = m_LDBackend.createBinaryWriter();
+ m_pBinaryReader = m_LDBackend.createBinaryReader(*m_pBuilder);
+ m_pWriter = m_LDBackend.createWriter();
// initialize Relocator
- m_LDBackend.initRelocator(*m_pLinker);
-
- // initialize BranchIslandFactory
- m_LDBackend.initBRIslandFactory();
-
- // initialize StubFactory
- m_LDBackend.initStubFactory();
-
- // initialize target stubs
- m_LDBackend.initTargetStubs(*m_pLinker);
+ m_LDBackend.initRelocator();
return true;
}
/// initStdSections - initialize standard sections
bool ObjectLinker::initStdSections()
{
- ObjectBuilder builder(m_Config, m_Module);
+ ObjectBuilder builder(m_Config, *m_pModule);
// initialize standard sections
if (!m_LDBackend.initStdSections(builder))
return false;
// initialize target-dependent sections
- m_LDBackend.initTargetSections(m_Module, builder);
+ m_LDBackend.initTargetSections(*m_pModule, builder);
return true;
}
@@ -133,11 +116,11 @@ bool ObjectLinker::initStdSections()
void ObjectLinker::normalize()
{
// ----- set up inputs ----- //
- Module::input_iterator input, inEnd = m_Module.input_end();
- for (input = m_Module.input_begin(); input!=inEnd; ++input) {
+ Module::input_iterator input, inEnd = m_pModule->input_end();
+ for (input = m_pModule->input_begin(); input!=inEnd; ++input) {
// is a group node
if (isGroup(input)) {
- getGroupReader()->readGroup(input, m_Builder.getInputBuilder(), m_Config);
+ getGroupReader()->readGroup(input, m_pBuilder->getInputBuilder(), m_Config);
continue;
}
@@ -149,12 +132,12 @@ void ObjectLinker::normalize()
continue;
if (Input::Object == (*input)->type()) {
- m_Module.getObjectList().push_back(*input);
+ m_pModule->getObjectList().push_back(*input);
continue;
}
if (Input::DynObj == (*input)->type()) {
- m_Module.getLibraryList().push_back(*input);
+ m_pModule->getLibraryList().push_back(*input);
continue;
}
@@ -162,7 +145,7 @@ void ObjectLinker::normalize()
if (m_Config.options().isBinaryInput()) {
(*input)->setType(Input::Object);
getBinaryReader()->readBinary(**input);
- m_Module.getObjectList().push_back(*input);
+ m_pModule->getObjectList().push_back(*input);
}
// is a relocatable object file
else if (getObjectReader()->isMyFormat(**input)) {
@@ -170,22 +153,22 @@ void ObjectLinker::normalize()
getObjectReader()->readHeader(**input);
getObjectReader()->readSections(**input);
getObjectReader()->readSymbols(**input);
- m_Module.getObjectList().push_back(*input);
+ m_pModule->getObjectList().push_back(*input);
}
// is a shared object file
else if (getDynObjReader()->isMyFormat(**input)) {
(*input)->setType(Input::DynObj);
getDynObjReader()->readHeader(**input);
getDynObjReader()->readSymbols(**input);
- m_Module.getLibraryList().push_back(*input);
+ m_pModule->getLibraryList().push_back(*input);
}
// is an archive
else if (getArchiveReader()->isMyFormat(**input)) {
(*input)->setType(Input::Archive);
- Archive archive(**input, m_Builder.getInputBuilder());
+ Archive archive(**input, m_pBuilder->getInputBuilder());
getArchiveReader()->readArchive(archive);
if(archive.numOfObjectMember() > 0) {
- m_Module.getInputTree().merge<InputTree::Inclusive>(input,
+ m_pModule->getInputTree().merge<InputTree::Inclusive>(input,
archive.inputs());
}
}
@@ -199,14 +182,14 @@ void ObjectLinker::normalize()
bool ObjectLinker::linkable() const
{
// check we have input and output files
- if (m_Module.getInputTree().empty()) {
+ if (m_pModule->getInputTree().empty()) {
error(diag::err_no_inputs);
return false;
}
// can not mix -static with shared objects
- Module::const_lib_iterator lib, libEnd = m_Module.lib_end();
- for (lib = m_Module.lib_begin(); lib != libEnd; ++lib) {
+ Module::const_lib_iterator lib, libEnd = m_pModule->lib_end();
+ for (lib = m_pModule->lib_begin(); lib != libEnd; ++lib) {
if((*lib)->attribute()->isStatic()) {
error(diag::err_mixed_shared_static_objects)
<< (*lib)->name() << (*lib)->path();
@@ -214,7 +197,21 @@ bool ObjectLinker::linkable() const
}
}
- // can not mix -r with shared objects
+ // --nmagic and --omagic options lead to static executable program.
+ // These options turn off page alignment of sections. Because the
+ // sections are not aligned to pages, these sections can not contain any
+ // exported functions. Also, because the two options disable linking
+ // against shared libraries, the output absolutely does not call outside
+ // functions.
+ if (m_Config.options().nmagic() && !m_Config.isCodeStatic()) {
+ error(diag::err_nmagic_not_static);
+ return false;
+ }
+ if (m_Config.options().omagic() && !m_Config.isCodeStatic()) {
+ error(diag::err_omagic_not_static);
+ return false;
+ }
+
return true;
}
@@ -225,8 +222,8 @@ bool ObjectLinker::readRelocations()
{
// Bitcode is read by the other path. This function reads relocation sections
// in object files.
- mcld::InputTree::bfs_iterator input, inEnd = m_Module.getInputTree().bfs_end();
- for (input=m_Module.getInputTree().bfs_begin(); input!=inEnd; ++input) {
+ mcld::InputTree::bfs_iterator input, inEnd = m_pModule->getInputTree().bfs_end();
+ for (input=m_pModule->getInputTree().bfs_begin(); input!=inEnd; ++input) {
if ((*input)->type() == Input::Object && (*input)->hasMemArea()) {
if (!getObjectReader()->readRelocations(**input))
return false;
@@ -239,9 +236,9 @@ bool ObjectLinker::readRelocations()
/// mergeSections - put allinput sections into output sections
bool ObjectLinker::mergeSections()
{
- ObjectBuilder builder(m_Config, m_Module);
- Module::obj_iterator obj, objEnd = m_Module.obj_end();
- for (obj = m_Module.obj_begin(); obj != objEnd; ++obj) {
+ ObjectBuilder builder(m_Config, *m_pModule);
+ Module::obj_iterator obj, objEnd = m_pModule->obj_end();
+ for (obj = m_pModule->obj_begin(); obj != objEnd; ++obj) {
LDContext::sect_iterator sect, sectEnd = (*obj)->context()->sectEnd();
for (sect = (*obj)->context()->sectBegin(); sect != sectEnd; ++sect) {
switch ((*sect)->kind()) {
@@ -255,7 +252,7 @@ bool ObjectLinker::mergeSections()
// skip
continue;
case LDFileFormat::Target:
- if (!m_LDBackend.mergeSection(m_Module, **sect)) {
+ if (!m_LDBackend.mergeSection(*m_pModule, **sect)) {
error(diag::err_cannot_merge_section) << (*sect)->name()
<< (*obj)->name();
return false;
@@ -265,7 +262,7 @@ bool ObjectLinker::mergeSections()
if (!(*sect)->hasEhFrame())
continue; // skip
- if (!builder.MergeSection(**sect)) {
+ if (NULL == builder.MergeSection(**sect)) {
error(diag::err_cannot_merge_section) << (*sect)->name()
<< (*obj)->name();
return false;
@@ -276,7 +273,15 @@ bool ObjectLinker::mergeSections()
if (!(*sect)->hasSectionData())
continue; // skip
- if (!builder.MergeSection(**sect)) {
+ LDSection* out_sect = builder.MergeSection(**sect);
+ if (NULL != out_sect) {
+ if (!m_LDBackend.updateSectionFlags(*out_sect, **sect)) {
+ error(diag::err_cannot_merge_section) << (*sect)->name()
+ << (*obj)->name();
+ return false;
+ }
+ }
+ else {
error(diag::err_cannot_merge_section) << (*sect)->name()
<< (*obj)->name();
return false;
@@ -296,12 +301,12 @@ bool ObjectLinker::mergeSections()
bool ObjectLinker::addStandardSymbols()
{
// create and add section symbols for each output section
- Module::iterator iter, iterEnd = m_Module.end();
- for (iter = m_Module.begin(); iter != iterEnd; ++iter) {
- m_Module.getSectionSymbolSet().add(**iter, m_Module.getNamePool());
+ Module::iterator iter, iterEnd = m_pModule->end();
+ for (iter = m_pModule->begin(); iter != iterEnd; ++iter) {
+ m_pModule->getSectionSymbolSet().add(**iter, m_pModule->getNamePool());
}
- return m_LDBackend.initStandardSymbols(*m_pLinker, m_Module);
+ return m_LDBackend.initStandardSymbols(*m_pBuilder, *m_pModule);
}
/// addTargetSymbols - some targets, such as MIPS and ARM, need some
@@ -310,15 +315,24 @@ bool ObjectLinker::addStandardSymbols()
/// target symbols, return false
bool ObjectLinker::addTargetSymbols()
{
- m_LDBackend.initTargetSymbols(*m_pLinker);
+ m_LDBackend.initTargetSymbols(*m_pBuilder, *m_pModule);
+ return true;
+}
+
+/// addScriptSymbols - define symbols from the command line option or linker
+/// scripts.
+/// @return if there are some existing symbols with identical name to the
+/// script symbols, return false.
+bool ObjectLinker::addScriptSymbols()
+{
return true;
}
bool ObjectLinker::scanRelocations()
{
// apply all relocations of all inputs
- Module::obj_iterator input, inEnd = m_Module.obj_end();
- for (input = m_Module.obj_begin(); input != inEnd; ++input) {
+ Module::obj_iterator input, inEnd = m_pModule->obj_end();
+ for (input = m_pModule->obj_begin(); input != inEnd; ++input) {
LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
// bypass the reloc section if
@@ -332,42 +346,54 @@ bool ObjectLinker::scanRelocations()
for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) {
Relocation* relocation = llvm::cast<Relocation>(reloc);
// scan relocation
- if (LinkerConfig::Object != m_Config.codeGenType()) {
- m_LDBackend.scanRelocation(*relocation,
- *m_pLinker,
- m_Module,
- *(*rs)->getLink());
- }
- else {
- m_LDBackend.partialScanRelocation(*relocation,
- *m_pLinker,
- m_Module,
- *(*rs)->getLink());
- }
+ if (LinkerConfig::Object != m_Config.codeGenType())
+ m_LDBackend.scanRelocation(*relocation, *m_pBuilder, *m_pModule, **rs);
+ else
+ m_LDBackend.partialScanRelocation(*relocation, *m_pModule, **rs);
} // for all relocations
} // for all relocation section
} // for all inputs
return true;
}
+/// initStubs - initialize stub-related stuff.
+bool ObjectLinker::initStubs()
+{
+ // initialize BranchIslandFactory
+ m_LDBackend.initBRIslandFactory();
+
+ // initialize StubFactory
+ m_LDBackend.initStubFactory();
+
+ // initialize target stubs
+ m_LDBackend.initTargetStubs();
+ return true;
+}
+
+/// allocateCommonSymobols - allocate fragments for common symbols to the
+/// corresponding sections
+bool ObjectLinker::allocateCommonSymbols()
+{
+ if (LinkerConfig::Object != m_Config.codeGenType() ||
+ m_Config.options().isDefineCommon())
+ return m_LDBackend.allocateCommonSymbols(*m_pModule);
+ return true;
+}
+
/// prelayout - help backend to do some modification before layout
bool ObjectLinker::prelayout()
{
// finalize the section symbols, set their fragment reference and push them
// into output symbol table
- Module::iterator sect, sEnd = m_Module.end();
- for (sect = m_Module.begin(); sect != sEnd; ++sect) {
- m_Module.getSectionSymbolSet().finalize(**sect, m_Module.getSymbolTable());
+ Module::iterator sect, sEnd = m_pModule->end();
+ for (sect = m_pModule->begin(); sect != sEnd; ++sect) {
+ m_pModule->getSectionSymbolSet().finalize(**sect, m_pModule->getSymbolTable());
}
- m_LDBackend.preLayout(m_Module, *m_pLinker);
-
- if (LinkerConfig::Object != m_Config.codeGenType() ||
- m_Config.options().isDefineCommon())
- m_LDBackend.allocateCommonSymbols(m_Module);
+ m_LDBackend.preLayout(*m_pModule, *m_pBuilder);
/// check program interpreter - computer the name size of the runtime dyld
- if (!m_pLinker->isStaticLink() &&
+ if (!m_Config.isCodeStatic() &&
(LinkerConfig::Exec == m_Config.codeGenType() ||
m_Config.options().isPIE() ||
m_Config.options().hasDyld()))
@@ -379,7 +405,7 @@ bool ObjectLinker::prelayout()
///
/// dump all symbols and strings from FragmentLinker and build the format-dependent
/// hash table.
- m_LDBackend.sizeNamePools(m_Module, m_pLinker->isStaticLink());
+ m_LDBackend.sizeNamePools(*m_pModule, m_Config.isCodeStatic());
return true;
}
@@ -391,14 +417,14 @@ bool ObjectLinker::prelayout()
/// directly
bool ObjectLinker::layout()
{
- m_LDBackend.layout(m_Module, *m_pLinker);
+ m_LDBackend.layout(*m_pModule);
return true;
}
/// prelayout - help backend to do some modification after layout
bool ObjectLinker::postlayout()
{
- m_LDBackend.postLayout(m_Module, *m_pLinker);
+ m_LDBackend.postLayout(*m_pModule, *m_pBuilder);
return true;
}
@@ -407,7 +433,7 @@ bool ObjectLinker::postlayout()
/// symbol.
bool ObjectLinker::finalizeSymbolValue()
{
- return m_pLinker->finalizeSymbols();
+ return (m_pLinker->finalizeSymbols() && m_LDBackend.finalizeSymbols());
}
/// relocate - applying relocation entries and create relocation
@@ -423,23 +449,7 @@ bool ObjectLinker::relocation()
/// emitOutput - emit the output file.
bool ObjectLinker::emitOutput(MemoryArea& pOutput)
{
- switch(m_Config.codeGenType()) {
- case LinkerConfig::Object:
- getObjectWriter()->writeObject(m_Module, pOutput);
- return true;
- case LinkerConfig::DynObj:
- getDynObjWriter()->writeDynObj(m_Module, pOutput);
- return true;
- case LinkerConfig::Exec:
- getExecWriter()->writeExecutable(m_Module, pOutput);
- return true;
- case LinkerConfig::Binary:
- getBinaryWriter()->writeBinary(m_Module, pOutput);
- return true;
- default:
- fatal(diag::unrecognized_output_file) << m_Config.codeGenType();
- }
- return false;
+ return llvm::errc::success == getWriter()->writeObject(*m_pModule, pOutput);
}
/// postProcessing - do modification after all processes
@@ -450,7 +460,7 @@ bool ObjectLinker::postProcessing(MemoryArea& pOutput)
// emit .eh_frame_hdr
// eh_frame_hdr should be emitted after syncRelocation, because eh_frame_hdr
// needs FDE PC value, which will be corrected at syncRelocation
- m_LDBackend.postProcessing(*m_pLinker, pOutput);
+ m_LDBackend.postProcessing(pOutput);
return true;
}
diff --git a/lib/Support/Directory.cpp b/lib/Support/Directory.cpp
index 78bb761..a47b162 100644
--- a/lib/Support/Directory.cpp
+++ b/lib/Support/Directory.cpp
@@ -26,8 +26,9 @@ bool is_symlink(FileStatus f)
} // namespace of anonymous
-//==========================
+//===----------------------------------------------------------------------===//
// Directory
+//===----------------------------------------------------------------------===//
Directory::Directory()
: m_Path(),
m_FileStatus(),
@@ -165,16 +166,16 @@ DirIterator::~DirIterator()
Path* DirIterator::path()
{
- if (m_pParent == 0) // end
- return 0;
- return m_pEntry->value();
+ if (NULL == m_pParent)
+ return NULL;
+ return &m_pEntry->value();
}
const Path* DirIterator::path() const
{
- if (m_pParent == 0) // end
- return 0;
- return m_pEntry->value();
+ if (NULL == m_pParent)
+ return NULL;
+ return &m_pEntry->value();
}
DirIterator& DirIterator::operator=(const DirIterator& pCopy)
diff --git a/lib/Support/FileHandle.cpp b/lib/Support/FileHandle.cpp
index 4800bfa..7876ac6 100644
--- a/lib/Support/FileHandle.cpp
+++ b/lib/Support/FileHandle.cpp
@@ -6,6 +6,7 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include "mcld/Config/Config.h"
#include <mcld/Support/FileHandle.h>
#include <mcld/Support/FileSystem.h>
#include <errno.h>
@@ -127,7 +128,7 @@ bool FileHandle::delegate(int pFD, FileHandle::OpenMode pMode)
m_Handler = pFD;
m_OpenMode = pMode;
- m_State = GoodBit;
+ m_State = (GoodBit | DeputedBit);
if (!get_size(m_Handler, m_Size)) {
setState(FailBit);
@@ -144,9 +145,11 @@ bool FileHandle::close()
return false;
}
- if (-1 == ::close(m_Handler)) {
- setState(FailBit);
- return false;
+ if (isOwned()) {
+ if (-1 == ::close(m_Handler)) {
+ setState(FailBit);
+ return false;
+ }
}
m_Path.native().clear();
@@ -327,3 +330,8 @@ bool FileHandle::isFailed() const
return (m_State & (BadBit | FailBit));
}
+bool FileHandle::isOwned() const
+{
+ return !(m_State & DeputedBit);
+}
+
diff --git a/lib/Support/FileSystem.cpp b/lib/Support/FileSystem.cpp
index fb2633d..715960e 100644
--- a/lib/Support/FileSystem.cpp
+++ b/lib/Support/FileSystem.cpp
@@ -6,6 +6,7 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include "mcld/Config/Config.h"
#include "mcld/Support/FileSystem.h"
#include "mcld/Support/Path.h"
diff --git a/lib/Support/MemoryArea.cpp b/lib/Support/MemoryArea.cpp
index 3a3fa0c..b5873bf 100644
--- a/lib/Support/MemoryArea.cpp
+++ b/lib/Support/MemoryArea.cpp
@@ -32,11 +32,6 @@ MemoryArea::MemoryArea(FileHandle& pFileHandle)
MemoryArea::~MemoryArea()
{
- SpaceMapType::iterator space, sEnd = m_SpaceMap.end();
- for (space = m_SpaceMap.begin(); space != sEnd; ++space) {
- if (space->second != NULL)
- Space::Destroy(space->second);
- }
}
// The layout of MemorySpace in the virtual memory space
@@ -68,7 +63,7 @@ MemoryRegion* MemoryArea::request(size_t pOffset, size_t pLength)
}
space = Space::Create(*m_pFileHandle, pOffset, pLength);
- m_SpaceMap.insert(std::make_pair(Key(pOffset, pLength), space));
+ m_SpaceMap.insert(std::make_pair(Key(space->start(), space->size()), space));
}
// adjust r_start
@@ -98,8 +93,19 @@ void MemoryArea::release(MemoryRegion* pRegion)
// synchronize writable space before we release it.
Space::Sync(space, *m_pFileHandle);
}
- m_SpaceMap.erase(Key(space->start(), space->size()));
+
+ std::pair<SpaceMapType::iterator, SpaceMapType::iterator> range =
+ m_SpaceMap.equal_range(Key(space->start(), space->size()));
+ SpaceMapType::iterator it;
+ for (it = range.first; it != range.second; ++it) {
+ if (space == it->second)
+ break;
+ }
+ m_SpaceMap.erase(it);
+
Space::Release(space, *m_pFileHandle);
+ assert(NULL != space);
+ Space::Destroy(space);
}
}
}
@@ -110,24 +116,23 @@ void MemoryArea::clear()
if (NULL == m_pFileHandle)
return;
+ SpaceMapType::iterator space, sEnd = m_SpaceMap.end();
if (m_pFileHandle->isWritable()) {
- SpaceMapType::iterator space, sEnd = m_SpaceMap.end();
for (space = m_SpaceMap.begin(); space != sEnd; ++space) {
Space::Sync(space->second, *m_pFileHandle);
Space::Release(space->second, *m_pFileHandle);
+ assert(NULL != space->second);
+ Space::Destroy(space->second);
}
}
else {
- SpaceMapType::iterator space, sEnd = m_SpaceMap.end();
- for (space = m_SpaceMap.begin(); space != sEnd; ++space)
+ for (space = m_SpaceMap.begin(); space != sEnd; ++space) {
Space::Release(space->second, *m_pFileHandle);
- }
-
- for (SpaceMapType::iterator space = m_SpaceMap.begin(),
- sEnd = m_SpaceMap.end(); space != sEnd; ++space) {
- if (space->second != NULL)
+ assert(NULL != space->second);
Space::Destroy(space->second);
+ }
}
+
m_SpaceMap.clear();
}
diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp
index d359162..ee700c0 100644
--- a/lib/Support/Path.cpp
+++ b/lib/Support/Path.cpp
@@ -6,6 +6,7 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include "mcld/Config/Config.h"
#include "mcld/Support/FileSystem.h"
#include "mcld/Support/Path.h"
#include <llvm/ADT/StringRef.h>
diff --git a/lib/Support/SystemUtils.cpp b/lib/Support/SystemUtils.cpp
index 5dfea36..19c5e90 100644
--- a/lib/Support/SystemUtils.cpp
+++ b/lib/Support/SystemUtils.cpp
@@ -6,6 +6,7 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include "mcld/Config/Config.h"
#include <mcld/Support/SystemUtils.h>
using namespace mcld::sys;
diff --git a/lib/Support/UniqueGCFactory.cpp b/lib/Support/UniqueGCFactory.cpp
deleted file mode 100644
index 2352181..0000000
--- a/lib/Support/UniqueGCFactory.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-//===- UniqueGCFactory.cpp ------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <UniqueGCFactory.h>
-
-using namespace mcld;
-
-//==========================
-// UniqueGCFactory
-
diff --git a/lib/Support/Unix/PathV3.inc b/lib/Support/Unix/PathV3.inc
index 68b0c36..1506e94 100644
--- a/lib/Support/Unix/PathV3.inc
+++ b/lib/Support/Unix/PathV3.inc
@@ -233,7 +233,7 @@ mcld::sys::fs::PathCache::entry_type* bring_one_into_cache(DirIterator& pIter)
bool exist = false;
entry = pIter.m_pParent->m_Cache.insert(path, exist);
if (!exist)
- entry->setValue(new Path(path));
+ entry->setValue(path);
break;
}
case 0:// meet real end
@@ -264,7 +264,7 @@ void open_dir(Directory& pDir)
bool exist = false;
mcld::sys::fs::PathCache::entry_type* entry = pDir.m_Cache.insert(path, exist);
if (!exist)
- entry->setValue(new Path(path));
+ entry->setValue(path);
return;
}
case 0:
diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp
index e294bc3..0b64646 100644
--- a/lib/Support/raw_ostream.cpp
+++ b/lib/Support/raw_ostream.cpp
@@ -6,6 +6,7 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include "mcld/Config/Config.h"
#include <mcld/Support/raw_ostream.h>
#if defined(HAVE_UNISTD_H)
diff --git a/lib/Target/ARM/ARMELFArchiveReader.cpp b/lib/Target/ARM/ARMELFArchiveReader.cpp
deleted file mode 100644
index 4c6d775..0000000
--- a/lib/Target/ARM/ARMELFArchiveReader.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-//===- ARMELFArchiveReader.cpp --------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include "ARMELFArchiveReader.h"
-
-using namespace mcld;
-
-//==========================
-// ARMELFArchiveReader
diff --git a/lib/Target/ARM/ARMELFArchiveReader.h b/lib/Target/ARM/ARMELFArchiveReader.h
deleted file mode 100644
index 2fa9ce2..0000000
--- a/lib/Target/ARM/ARMELFArchiveReader.h
+++ /dev/null
@@ -1,29 +0,0 @@
-//===- ARMELFArchiveReader.h ----------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MCLD_ARM_ELF_ARCHIVE_READER_H
-#define MCLD_ARM_ELF_ARCHIVE_READER_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-
-#include "mcld/MC/MCELFArchiveTargetReader.h"
-
-namespace mcld
-{
-
-/// ARMELFArchiveReader - ARMELFArchiveReader is
-/// a target-dependent reader for ELF archive files.
-class ARMELFArchiveReader : public MCELFArchiveTargetReader
-{
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/lib/Target/ARM/ARMGNUInfo.h b/lib/Target/ARM/ARMGNUInfo.h
index 9091dce..0162f83 100644
--- a/lib/Target/ARM/ARMGNUInfo.h
+++ b/lib/Target/ARM/ARMGNUInfo.h
@@ -21,6 +21,11 @@ public:
uint32_t machine() const { return llvm::ELF::EM_ARM; }
+ uint64_t defaultTextSegmentAddr() const { return 0x8000; }
+
+ uint64_t flags() const
+ { return (llvm::ELF::EF_ARM_EABIMASK & 0x05000000); }
+
};
} // namespace of mcld
diff --git a/lib/Target/ARM/ARMLDBackend.cpp b/lib/Target/ARM/ARMLDBackend.cpp
index 844c8ba..8b96670 100644
--- a/lib/Target/ARM/ARMLDBackend.cpp
+++ b/lib/Target/ARM/ARMLDBackend.cpp
@@ -28,7 +28,6 @@
#include <mcld/Fragment/FillFragment.h>
#include <mcld/Fragment/AlignFragment.h>
#include <mcld/Fragment/RegionFragment.h>
-#include <mcld/Fragment/FragmentLinker.h>
#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/MsgHandling.h>
@@ -115,63 +114,80 @@ void ARMGNULDBackend::initTargetSections(Module& pModule, ObjectBuilder& pBuilde
}
}
-void ARMGNULDBackend::initTargetSymbols(FragmentLinker& pLinker)
+void ARMGNULDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule)
{
// Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
// same name in input
- m_pGOTSymbol = pLinker.defineSymbol<FragmentLinker::AsRefered, FragmentLinker::Resolve>(
- "_GLOBAL_OFFSET_TABLE_",
- false,
- ResolveInfo::Object,
- ResolveInfo::Define,
- ResolveInfo::Local,
- 0x0, // size
- 0x0, // value
- FragmentRef::Null(), // FragRef
- ResolveInfo::Hidden);
-
- FragmentRef* exidx_start = NULL;
- FragmentRef* exidx_end = NULL;
- ResolveInfo::Desc desc = ResolveInfo::Undefined;
- if (NULL != m_pEXIDX && 0x0 != m_pEXIDX->size()) {
- exidx_start = FragmentRef::Create(m_pEXIDX->getSectionData()->front(), 0x0);
- exidx_end = FragmentRef::Create(m_pEXIDX->getSectionData()->back(), 0x0);
- desc = ResolveInfo::Define;
- }
- else {
- exidx_start = FragmentRef::Null();
- exidx_end = FragmentRef::Null();
- }
- m_pEXIDXStart =
- pLinker.defineSymbol<FragmentLinker::Force,
- FragmentLinker::Resolve>("__exidx_start",
- false,
- ResolveInfo::NoType,
- desc, // ResolveInfo::Desc
- ResolveInfo::Global,
- 0x0, // size
- 0x0, // value
- exidx_start, // FragRef
- ResolveInfo::Hidden);
-
- m_pEXIDXEnd =
- pLinker.defineSymbol<FragmentLinker::Force,
- FragmentLinker::Resolve>("__exidx_end",
- false,
- ResolveInfo::NoType,
- desc, //ResolveInfo::Desc
- ResolveInfo::Global,
+ m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
0x0, // size
0x0, // value
- exidx_end, // FragRef
+ FragmentRef::Null(),
ResolveInfo::Hidden);
+ if (NULL != m_pEXIDX && 0x0 != m_pEXIDX->size()) {
+ FragmentRef* exidx_start =
+ FragmentRef::Create(m_pEXIDX->getSectionData()->front(), 0x0);
+ FragmentRef* exidx_end =
+ FragmentRef::Create(m_pEXIDX->getSectionData()->front(),
+ m_pEXIDX->size());
+ m_pEXIDXStart =
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "__exidx_start",
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ exidx_start, // FragRef
+ ResolveInfo::Default);
+
+ m_pEXIDXEnd =
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "__exidx_end",
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ exidx_end, // FragRef
+ ResolveInfo::Default);
+ // change __exidx_start/_end to local dynamic category
+ if (NULL != m_pEXIDXStart)
+ pModule.getSymbolTable().changeLocalToDynamic(*m_pEXIDXStart);
+ if (NULL != m_pEXIDXEnd)
+ pModule.getSymbolTable().changeLocalToDynamic(*m_pEXIDXEnd);
+ } else {
+ m_pEXIDXStart =
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "__exidx_start",
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ FragmentRef::Null(),
+ ResolveInfo::Default);
+
+ m_pEXIDXEnd =
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "__exidx_end",
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ FragmentRef::Null(),
+ ResolveInfo::Default);
+ }
}
-bool ARMGNULDBackend::initRelocator(const FragmentLinker& pLinker)
+bool ARMGNULDBackend::initRelocator()
{
if (NULL == m_pRelocator) {
m_pRelocator = new ARMRelocator(*this);
- m_pRelocator->setFragmentLinker(pLinker);
}
return true;
}
@@ -182,8 +198,12 @@ Relocator* ARMGNULDBackend::getRelocator()
return m_pRelocator;
}
-void ARMGNULDBackend::doPreLayout(FragmentLinker& pLinker)
+void ARMGNULDBackend::doPreLayout(IRBuilder& pBuilder)
{
+ // initialize .dynamic data
+ if (!config().isCodeStatic() && NULL == m_pDynamic)
+ m_pDynamic = new ARMELFDynamic(*this, config());
+
// set .got size
// when building shared object, the .got section is must
if (LinkerConfig::Object != config().codeGenType()) {
@@ -191,7 +211,7 @@ void ARMGNULDBackend::doPreLayout(FragmentLinker& pLinker)
m_pGOT->hasGOT1() ||
NULL != m_pGOTSymbol) {
m_pGOT->finalizeSectionSize();
- defineGOTSymbol(pLinker);
+ defineGOTSymbol(pBuilder);
}
// set .plt size
@@ -200,19 +220,24 @@ void ARMGNULDBackend::doPreLayout(FragmentLinker& pLinker)
ELFFileFormat* file_format = getOutputFormat();
// set .rel.dyn size
- if (!m_pRelDyn->empty())
+ if (!m_pRelDyn->empty()) {
+ assert(!config().isCodeStatic() &&
+ "static linkage should not result in a dynamic relocation section");
file_format->getRelDyn().setSize(
m_pRelDyn->numOfRelocs() * getRelEntrySize());
+ }
// set .rel.plt size
- if (!m_pRelPLT->empty())
+ if (!m_pRelPLT->empty()) {
+ assert(!config().isCodeStatic() &&
+ "static linkage should not result in a dynamic relocation section");
file_format->getRelPlt().setSize(
m_pRelPLT->numOfRelocs() * getRelEntrySize());
+ }
}
}
-void ARMGNULDBackend::doPostLayout(Module& pModule,
- FragmentLinker& pLinker)
+void ARMGNULDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder)
{
const ELFFileFormat *file_format = getOutputFormat();
@@ -242,9 +267,7 @@ void ARMGNULDBackend::doPostLayout(Module& pModule,
/// Use co-variant return type to return its own dynamic section.
ARMELFDynamic& ARMGNULDBackend::dynamic()
{
- if (NULL == m_pDynamic)
- m_pDynamic = new ARMELFDynamic(*this, config());
-
+ assert(NULL != m_pDynamic);
return *m_pDynamic;
}
@@ -252,17 +275,16 @@ ARMELFDynamic& ARMGNULDBackend::dynamic()
/// Use co-variant return type to return its own dynamic section.
const ARMELFDynamic& ARMGNULDBackend::dynamic() const
{
- assert( NULL != m_pDynamic);
+ assert(NULL != m_pDynamic);
return *m_pDynamic;
}
-void ARMGNULDBackend::defineGOTSymbol(FragmentLinker& pLinker)
+void ARMGNULDBackend::defineGOTSymbol(IRBuilder& pBuilder)
{
// define symbol _GLOBAL_OFFSET_TABLE_ when .got create
if (m_pGOTSymbol != NULL) {
- pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Unresolve>(
+ pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
"_GLOBAL_OFFSET_TABLE_",
- false,
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Local,
@@ -272,9 +294,8 @@ void ARMGNULDBackend::defineGOTSymbol(FragmentLinker& pLinker)
ResolveInfo::Hidden);
}
else {
- m_pGOTSymbol = pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Resolve>(
+ m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
"_GLOBAL_OFFSET_TABLE_",
- false,
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Local,
@@ -301,7 +322,7 @@ void ARMGNULDBackend::addCopyReloc(ResolveInfo& pSym)
/// copy.
/// This is executed at scan relocation stage.
LDSymbol&
-ARMGNULDBackend::defineSymbolforCopyReloc(FragmentLinker& pLinker,
+ARMGNULDBackend::defineSymbolforCopyReloc(IRBuilder& pBuilder,
const ResolveInfo& pSym)
{
// get or create corresponding BSS LDSection
@@ -336,9 +357,8 @@ ARMGNULDBackend::defineSymbolforCopyReloc(FragmentLinker& pLinker,
binding = ResolveInfo::Global;
// Define the copy symbol in the bss section and resolve it
- LDSymbol* cpy_sym = pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Resolve>(
+ LDSymbol* cpy_sym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
pSym.name(),
- false,
(ResolveInfo::Type)pSym.type(),
ResolveInfo::Define,
binding,
@@ -352,11 +372,10 @@ ARMGNULDBackend::defineSymbolforCopyReloc(FragmentLinker& pLinker,
/// checkValidReloc - When we attempt to generate a dynamic relocation for
/// ouput file, check if the relocation is supported by dynamic linker.
-void ARMGNULDBackend::checkValidReloc(Relocation& pReloc,
- const FragmentLinker& pLinker) const
+void ARMGNULDBackend::checkValidReloc(Relocation& pReloc) const
{
// If not PIC object, no relocation type is invalid
- if (!pLinker.isOutputPIC())
+ if (!config().isCodeIndep())
return;
switch(pReloc.type()) {
@@ -379,8 +398,8 @@ void ARMGNULDBackend::checkValidReloc(Relocation& pReloc,
}
}
-void ARMGNULDBackend::scanLocalReloc(Relocation& pReloc,
- FragmentLinker& pLinker)
+void
+ARMGNULDBackend::scanLocalReloc(Relocation& pReloc, const LDSection& pSection)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
@@ -398,11 +417,12 @@ void ARMGNULDBackend::scanLocalReloc(Relocation& pReloc,
// 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 (pLinker.isOutputPIC()) {
+ if (config().isCodeIndep()) {
m_pRelDyn->reserveEntry();
// set Rel bit
rsym->setReserved(rsym->reserved() | ReserveRel);
- }
+ checkAndSetHasTextRel(*pSection.getLink());
+ }
return;
}
@@ -416,7 +436,7 @@ void ARMGNULDBackend::scanLocalReloc(Relocation& pReloc,
case llvm::ELF::R_ARM_THM_MOVW_ABS_NC:
case llvm::ELF::R_ARM_THM_MOVT_ABS: {
// PIC code should not contain these kinds of relocation
- if (pLinker.isOutputPIC()) {
+ if (config().isCodeIndep()) {
error(diag::non_pic_relocation) << (int)pReloc.type()
<< pReloc.symInfo()->name();
}
@@ -443,7 +463,7 @@ void ARMGNULDBackend::scanLocalReloc(Relocation& pReloc,
// If building PIC object, a dynamic relocation with
// type RELATIVE is needed to relocate this GOT entry.
// Reserve an entry in .rel.dyn
- if (pLinker.isOutputPIC()) {
+ if (config().isCodeIndep()) {
// create .rel.dyn section if not exist
m_pRelDyn->reserveEntry();
// set GOTRel bit
@@ -479,7 +499,8 @@ void ARMGNULDBackend::scanLocalReloc(Relocation& pReloc,
}
void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc,
- FragmentLinker& pLinker)
+ IRBuilder& pBuilder,
+ const LDSection& pSection)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
@@ -505,7 +526,7 @@ void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc,
case llvm::ELF::R_ARM_ABS32_NOI: {
// Absolute relocation type, symbol may needs PLT entry or
// dynamic relocation entry
- if (symbolNeedsPLT(pLinker, *rsym)) {
+ if (symbolNeedsPLT(*rsym)) {
// create plt for this symbol if it does not have one
if (!(rsym->reserved() & ReservePLT)){
// Symbol needs PLT entry, we need to reserve a PLT entry
@@ -519,18 +540,18 @@ void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc,
}
}
- if (symbolNeedsDynRel(
- pLinker, *rsym, (rsym->reserved() & ReservePLT), true)) {
+ if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), true)) {
// symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
m_pRelDyn->reserveEntry();
- if (symbolNeedsCopyReloc(pLinker, pReloc, *rsym)) {
- LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym);
+ if (symbolNeedsCopyReloc(pReloc, *rsym)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
addCopyReloc(*cpy_sym.resolveInfo());
}
else {
- checkValidReloc(pReloc, pLinker);
+ checkValidReloc(pReloc);
// set Rel bit
rsym->setReserved(rsym->reserved() | ReserveRel);
+ checkAndSetHasTextRel(*pSection.getLink());
}
}
return;
@@ -594,18 +615,18 @@ void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc,
case llvm::ELF::R_ARM_MOVT_BREL:
case llvm::ELF::R_ARM_MOVW_BREL: {
// Relative addressing relocation, may needs dynamic relocation
- if (symbolNeedsDynRel(
- pLinker, *rsym, (rsym->reserved() & ReservePLT), false)) {
+ if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), false)) {
// symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
m_pRelDyn->reserveEntry();
- if (symbolNeedsCopyReloc(pLinker, pReloc, *rsym)) {
- LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym);
+ if (symbolNeedsCopyReloc(pReloc, *rsym)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
addCopyReloc(*cpy_sym.resolveInfo());
}
else {
- checkValidReloc(pReloc, pLinker);
+ checkValidReloc(pReloc);
// set Rel bit
rsym->setReserved(rsym->reserved() | ReserveRel);
+ checkAndSetHasTextRel(*pSection.getLink());
}
}
return;
@@ -630,7 +651,7 @@ void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc,
return;
// if the symbol's value can be decided at link time, then no need plt
- if (symbolFinalValueIsKnown(pLinker, *rsym))
+ if (symbolFinalValueIsKnown(*rsym))
return;
// if symbol is defined in the ouput file and it's not
@@ -666,7 +687,7 @@ void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc,
m_pGOT->reserveGOT();
// if the symbol cannot be fully resolved at link time, then we need a
// dynamic relocation
- if (!symbolFinalValueIsKnown(pLinker, *rsym)) {
+ if (!symbolFinalValueIsKnown(*rsym)) {
m_pRelDyn->reserveEntry();
// set GOTRel bit
rsym->setReserved(rsym->reserved() | GOTRel);
@@ -693,16 +714,17 @@ void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc,
}
void ARMGNULDBackend::scanRelocation(Relocation& pReloc,
- FragmentLinker& pLinker,
+ IRBuilder& pBuilder,
Module& pModule,
- const LDSection& pSection)
+ LDSection& pSection)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
pReloc.updateAddend();
- if (0 == (pSection.flag() & llvm::ELF::SHF_ALLOC))
+ assert(NULL != pSection.getLink());
+ if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC))
return;
// Scan relocation type to determine if an GOT/PLT/Dynamic Relocation
@@ -711,21 +733,16 @@ void ARMGNULDBackend::scanRelocation(Relocation& pReloc,
// rsym is local
if (rsym->isLocal())
- scanLocalReloc(pReloc, pLinker);
+ scanLocalReloc(pReloc, pSection);
// rsym is external
else
- scanGlobalReloc(pReloc, pLinker);
+ scanGlobalReloc(pReloc, pBuilder, pSection);
// check if we shoule issue undefined reference for the relocation target
// symbol
if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
fatal(diag::undefined_reference) << rsym->name();
-
- if ((rsym->reserved() & ReserveRel) != 0x0) {
- // set hasTextRelSection if needed
- checkAndSetHasTextRel(pSection);
- }
}
uint64_t ARMGNULDBackend::emitSectionData(const LDSection& pSection,
@@ -765,7 +782,7 @@ uint64_t ARMGNULDBackend::emitSectionData(const LDSection& pSection,
break;
}
case Fragment::Alignment: {
- AlignFragment& align_frag = llvm::cast<AlignFragment>(*frag_iter);
+ const AlignFragment& align_frag = llvm::cast<AlignFragment>(*frag_iter);
uint64_t count = size / align_frag.getValueSize();
switch (align_frag.getValueSize()) {
case 1u:
@@ -809,17 +826,8 @@ uint64_t ARMGNULDBackend::emitSectionData(const LDSection& pSection,
}
/// finalizeSymbol - finalize the symbol value
-bool ARMGNULDBackend::finalizeTargetSymbols(FragmentLinker& pLinker)
+bool ARMGNULDBackend::finalizeTargetSymbols()
{
- if (NULL != m_pEXIDXStart) {
- if (NULL != m_pEXIDX && 0x0 != m_pEXIDX->size())
- m_pEXIDXStart->setValue(m_pEXIDX->addr());
- }
-
- if (NULL != m_pEXIDXEnd) {
- if (NULL != m_pEXIDX && 0x0 != m_pEXIDX->size())
- m_pEXIDXEnd->setValue(m_pEXIDX->addr() + m_pEXIDX->size());
- }
return true;
}
@@ -829,7 +837,7 @@ bool ARMGNULDBackend::mergeSection(Module& pModule, LDSection& pSection)
case llvm::ELF::SHT_ARM_ATTRIBUTES: {
// FIXME: (Luba)
// Handle ARM attributes in the right way.
- // In current milestone, FragmentLinker goes through the shortcut.
+ // In current milestone, we goes through the shortcut.
// It reads input's ARM attributes and copies the first ARM attributes
// into the output file. The correct way is merge these sections, not
// just copy.
@@ -940,7 +948,8 @@ ARMGNULDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const
}
/// doRelax
-bool ARMGNULDBackend::doRelax(Module& pModule, FragmentLinker& pLinker, bool& pFinished)
+bool
+ARMGNULDBackend::doRelax(Module& pModule, IRBuilder& pBuilder, bool& pFinished)
{
assert(NULL != getStubFactory() && NULL != getBRIslandFactory());
@@ -984,17 +993,20 @@ bool ARMGNULDBackend::doRelax(Module& pModule, FragmentLinker& pLinker, bool& pF
Stub* stub = getStubFactory()->create(*relocation, // relocation
sym_value, // symbol value
- pLinker,
+ pBuilder,
*getBRIslandFactory());
if (NULL != stub) {
- assert(NULL != stub->symInfo());
- // increase the size of .symtab and .strtab
+ // a stub symbol should be local
+ assert(NULL != stub->symInfo() && stub->symInfo()->isLocal());
LDSection& symtab = file_format->getSymTab();
LDSection& strtab = file_format->getStrTab();
+
+ // increase the size of .symtab and .strtab if needed
if (config().targets().is32Bits())
symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf32_Sym));
else
symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf64_Sym));
+ symtab.setInfo(symtab.getInfo() + 1);
strtab.setSize(strtab.size() + stub->symInfo()->nameSize() + 1);
isRelaxed = true;
@@ -1042,13 +1054,13 @@ bool ARMGNULDBackend::doRelax(Module& pModule, FragmentLinker& pLinker, bool& pF
}
/// initTargetStubs
-bool ARMGNULDBackend::initTargetStubs(FragmentLinker& pLinker)
+bool ARMGNULDBackend::initTargetStubs()
{
if (NULL != getStubFactory()) {
- getStubFactory()->addPrototype(new ARMToARMStub(pLinker.isOutputPIC()));
- getStubFactory()->addPrototype(new ARMToTHMStub(pLinker.isOutputPIC()));
- getStubFactory()->addPrototype(new THMToTHMStub(pLinker.isOutputPIC()));
- getStubFactory()->addPrototype(new THMToARMStub(pLinker.isOutputPIC()));
+ getStubFactory()->addPrototype(new ARMToARMStub(config().isCodeIndep()));
+ getStubFactory()->addPrototype(new ARMToTHMStub(config().isCodeIndep()));
+ getStubFactory()->addPrototype(new THMToTHMStub(config().isCodeIndep()));
+ getStubFactory()->addPrototype(new THMToARMStub(config().isCodeIndep()));
return true;
}
return false;
@@ -1056,8 +1068,7 @@ bool ARMGNULDBackend::initTargetStubs(FragmentLinker& pLinker)
/// doCreateProgramHdrs - backend can implement this function to create the
/// target-dependent segments
-void ARMGNULDBackend::doCreateProgramHdrs(Module& pModule,
- const FragmentLinker& pLinker)
+void ARMGNULDBackend::doCreateProgramHdrs(Module& pModule)
{
if (NULL != m_pEXIDX && 0x0 != m_pEXIDX->size()) {
// make PT_ARM_EXIDX
diff --git a/lib/Target/ARM/ARMLDBackend.h b/lib/Target/ARM/ARMLDBackend.h
index 6110b1c..170a7bf 100644
--- a/lib/Target/ARM/ARMLDBackend.h
+++ b/lib/Target/ARM/ARMLDBackend.h
@@ -20,7 +20,6 @@ namespace mcld {
class LinkerConfig;
class GNUInfo;
-class FragmentLinker;
class SectionMap;
//===----------------------------------------------------------------------===//
@@ -93,10 +92,10 @@ public:
void initTargetSections(Module& pModule, ObjectBuilder& pBuilder);
/// initTargetSymbols - initialize target dependent symbols in output.
- void initTargetSymbols(FragmentLinker& pLinker);
+ void initTargetSymbols(IRBuilder& pBuilder, Module& pModule);
/// initRelocator - create and initialize Relocator.
- bool initRelocator(const FragmentLinker& pLinker);
+ bool initRelocator();
/// getRelocator - return relocator.
Relocator* getRelocator();
@@ -108,22 +107,15 @@ public:
/// - PLT entry (for .plt section)
/// - dynamin relocation entries (for .rel.plt and .rel.dyn sections)
void scanRelocation(Relocation& pReloc,
- FragmentLinker& pLinker,
+ IRBuilder& pBuilder,
Module& pModule,
- const LDSection& pSection);
-
- /// flags - the value of ElfXX_Ehdr::e_flags
- virtual uint64_t flags() const
- { return (llvm::ELF::EF_ARM_EABIMASK & 0x05000000); }
-
- uint64_t defaultTextSegmentAddr() const
- { return 0x8000; }
+ LDSection& pSection);
/// doPreLayout - Backend can do any needed modification before layout
- void doPreLayout(FragmentLinker& pLinker);
+ void doPreLayout(IRBuilder& pBuilder);
/// doPostLayout -Backend can do any needed modification after layout
- void doPostLayout(Module& pModule, FragmentLinker& pLinker);
+ void doPostLayout(Module& pModule, IRBuilder& pBuilder);
/// dynamic - the dynamic section of the target machine.
/// Use co-variant return type to return its own dynamic section.
@@ -172,7 +164,7 @@ public:
unsigned int getTargetSectionOrder(const LDSection& pSectHdr) const;
/// finalizeTargetSymbols - finalize the symbol value
- bool finalizeTargetSymbols(FragmentLinker& pLinker);
+ bool finalizeTargetSymbols();
/// mergeSection - merge target dependent sections
bool mergeSection(Module& pModule, LDSection& pSection);
@@ -181,12 +173,13 @@ public:
bool readSection(Input& pInput, SectionData& pSD);
private:
- void scanLocalReloc(Relocation& pReloc, FragmentLinker& pLinker);
+ void scanLocalReloc(Relocation& pReloc, const LDSection& pSection);
- void scanGlobalReloc(Relocation& pReloc, FragmentLinker& pLinker);
+ void scanGlobalReloc(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ const LDSection& pSection);
- void checkValidReloc(Relocation& pReloc,
- const FragmentLinker& pLinker) const;
+ void checkValidReloc(Relocation& pReloc) const;
/// addCopyReloc - add a copy relocation into .rel.dyn for pSym
/// @param pSym - A resolved copy symbol that defined in BSS section
@@ -195,10 +188,10 @@ private:
/// 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(FragmentLinker& pLinker,
+ LDSymbol& defineSymbolforCopyReloc(IRBuilder& pLinker,
const ResolveInfo& pSym);
- void defineGOTSymbol(FragmentLinker& pLinker);
+ void defineGOTSymbol(IRBuilder& pBuilder);
/// maxBranchOffset
/// FIXME: if we can handle arm attributes, we may refine this!
@@ -211,10 +204,10 @@ private:
/// implementation. Return true if the output (e.g., .text) is "relaxed"
/// (i.e. layout is changed), and set pFinished to true if everything is fit,
/// otherwise set it to false.
- bool doRelax(Module& pModule, FragmentLinker& pLinker, bool& pFinished);
+ bool doRelax(Module& pModule, IRBuilder& pBuilder, bool& pFinished);
/// initTargetStubs
- bool initTargetStubs(FragmentLinker& pLinker);
+ bool initTargetStubs();
/// getRelEntrySize - the size in BYTE of rel type relocation
size_t getRelEntrySize()
@@ -226,8 +219,7 @@ private:
/// doCreateProgramHdrs - backend can implement this function to create the
/// target-dependent segments
- virtual void doCreateProgramHdrs(Module& pModule,
- const FragmentLinker& pLinker);
+ virtual void doCreateProgramHdrs(Module& pModule);
private:
Relocator* m_pRelocator;
@@ -252,24 +244,6 @@ private:
// LDSection* m_pDebugOverlay; // .ARM.debug_overlay
// LDSection* m_pOverlayTable; // .ARM.overlay_table
};
-
-//===----------------------------------------------------------------------===//
-/// ARMMachOLDBackend - linker backend of ARM target of MachO format
-///
-/**
-class ARMMachOLDBackend : public DarwinARMLDBackend
-{
-public:
- ARMMachOLDBackend();
- ~ARMMachOLDBackend();
-
-private:
- MCMachOTargetArchiveReader *createTargetArchiveReader() const;
- MCMachOTargetObjectReader *createTargetObjectReader() const;
- MCMachOTargetObjectWriter *createTargetObjectWriter() const;
-
-};
-**/
} // namespace of mcld
#endif
diff --git a/lib/Target/ARM/ARMRelocator.cpp b/lib/Target/ARM/ARMRelocator.cpp
index d613d66..d400818 100644
--- a/lib/Target/ARM/ARMRelocator.cpp
+++ b/lib/Target/ARM/ARMRelocator.cpp
@@ -11,7 +11,6 @@
#include <llvm/Support/DataTypes.h>
#include <llvm/Support/ELF.h>
#include <llvm/Support/Host.h>
-#include <mcld/Fragment/FragmentLinker.h>
#include <mcld/Support/MsgHandling.h>
#include "ARMRelocator.h"
#include "ARMRelocationFunctions.h"
@@ -68,8 +67,14 @@ const char* ARMRelocator::getName(Relocator::Type pType) const
return ApplyFunctions[pType].name;
}
+Relocator::Size ARMRelocator::getSize(Relocation::Type pType) const
+{
+ return 32;
+}
+
//===--------------------------------------------------------------------===//
// non-member functions
+//===--------------------------------------------------------------------===//
static Relocator::DWord getThumbBit(const Relocation& pReloc)
{
// Set thumb bit if
diff --git a/lib/Target/ARM/ARMRelocator.h b/lib/Target/ARM/ARMRelocator.h
index 0bf3653..4af48f9 100644
--- a/lib/Target/ARM/ARMRelocator.h
+++ b/lib/Target/ARM/ARMRelocator.h
@@ -43,6 +43,8 @@ public:
const char* getName(Relocation::Type pType) const;
+ Size getSize(Relocation::Type pType) const;
+
const SymGOTMap& getSymGOTMap() const { return m_SymGOTMap; }
SymGOTMap& getSymGOTMap() { return m_SymGOTMap; }
diff --git a/lib/Target/DarwinLDBackend.cpp b/lib/Target/DarwinLDBackend.cpp
deleted file mode 100644
index 5bd55c3..0000000
--- a/lib/Target/DarwinLDBackend.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-//===- DarwinLDBackend.cpp ------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <DarwinLDBackend.h>
-
-using namespace mcld;
-
-//==========================
-// DarwinLDBackend
-
diff --git a/lib/Target/ELFDynamic.cpp b/lib/Target/ELFDynamic.cpp
index 89917cc..aeccd92 100644
--- a/lib/Target/ELFDynamic.cpp
+++ b/lib/Target/ELFDynamic.cpp
@@ -35,10 +35,17 @@ EntryIF::~EntryIF()
ELFDynamic::ELFDynamic(const GNULDBackend& pParent,
const LinkerConfig& pConfig)
: m_pEntryFactory(NULL), m_Backend(pParent), m_Config(pConfig), m_Idx(0) {
- if (m_Config.targets().is32Bits() && m_Config.targets().isLittleEndian()) {
- m_pEntryFactory = new Entry<32, true>();
+ // FIXME: support big-endian machine.
+ if (m_Config.targets().is32Bits()) {
+ if (m_Config.targets().isLittleEndian())
+ m_pEntryFactory = new Entry<32, true>();
+ } else if (m_Config.targets().is64Bits()) {
+ if (m_Config.targets().isLittleEndian())
+ m_pEntryFactory = new Entry<64, true>();
+ } else {
+ fatal(diag::unsupported_bitclass) << m_Config.targets().triple().str()
+ << m_Config.targets().bitclass();
}
- // FIXME: support big-endian and 64-bit machine.
}
@@ -78,7 +85,7 @@ size_t ELFDynamic::entrySize() const
void ELFDynamic::reserveOne(uint64_t pTag)
{
assert(NULL != m_pEntryFactory);
- m_EntryList.push_back(new elf_dynamic::Entry<32, true>());
+ m_EntryList.push_back(m_pEntryFactory->clone());
}
void ELFDynamic::applyOne(uint64_t pTag, uint64_t pValue)
@@ -117,6 +124,10 @@ void ELFDynamic::reserveEntries(const ELFFileFormat& pFormat)
if (pFormat.hasHashTab())
reserveOne(llvm::ELF::DT_HASH); // DT_HASH
+ // FIXME: use llvm enum constant
+ if (pFormat.hasGNUHashTab())
+ reserveOne(0x6ffffef5); // DT_GNU_HASH
+
if (pFormat.hasDynSymTab()) {
reserveOne(llvm::ELF::DT_SYMTAB); // DT_SYMTAB
reserveOne(llvm::ELF::DT_SYMENT); // DT_SYMENT
@@ -149,14 +160,22 @@ void ELFDynamic::reserveEntries(const ELFFileFormat& pFormat)
reserveOne(llvm::ELF::DT_RELAENT); // DT_RELAENT
}
- if (m_Config.options().hasOrigin() ||
- m_Config.options().Bsymbolic() ||
- m_Config.options().hasNow() ||
- m_Backend.hasTextRel() ||
- (m_Backend.hasStaticTLS() &&
- (LinkerConfig::DynObj == m_Config.codeGenType()))) {
+ uint64_t dt_flags = 0x0;
+ if (m_Config.options().hasOrigin())
+ dt_flags |= llvm::ELF::DF_ORIGIN;
+ if (m_Config.options().Bsymbolic())
+ dt_flags |= llvm::ELF::DF_SYMBOLIC;
+ if (m_Config.options().hasNow())
+ dt_flags |= llvm::ELF::DF_BIND_NOW;
+ if (m_Backend.hasTextRel())
+ dt_flags |= llvm::ELF::DF_TEXTREL;
+ if (m_Backend.hasStaticTLS() &&
+ (LinkerConfig::DynObj == m_Config.codeGenType()))
+ dt_flags |= llvm::ELF::DF_STATIC_TLS;
+
+ if ((m_Config.options().hasNewDTags() && 0x0 != dt_flags) ||
+ 0 != (dt_flags & llvm::ELF::DF_STATIC_TLS))
reserveOne(llvm::ELF::DT_FLAGS); // DT_FLAGS
- }
if (m_Backend.hasTextRel())
reserveOne(llvm::ELF::DT_TEXTREL); // DT_TEXTREL
@@ -211,6 +230,10 @@ void ELFDynamic::applyEntries(const ELFFileFormat& pFormat)
if (pFormat.hasHashTab())
applyOne(llvm::ELF::DT_HASH, pFormat.getHashTab().addr()); // DT_HASH
+ // FIXME: use llvm enum constant
+ if (pFormat.hasGNUHashTab())
+ applyOne(0x6ffffef5, pFormat.getGNUHashTab().addr()); // DT_GNU_HASH
+
if (pFormat.hasDynSymTab()) {
applyOne(llvm::ELF::DT_SYMTAB, pFormat.getDynSymTab().addr()); // DT_SYMTAB
applyOne(llvm::ELF::DT_SYMENT, symbolSize()); // DT_SYMENT
@@ -223,15 +246,16 @@ void ELFDynamic::applyEntries(const ELFFileFormat& pFormat)
applyTargetEntries(pFormat); // DT_PLTGOT
- if (pFormat.hasRelPlt())
- applyOne(llvm::ELF::DT_PLTREL, llvm::ELF::DT_REL); // DT_PLTREL
- else if (pFormat.hasRelaPlt())
- applyOne(llvm::ELF::DT_PLTREL, llvm::ELF::DT_RELA); // DT_PLTREL
-
if (pFormat.hasRelPlt()) {
+ applyOne(llvm::ELF::DT_PLTREL, llvm::ELF::DT_REL); // DT_PLTREL
applyOne(llvm::ELF::DT_JMPREL, pFormat.getRelPlt().addr()); // DT_JMPREL
applyOne(llvm::ELF::DT_PLTRELSZ, pFormat.getRelPlt().size()); // DT_PLTRELSZ
}
+ else if (pFormat.hasRelaPlt()) {
+ applyOne(llvm::ELF::DT_PLTREL, llvm::ELF::DT_RELA); // DT_PLTREL
+ applyOne(llvm::ELF::DT_JMPREL, pFormat.getRelaPlt().addr()); // DT_JMPREL
+ applyOne(llvm::ELF::DT_PLTRELSZ, pFormat.getRelaPlt().size()); // DT_PLTRELSZ
+ }
if (pFormat.hasRelDyn()) {
applyOne(llvm::ELF::DT_REL, pFormat.getRelDyn().addr()); // DT_REL
@@ -265,9 +289,10 @@ void ELFDynamic::applyEntries(const ELFFileFormat& pFormat)
if (m_Backend.hasStaticTLS() &&
(LinkerConfig::DynObj == m_Config.codeGenType()))
dt_flags |= llvm::ELF::DF_STATIC_TLS;
- if (0x0 != dt_flags) {
+
+ if ((m_Config.options().hasNewDTags() && 0x0 != dt_flags) ||
+ 0 != (dt_flags & llvm::ELF::DF_STATIC_TLS))
applyOne(llvm::ELF::DT_FLAGS, dt_flags); // DT_FLAGS
- }
uint64_t dt_flags_1 = 0x0;
if (m_Config.options().hasNow())
diff --git a/lib/Target/ELFEmulation.cpp b/lib/Target/ELFEmulation.cpp
index 3bd2094..bdd76aa 100644
--- a/lib/Target/ELFEmulation.cpp
+++ b/lib/Target/ELFEmulation.cpp
@@ -9,6 +9,8 @@
#include <mcld/Target/ELFEmulation.h>
#include <mcld/LinkerConfig.h>
+#include <llvm/Support/Host.h>
+
using namespace mcld;
struct NameMap {
@@ -61,6 +63,7 @@ static const NameMap map[] =
bool mcld::MCLDEmulateELF(LinkerConfig& pConfig)
{
+ // set up section map
if (pConfig.codeGenType() != LinkerConfig::Object) {
const unsigned int map_size = (sizeof(map) / sizeof(map[0]) );
for (unsigned int i = 0; i < map_size; ++i) {
@@ -70,6 +73,18 @@ bool mcld::MCLDEmulateELF(LinkerConfig& pConfig)
return false;
}
}
+
+ if (!pConfig.options().nostdlib()) {
+ // TODO: check if user sets the default search path instead via -Y option
+ // set up default search path
+ if (llvm::Triple::NetBSD == pConfig.targets().triple().getOS()) {
+ pConfig.options().directories().insert("=/usr/lib");
+ }
+ else {
+ pConfig.options().directories().insert("=/lib");
+ pConfig.options().directories().insert("=/usr/lib");
+ }
+ }
return true;
}
diff --git a/lib/Target/GNULDBackend.cpp b/lib/Target/GNULDBackend.cpp
index 590c14f..ef4f1fb 100644
--- a/lib/Target/GNULDBackend.cpp
+++ b/lib/Target/GNULDBackend.cpp
@@ -13,6 +13,7 @@
#include <cassert>
#include <vector>
#include <algorithm>
+#include <map>
#include <mcld/Module.h>
#include <mcld/LinkerConfig.h>
@@ -28,7 +29,6 @@
#include <mcld/LD/RelocData.h>
#include <mcld/LD/RelocationFactory.h>
#include <mcld/MC/Attribute.h>
-#include <mcld/Fragment/FragmentLinker.h>
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MsgHandling.h>
@@ -66,7 +66,6 @@ GNULDBackend::GNULDBackend(const LinkerConfig& pConfig, GNUInfo* pInfo)
m_ELFSegmentTable(9), // magic number
m_pBRIslandFactory(NULL),
m_pStubFactory(NULL),
- m_pEhFrame(NULL),
m_pEhFrameHdr(NULL),
m_bHasTextRel(false),
m_bHasStaticTLS(false),
@@ -97,14 +96,11 @@ GNULDBackend::~GNULDBackend()
delete m_pInfo;
delete m_pDynObjFileFormat;
delete m_pExecFileFormat;
+ delete m_pObjectFileFormat;
delete m_pSymIndexMap;
- delete m_pEhFrame;
delete m_pEhFrameHdr;
-
- if (NULL != m_pBRIslandFactory)
- delete m_pBRIslandFactory;
- if (NULL != m_pStubFactory)
- delete m_pStubFactory;
+ delete m_pBRIslandFactory;
+ delete m_pStubFactory;
}
size_t GNULDBackend::sectionStartOffset() const
@@ -126,16 +122,16 @@ size_t GNULDBackend::sectionStartOffset() const
}
}
-uint64_t GNULDBackend::segmentStartAddr(const FragmentLinker& pLinker) const
+uint64_t GNULDBackend::segmentStartAddr() const
{
ScriptOptions::AddressMap::const_iterator mapping =
config().scripts().addressMap().find(".text");
if (mapping != config().scripts().addressMap().end())
return mapping.getEntry()->value();
- else if (pLinker.isOutputPIC())
+ else if (config().isCodeIndep())
return 0x0;
else
- return defaultTextSegmentAddr();
+ return m_pInfo->defaultTextSegmentAddr();
}
GNUArchiveReader*
@@ -161,26 +157,11 @@ ELFBinaryReader* GNULDBackend::createBinaryReader(IRBuilder& pBuilder)
return new ELFBinaryReader(*this, pBuilder, config());
}
-ELFObjectWriter* GNULDBackend::createObjectWriter()
+ELFObjectWriter* GNULDBackend::createWriter()
{
return new ELFObjectWriter(*this, config());
}
-ELFDynObjWriter* GNULDBackend::createDynObjWriter()
-{
- return new ELFDynObjWriter(*this, config());
-}
-
-ELFExecWriter* GNULDBackend::createExecWriter()
-{
- return new ELFExecWriter(*this, config());
-}
-
-ELFBinaryWriter* GNULDBackend::createBinaryWriter()
-{
- return new ELFBinaryWriter(*this, config());
-}
-
bool GNULDBackend::initStdSections(ObjectBuilder& pBuilder)
{
switch (config().codeGenType()) {
@@ -214,7 +195,7 @@ bool GNULDBackend::initStdSections(ObjectBuilder& pBuilder)
/// initStandardSymbols - define and initialize standard symbols.
/// This function is called after section merging but before read relocations.
-bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
+bool GNULDBackend::initStandardSymbols(IRBuilder& pBuilder,
Module& pModule)
{
if (LinkerConfig::Object == config().codeGenType())
@@ -244,9 +225,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
llvm::StringRef start_name = llvm::StringRef("__start_" + section->name());
FragmentRef* start_fragref = FragmentRef::Create(
section->getSectionData()->front(), 0x0);
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>(start_name,
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ start_name,
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
@@ -258,9 +238,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
llvm::StringRef stop_name = llvm::StringRef("__stop_" + section->name());
FragmentRef* stop_fragref = FragmentRef::Create(
section->getSectionData()->front(), section->size());
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>(stop_name,
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ stop_name,
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
@@ -285,9 +264,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
preinit_array = FragmentRef::Null();
}
f_pPreInitArrayStart =
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>("__preinit_array_start",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "__preinit_array_start",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
@@ -296,9 +274,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
preinit_array, // FragRef
ResolveInfo::Hidden);
f_pPreInitArrayEnd =
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>("__preinit_array_end",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "__preinit_array_end",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
@@ -319,9 +296,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
}
f_pInitArrayStart =
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>("__init_array_start",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "__init_array_start",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
@@ -330,9 +306,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
init_array, // FragRef
ResolveInfo::Hidden);
f_pInitArrayEnd =
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>("__init_array_end",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "__init_array_end",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
@@ -353,9 +328,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
}
f_pFiniArrayStart =
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>("__fini_array_start",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "__fini_array_start",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
@@ -364,9 +338,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
fini_array, // FragRef
ResolveInfo::Hidden);
f_pFiniArrayEnd =
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>("__fini_array_end",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "__fini_array_end",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
@@ -387,9 +360,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
}
f_pStack =
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>("__stack",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "__stack",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
@@ -402,9 +374,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
// TODO: add SectionData for .dynamic section, and then we can get the correct
// symbol section index for _DYNAMIC. Now it will be ABS.
f_pDynamic =
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>("_DYNAMIC",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "_DYNAMIC",
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Local,
@@ -415,9 +386,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
// ----- segment symbols ----- //
f_pExecutableStart =
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>("__executable_start",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "__executable_start",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
@@ -426,9 +396,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
f_pEText =
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>("etext",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "etext",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
@@ -437,9 +406,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
f_p_EText =
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>("_etext",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "_etext",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
@@ -448,9 +416,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
f_p__EText =
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>("__etext",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "__etext",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
@@ -459,9 +426,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
f_pEData =
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>("edata",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "edata",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
@@ -471,9 +437,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
ResolveInfo::Default);
f_pEnd =
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>("end",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "end",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
@@ -485,9 +450,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
// _edata is defined forcefully.
// @ref Google gold linker: defstd.cc: 186
f_p_EData =
- pLinker.defineSymbol<FragmentLinker::Force,
- FragmentLinker::Resolve>("_edata",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
+ "_edata",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
@@ -499,9 +463,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
// __bss_start is defined forcefully.
// @ref Google gold linker: defstd.cc: 214
f_pBSSStart =
- pLinker.defineSymbol<FragmentLinker::Force,
- FragmentLinker::Resolve>("__bss_start",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
+ "__bss_start",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
@@ -513,9 +476,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
// _end is defined forcefully.
// @ref Google gold linker: defstd.cc: 228
f_p_End =
- pLinker.defineSymbol<FragmentLinker::Force,
- FragmentLinker::Resolve>("_end",
- false, // isDyn
+ pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
+ "_end",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
@@ -527,8 +489,7 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker,
return true;
}
-bool
-GNULDBackend::finalizeStandardSymbols(FragmentLinker& pLinker)
+bool GNULDBackend::finalizeStandardSymbols()
{
if (LinkerConfig::Object == config().codeGenType())
return true;
@@ -752,7 +713,6 @@ const ELFFileFormat* GNULDBackend::getOutputFormat() const
}
void GNULDBackend::partialScanRelocation(Relocation& pReloc,
- FragmentLinker& pLinker,
Module& pModule,
const LDSection& pSection)
{
@@ -778,8 +738,7 @@ void GNULDBackend::partialScanRelocation(Relocation& pReloc,
/// sizeNamePools - compute the size of regular name pools
/// In ELF executable files, regular name pools are .symtab, .strtab,
/// .dynsym, .dynstr, .hash and .shstrtab.
-void
-GNULDBackend::sizeNamePools(const Module& pModule, bool pIsStaticLink)
+void GNULDBackend::sizeNamePools(Module& pModule, bool pIsStaticLink)
{
// number of entries in symbol tables starts from 1 to hold the special entry
// at index 0 (STN_UNDEF). See ELF Spec Book I, p1-21.
@@ -788,112 +747,118 @@ GNULDBackend::sizeNamePools(const Module& pModule, bool pIsStaticLink)
// size of string tables starts from 1 to hold the null character in their
// first byte
- size_t strtab = 1;
- size_t dynstr = pIsStaticLink ? 0 : 1;
+ size_t strtab = 1;
+ size_t dynstr = pIsStaticLink ? 0 : 1;
size_t shstrtab = 1;
- size_t hash = 0;
+ size_t hash = 0;
+ size_t gnuhash = 0;
- // number of local symbol in the .dynsym
+ // number of local symbol in the .symtab and .dynsym
+ size_t symtab_local_cnt = 0;
size_t dynsym_local_cnt = 0;
- /// compute the size of .symtab, .dynsym and .strtab
+ Module::SymbolTable& symbols = pModule.getSymbolTable();
+ Module::const_sym_iterator symbol, symEnd;
+ /// Compute the size of .symtab, .strtab, and symtab_local_cnt
/// @{
- Module::const_sym_iterator symbol;
- const Module::SymbolTable& symbols = pModule.getSymbolTable();
- size_t str_size = 0;
- // compute the size of symbols in Local and File category
- Module::const_sym_iterator symEnd = symbols.localEnd();
- for (symbol = symbols.localBegin(); symbol != symEnd; ++symbol) {
- str_size = (*symbol)->nameSize() + 1;
- if (!pIsStaticLink && isDynamicSymbol(**symbol)) {
- ++dynsym;
- if (ResolveInfo::Section != (*symbol)->type())
- dynstr += str_size;
- }
+ symEnd = symbols.end();
+ for (symbol = symbols.begin(); symbol != symEnd; ++symbol) {
++symtab;
if (ResolveInfo::Section != (*symbol)->type())
- strtab += str_size;
- }
- // compute the size of symbols in TLS category
- symEnd = symbols.tlsEnd();
- for (symbol = symbols.tlsBegin(); symbol != symEnd; ++symbol) {
- str_size = (*symbol)->nameSize() + 1;
- if (!pIsStaticLink) {
- ++dynsym;
- if (ResolveInfo::Section != (*symbol)->type())
- dynstr += str_size;
- }
- ++symtab;
- if (ResolveInfo::Section != (*symbol)->type())
- strtab += str_size;
- }
- dynsym_local_cnt = dynsym;
- // compute the size of the reset of symbols
- symEnd = pModule.sym_end();
- for (symbol = symbols.tlsEnd(); symbol != symEnd; ++symbol) {
- str_size = (*symbol)->nameSize() + 1;
- if (!pIsStaticLink && isDynamicSymbol(**symbol)) {
- ++dynsym;
- if (ResolveInfo::Section != (*symbol)->type())
- dynstr += str_size;
- }
- ++symtab;
- if (ResolveInfo::Section != (*symbol)->type())
- strtab += str_size;
+ strtab += (*symbol)->nameSize() + 1;
}
+ symtab_local_cnt = 1 + symbols.numOfFiles() + symbols.numOfLocals() +
+ symbols.numOfLocalDyns();
ELFFileFormat* file_format = getOutputFormat();
switch(config().codeGenType()) {
- // compute size of .dynstr and .hash
case LinkerConfig::DynObj: {
// soname
- if (!pIsStaticLink)
- dynstr += pModule.name().size() + 1;
+ dynstr += pModule.name().size() + 1;
}
/** fall through **/
case LinkerConfig::Exec:
case LinkerConfig::Binary: {
- // add DT_NEED strings into .dynstr and .dynamic
- // Rules:
- // 1. ignore --no-add-needed
- // 2. force count in --no-as-needed
- // 3. judge --as-needed
if (!pIsStaticLink) {
- Module::const_lib_iterator lib, libEnd = pModule.lib_end();
- for (lib = pModule.lib_begin(); lib != libEnd; ++lib) {
- // --add-needed
- if ((*lib)->attribute()->isAddNeeded()) {
- // --no-as-needed
- if (!(*lib)->attribute()->isAsNeeded()) {
- dynstr += (*lib)->name().size() + 1;
- dynamic().reserveNeedEntry();
- }
- // --as-needed
- else if ((*lib)->isNeeded()) {
- dynstr += (*lib)->name().size() + 1;
- dynamic().reserveNeedEntry();
- }
+ /// Compute the size of .dynsym, .dynstr, and dynsym_local_cnt
+ symEnd = symbols.dynamicEnd();
+ for (symbol = symbols.localDynBegin(); symbol != symEnd; ++symbol) {
+ ++dynsym;
+ if (ResolveInfo::Section != (*symbol)->type())
+ dynstr += (*symbol)->nameSize() + 1;
+ }
+ dynsym_local_cnt = 1 + symbols.numOfLocalDyns();
+
+ // compute .gnu.hash
+ if (GeneralOptions::GNU == config().options().getHashStyle() ||
+ GeneralOptions::Both == config().options().getHashStyle()) {
+ // count the number of dynsym to hash
+ size_t hashed_sym_cnt = 0;
+ symEnd = symbols.dynamicEnd();
+ for (symbol = symbols.dynamicBegin(); symbol != symEnd; ++symbol) {
+ if (DynsymCompare().needGNUHash(**symbol))
+ ++hashed_sym_cnt;
+ }
+ // Special case for empty .dynsym
+ if (hashed_sym_cnt == 0)
+ gnuhash = 5 * 4 + config().targets().bitclass() / 8;
+ else {
+ size_t nbucket = getHashBucketCount(hashed_sym_cnt, true);
+ gnuhash = (4 + nbucket + hashed_sym_cnt) * 4;
+ gnuhash += (1U << getGNUHashMaskbitslog2(hashed_sym_cnt)) / 8;
}
}
// compute .hash
- // Both Elf32_Word and Elf64_Word are 4 bytes
- hash = (2 + getHashBucketCount(dynsym, false) + dynsym) *
- sizeof(llvm::ELF::Elf32_Word);
- }
+ if (GeneralOptions::SystemV == config().options().getHashStyle() ||
+ GeneralOptions::Both == config().options().getHashStyle()) {
+ // Both Elf32_Word and Elf64_Word are 4 bytes
+ hash = (2 + getHashBucketCount(dynsym, false) + dynsym) *
+ sizeof(llvm::ELF::Elf32_Word);
+ }
- // set size
- if (config().targets().is32Bits())
- file_format->getDynSymTab().setSize(dynsym*sizeof(llvm::ELF::Elf32_Sym));
- else
- file_format->getDynSymTab().setSize(dynsym*sizeof(llvm::ELF::Elf64_Sym));
- file_format->getDynStrTab().setSize(dynstr);
- file_format->getHashTab().setSize(hash);
+ // add DT_NEEDED
+ Module::const_lib_iterator lib, libEnd = pModule.lib_end();
+ for (lib = pModule.lib_begin(); lib != libEnd; ++lib) {
+ if (!(*lib)->attribute()->isAsNeeded() || (*lib)->isNeeded()) {
+ dynstr += (*lib)->name().size() + 1;
+ dynamic().reserveNeedEntry();
+ }
+ }
- // set .dynsym sh_info to one greater than the symbol table
- // index of the last local symbol
- file_format->getDynSymTab().setInfo(dynsym_local_cnt);
+ // add DT_RPATH
+ if (!config().options().getRpathList().empty()) {
+ dynamic().reserveNeedEntry();
+ GeneralOptions::const_rpath_iterator rpath,
+ rpathEnd = config().options().rpath_end();
+ for (rpath = config().options().rpath_begin();
+ rpath != rpathEnd; ++rpath)
+ dynstr += (*rpath).size() + 1;
+ }
+
+ // set size
+ if (config().targets().is32Bits()) {
+ file_format->getDynSymTab().setSize(dynsym *
+ sizeof(llvm::ELF::Elf32_Sym));
+ } else {
+ file_format->getDynSymTab().setSize(dynsym *
+ sizeof(llvm::ELF::Elf64_Sym));
+ }
+ file_format->getDynStrTab().setSize(dynstr);
+ file_format->getHashTab().setSize(hash);
+ file_format->getGNUHashTab().setSize(gnuhash);
+
+ // set .dynsym sh_info to one greater than the symbol table
+ // index of the last local symbol
+ file_format->getDynSymTab().setInfo(dynsym_local_cnt);
+
+ // Because some entries in .dynamic section need information of .dynsym,
+ // .dynstr, .symtab, .strtab and .hash, we can not reserve non-DT_NEEDED
+ // entries until we get the size of the sections mentioned above
+ dynamic().reserveEntries(*file_format);
+ file_format->getDynamic().setSize(dynamic().numOfBytes());
+ }
}
/* fall through */
case LinkerConfig::Object: {
@@ -905,41 +870,46 @@ GNULDBackend::sizeNamePools(const Module& pModule, bool pIsStaticLink)
// set .symtab sh_info to one greater than the symbol table
// index of the last local symbol
- file_format->getSymTab().setInfo(symbols.numOfLocals() + 1);
+ file_format->getSymTab().setInfo(symtab_local_cnt);
+
+ // compute the size of .shstrtab section.
+ Module::const_iterator sect, sectEnd = pModule.end();
+ for (sect = pModule.begin(); sect != sectEnd; ++sect) {
+ switch ((*sect)->kind()) {
+ case LDFileFormat::Null:
+ break;
+ // take StackNote directly
+ case LDFileFormat::StackNote:
+ shstrtab += ((*sect)->name().size() + 1);
+ break;
+ case LDFileFormat::EhFrame:
+ if (((*sect)->size() != 0) ||
+ ((*sect)->hasEhFrame() &&
+ config().codeGenType() == LinkerConfig::Object))
+ shstrtab += ((*sect)->name().size() + 1);
+ break;
+ case LDFileFormat::Relocation:
+ if (((*sect)->size() != 0) ||
+ ((*sect)->hasRelocData() &&
+ config().codeGenType() == LinkerConfig::Object))
+ shstrtab += ((*sect)->name().size() + 1);
+ break;
+ default:
+ if (((*sect)->size() != 0) ||
+ ((*sect)->hasSectionData() &&
+ config().codeGenType() == LinkerConfig::Object))
+ shstrtab += ((*sect)->name().size() + 1);
+ break;
+ } // end of switch
+ } // end of for
+ shstrtab += (strlen(".shstrtab") + 1);
+ file_format->getShStrTab().setSize(shstrtab);
break;
}
default:
fatal(diag::fatal_illegal_codegen_type) << pModule.name();
break;
} // end of switch
- /// @}
-
- /// reserve fixed entries in the .dynamic section.
- /// @{
- if (LinkerConfig::DynObj == config().codeGenType() ||
- LinkerConfig::Exec == config().codeGenType() ||
- LinkerConfig::Binary == config().codeGenType()) {
- // Because some entries in .dynamic section need information of .dynsym,
- // .dynstr, .symtab, .strtab and .hash, we can not reserve non-DT_NEEDED
- // entries until we get the size of the sections mentioned above
- if (!pIsStaticLink)
- dynamic().reserveEntries(*file_format);
- file_format->getDynamic().setSize(dynamic().numOfBytes());
- }
- /// @}
-
- /// compute the size of .shstrtab section.
- /// @{
- Module::const_iterator sect, sectEnd = pModule.end();
- for (sect = pModule.begin(); sect != sectEnd; ++sect) {
- // StackNote sections will always be in output!
- if (0 != (*sect)->size() || LDFileFormat::StackNote == (*sect)->kind()) {
- shstrtab += ((*sect)->name().size() + 1);
- }
- }
- shstrtab += (strlen(".shstrtab") + 1);
- file_format->getShStrTab().setSize(shstrtab);
- /// @}
}
/// emitSymbol32 - emit an ELF32 symbol
@@ -974,14 +944,19 @@ void GNULDBackend::emitSymbol64(llvm::ELF::Elf64_Sym& pSym,
{
// FIXME: check the endian between host and target
// write out symbol
+ if (ResolveInfo::Section != pSymbol.type()) {
+ pSym.st_name = pStrtabsize;
+ strcpy((pStrtab + pStrtabsize), pSymbol.name());
+ }
+ else {
+ pSym.st_name = 0;
+ }
pSym.st_name = pStrtabsize;
pSym.st_value = pSymbol.value();
pSym.st_size = getSymbolSize(pSymbol);
pSym.st_info = getSymbolInfo(pSymbol);
pSym.st_other = pSymbol.visibility();
pSym.st_shndx = getSymbolShndx(pSymbol);
- // write out string
- strcpy((pStrtab + pStrtabsize), pSymbol.name());
}
/// emitRegNamePools - emit regular name pools - .symtab, .strtab
@@ -1015,54 +990,37 @@ void GNULDBackend::emitRegNamePools(const Module& pModule,
// set up strtab_region
char* strtab = (char*)strtab_region->start();
- strtab[0] = '\0';
- // initialize the first ELF symbol
- if (config().targets().is32Bits()) {
- symtab32[0].st_name = 0;
- symtab32[0].st_value = 0;
- symtab32[0].st_size = 0;
- symtab32[0].st_info = 0;
- symtab32[0].st_other = 0;
- symtab32[0].st_shndx = 0;
- }
- else { // must 64
- symtab64[0].st_name = 0;
- symtab64[0].st_value = 0;
- symtab64[0].st_size = 0;
- symtab64[0].st_info = 0;
- symtab64[0].st_other = 0;
- symtab64[0].st_shndx = 0;
- }
+ // emit the first ELF symbol
+ if (config().targets().is32Bits())
+ emitSymbol32(symtab32[0], *LDSymbol::Null(), strtab, 0, 0);
+ else
+ emitSymbol64(symtab64[0], *LDSymbol::Null(), strtab, 0, 0);
bool sym_exist = false;
HashTableType::entry_type* entry = NULL;
if (LinkerConfig::Object == config().codeGenType()) {
- entry = m_pSymIndexMap->insert(NULL, sym_exist);
+ entry = m_pSymIndexMap->insert(LDSymbol::Null(), sym_exist);
entry->setValue(0);
}
- size_t symtabIdx = 1;
+ size_t symIdx = 1;
size_t strtabsize = 1;
- // compute size of .symtab, .dynsym and .strtab
- Module::const_sym_iterator symbol;
- Module::const_sym_iterator symEnd = pModule.sym_end();
- for (symbol = pModule.sym_begin(); symbol != symEnd; ++symbol) {
- // maintain output's symbol and index map if building .o file
+
+ const Module::SymbolTable& symbols = pModule.getSymbolTable();
+ Module::const_sym_iterator symbol, symEnd;
+
+ symEnd = symbols.end();
+ for (symbol = symbols.begin(); symbol != symEnd; ++symbol) {
if (LinkerConfig::Object == config().codeGenType()) {
entry = m_pSymIndexMap->insert(*symbol, sym_exist);
- entry->setValue(symtabIdx);
+ entry->setValue(symIdx);
}
-
if (config().targets().is32Bits())
- emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize,
- symtabIdx);
+ emitSymbol32(symtab32[symIdx], **symbol, strtab, strtabsize, symIdx);
else
- emitSymbol64(symtab64[symtabIdx], **symbol, strtab, strtabsize,
- symtabIdx);
-
- // sum up counters
- ++symtabIdx;
+ emitSymbol64(symtab64[symIdx], **symbol, strtab, strtabsize, symIdx);
+ ++symIdx;
if (ResolveInfo::Section != (*symbol)->type())
strtabsize += (*symbol)->nameSize() + 1;
}
@@ -1072,13 +1030,11 @@ void GNULDBackend::emitRegNamePools(const Module& pModule,
///
/// the size of these tables should be computed before layout
/// layout should computes the start offset of these tables
-void GNULDBackend::emitDynNamePools(const Module& pModule,
- MemoryArea& pOutput)
+void GNULDBackend::emitDynNamePools(Module& pModule, MemoryArea& pOutput)
{
ELFFileFormat* file_format = getOutputFormat();
if (!file_format->hasDynSymTab() ||
!file_format->hasDynStrTab() ||
- !file_format->hasHashTab() ||
!file_format->hasDynamic())
return;
@@ -1087,15 +1043,12 @@ void GNULDBackend::emitDynNamePools(const Module& pModule,
LDSection& symtab_sect = file_format->getDynSymTab();
LDSection& strtab_sect = file_format->getDynStrTab();
- LDSection& hash_sect = file_format->getHashTab();
LDSection& dyn_sect = file_format->getDynamic();
MemoryRegion* symtab_region = pOutput.request(symtab_sect.offset(),
symtab_sect.size());
MemoryRegion* strtab_region = pOutput.request(strtab_sect.offset(),
strtab_sect.size());
- MemoryRegion* hash_region = pOutput.request(hash_sect.offset(),
- hash_sect.size());
MemoryRegion* dyn_region = pOutput.request(dyn_sect.offset(),
dyn_sect.size());
// set up symtab_region
@@ -1110,125 +1063,76 @@ void GNULDBackend::emitDynNamePools(const Module& pModule,
<< config().targets().bitclass();
}
- // initialize the first ELF symbol
- if (config().targets().is32Bits()) {
- symtab32[0].st_name = 0;
- symtab32[0].st_value = 0;
- symtab32[0].st_size = 0;
- symtab32[0].st_info = 0;
- symtab32[0].st_other = 0;
- symtab32[0].st_shndx = 0;
- }
- else { // must 64
- symtab64[0].st_name = 0;
- symtab64[0].st_value = 0;
- symtab64[0].st_size = 0;
- symtab64[0].st_info = 0;
- symtab64[0].st_other = 0;
- symtab64[0].st_shndx = 0;
- }
// set up strtab_region
char* strtab = (char*)strtab_region->start();
- strtab[0] = '\0';
- // add the first symbol into m_pSymIndexMap
- entry = m_pSymIndexMap->insert(NULL, sym_exist);
- entry->setValue(0);
+ // emit the first ELF symbol
+ if (config().targets().is32Bits())
+ emitSymbol32(symtab32[0], *LDSymbol::Null(), strtab, 0, 0);
+ else
+ emitSymbol64(symtab64[0], *LDSymbol::Null(), strtab, 0, 0);
- size_t symtabIdx = 1;
+ size_t symIdx = 1;
size_t strtabsize = 1;
- // emit of .dynsym, and .dynstr
- Module::const_sym_iterator symbol;
- const Module::SymbolTable& symbols = pModule.getSymbolTable();
- // emit symbol in File and Local category if it's dynamic symbol
- Module::const_sym_iterator symEnd = symbols.localEnd();
- for (symbol = symbols.localBegin(); symbol != symEnd; ++symbol) {
- if (!isDynamicSymbol(**symbol))
- continue;
-
+ Module::SymbolTable& symbols = pModule.getSymbolTable();
+ // emit .gnu.hash
+ if (GeneralOptions::GNU == config().options().getHashStyle() ||
+ GeneralOptions::Both == config().options().getHashStyle()) {
+ // Currently we may add output symbols after sizeNamePools(), and a
+ // non-stable sort is used in SymbolCategory::arrange(), so we just
+ // sort .dynsym right before emitting .gnu.hash
+ std::stable_sort(symbols.dynamicBegin(), symbols.dynamicEnd(),
+ DynsymCompare());
+ emitGNUHashTab(symbols, pOutput);
+ }
+ // emit .hash
+ if (GeneralOptions::SystemV == config().options().getHashStyle() ||
+ GeneralOptions::Both == config().options().getHashStyle())
+ emitELFHashTab(symbols, pOutput);
+
+ // emit .dynsym, and .dynstr (emit LocalDyn and Dynamic category)
+ Module::const_sym_iterator symbol, symEnd = symbols.dynamicEnd();
+ for (symbol = symbols.localDynBegin(); symbol != symEnd; ++symbol) {
if (config().targets().is32Bits())
- emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize,
- symtabIdx);
+ emitSymbol32(symtab32[symIdx], **symbol, strtab, strtabsize, symIdx);
else
- emitSymbol64(symtab64[symtabIdx], **symbol, strtab, strtabsize,
- symtabIdx);
-
+ emitSymbol64(symtab64[symIdx], **symbol, strtab, strtabsize, symIdx);
// maintain output's symbol and index map
entry = m_pSymIndexMap->insert(*symbol, sym_exist);
- entry->setValue(symtabIdx);
+ entry->setValue(symIdx);
// sum up counters
- ++symtabIdx;
- if (ResolveInfo::Section != (*symbol)->type())
- strtabsize += (*symbol)->nameSize() + 1;
- }
-
- // emit symbols in TLS category, all symbols in TLS category shold be emitited
- symEnd = symbols.tlsEnd();
- for (symbol = symbols.tlsBegin(); symbol != symEnd; ++symbol) {
- if (config().targets().is32Bits())
- emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize,
- symtabIdx);
- else
- emitSymbol64(symtab64[symtabIdx], **symbol, strtab, strtabsize,
- symtabIdx);
-
- // maintain output's symbol and index map
- entry = m_pSymIndexMap->insert(*symbol, sym_exist);
- entry->setValue(symtabIdx);
- // sum up counters
- ++symtabIdx;
- if (ResolveInfo::Section != (*symbol)->type())
- strtabsize += (*symbol)->nameSize() + 1;
- }
-
- // emit the reset of the symbols if the symbol is dynamic symbol
- symEnd = pModule.sym_end();
- for (symbol = symbols.tlsEnd(); symbol != symEnd; ++symbol) {
- if (!isDynamicSymbol(**symbol))
- continue;
-
- if (config().targets().is32Bits())
- emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize,
- symtabIdx);
- else
- emitSymbol64(symtab64[symtabIdx], **symbol, strtab, strtabsize,
- symtabIdx);
-
- // maintain output's symbol and index map
- entry = m_pSymIndexMap->insert(*symbol, sym_exist);
- entry->setValue(symtabIdx);
- // sum up counters
- ++symtabIdx;
+ ++symIdx;
if (ResolveInfo::Section != (*symbol)->type())
strtabsize += (*symbol)->nameSize() + 1;
}
// emit DT_NEED
// add DT_NEED strings into .dynstr
- // Rules:
- // 1. ignore --no-add-needed
- // 2. force count in --no-as-needed
- // 3. judge --as-needed
ELFDynamic::iterator dt_need = dynamic().needBegin();
Module::const_lib_iterator lib, libEnd = pModule.lib_end();
for (lib = pModule.lib_begin(); lib != libEnd; ++lib) {
- // --add-needed
- if ((*lib)->attribute()->isAddNeeded()) {
- // --no-as-needed
- if (!(*lib)->attribute()->isAsNeeded()) {
- strcpy((strtab + strtabsize), (*lib)->name().c_str());
- (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
- strtabsize += (*lib)->name().size() + 1;
- ++dt_need;
- }
- // --as-needed
- else if ((*lib)->isNeeded()) {
- strcpy((strtab + strtabsize), (*lib)->name().c_str());
- (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
- strtabsize += (*lib)->name().size() + 1;
- ++dt_need;
- }
+ if (!(*lib)->attribute()->isAsNeeded() || (*lib)->isNeeded()) {
+ strcpy((strtab + strtabsize), (*lib)->name().c_str());
+ (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
+ strtabsize += (*lib)->name().size() + 1;
+ ++dt_need;
+ }
+ }
+
+ if (!config().options().getRpathList().empty()) {
+ if (!config().options().hasNewDTags())
+ (*dt_need)->setValue(llvm::ELF::DT_RPATH, strtabsize);
+ else
+ (*dt_need)->setValue(llvm::ELF::DT_RUNPATH, strtabsize);
+ ++dt_need;
+
+ GeneralOptions::const_rpath_iterator rpath,
+ rpathEnd = config().options().rpath_end();
+ for (rpath = config().options().rpath_begin(); rpath != rpathEnd; ++rpath) {
+ memcpy((strtab + strtabsize), (*rpath).data(), (*rpath).size());
+ strtabsize += (*rpath).size();
+ strtab[strtabsize++] = (rpath + 1 == rpathEnd ? '\0' : ':');
}
}
@@ -1245,18 +1149,27 @@ void GNULDBackend::emitDynNamePools(const Module& pModule,
strcpy((strtab + strtabsize), pModule.name().c_str());
strtabsize += pModule.name().size() + 1;
}
- // emit hash table
- // FIXME: this verion only emit SVR4 hash section.
- // Please add GNU new hash section
+}
+/// emitELFHashTab - emit .hash
+void GNULDBackend::emitELFHashTab(const Module::SymbolTable& pSymtab,
+ MemoryArea& pOutput)
+{
+ ELFFileFormat* file_format = getOutputFormat();
+ if (!file_format->hasHashTab())
+ return;
+ LDSection& hash_sect = file_format->getHashTab();
+ MemoryRegion* hash_region = pOutput.request(hash_sect.offset(),
+ hash_sect.size());
// both 32 and 64 bits hash table use 32-bit entry
// set up hash_region
uint32_t* word_array = (uint32_t*)hash_region->start();
uint32_t& nbucket = word_array[0];
uint32_t& nchain = word_array[1];
- nbucket = getHashBucketCount(symtabIdx, false);
- nchain = symtabIdx;
+ size_t dynsymSize = 1 + pSymtab.numOfLocalDyns() + pSymtab.numOfDynamics();
+ nbucket = getHashBucketCount(dynsymSize, false);
+ nchain = dynsymSize;
uint32_t* bucket = (word_array + 2);
uint32_t* chain = (bucket + nbucket);
@@ -1266,21 +1179,140 @@ void GNULDBackend::emitDynNamePools(const Module& pModule,
StringHash<ELF> hash_func;
- if (config().targets().is32Bits()) {
- for (size_t sym_idx=0; sym_idx < symtabIdx; ++sym_idx) {
- llvm::StringRef name(strtab + symtab32[sym_idx].st_name);
- size_t bucket_pos = hash_func(name) % nbucket;
- chain[sym_idx] = bucket[bucket_pos];
- bucket[bucket_pos] = sym_idx;
+ size_t idx = 1;
+ Module::const_sym_iterator symbol, symEnd = pSymtab.dynamicEnd();
+ for (symbol = pSymtab.localDynBegin(); symbol != symEnd; ++symbol) {
+ llvm::StringRef name((*symbol)->name());
+ size_t bucket_pos = hash_func(name) % nbucket;
+ chain[idx] = bucket[bucket_pos];
+ bucket[bucket_pos] = idx;
+ ++idx;
+ }
+}
+
+/// emitGNUHashTab - emit .gnu.hash
+void GNULDBackend::emitGNUHashTab(Module::SymbolTable& pSymtab,
+ MemoryArea& pOutput)
+{
+ ELFFileFormat* file_format = getOutputFormat();
+ if (!file_format->hasGNUHashTab())
+ return;
+
+ MemoryRegion* gnuhash_region =
+ pOutput.request(file_format->getGNUHashTab().offset(),
+ file_format->getGNUHashTab().size());
+
+ uint32_t* word_array = (uint32_t*)gnuhash_region->start();
+ // fixed-length fields
+ uint32_t& nbucket = word_array[0];
+ uint32_t& symidx = word_array[1];
+ uint32_t& maskwords = word_array[2];
+ uint32_t& shift2 = word_array[3];
+ // variable-length fields
+ uint8_t* bitmask = (uint8_t*)(word_array + 4);
+ uint32_t* bucket = NULL;
+ uint32_t* chain = NULL;
+
+ // count the number of dynsym to hash
+ size_t unhashed_sym_cnt = pSymtab.numOfLocalDyns();
+ size_t hashed_sym_cnt = pSymtab.numOfDynamics();
+ Module::const_sym_iterator symbol, symEnd = pSymtab.dynamicEnd();
+ for (symbol = pSymtab.dynamicBegin(); symbol != symEnd; ++symbol) {
+ if (DynsymCompare().needGNUHash(**symbol))
+ break;
+ ++unhashed_sym_cnt;
+ --hashed_sym_cnt;
+ }
+
+ // special case for the empty hash table
+ if (hashed_sym_cnt == 0) {
+ nbucket = 1; // one empty bucket
+ symidx = 1 + unhashed_sym_cnt; // symidx above unhashed symbols
+ maskwords = 1; // bitmask length
+ shift2 = 0; // bloom filter
+
+ if (config().targets().is32Bits()) {
+ uint32_t* maskval = (uint32_t*)bitmask;
+ *maskval = 0; // no valid hashes
+ } else {
+ // must be 64
+ uint64_t* maskval = (uint64_t*)bitmask;
+ *maskval = 0; // no valid hashes
}
+ bucket = (uint32_t*)(bitmask + config().targets().bitclass() / 8);
+ *bucket = 0; // no hash in the only bucket
+ return;
}
- else if (config().targets().is64Bits()) {
- for (size_t sym_idx=0; sym_idx < symtabIdx; ++sym_idx) {
- llvm::StringRef name(strtab + symtab64[sym_idx].st_name);
- size_t bucket_pos = hash_func(name) % nbucket;
- chain[sym_idx] = bucket[bucket_pos];
- bucket[bucket_pos] = sym_idx;
+
+ uint32_t maskbitslog2 = getGNUHashMaskbitslog2(hashed_sym_cnt);
+ uint32_t maskbits = 1u << maskbitslog2;
+ uint32_t shift1 = config().targets().is32Bits() ? 5 : 6;
+ uint32_t mask = (1u << shift1) - 1;
+
+ nbucket = getHashBucketCount(hashed_sym_cnt, true);
+ symidx = 1 + unhashed_sym_cnt;
+ maskwords = 1 << (maskbitslog2 - shift1);
+ shift2 = maskbitslog2;
+
+ // setup bucket and chain
+ bucket = (uint32_t*)(bitmask + maskbits / 8);
+ chain = (bucket + nbucket);
+
+ // build the gnu style hash table
+ typedef std::multimap<uint32_t,
+ std::pair<LDSymbol*, uint32_t> > SymMapType;
+ SymMapType symmap;
+ symEnd = pSymtab.dynamicEnd();
+ for (symbol = pSymtab.localDynBegin() + symidx - 1; symbol != symEnd;
+ ++symbol) {
+ StringHash<DJB> hasher;
+ uint32_t djbhash = hasher((*symbol)->name());
+ uint32_t hash = djbhash % nbucket;
+ symmap.insert(std::make_pair(hash, std::make_pair(*symbol, djbhash)));
+ }
+
+ // compute bucket, chain, and bitmask
+ std::vector<uint64_t> bitmasks(maskwords);
+ size_t hashedidx = symidx;
+ for (size_t idx = 0; idx < nbucket; ++idx) {
+ size_t count = 0;
+ std::pair<SymMapType::iterator, SymMapType::iterator> ret;
+ ret = symmap.equal_range(idx);
+ for (SymMapType::iterator it = ret.first; it != ret.second; ) {
+ // rearrange the hashed symbol ordering
+ *(pSymtab.localDynBegin() + hashedidx - 1) = it->second.first;
+ uint32_t djbhash = it->second.second;
+ uint32_t val = ((djbhash >> shift1) & ((maskbits >> shift1) - 1));
+ bitmasks[val] |= 1u << (djbhash & mask);
+ bitmasks[val] |= 1u << ((djbhash >> shift2) & mask);
+ val = djbhash & ~1u;
+ // advance the iterator and check if we're dealing w/ the last elment
+ if (++it == ret.second) {
+ // last element terminates the chain
+ val |= 1;
+ }
+ chain[hashedidx - symidx] = val;
+
+ ++hashedidx;
+ ++count;
}
+
+ if (count == 0)
+ bucket[idx] = 0;
+ else
+ bucket[idx] = hashedidx - count;
+ }
+
+ // write the bitmasks
+ if (config().targets().is32Bits()) {
+ uint32_t* maskval = (uint32_t*)bitmask;
+ for (size_t i = 0; i < maskwords; ++i)
+ std::memcpy(maskval + i, &bitmasks[i], 4);
+ } else {
+ // must be 64
+ uint64_t* maskval = (uint64_t*)bitmask;
+ for (size_t i = 0; i < maskwords; ++i)
+ std::memcpy(maskval + i, &bitmasks[i], 8);
}
}
@@ -1291,7 +1323,7 @@ void GNULDBackend::sizeInterp()
if (config().options().hasDyld())
dyld_name = config().options().dyld().c_str();
else
- dyld_name = dyld();
+ dyld_name = m_pInfo->dyld();
LDSection& interp = getOutputFormat()->getInterp();
interp.setSize(std::strlen(dyld_name) + 1);
@@ -1307,7 +1339,7 @@ void GNULDBackend::emitInterp(MemoryArea& pOutput)
if (config().options().hasDyld())
dyld_name = config().options().dyld().c_str();
else
- dyld_name = dyld();
+ dyld_name = m_pInfo->dyld();
std::memcpy(region->start(), dyld_name, interp.size());
}
@@ -1381,9 +1413,14 @@ unsigned int GNULDBackend::getSectionOrder(const LDSection& pSectHdr) const
case LDFileFormat::Target:
return getTargetSectionOrder(pSectHdr);
- // handle .interp
+ // handle .interp and .note.* sections
case LDFileFormat::Note:
- return SHO_INTERP;
+ if (file_format->hasInterp() && (&pSectHdr == &file_format->getInterp()))
+ return SHO_INTERP;
+ else if (is_write)
+ return SHO_RW_NOTE;
+ else
+ return SHO_RO_NOTE;
case LDFileFormat::EhFrame:
case LDFileFormat::EhFrameHdr:
@@ -1456,7 +1493,8 @@ GNULDBackend::getSymbolShndx(const LDSymbol& pSymbol) const
if (pSymbol.resolveInfo()->isUndef() || pSymbol.isDyn())
return llvm::ELF::SHN_UNDEF;
- if (pSymbol.resolveInfo()->isLocal()) {
+ if (pSymbol.resolveInfo()->isLocal() &&
+ LinkerConfig::Object != config().codeGenType()) {
switch (pSymbol.type()) {
case ResolveInfo::NoType:
case ResolveInfo::File:
@@ -1472,12 +1510,43 @@ GNULDBackend::getSymbolShndx(const LDSymbol& pSymbol) const
}
/// getSymbolIdx - called by emitRelocation to get the ouput symbol table index
-size_t GNULDBackend::getSymbolIdx(LDSymbol* pSymbol) const
+size_t GNULDBackend::getSymbolIdx(const LDSymbol* pSymbol) const
{
- HashTableType::iterator entry = m_pSymIndexMap->find(pSymbol);
+ HashTableType::iterator entry = m_pSymIndexMap->find(const_cast<LDSymbol *>(pSymbol));
+ assert(entry != m_pSymIndexMap->end() && "symbol not found in the symbol table");
return entry.getEntry()->value();
}
+/// isTemporary - Whether pSymbol is a local label.
+bool GNULDBackend::isTemporary(const LDSymbol& pSymbol) const
+{
+ if (ResolveInfo::Local != pSymbol.binding())
+ return false;
+
+ if (pSymbol.nameSize() < 2)
+ return false;
+
+ const char* name = pSymbol.name();
+ if ('.' == name[0] && 'L' == name[1])
+ return true;
+
+ // UnixWare 2.1 cc generate DWARF debugging symbols with `..' prefix.
+ // @ref Google gold linker, target.cc:39 @@ Target::do_is_local_label_name()
+ if (name[0] == '.' && name[1] == '.')
+ return true;
+
+ // Work arround for gcc's bug
+ // gcc sometimes generate symbols with '_.L_' prefix.
+ // @ref Google gold linker, target.cc:39 @@ Target::do_is_local_label_name()
+ if (pSymbol.nameSize() < 4)
+ return false;
+
+ if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_')
+ return true;
+
+ return false;
+}
+
/// allocateCommonSymbols - allocate common symbols in the corresponding
/// sections. This is executed at pre-layout stage.
/// @refer Google gold linker: common.cc: 214
@@ -1486,7 +1555,8 @@ GNULDBackend::allocateCommonSymbols(Module& pModule)
{
SymbolCategory& symbol_list = pModule.getSymbolTable();
- if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
+ if (symbol_list.emptyCommons() && symbol_list.emptyFiles() &&
+ symbol_list.emptyLocals() && symbol_list.emptyLocalDyns())
return true;
SymbolCategory::iterator com_sym, com_end;
@@ -1575,10 +1645,33 @@ GNULDBackend::allocateCommonSymbols(Module& pModule)
return true;
}
+/// updateSectionFlags - update pTo's flags when merging pFrom
+/// update the output section flags based on input section flags.
+/// @ref The Google gold linker:
+/// output.cc: 2809: Output_section::update_flags_for_input_section
+bool GNULDBackend::updateSectionFlags(LDSection& pTo, const LDSection& pFrom)
+{
+ // union the flags from input
+ uint32_t flags = pTo.flag();
+ flags |= (pFrom.flag() &
+ (llvm::ELF::SHF_WRITE |
+ llvm::ELF::SHF_ALLOC |
+ llvm::ELF::SHF_EXECINSTR));
+
+ // if there is an input section is not SHF_MERGE, clean this flag
+ if (0 == (pFrom.flag() & llvm::ELF::SHF_MERGE))
+ flags &= ~llvm::ELF::SHF_MERGE;
+
+ // if there is an input section is not SHF_STRINGS, clean this flag
+ if (0 == (pFrom.flag() & llvm::ELF::SHF_STRINGS))
+ flags &= ~llvm::ELF::SHF_STRINGS;
+
+ pTo.setFlag(flags);
+ return true;
+}
/// createProgramHdrs - base on output sections to create the program headers
-void GNULDBackend::createProgramHdrs(Module& pModule,
- const FragmentLinker& pLinker)
+void GNULDBackend::createProgramHdrs(Module& pModule)
{
ELFFileFormat *file_format = getOutputFormat();
@@ -1633,7 +1726,8 @@ void GNULDBackend::createProgramHdrs(Module& pModule,
if (createPT_LOAD) {
// create new PT_LOAD segment
load_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_LOAD, cur_flag);
- load_seg->setAlign(abiPageSize());
+ if (!config().options().nmagic() && !config().options().omagic())
+ load_seg->setAlign(abiPageSize());
}
assert(NULL != load_seg);
@@ -1695,12 +1789,31 @@ void GNULDBackend::createProgramHdrs(Module& pModule,
getSegmentFlag(file_format->getStackNote().flag()));
}
+ // make PT_NOTE
+ ELFSegment *note_seg = NULL;
+ prev_flag = getSegmentFlag(0);
+ for (sect = pModule.begin(); sect != sect_end; ++sect) {
+ if ((*sect)->kind() != LDFileFormat::Note ||
+ ((*sect)->flag() & llvm::ELF::SHF_ALLOC) == 0)
+ continue;
+
+ cur_flag = getSegmentFlag((*sect)->flag());
+ // we have different section orders for read-only and writable notes, so
+ // create 2 segments if needed.
+ if (note_seg == NULL ||
+ (cur_flag & llvm::ELF::PF_W) != (prev_flag & llvm::ELF::PF_W))
+ note_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_NOTE, cur_flag);
+
+ note_seg->addSection(*sect);
+ prev_flag = cur_flag;
+ }
+
// create target dependent segments
- doCreateProgramHdrs(pModule, pLinker);
+ doCreateProgramHdrs(pModule);
}
/// setupProgramHdrs - set up the attributes of segments
-void GNULDBackend::setupProgramHdrs(const FragmentLinker& pLinker)
+void GNULDBackend::setupProgramHdrs()
{
// update segment info
ELFSegmentFactory::iterator seg, seg_end = m_ELFSegmentTable.end();
@@ -1719,7 +1832,7 @@ void GNULDBackend::setupProgramHdrs(const FragmentLinker& pLinker)
phdr_size = sizeof(llvm::ELF::Elf64_Phdr);
}
segment.setOffset(offset);
- segment.setVaddr(segmentStartAddr(pLinker) + offset);
+ segment.setVaddr(segmentStartAddr() + offset);
segment.setPaddr(segment.vaddr());
segment.setFilesz(numOfSegments() * phdr_size);
segment.setMemsz(numOfSegments() * phdr_size);
@@ -1734,7 +1847,7 @@ void GNULDBackend::setupProgramHdrs(const FragmentLinker& pLinker)
segment.setOffset(segment.front()->offset());
if (llvm::ELF::PT_LOAD == segment.type() &&
LDFileFormat::Null == segment.front()->kind())
- segment.setVaddr(segmentStartAddr(pLinker));
+ segment.setVaddr(segmentStartAddr());
else
segment.setVaddr(segment.front()->addr());
segment.setPaddr(segment.vaddr());
@@ -1752,7 +1865,7 @@ void GNULDBackend::setupProgramHdrs(const FragmentLinker& pLinker)
/// setupGNUStackInfo - setup the section flag of .note.GNU-stack in output
/// @ref gold linker: layout.cc:2608
-void GNULDBackend::setupGNUStackInfo(Module& pModule, FragmentLinker& pLinker)
+void GNULDBackend::setupGNUStackInfo(Module& pModule)
{
uint32_t flag = 0x0;
if (config().options().hasStackSet()) {
@@ -1787,7 +1900,7 @@ void GNULDBackend::setupGNUStackInfo(Module& pModule, FragmentLinker& pLinker)
// 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())
+ if (m_pInfo->isDefaultExecStack())
flag = llvm::ELF::SHF_EXECINSTR;
}
@@ -1877,8 +1990,7 @@ void GNULDBackend::setOutputSectionOffset(Module& pModule,
}
/// setOutputSectionOffset - helper function to set output sections' address
-void GNULDBackend::setOutputSectionAddress(FragmentLinker& pLinker,
- Module& pModule,
+void GNULDBackend::setOutputSectionAddress(Module& pModule,
Module::iterator pSectBegin,
Module::iterator pSectEnd)
{
@@ -1907,39 +2019,43 @@ void GNULDBackend::setOutputSectionAddress(FragmentLinker& pLinker,
mapping = config().scripts().addressMap().find((*seg).front()->name());
if (mapping != config().scripts().addressMap().end()) {
- // check address mapping
+ // use address mapping in script options
start_addr = mapping.getEntry()->value();
- if ((*seg).front()->kind() != LDFileFormat::Null) {
- const uint64_t remainder = start_addr % abiPageSize();
- if (remainder != (*seg).front()->offset() % abiPageSize()) {
- uint64_t padding = abiPageSize() + remainder -
- (*seg).front()->offset() % abiPageSize();
- setOutputSectionOffset(pModule,
- pModule.begin() + (*seg).front()->index(),
- pModule.end(),
- (*seg).front()->offset() + padding);
- if (config().options().hasRelro())
- setupRelro(pModule);
- }
- }
}
else {
if ((*seg).front()->kind() == LDFileFormat::Null) {
// 1st PT_LOAD
- start_addr = segmentStartAddr(pLinker);
+ start_addr = segmentStartAddr();
}
else if ((*prev).front()->kind() == LDFileFormat::Null) {
// prev segment is 1st PT_LOAD
- start_addr = segmentStartAddr(pLinker) + (*seg).front()->offset();
+ start_addr = segmentStartAddr() + (*seg).front()->offset();
}
else {
// Others
start_addr = (*prev).front()->addr() + (*seg).front()->offset();
}
+ // Try to align p_vaddr at page boundary if not in script options.
+ // To do so will add more padding in file, but can save one page
+ // at runtime.
+ alignAddress(start_addr, (*seg).align());
+ }
- // padding
- if (((*seg).front()->offset() & (abiPageSize() - 1)) != 0)
- start_addr += abiPageSize();
+ // in p75, http://www.sco.com/developers/devspecs/gabi41.pdf
+ // p_align: As "Program Loading" describes in this chapter of the
+ // processor supplement, loadable process segments must have congruent
+ // values for p_vaddr and p_offset, modulo the page size.
+ if ((start_addr & ((*seg).align() - 1)) !=
+ ((*seg).front()->offset() & ((*seg).align() - 1))) {
+ uint64_t padding = (*seg).align() +
+ (start_addr & ((*seg).align() - 1)) -
+ ((*seg).front()->offset() & ((*seg).align() - 1));
+ setOutputSectionOffset(pModule,
+ pModule.begin() + (*seg).front()->index(),
+ pModule.end(),
+ (*seg).front()->offset() + padding);
+ if (config().options().hasRelro())
+ setupRelro(pModule);
}
for (ELFSegment::sect_iterator sect = (*seg).begin(),
@@ -1963,7 +2079,7 @@ void GNULDBackend::setOutputSectionAddress(FragmentLinker& pLinker,
}
/// layout - layout method
-void GNULDBackend::layout(Module& pModule, FragmentLinker& pLinker)
+void GNULDBackend::layout(Module& pModule)
{
std::vector<SHOEntry> output_list;
// 1. determine what sections will go into final output, and push the needed
@@ -1971,44 +2087,55 @@ void GNULDBackend::layout(Module& pModule, FragmentLinker& pLinker)
for (Module::iterator it = pModule.begin(), ie = pModule.end(); it != ie;
++it) {
switch ((*it)->kind()) {
- // take NULL and StackNote directly
- case LDFileFormat::Null:
- case LDFileFormat::StackNote:
+ // take NULL and StackNote directly
+ case LDFileFormat::Null:
+ case LDFileFormat::StackNote:
+ output_list.push_back(std::make_pair(*it, getSectionOrder(**it)));
+ break;
+ // ignore if section size is 0
+ case LDFileFormat::EhFrame:
+ if (((*it)->size() != 0) ||
+ ((*it)->hasEhFrame() &&
+ config().codeGenType() == LinkerConfig::Object))
output_list.push_back(std::make_pair(*it, getSectionOrder(**it)));
- break;
- // ignore if section size is 0
- case LDFileFormat::Regular:
- case LDFileFormat::Target:
- case LDFileFormat::MetaData:
- case LDFileFormat::BSS:
- case LDFileFormat::Debug:
- case LDFileFormat::EhFrame:
- case LDFileFormat::GCCExceptTable:
- case LDFileFormat::NamePool:
- case LDFileFormat::Relocation:
- case LDFileFormat::Note:
- case LDFileFormat::EhFrameHdr:
- if (0 != (*it)->size()) {
- output_list.push_back(std::make_pair(*it, getSectionOrder(**it)));
- }
- break;
- case LDFileFormat::Group:
- if (LinkerConfig::Object == config().codeGenType()) {
- //TODO: support incremental linking
- ;
- }
- break;
- case LDFileFormat::Version:
- if (0 != (*it)->size()) {
- output_list.push_back(std::make_pair(*it, getSectionOrder(**it)));
- warning(diag::warn_unsupported_symbolic_versioning) << (*it)->name();
- }
- break;
- default:
- if (0 != (*it)->size()) {
- error(diag::err_unsupported_section) << (*it)->name() << (*it)->kind();
- }
- break;
+ break;
+ case LDFileFormat::Relocation:
+ if (((*it)->size() != 0) ||
+ ((*it)->hasRelocData() &&
+ config().codeGenType() == LinkerConfig::Object))
+ output_list.push_back(std::make_pair(*it, getSectionOrder(**it)));
+ break;
+ case LDFileFormat::Regular:
+ case LDFileFormat::Target:
+ case LDFileFormat::MetaData:
+ case LDFileFormat::BSS:
+ case LDFileFormat::Debug:
+ case LDFileFormat::GCCExceptTable:
+ case LDFileFormat::Note:
+ case LDFileFormat::NamePool:
+ case LDFileFormat::EhFrameHdr:
+ if (((*it)->size() != 0) ||
+ ((*it)->hasSectionData() &&
+ config().codeGenType() == LinkerConfig::Object))
+ output_list.push_back(std::make_pair(*it, getSectionOrder(**it)));
+ break;
+ case LDFileFormat::Group:
+ if (LinkerConfig::Object == config().codeGenType()) {
+ //TODO: support incremental linking
+ ;
+ }
+ break;
+ case LDFileFormat::Version:
+ if (0 != (*it)->size()) {
+ output_list.push_back(std::make_pair(*it, getSectionOrder(**it)));
+ warning(diag::warn_unsupported_symbolic_versioning) << (*it)->name();
+ }
+ break;
+ default:
+ if (0 != (*it)->size()) {
+ error(diag::err_unsupported_section) << (*it)->name() << (*it)->kind();
+ }
+ break;
}
} // end of for
@@ -2024,7 +2151,7 @@ void GNULDBackend::layout(Module& pModule, FragmentLinker& pLinker)
// 4. create program headers
if (LinkerConfig::Object != config().codeGenType()) {
- createProgramHdrs(pModule, pLinker);
+ createProgramHdrs(pModule);
}
// 5. set output section offset
@@ -2032,12 +2159,13 @@ void GNULDBackend::layout(Module& pModule, FragmentLinker& pLinker)
}
/// preLayout - Backend can do any needed modification before layout
-void GNULDBackend::preLayout(Module& pModule, FragmentLinker& pLinker)
+void GNULDBackend::preLayout(Module& pModule, IRBuilder& pBuilder)
{
// prelayout target first
- doPreLayout(pLinker);
+ doPreLayout(pBuilder);
- if (config().options().hasEhFrameHdr() && getOutputFormat()->hasEhFrame()) {
+ if (LinkerConfig::Object != config().codeGenType() &&
+ config().options().hasEhFrameHdr() && getOutputFormat()->hasEhFrame()) {
// init EhFrameHdr and size the output section
ELFFileFormat* format = getOutputFormat();
m_pEhFrameHdr = new EhFrameHdr(format->getEhFrameHdr(),
@@ -2045,12 +2173,12 @@ void GNULDBackend::preLayout(Module& pModule, FragmentLinker& pLinker)
m_pEhFrameHdr->sizeOutput();
}
- // change .tbss and .tdata section symbol from Local to TLS category
+ // change .tbss and .tdata section symbol from Local to LocalDyn category
if (NULL != f_pTDATA)
- pModule.getSymbolTable().changeLocalToTLS(*f_pTDATA);
+ pModule.getSymbolTable().changeLocalToDynamic(*f_pTDATA);
if (NULL != f_pTBSS)
- pModule.getSymbolTable().changeLocalToTLS(*f_pTBSS);
+ pModule.getSymbolTable().changeLocalToDynamic(*f_pTBSS);
// To merge input's relocation sections into output's relocation sections.
//
@@ -2111,12 +2239,11 @@ void GNULDBackend::preLayout(Module& pModule, FragmentLinker& pLinker)
} // end of if
// set up the section flag of .note.GNU-stack section
- setupGNUStackInfo(pModule, pLinker);
+ setupGNUStackInfo(pModule);
}
/// postLayout - Backend can do any needed modification after layout
-void GNULDBackend::postLayout(Module& pModule,
- FragmentLinker& pLinker)
+void GNULDBackend::postLayout(Module& pModule, IRBuilder& pBuilder)
{
// 1. set up section address and segment attributes
if (LinkerConfig::Object != config().codeGenType()) {
@@ -2126,25 +2253,28 @@ void GNULDBackend::postLayout(Module& pModule,
}
// 1.2 set up the output sections' address
- setOutputSectionAddress(pLinker, pModule, pModule.begin(), pModule.end());
+ setOutputSectionAddress(pModule, pModule.begin(), pModule.end());
// 1.3 do relaxation
- relax(pModule, pLinker);
+ relax(pModule, pBuilder);
// 1.4 set up the attributes of program headers
- setupProgramHdrs(pLinker);
+ setupProgramHdrs();
}
// 2. target specific post layout
- doPostLayout(pModule, pLinker);
+ doPostLayout(pModule, pBuilder);
}
-void GNULDBackend::postProcessing(FragmentLinker& pLinker, MemoryArea& pOutput)
+void GNULDBackend::postProcessing(MemoryArea& pOutput)
{
- if (config().options().hasEhFrameHdr() && getOutputFormat()->hasEhFrame()) {
+ if (LinkerConfig::Object != config().codeGenType() &&
+ config().options().hasEhFrameHdr() && getOutputFormat()->hasEhFrame()) {
// emit eh_frame_hdr
if (config().targets().is32Bits())
m_pEhFrameHdr->emitOutput<32>(pOutput);
+ else
+ m_pEhFrameHdr->emitOutput<64>(pOutput);
}
}
@@ -2174,6 +2304,27 @@ unsigned GNULDBackend::getHashBucketCount(unsigned pNumOfSymbols,
return result;
}
+/// getGNUHashMaskbitslog2 - calculate the number of mask bits in log2
+/// @ref binutils gold, dynobj.cc:1165
+unsigned GNULDBackend::getGNUHashMaskbitslog2(unsigned pNumOfSymbols) const
+{
+ uint32_t maskbitslog2 = 1;
+ for (uint32_t x = pNumOfSymbols >> 1; x != 0; x >>=1)
+ ++maskbitslog2;
+
+ if (maskbitslog2 < 3)
+ maskbitslog2 = 5;
+ else if (((1U << (maskbitslog2 - 2)) & pNumOfSymbols) != 0)
+ maskbitslog2 += 3;
+ else
+ maskbitslog2 += 2;
+
+ if (config().targets().bitclass() == 64 && maskbitslog2 == 5)
+ maskbitslog2 = 6;
+
+ return maskbitslog2;
+}
+
/// isDynamicSymbol
/// @ref Google gold linker: symtab.cc:311
bool GNULDBackend::isDynamicSymbol(const LDSymbol& pSymbol)
@@ -2189,10 +2340,8 @@ bool GNULDBackend::isDynamicSymbol(const LDSymbol& pSymbol)
LinkerConfig::Exec == config().codeGenType() ||
LinkerConfig::Binary == config().codeGenType()) {
if (pSymbol.resolveInfo()->visibility() == ResolveInfo::Default ||
- pSymbol.resolveInfo()->visibility() == ResolveInfo::Protected ||
- pSymbol.resolveInfo()->type() == ResolveInfo::ThreadLocal) {
+ pSymbol.resolveInfo()->visibility() == ResolveInfo::Protected)
return true;
- }
}
return false;
}
@@ -2212,10 +2361,8 @@ bool GNULDBackend::isDynamicSymbol(const ResolveInfo& pResolveInfo)
LinkerConfig::Exec == config().codeGenType() ||
LinkerConfig::Binary == config().codeGenType()) {
if (pResolveInfo.visibility() == ResolveInfo::Default ||
- pResolveInfo.visibility() == ResolveInfo::Protected ||
- pResolveInfo.type() == ResolveInfo::ThreadLocal) {
+ pResolveInfo.visibility() == ResolveInfo::Protected)
return true;
- }
}
return false;
}
@@ -2227,7 +2374,7 @@ uint64_t GNULDBackend::commonPageSize() const
if (config().options().commPageSize() > 0)
return std::min(config().options().commPageSize(), abiPageSize());
else
- return std::min(static_cast<uint64_t>(0x1000), abiPageSize());
+ return std::min(m_pInfo->commonPageSize(), abiPageSize());
}
/// abiPageSize - the abi page size of the target machine.
@@ -2237,7 +2384,7 @@ uint64_t GNULDBackend::abiPageSize() const
if (config().options().maxPageSize() > 0)
return config().options().maxPageSize();
else
- return static_cast<uint64_t>(0x1000);
+ return m_pInfo->abiPageSize();
}
/// isSymbolPreemtible - whether the symbol can be preemted by other
@@ -2271,8 +2418,7 @@ bool GNULDBackend::isSymbolPreemptible(const ResolveInfo& pSym) const
/// symbolNeedsDynRel - return whether the symbol needs a dynamic relocation
/// @ref Google gold linker, symtab.h:645
-bool GNULDBackend::symbolNeedsDynRel(const FragmentLinker& pLinker,
- const ResolveInfo& pSym,
+bool GNULDBackend::symbolNeedsDynRel(const ResolveInfo& pSym,
bool pSymHasPLT,
bool isAbsReloc) const
{
@@ -2284,13 +2430,17 @@ bool GNULDBackend::symbolNeedsDynRel(const FragmentLinker& pLinker,
LinkerConfig::Binary == config().codeGenType()))
return false;
- if (pSym.isAbsolute())
+ // An absolute symbol can be resolved directly if it is either local
+ // or we are linking statically. Otherwise it can still be overridden
+ // at runtime.
+ if (pSym.isAbsolute() &&
+ (pSym.binding() == ResolveInfo::Local || config().isCodeStatic()))
return false;
- if (pLinker.isOutputPIC() && isAbsReloc)
+ if (config().isCodeIndep() && isAbsReloc)
return true;
if (pSymHasPLT && ResolveInfo::Function == pSym.type())
return false;
- if (!pLinker.isOutputPIC() && pSymHasPLT)
+ if (!config().isCodeIndep() && pSymHasPLT)
return false;
if (pSym.isDyn() || pSym.isUndef() ||
isSymbolPreemptible(pSym))
@@ -2301,8 +2451,7 @@ bool GNULDBackend::symbolNeedsDynRel(const FragmentLinker& pLinker,
/// symbolNeedsPLT - return whether the symbol needs a PLT entry
/// @ref Google gold linker, symtab.h:596
-bool GNULDBackend::symbolNeedsPLT(const FragmentLinker& pLinker,
- const ResolveInfo& pSym) const
+bool GNULDBackend::symbolNeedsPLT(const ResolveInfo& pSym) const
{
if (pSym.isUndef() &&
!pSym.isDyn() &&
@@ -2316,7 +2465,7 @@ bool GNULDBackend::symbolNeedsPLT(const FragmentLinker& pLinker,
if (pSym.type() != ResolveInfo::Function)
return false;
- if (pLinker.isStaticLink() && !pLinker.isOutputPIC())
+ if (config().isCodeStatic())
return false;
if (config().options().isPIE())
@@ -2330,12 +2479,12 @@ bool GNULDBackend::symbolNeedsPLT(const FragmentLinker& pLinker,
/// symbolHasFinalValue - return true if the symbol's value can be decided at
/// link time
/// @ref Google gold linker, Symbol::final_value_is_known
-bool GNULDBackend::symbolFinalValueIsKnown(const FragmentLinker& pLinker,
- const ResolveInfo& pSym) const
+bool GNULDBackend::symbolFinalValueIsKnown(const ResolveInfo& pSym) const
{
// if the output is pic code or if not executables, symbols' value may change
// at runtime
- if (pLinker.isOutputPIC() ||
+ // FIXME: CodeIndep() || LinkerConfig::Relocatable == CodeGenType
+ if (config().isCodeIndep() ||
(LinkerConfig::Exec != config().codeGenType() &&
LinkerConfig::Binary != config().codeGenType()))
return false;
@@ -2352,17 +2501,16 @@ bool GNULDBackend::symbolFinalValueIsKnown(const FragmentLinker& pLinker,
// if the symbol is undefined and not in dynamic objects, for example, a weak
// undefined symbol, then whether the symbol's final value can be known
// depends on whrther we're doing static link
- return pLinker.isStaticLink();
+ return config().isCodeStatic();
}
/// symbolNeedsCopyReloc - return whether the symbol needs a copy relocation
-bool GNULDBackend::symbolNeedsCopyReloc(const FragmentLinker& pLinker,
- const Relocation& pReloc,
+bool GNULDBackend::symbolNeedsCopyReloc(const Relocation& pReloc,
const ResolveInfo& pSym) const
{
// only the reference from dynamic executable to non-function symbol in
// the dynamic objects may need copy relocation
- if (pLinker.isOutputPIC() ||
+ if (config().isCodeIndep() ||
!pSym.isDyn() ||
pSym.type() == ResolveInfo::Function ||
pSym.size() == 0)
@@ -2437,14 +2585,14 @@ bool GNULDBackend::initStubFactory()
return true;
}
-bool GNULDBackend::relax(Module& pModule, FragmentLinker& pLinker)
+bool GNULDBackend::relax(Module& pModule, IRBuilder& pBuilder)
{
if (!mayRelax())
return true;
bool finished = true;
do {
- if (doRelax(pModule, pLinker, finished)) {
+ if (doRelax(pModule, pBuilder, finished)) {
// If the sections (e.g., .text) are relaxed, the layout is also changed
// We need to do the following:
@@ -2456,10 +2604,24 @@ bool GNULDBackend::relax(Module& pModule, FragmentLinker& pLinker)
setupRelro(pModule);
// 3. set up the output sections' address
- setOutputSectionAddress(pLinker, pModule, pModule.begin(), pModule.end());
+ setOutputSectionAddress(pModule, pModule.begin(), pModule.end());
}
} while (!finished);
return true;
}
+bool GNULDBackend::DynsymCompare::needGNUHash(const LDSymbol& X) const
+{
+ // FIXME: in bfd and gold linker, an undefined symbol might be hashed
+ // when the ouput is not PIC, if the symbol is referred by a non pc-relative
+ // reloc, and its value is set to the addr of the plt entry.
+ return !X.resolveInfo()->isUndef() && !X.isDyn();
+}
+
+bool GNULDBackend::DynsymCompare::operator()(const LDSymbol* X,
+ const LDSymbol* Y) const
+{
+ return !needGNUHash(*X) && needGNUHash(*Y);
+}
+
diff --git a/lib/Target/Hexagon/Hexagon.h b/lib/Target/Hexagon/Hexagon.h
new file mode 100644
index 0000000..5a286ef
--- /dev/null
+++ b/lib/Target/Hexagon/Hexagon.h
@@ -0,0 +1,32 @@
+//===- Hexagon.h ----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_HEXAGON_H
+#define MCLD_HEXAGON_H
+#include <string>
+#include <mcld/Target/TargetMachine.h>
+
+namespace llvm {
+
+class Target;
+
+} // namespace of llvm
+
+namespace mcld {
+
+class TargetLDBackend;
+
+extern mcld::Target TheHexagonTarget;
+
+TargetLDBackend*
+createHexagonLDBackend(const llvm::Target&, const std::string&);
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/Hexagon/HexagonDiagnostic.cpp b/lib/Target/Hexagon/HexagonDiagnostic.cpp
new file mode 100644
index 0000000..01b8f9b
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonDiagnostic.cpp
@@ -0,0 +1,37 @@
+//===- HexagonDiagnostic.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 "Hexagon.h"
+
+using namespace mcld;
+
+namespace mcld {
+
+// createHexagonDiagnostic - the help function to create corresponding
+// HexagonDiagnostic
+//
+DiagnosticLineInfo*
+createHexagonDiagLineInfo(const Target& pTarget, const std::string &pTriple)
+{
+ return new DWARFLineInfo();
+}
+
+} // namespace of mcld
+
+//===----------------------------------------------------------------------===//
+// InitializeHexagonDiagnostic
+//===----------------------------------------------------------------------===//
+extern "C" void MCLDInitializeHexagonDiagnosticLineInfo() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheHexagonTarget,
+ createHexagonDiagLineInfo);
+}
+
diff --git a/lib/Target/Hexagon/HexagonELFDynamic.cpp b/lib/Target/Hexagon/HexagonELFDynamic.cpp
new file mode 100644
index 0000000..96d0946
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonELFDynamic.cpp
@@ -0,0 +1,37 @@
+//===- HexagonELFDynamic.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "HexagonELFDynamic.h"
+
+#include <mcld/LD/ELFFileFormat.h>
+
+using namespace mcld;
+
+HexagonELFDynamic::HexagonELFDynamic(const GNULDBackend& pParent,
+ const LinkerConfig& pConfig)
+ : ELFDynamic(pParent, pConfig) {
+}
+
+HexagonELFDynamic::~HexagonELFDynamic()
+{
+}
+
+void HexagonELFDynamic::reserveTargetEntries(const ELFFileFormat& pFormat)
+{
+ // reservePLTGOT
+ if (pFormat.hasGOTPLT())
+ reserveOne(llvm::ELF::DT_PLTGOT);
+}
+
+void HexagonELFDynamic::applyTargetEntries(const ELFFileFormat& pFormat)
+{
+ // applyPLTGOT
+ if (pFormat.hasGOTPLT())
+ applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOTPLT().addr());
+}
+
diff --git a/lib/Target/Hexagon/HexagonELFDynamic.h b/lib/Target/Hexagon/HexagonELFDynamic.h
new file mode 100644
index 0000000..423d918
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonELFDynamic.h
@@ -0,0 +1,32 @@
+//===- HexagonELFDynamic.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_HEXAGON_ELFDYNAMIC_SECTION_H
+#define MCLD_HEXAGON_ELFDYNAMIC_SECTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Target/ELFDynamic.h>
+
+namespace mcld {
+
+class HexagonELFDynamic : public ELFDynamic
+{
+public:
+ HexagonELFDynamic(const GNULDBackend& pParent, const LinkerConfig& pConfig);
+ ~HexagonELFDynamic();
+
+private:
+ void reserveTargetEntries(const ELFFileFormat& pFormat);
+ void applyTargetEntries(const ELFFileFormat& pFormat);
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Hexagon/HexagonELFMCLinker.cpp b/lib/Target/Hexagon/HexagonELFMCLinker.cpp
new file mode 100644
index 0000000..6cc4a01
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonELFMCLinker.cpp
@@ -0,0 +1,23 @@
+//===- HexagonELFMCLinker.cpp ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "HexagonELFMCLinker.h"
+#include <mcld/LinkerConfig.h>
+
+using namespace mcld;
+
+HexagonELFMCLinker::HexagonELFMCLinker(LinkerConfig& pConfig,
+ mcld::Module& pModule,
+ MemoryArea& pOutput)
+ : ELFMCLinker(pConfig, pModule, pOutput) {
+}
+
+HexagonELFMCLinker::~HexagonELFMCLinker()
+{
+}
+
diff --git a/lib/Target/Hexagon/HexagonELFMCLinker.h b/lib/Target/Hexagon/HexagonELFMCLinker.h
new file mode 100644
index 0000000..c588ddf
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonELFMCLinker.h
@@ -0,0 +1,38 @@
+//===- HexagonELFMCLinker.h -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef HEXAGON_ELFSECTLINKER_H
+#define HEXAGON_ELFSECTLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Target/ELFMCLinker.h>
+
+namespace mcld {
+
+class Module;
+class MemoryArea;
+
+/** \class HexagonELFMCLinker
+ * \brief HexagonELFMCLinker sets up the environment for linking.
+ *
+ * \see
+ */
+class HexagonELFMCLinker : public ELFMCLinker
+{
+public:
+ HexagonELFMCLinker(LinkerConfig& pConfig,
+ mcld::Module& pModule,
+ MemoryArea& pOutput);
+
+ ~HexagonELFMCLinker();
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Hexagon/HexagonEmulation.cpp b/lib/Target/Hexagon/HexagonEmulation.cpp
new file mode 100644
index 0000000..3b8ee0d
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonEmulation.cpp
@@ -0,0 +1,65 @@
+//===- HexagonEmulation.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "Hexagon.h"
+#include <mcld/LinkerConfig.h>
+#include <mcld/Target/ELFEmulation.h>
+#include <mcld/Support/TargetRegistry.h>
+
+namespace mcld {
+
+static bool MCLDEmulateHexagonELF(LinkerConfig& pConfig)
+{
+ if (!MCLDEmulateELF(pConfig))
+ return false;
+
+ // set up bitclass and endian
+ pConfig.targets().setEndian(TargetOptions::Little);
+ pConfig.targets().setBitClass(32);
+
+ // set up target-dependent constraints of attributes
+ pConfig.attribute().constraint().enableWholeArchive();
+ pConfig.attribute().constraint().enableAsNeeded();
+ pConfig.attribute().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ pConfig.attribute().predefined().unsetWholeArchive();
+ pConfig.attribute().predefined().unsetAsNeeded();
+ pConfig.attribute().predefined().setDynamic();
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// emulateHexagonLD - the help function to emulate Hexagon ld
+//===----------------------------------------------------------------------===//
+bool emulateHexagonLD(const std::string& pTriple, LinkerConfig& pConfig)
+{
+ llvm::Triple theTriple(pTriple);
+ if (theTriple.isOSDarwin()) {
+ assert(0 && "MachO linker has not supported yet");
+ return false;
+ }
+ if (theTriple.isOSWindows()) {
+ assert(0 && "COFF linker has not supported yet");
+ return false;
+ }
+
+ return MCLDEmulateHexagonELF(pConfig);
+}
+
+} // namespace of mcld
+
+//===----------------------------------------------------------------------===//
+// HexagonEmulation
+//===----------------------------------------------------------------------===//
+extern "C" void MCLDInitializeHexagonEmulation() {
+ // Register the emulation
+ mcld::TargetRegistry::RegisterEmulation(mcld::TheHexagonTarget,
+ mcld::emulateHexagonLD);
+}
+
diff --git a/lib/Target/Hexagon/HexagonGNUInfo.h b/lib/Target/Hexagon/HexagonGNUInfo.h
new file mode 100644
index 0000000..082e2e5
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonGNUInfo.h
@@ -0,0 +1,33 @@
+//===- HexagonGNUInfo.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TARGET_HEXAGON_GNU_INFO_H
+#define MCLD_TARGET_HEXAGON_GNU_INFO_H
+#include <mcld/Target/GNUInfo.h>
+
+#include <llvm/Support/ELF.h>
+
+namespace mcld {
+
+class HexagonGNUInfo : public GNUInfo
+{
+public:
+ HexagonGNUInfo(const llvm::Triple& pTriple) : GNUInfo(pTriple) { }
+
+ uint32_t machine() const { return llvm::ELF::EM_HEXAGON; }
+
+ uint64_t defaultTextSegmentAddr() const { return 0x0; }
+
+ /// flags - the value of ElfXX_Ehdr::e_flags
+ uint64_t flags() const { return 0x2; }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/Hexagon/HexagonGOT.cpp b/lib/Target/Hexagon/HexagonGOT.cpp
new file mode 100644
index 0000000..551b40f
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonGOT.cpp
@@ -0,0 +1,48 @@
+//===- HexagonGOT.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "HexagonGOT.h"
+
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/LD/SectionData.h>
+
+#include <llvm/Support/Casting.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// HexagonGOT
+//===----------------------------------------------------------------------===//
+HexagonGOT::HexagonGOT(LDSection& pSection)
+ : GOT(pSection), m_pLast(NULL)
+{
+}
+
+HexagonGOT::~HexagonGOT()
+{
+}
+
+void HexagonGOT::reserve(size_t pNum)
+{
+ for (size_t i = 0; i < pNum; i++) {
+ new HexagonGOTEntry(0, m_SectionData);
+ }
+}
+
+HexagonGOTEntry* HexagonGOT::consume()
+{
+ if (NULL == m_pLast) {
+ assert(!empty() && "Consume empty GOT entry!");
+ m_pLast = llvm::cast<HexagonGOTEntry>(&m_SectionData->front());
+ return m_pLast;
+ }
+
+ m_pLast = llvm::cast<HexagonGOTEntry>(m_pLast->getNextNode());
+ return m_pLast;
+}
+
diff --git a/lib/Target/Hexagon/HexagonGOT.h b/lib/Target/Hexagon/HexagonGOT.h
new file mode 100644
index 0000000..4f9120c
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonGOT.h
@@ -0,0 +1,55 @@
+//===- HexagonGOT.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TARGET_HEXAGON_GOT_H
+#define MCLD_TARGET_HEXAGON_GOT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Target/GOT.h>
+
+namespace mcld {
+
+class LDSection;
+class SectionData;
+
+/** \class HexagonGOTEntry
+ * \brief GOT Entry with size of 4 bytes
+ */
+class HexagonGOTEntry : public GOT::Entry<4>
+{
+public:
+ HexagonGOTEntry(uint64_t pContent, SectionData* pParent)
+ : GOT::Entry<4>(pContent, pParent)
+ {}
+};
+
+/** \class HexagonGOT
+ * \brief Hexagon Global Offset Table.
+ */
+
+class HexagonGOT : public GOT
+{
+public:
+ HexagonGOT(LDSection& pSection);
+
+ ~HexagonGOT();
+
+ void reserve(size_t pNum = 1);
+
+ HexagonGOTEntry* consume();
+
+private:
+ HexagonGOTEntry* m_pLast; ///< the last consumed entry
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/Hexagon/HexagonLDBackend.cpp b/lib/Target/Hexagon/HexagonLDBackend.cpp
new file mode 100644
index 0000000..0d7ba26
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonLDBackend.cpp
@@ -0,0 +1,270 @@
+//===- HexagonLDBackend.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "Hexagon.h"
+#include "HexagonELFDynamic.h"
+#include "HexagonLDBackend.h"
+#include "HexagonRelocator.h"
+#include "HexagonGNUInfo.h"
+
+#include <llvm/ADT/Triple.h>
+#include <llvm/Support/Casting.h>
+
+#include <mcld/LinkerConfig.h>
+#include <mcld/IRBuilder.h>
+#include <mcld/Fragment/FillFragment.h>
+#include <mcld/Fragment/RegionFragment.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/Object/ObjectBuilder.h>
+
+#include <cstring>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// HexagonLDBackend
+//===----------------------------------------------------------------------===//
+HexagonLDBackend::HexagonLDBackend(const LinkerConfig& pConfig,
+ HexagonGNUInfo* pInfo)
+ : GNULDBackend(pConfig, pInfo),
+ m_pRelocator(NULL),
+ m_pGOT(NULL),
+ m_pPLT(NULL),
+ m_pRelDyn(NULL),
+ m_pRelPLT(NULL),
+ m_pDynamic(NULL),
+ m_pGOTSymbol(NULL) {
+}
+
+HexagonLDBackend::~HexagonLDBackend()
+{
+ delete m_pRelocator;
+ delete m_pGOT;
+ delete m_pPLT;
+ delete m_pRelDyn;
+ delete m_pRelPLT;
+ delete m_pDynamic;
+}
+
+bool HexagonLDBackend::initRelocator()
+{
+ if (NULL == m_pRelocator) {
+ m_pRelocator = new HexagonRelocator(*this);
+ }
+ return true;
+}
+
+Relocator* HexagonLDBackend::getRelocator()
+{
+ assert(NULL != m_pRelocator);
+ return m_pRelocator;
+}
+
+void HexagonLDBackend::doPreLayout(IRBuilder& pBuilder)
+{
+ // initialize .dynamic data
+ if (!config().isCodeStatic() && NULL == m_pDynamic)
+ m_pDynamic = new HexagonELFDynamic(*this, config());
+}
+
+void HexagonLDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder)
+{
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+HexagonELFDynamic& HexagonLDBackend::dynamic()
+{
+ assert(NULL != m_pDynamic);
+ return *m_pDynamic;
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+const HexagonELFDynamic& HexagonLDBackend::dynamic() const
+{
+ assert(NULL != m_pDynamic);
+ return *m_pDynamic;
+}
+
+void HexagonLDBackend::scanRelocation(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection)
+{
+ pReloc.updateAddend();
+}
+
+uint64_t HexagonLDBackend::emitSectionData(const LDSection& pSection,
+ MemoryRegion& pRegion) const
+{
+ return 0;
+}
+
+HexagonGOT& HexagonLDBackend::getGOT()
+{
+ assert(NULL != m_pGOT);
+ return *m_pGOT;
+}
+
+const HexagonGOT& HexagonLDBackend::getGOT() const
+{
+ assert(NULL != m_pGOT);
+ return *m_pGOT;
+}
+
+HexagonPLT& HexagonLDBackend::getPLT()
+{
+ assert(NULL != m_pPLT && "PLT section not exist");
+ return *m_pPLT;
+}
+
+const HexagonPLT& HexagonLDBackend::getPLT() const
+{
+ assert(NULL != m_pPLT && "PLT section not exist");
+ return *m_pPLT;
+}
+
+OutputRelocSection& HexagonLDBackend::getRelDyn()
+{
+ assert(NULL != m_pRelDyn && ".rel.dyn section not exist");
+ return *m_pRelDyn;
+}
+
+const OutputRelocSection& HexagonLDBackend::getRelDyn() const
+{
+ assert(NULL != m_pRelDyn && ".rel.dyn section not exist");
+ return *m_pRelDyn;
+}
+
+OutputRelocSection& HexagonLDBackend::getRelPLT()
+{
+ assert(NULL != m_pRelPLT && ".rel.plt section not exist");
+ return *m_pRelPLT;
+}
+
+const OutputRelocSection& HexagonLDBackend::getRelPLT() const
+{
+ assert(NULL != m_pRelPLT && ".rel.plt section not exist");
+ return *m_pRelPLT;
+}
+
+unsigned int
+HexagonLDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const
+{
+ const ELFFileFormat* file_format = getOutputFormat();
+
+ if (&pSectHdr == &file_format->getGOT()) {
+ if (config().options().hasNow())
+ return SHO_RELRO;
+ return SHO_RELRO_LAST;
+ }
+
+ if (&pSectHdr == &file_format->getPLT())
+ return SHO_PLT;
+
+ return SHO_UNDEFINED;
+}
+
+void HexagonLDBackend::initTargetSections(Module& pModule,
+ ObjectBuilder& pBuilder)
+{
+ if (LinkerConfig::Object != config().codeGenType()) {
+ ELFFileFormat* file_format = getOutputFormat();
+ // initialize .got
+ LDSection& got = file_format->getGOT();
+ m_pGOT = new HexagonGOT(got);
+
+ // initialize .plt
+ LDSection& plt = file_format->getPLT();
+ m_pPLT = new HexagonPLT(plt,
+ *m_pGOT,
+ config());
+
+ // initialize .rel.plt
+ LDSection& relplt = file_format->getRelPlt();
+ relplt.setLink(&plt);
+ m_pRelPLT = new OutputRelocSection(pModule, relplt);
+
+ // initialize .rel.dyn
+ LDSection& reldyn = file_format->getRelDyn();
+ m_pRelDyn = new OutputRelocSection(pModule, reldyn);
+
+ }
+}
+
+void HexagonLDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule)
+{
+ if (LinkerConfig::Object != config().codeGenType()) {
+ // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
+ // same name in input
+ m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ FragmentRef::Null(),
+ ResolveInfo::Hidden);
+ }
+}
+
+/// finalizeSymbol - finalize the symbol value
+bool HexagonLDBackend::finalizeTargetSymbols()
+{
+ return true;
+}
+
+/// doCreateProgramHdrs - backend can implement this function to create the
+/// target-dependent segments
+void HexagonLDBackend::doCreateProgramHdrs(Module& pModule)
+{
+ // TODO
+}
+
+namespace mcld {
+
+//===----------------------------------------------------------------------===//
+/// createHexagonLDBackend - the help funtion to create corresponding
+/// HexagonLDBackend
+TargetLDBackend* createHexagonLDBackend(const llvm::Target& pTarget,
+ const LinkerConfig& pConfig)
+{
+ if (pConfig.targets().triple().isOSDarwin()) {
+ assert(0 && "MachO linker is not supported yet");
+ /**
+ return new HexagonMachOLDBackend(createHexagonMachOArchiveReader,
+ createHexagonMachOObjectReader,
+ createHexagonMachOObjectWriter);
+ **/
+ }
+ if (pConfig.targets().triple().isOSWindows()) {
+ assert(0 && "COFF linker is not supported yet");
+ /**
+ return new HexagonCOFFLDBackend(createHexagonCOFFArchiveReader,
+ createHexagonCOFFObjectReader,
+ createHexagonCOFFObjectWriter);
+ **/
+ }
+ return new HexagonLDBackend(pConfig,
+ new HexagonGNUInfo(pConfig.targets().triple()));
+}
+
+} // namespace of mcld
+
+//===----------------------------------------------------------------------===//
+// Force static initialization.
+//===----------------------------------------------------------------------===//
+extern "C" void MCLDInitializeHexagonLDBackend() {
+ // Register the linker backend
+ mcld::TargetRegistry::RegisterTargetLDBackend(TheHexagonTarget,
+ createHexagonLDBackend);
+}
diff --git a/lib/Target/Hexagon/HexagonLDBackend.h b/lib/Target/Hexagon/HexagonLDBackend.h
new file mode 100644
index 0000000..46da924
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonLDBackend.h
@@ -0,0 +1,149 @@
+//===- HexagonLDBackend.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef HEXAGON_LDBACKEND_H
+#define HEXAGON_LDBACKEND_H
+
+#include "HexagonELFDynamic.h"
+#include "HexagonGOT.h"
+#include "HexagonPLT.h"
+#include <mcld/LD/LDSection.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/Target/OutputRelocSection.h>
+
+namespace mcld {
+
+class LinkerConfig;
+class HexagonGNUInfo;
+
+//===----------------------------------------------------------------------===//
+/// HexagonLDBackend - linker backend of Hexagon target of GNU ELF format
+///
+class HexagonLDBackend : public GNULDBackend
+{
+public:
+ HexagonLDBackend(const LinkerConfig& pConfig, HexagonGNUInfo* pInfo);
+
+ ~HexagonLDBackend();
+
+ uint32_t machine() const;
+
+ HexagonGOT& getGOT();
+
+ const HexagonGOT& getGOT() const;
+
+ HexagonPLT& getPLT();
+
+ const HexagonPLT& getPLT() const;
+
+ /// preLayout - Backend can do any needed modification before layout
+ void doPreLayout(IRBuilder& pBuilder);
+
+ /// postLayout - Backend can do any needed modification after layout
+ void doPostLayout(Module& pModule, IRBuilder& pBuilder);
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ HexagonELFDynamic& dynamic();
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ const HexagonELFDynamic& dynamic() const;
+
+ /// emitSectionData - write out the section data into the memory region.
+ /// When writers get a LDSection whose kind is LDFileFormat::Target, writers
+ /// call back target backend to emit the data.
+ ///
+ /// Backends handle the target-special tables (plt, gp,...) by themselves.
+ /// Backend can put the data of the tables in MCSectionData directly
+ /// - LDSection.getSectionData can get the section data.
+ /// Or, backend can put the data into special data structure
+ /// - backend can maintain its own map<LDSection, table> to get the table
+ /// from given LDSection.
+ ///
+ /// @param pSection - the given LDSection
+ /// @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 LDSection& pSection,
+ MemoryRegion& pRegion) const;
+
+ /// initRelocator - create and initialize Relocator.
+ bool initRelocator();
+
+ /// getRelocator - return relocator.
+ Relocator* getRelocator();
+
+ ResolveInfo::Desc getSymDesc(uint16_t shndx) const
+ {
+ if (shndx >= llvm::ELF::SHN_HEXAGON_SCOMMON &&
+ shndx <= llvm::ELF::SHN_HEXAGON_SCOMMON_8)
+ return ResolveInfo::Common;
+ return ResolveInfo::NoneDesc;
+ }
+
+ void initTargetSections(Module& pModule, ObjectBuilder& pBuilder);
+
+ void initTargetSymbols(IRBuilder& pBuilder, Module& pModule);
+
+ /// scanRelocation - determine the empty entries are needed or not and create
+ /// the empty entries if needed.
+ /// For Hexagon, following entries are check to create:
+ /// - GOT entry (for .got and .got.plt sections)
+ /// - PLT entry (for .plt section)
+ /// - dynamin relocation entries (for .rel.plt and .rel.dyn sections)
+ void scanRelocation(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection);
+
+ OutputRelocSection& getRelDyn();
+
+ const OutputRelocSection& getRelDyn() const;
+
+ OutputRelocSection& getRelPLT();
+
+ const OutputRelocSection& getRelPLT() const;
+
+ /// getTargetSectionOrder - compute the layout order of Hexagon target section
+ unsigned int getTargetSectionOrder(const LDSection& pSectHdr) const;
+
+ /// finalizeTargetSymbols - finalize the symbol value
+ bool finalizeTargetSymbols();
+
+private:
+
+ /// getRelEntrySize - the size in BYTE of rel type relocation
+ size_t getRelEntrySize()
+ { return 8; }
+
+ /// getRelEntrySize - the size in BYTE of rela type relocation
+ size_t getRelaEntrySize()
+ { return 12; }
+
+ /// doCreateProgramHdrs - backend can implement this function to create the
+ /// target-dependent segments
+ void doCreateProgramHdrs(Module& pModule);
+
+private:
+ Relocator* m_pRelocator;
+ HexagonGOT* m_pGOT;
+ HexagonPLT* m_pPLT;
+ /// m_RelDyn - dynamic relocation table of .rel.dyn
+ OutputRelocSection* m_pRelDyn;
+ /// m_RelPLT - dynamic relocation table of .rel.plt
+ OutputRelocSection* m_pRelPLT;
+
+ HexagonELFDynamic* m_pDynamic;
+ LDSymbol* m_pGOTSymbol;
+ LDSymbol* m_pBSSEnd;
+};
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/Hexagon/HexagonMCLinker.cpp b/lib/Target/Hexagon/HexagonMCLinker.cpp
new file mode 100644
index 0000000..4f4f839
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonMCLinker.cpp
@@ -0,0 +1,53 @@
+//===- HexagonMCLinker.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "Hexagon.h"
+#include "HexagonELFMCLinker.h"
+#include <mcld/Module.h>
+#include <mcld/Support/TargetRegistry.h>
+#include <llvm/ADT/Triple.h>
+
+using namespace mcld;
+
+namespace mcld {
+
+/// createHexagonMCLinker - the help funtion to create corresponding
+/// HexagonMCLinker
+MCLinker* createHexagonMCLinker(const std::string &pTriple,
+ LinkerConfig& pConfig,
+ mcld::Module& pModule,
+ MemoryArea& pOutput)
+{
+ Triple theTriple(pTriple);
+ if (theTriple.isOSDarwin()) {
+ assert(0 && "MachO linker has not supported yet");
+ return NULL;
+ }
+ if (theTriple.isOSWindows()) {
+ assert(0 && "COFF linker has not supported yet");
+ return NULL;
+ }
+
+ if (theTriple.isArch32Bit())
+ return new HexagonELFMCLinker(pConfig, pModule, pOutput);
+
+ assert(0 && "Hexagon_64 has not supported yet");
+ return NULL;
+}
+
+} // namespace of mcld
+
+//===----------------------------------------------------------------------===//
+// HexagonMCLinker
+//===----------------------------------------------------------------------===//
+extern "C" void MCLDInitializeHexagonMCLinker() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterMCLinker(TheHexagonTarget,
+ createHexagonMCLinker);
+}
+
diff --git a/lib/Target/Hexagon/HexagonPLT.cpp b/lib/Target/Hexagon/HexagonPLT.cpp
new file mode 100644
index 0000000..ae39af2
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonPLT.cpp
@@ -0,0 +1,97 @@
+//===- HexagonPLT.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "HexagonPLT.h"
+
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/Casting.h>
+
+#include <mcld/LD/LDSection.h>
+#include <mcld/LinkerConfig.h>
+#include <mcld/Support/MsgHandling.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// PLT entry data
+//===----------------------------------------------------------------------===//
+HexagonDynPLT0::HexagonDynPLT0(SectionData& pParent)
+ : PLT::Entry<sizeof(hexagon_dyn_plt0)>(pParent)
+{
+}
+
+HexagonExecPLT0::HexagonExecPLT0(SectionData& pParent)
+ : PLT::Entry<sizeof(hexagon_exec_plt0)>(pParent)
+{
+}
+
+//===----------------------------------------------------------------------===//
+// HexagonPLT
+//===----------------------------------------------------------------------===//
+HexagonPLT::HexagonPLT(LDSection& pSection,
+ HexagonGOT &pGOTPLT,
+ const LinkerConfig& pConfig)
+ : PLT(pSection),
+ m_GOT(pGOTPLT),
+ m_Config(pConfig)
+{
+ assert(LinkerConfig::DynObj == m_Config.codeGenType() ||
+ LinkerConfig::Exec == m_Config.codeGenType() ||
+ LinkerConfig::Binary == m_Config.codeGenType());
+
+ if (LinkerConfig::DynObj == m_Config.codeGenType()) {
+ m_PLT0 = hexagon_dyn_plt0;
+ m_PLT0Size = sizeof (hexagon_dyn_plt0);
+ // create PLT0
+ new HexagonDynPLT0(*m_SectionData);
+ }
+ else {
+ m_PLT0 = hexagon_exec_plt0;
+ m_PLT0Size = sizeof (hexagon_exec_plt0);
+ // create PLT0
+ new HexagonExecPLT0(*m_SectionData);
+ }
+ m_Last = m_SectionData->begin();
+}
+
+HexagonPLT::~HexagonPLT()
+{
+}
+
+PLTEntryBase* HexagonPLT::getPLT0() const
+{
+ iterator first = m_SectionData->getFragmentList().begin();
+
+ assert(first != m_SectionData->getFragmentList().end() &&
+ "FragmentList is empty, getPLT0 failed!");
+
+ PLTEntryBase* plt0 = &(llvm::cast<PLTEntryBase>(*first));
+
+ return plt0;
+}
+
+void HexagonPLT::finalizeSectionSize()
+{
+ uint64_t size = 0;
+ // plt0 size
+ size = getPLT0()->size();
+
+ m_Section.setSize(size);
+
+ uint32_t offset = 0;
+ SectionData::iterator frag, fragEnd = m_SectionData->end();
+ for (frag = m_SectionData->begin(); frag != fragEnd; ++frag) {
+ frag->setOffset(offset);
+ offset += frag->size();
+ }
+}
+
+void HexagonPLT::reserveEntry(size_t pNum)
+{
+}
+
diff --git a/lib/Target/Hexagon/HexagonPLT.h b/lib/Target/Hexagon/HexagonPLT.h
new file mode 100644
index 0000000..a5743d4
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonPLT.h
@@ -0,0 +1,84 @@
+//===- HexagonPLT.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TARGET_HEXAGON_PLT_H
+#define MCLD_TARGET_HEXAGON_PLT_H
+
+#include "HexagonGOT.h"
+#include <mcld/Target/PLT.h>
+
+namespace {
+
+const uint8_t hexagon_dyn_plt0[] = {
+ 0
+};
+
+const uint8_t hexagon_exec_plt0[] = {
+ 0
+};
+
+} // anonymous namespace
+
+namespace mcld {
+
+class GOTEntry;
+class LinkerConfig;
+
+//===----------------------------------------------------------------------===//
+// HexagonPLT Entry
+//===----------------------------------------------------------------------===//
+class HexagonDynPLT0 : public PLT::Entry<sizeof(hexagon_dyn_plt0)>
+{
+public:
+ HexagonDynPLT0(SectionData& pParent);
+};
+
+class HexagonExecPLT0 : public PLT::Entry<sizeof(hexagon_exec_plt0)>
+{
+public:
+ HexagonExecPLT0(SectionData& pParent);
+};
+
+//===----------------------------------------------------------------------===//
+// HexagonPLT
+//===----------------------------------------------------------------------===//
+/** \class HexagonPLT
+ * \brief Hexagon Procedure Linkage Table
+ */
+class HexagonPLT : public PLT
+{
+public:
+ HexagonPLT(LDSection& pSection,
+ HexagonGOT& pGOTPLT,
+ const LinkerConfig& pConfig);
+ ~HexagonPLT();
+
+ // finalizeSectionSize - set LDSection size
+ void finalizeSectionSize();
+
+ void reserveEntry(size_t pNum = 1) ;
+
+private:
+ PLTEntryBase* getPLT0() const;
+
+private:
+ HexagonGOT& m_GOT;
+
+ // the last consumed entry.
+ SectionData::iterator m_Last;
+
+ const uint8_t *m_PLT0;
+ unsigned int m_PLT0Size;
+
+ const LinkerConfig& m_Config;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/Hexagon/HexagonRelocationFunctions.h b/lib/Target/Hexagon/HexagonRelocationFunctions.h
new file mode 100644
index 0000000..c854dcb
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonRelocationFunctions.h
@@ -0,0 +1,113 @@
+//===- HexagonRelocationFunction.h ----------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#define DECL_HEXAGON_APPLY_RELOC_FUNC(Name) \
+static HexagonRelocator::Result Name (Relocation& pEntry, \
+ HexagonRelocator& pParent);
+
+#define DECL_HEXAGON_APPLY_RELOC_FUNCS \
+DECL_HEXAGON_APPLY_RELOC_FUNC(none) \
+DECL_HEXAGON_APPLY_RELOC_FUNC(relocB22PCREL) \
+DECL_HEXAGON_APPLY_RELOC_FUNC(relocB15PCREL) \
+DECL_HEXAGON_APPLY_RELOC_FUNC(relocLO16) \
+DECL_HEXAGON_APPLY_RELOC_FUNC(relocHI16) \
+DECL_HEXAGON_APPLY_RELOC_FUNC(reloc32) \
+DECL_HEXAGON_APPLY_RELOC_FUNC(reloc16) \
+DECL_HEXAGON_APPLY_RELOC_FUNC(reloc8) \
+DECL_HEXAGON_APPLY_RELOC_FUNC(relocB13PCREL) \
+DECL_HEXAGON_APPLY_RELOC_FUNC(reloc32PCREL) \
+DECL_HEXAGON_APPLY_RELOC_FUNC(unsupport)
+
+
+#define DECL_HEXAGON_APPLY_RELOC_FUNC_PTRS \
+ { &none, 0, "R_HEX_NONE" }, \
+ { &relocB22PCREL, 1, "R_HEX_B22_PCREL" }, \
+ { &relocB15PCREL, 2, "R_HEX_B15_PCREL" }, \
+ { &unsupport, 3, "R_HEX_B7_PCREL" }, \
+ { &relocLO16, 4, "R_HEX_LO16" }, \
+ { &relocHI16, 5, "R_HEX_HI16" }, \
+ { &reloc32, 6, "R_HEX_32" }, \
+ { &reloc16, 7, "R_HEX_16" }, \
+ { &reloc8, 8, "R_HEX_8" }, \
+ { &unsupport, 9, "R_HEX_GPREL16_0" }, \
+ { &unsupport, 10, "R_HEX_GPREL16_1" }, \
+ { &unsupport, 11, "R_HEX_GPREL16_2" }, \
+ { &unsupport, 12, "R_HEX_GPREL16_3" }, \
+ { &unsupport, 13, "R_HEX_HL16" }, \
+ { &relocB13PCREL, 14, "R_HEX_B13_PCREL" }, \
+ { &unsupport, 15, "R_HEX_B9_PCREL" }, \
+ { &unsupport, 16, "R_HEX_B32_PCREL_X" }, \
+ { &unsupport, 17, "R_HEX_32_6_X" }, \
+ { &unsupport, 18, "R_HEX_B22_PCREL_X" }, \
+ { &unsupport, 19, "R_HEX_B15_PCREL_X" }, \
+ { &unsupport, 20, "R_HEX_B13_PCREL_X" }, \
+ { &unsupport, 21, "R_HEX_B9_PCREL_X" }, \
+ { &unsupport, 22, "R_HEX_B7_PCREL_X" }, \
+ { &unsupport, 23, "R_HEX_16_X" }, \
+ { &unsupport, 24, "R_HEX_12_X" }, \
+ { &unsupport, 25, "R_HEX_11_X" }, \
+ { &unsupport, 26, "R_HEX_10_X" }, \
+ { &unsupport, 27, "R_HEX_9_X" }, \
+ { &unsupport, 28, "R_HEX_8_X" }, \
+ { &unsupport, 29, "R_HEX_7_X" }, \
+ { &unsupport, 30, "R_HEX_6_X" }, \
+ { &reloc32PCREL, 31, "R_HEX_32_PCREL" }, \
+ { &unsupport, 32, "R_HEX_COPY" }, \
+ { &unsupport, 33, "R_HEX_GLOB_DAT" }, \
+ { &unsupport, 34, "R_HEX_JMP_SLOT" }, \
+ { &unsupport, 35, "R_HEX_RELATIVE" }, \
+ { &unsupport, 36, "R_HEX_PLT_B22_PCREL" }, \
+ { &unsupport, 37, "R_HEX_GOTREL_LO16" }, \
+ { &unsupport, 38, "R_HEX_GOTREL_HI16" }, \
+ { &unsupport, 39, "R_HEX_GOTREL_32" }, \
+ { &unsupport, 40, "R_HEX_GOT_LO16" }, \
+ { &unsupport, 41, "R_HEX_GOT_HI16" }, \
+ { &unsupport, 42, "R_HEX_GOT_32" }, \
+ { &unsupport, 43, "R_HEX_GOT_16" }, \
+ { &unsupport, 44, "R_HEX_DTPMOD_32" }, \
+ { &unsupport, 45, "R_HEX_DTPREL_LO16" }, \
+ { &unsupport, 46, "R_HEX_DTPREL_HI16" }, \
+ { &unsupport, 47, "R_HEX_DTPREL_32" }, \
+ { &unsupport, 48, "R_HEX_DTPREL_16" }, \
+ { &unsupport, 49, "R_HEX_GD_PLT_B22_PCREL" }, \
+ { &unsupport, 50, "R_HEX_GD_GOT_LO16" }, \
+ { &unsupport, 51, "R_HEX_GD_GOT_HI16" }, \
+ { &unsupport, 52, "R_HEX_GD_GOT_32" }, \
+ { &unsupport, 53, "R_HEX_GD_GOT_16" }, \
+ { &unsupport, 54, "R_HEX_IE_LO16" }, \
+ { &unsupport, 55, "R_HEX_IE_HI16" }, \
+ { &unsupport, 56, "R_HEX_IE_32" }, \
+ { &unsupport, 57, "R_HEX_IE_GOT_LO16" }, \
+ { &unsupport, 58, "R_HEX_IE_GOT_HI16" }, \
+ { &unsupport, 59, "R_HEX_IE_GOT_32" }, \
+ { &unsupport, 60, "R_HEX_IE_GOT_16" }, \
+ { &unsupport, 61, "R_HEX_TPREL_LO16" }, \
+ { &unsupport, 62, "R_HEX_TPREL_HI16" }, \
+ { &unsupport, 63, "R_HEX_TPREL_32" }, \
+ { &unsupport, 64, "R_HEX_TPREL_16" }, \
+ { &unsupport, 65, "R_HEX_6_PCREL_X" }, \
+ { &unsupport, 66, "R_HEX_GOTREL_32_6_X" }, \
+ { &unsupport, 67, "R_HEX_GOTREL_16_X" }, \
+ { &unsupport, 68, "R_HEX_GOTREL_11_X" }, \
+ { &unsupport, 69, "R_HEX_GOT_32_6_X" }, \
+ { &unsupport, 70, "R_HEX_GOT_16_X" }, \
+ { &unsupport, 71, "R_HEX_GOT_11_X" }, \
+ { &unsupport, 72, "R_HEX_DTPREL_32_6_X" }, \
+ { &unsupport, 73, "R_HEX_DTPREL_16_X" }, \
+ { &unsupport, 74, "R_HEX_DTPREL_11_X" }, \
+ { &unsupport, 75, "R_HEX_GD_GOT_32_6_X" }, \
+ { &unsupport, 76, "R_HEX_GD_GOT_16_X" }, \
+ { &unsupport, 77, "R_HEX_GD_GOT_11_X" }, \
+ { &unsupport, 78, "R_HEX_IE_32_6_X" }, \
+ { &unsupport, 79, "R_HEX_IE_16_X" }, \
+ { &unsupport, 80, "R_HEX_IE_GOT_32_6_X" }, \
+ { &unsupport, 81, "R_HEX_IE_GOT_16_X" }, \
+ { &unsupport, 82, "R_HEX_IE_GOT_11_X" }, \
+ { &unsupport, 83, "R_HEX_TPREL_32_6_X" }, \
+ { &unsupport, 84, "R_HEX_TPREL_16_X" }, \
+ { &unsupport, 85, "R_HEX_TPREL_11_X" }
diff --git a/lib/Target/Hexagon/HexagonRelocator.cpp b/lib/Target/Hexagon/HexagonRelocator.cpp
new file mode 100644
index 0000000..1bfa2b0
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonRelocator.cpp
@@ -0,0 +1,259 @@
+//===- HexagonRelocator.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/DataTypes.h>
+#include <llvm/Support/ELF.h>
+#include <mcld/Support/MsgHandling.h>
+
+#include "HexagonRelocator.h"
+#include "HexagonRelocationFunctions.h"
+
+using namespace mcld;
+
+//===--------------------------------------------------------------------===//
+// Relocation Functions and Tables
+//===--------------------------------------------------------------------===//
+DECL_HEXAGON_APPLY_RELOC_FUNCS
+
+/// the prototype of applying function
+typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc,
+ HexagonRelocator& pParent);
+
+// the table entry of applying functions
+struct ApplyFunctionTriple
+{
+ ApplyFunctionType func;
+ unsigned int type;
+ const char* name;
+};
+
+// declare the table of applying functions
+static const ApplyFunctionTriple ApplyFunctions[] = {
+ DECL_HEXAGON_APPLY_RELOC_FUNC_PTRS
+};
+
+//===--------------------------------------------------------------------===//
+// HexagonRelocator
+//===--------------------------------------------------------------------===//
+HexagonRelocator::HexagonRelocator(HexagonLDBackend& pParent)
+ : Relocator(),
+ m_Target(pParent) {
+}
+
+HexagonRelocator::~HexagonRelocator()
+{
+}
+
+Relocator::Result
+HexagonRelocator::applyRelocation(Relocation& pRelocation)
+{
+ Relocation::Type type = pRelocation.type();
+
+ if (type > 85) { // 86-255 relocs do not exists for Hexagon
+ return Relocator::Unknown;
+ }
+
+ // apply the relocation
+ return ApplyFunctions[type].func(pRelocation, *this);
+}
+
+const char* HexagonRelocator::getName(Relocation::Type pType) const
+{
+ return ApplyFunctions[pType].name;
+}
+
+Relocator::Size HexagonRelocator::getSize(Relocation::Type pType) const
+{
+ return 32;
+}
+//===--------------------------------------------------------------------===//
+// Relocation helper function
+//===--------------------------------------------------------------------===//
+template<typename T1, typename T2>
+T1 ApplyMask(T2 pMask, T1 pData) {
+ T1 result = 0;
+ size_t off = 0;
+
+ for (size_t bit = 0; bit != sizeof (T1) * 8; ++bit) {
+ const bool valBit = (pData >> off) & 1;
+ const bool maskBit = (pMask >> bit) & 1;
+ if (maskBit) {
+ result |= static_cast<T1>(valBit) << bit;
+ ++off;
+ }
+ }
+ return result;
+}
+
+//=========================================//
+// Each relocation function implementation //
+//=========================================//
+
+// R_HEX_NONE
+HexagonRelocator::Result none(Relocation& pReloc, HexagonRelocator& pParent)
+{
+ return HexagonRelocator::OK;
+}
+
+// R_HEX_B22_PCREL: Word32_B22 : 0x01ff3ffe (S + A - P) >> 2 : Signed Verify
+HexagonRelocator::Result relocB22PCREL(Relocation& pReloc,
+ HexagonRelocator& pParent)
+{
+ HexagonRelocator::Address S = pReloc.symValue();
+ HexagonRelocator::DWord A = pReloc.addend();
+ HexagonRelocator::DWord P = pReloc.place();
+
+ int32_t result = (int32_t) ((S + A - P) >> 2);
+ int32_t range = 1 << 21;
+
+ if ( (result < range) && (result > -range)) {
+ pReloc.target() = pReloc.target() | ApplyMask(0x01ff3ffe, result);
+ return HexagonRelocator::OK;
+ }
+ return HexagonRelocator::Overflow;
+}
+
+// R_HEX_B15_PCREL: Word32_B15 : 0x00df20fe (S + A - P) >> 2 : Signed Verify
+HexagonRelocator::Result relocB15PCREL(Relocation& pReloc,
+ HexagonRelocator& pParent)
+{
+ HexagonRelocator::Address S = pReloc.symValue();
+ HexagonRelocator::DWord A = pReloc.addend();
+ HexagonRelocator::DWord P = pReloc.place();
+
+ int32_t result = (int32_t) ((S + A - P) >> 2);
+ int32_t range = 1 << 14;
+ if ( (result < range) && (result > -range)) {
+ pReloc.target() = pReloc.target() | ApplyMask(0x00df20fe,result);
+ return HexagonRelocator::OK;
+ }
+ return HexagonRelocator::Overflow;
+}
+
+// R_HEX_B7_PCREL: Word32_B7 : 0x0001f18 (S + A - P) >> 2 : Signed Verify
+HexagonRelocator::Result relocB7PCREL(Relocation& pReloc,
+ HexagonRelocator& pParent)
+{
+ HexagonRelocator::Address S = pReloc.symValue();
+ HexagonRelocator::DWord A = pReloc.addend();
+ HexagonRelocator::DWord P = pReloc.place();
+
+ int32_t result = (int32_t) ((S + A - P) >> 2);
+ int32_t range = 1 << 6;
+ if ( (result < range) && (result > -range)) {
+ pReloc.target() = pReloc.target() | ApplyMask(0x00001f18, result);
+ return HexagonRelocator::OK;
+ }
+ return HexagonRelocator::Overflow;
+}
+
+// R_HEX_LO16: Word32_LO : 0x00c03fff (S + A) : Unsigned Truncate
+HexagonRelocator::Result relocLO16(Relocation& pReloc,
+ HexagonRelocator& pParent)
+{
+ HexagonRelocator::Address S = pReloc.symValue();
+ HexagonRelocator::DWord A = pReloc.addend();
+
+ uint32_t result = (uint32_t) (S + A);
+ pReloc.target() = pReloc.target() | ApplyMask(0x00c03fff, result);
+ return HexagonRelocator::OK;
+}
+
+// R_HEX_HI16: Word32_LO : 0x00c03fff (S + A) >> 16 : Unsigned Truncate
+HexagonRelocator::Result relocHI16(Relocation& pReloc,
+ HexagonRelocator& pParent)
+{
+ HexagonRelocator::Address S = pReloc.symValue();
+ HexagonRelocator::DWord A = pReloc.addend();
+
+ uint32_t result = (uint32_t) ((S + A) >> 16);
+ pReloc.target() = pReloc.target() | ApplyMask(0x00c03fff, result);
+ return HexagonRelocator::OK;
+}
+
+// R_HEX_32: Word32 : 0xffffffff : (S + A) : Unsigned Truncate
+HexagonRelocator::Result reloc32(Relocation& pReloc, HexagonRelocator& pParent)
+{
+ HexagonRelocator::DWord A = pReloc.addend();
+ HexagonRelocator::DWord S = pReloc.symValue();
+
+ uint32_t result = (uint32_t) (S + A);
+
+ pReloc.target() = result | pReloc.target();
+ return HexagonRelocator::OK;
+}
+
+// R_HEX_16: Word32 : 0xffff : (S + A) : Unsigned Truncate
+HexagonRelocator::Result reloc16(Relocation& pReloc, HexagonRelocator& pParent)
+{
+ HexagonRelocator::DWord A = pReloc.addend();
+ HexagonRelocator::DWord S = pReloc.symValue();
+
+ uint32_t result = (uint32_t) (S + A);
+ pReloc.target() = pReloc.target() | ApplyMask(0x0000ffff, result);
+
+ return HexagonRelocator::OK;
+}
+
+// R_HEX_8: Word32 : 0xff : (S + A) : Unsigned Truncate
+HexagonRelocator::Result reloc8(Relocation& pReloc, HexagonRelocator& pParent)
+{
+ HexagonRelocator::DWord A = pReloc.addend();
+ HexagonRelocator::DWord S = pReloc.symValue();
+
+ uint32_t result = (uint32_t) (S + A);
+ pReloc.target() = pReloc.target() | ApplyMask(0x000000ff, result);
+
+ return HexagonRelocator::OK;
+}
+
+// R_HEX_B13_PCREL : Word32_B13 : 0x00202ffe (S + A - P)>>2 : Signed Verify
+HexagonRelocator::Result relocB13PCREL(Relocation& pReloc,
+ HexagonRelocator& pParent)
+{
+ HexagonRelocator::Address S = pReloc.symValue();
+ HexagonRelocator::DWord A = pReloc.addend();
+ HexagonRelocator::DWord P = pReloc.place();
+
+ int32_t result = ((S + A - P) >> 2);
+ int32_t range = 1L << 12;
+ if (result < range && result > -range) {
+ pReloc.target() = pReloc.target() | ApplyMask(0x00202ffe, result);
+ return HexagonRelocator::OK;
+ }
+ return HexagonRelocator::Overflow;
+}
+
+HexagonRelocator::Result unsupport(Relocation& pReloc,
+ HexagonRelocator& pParent)
+{
+ return HexagonRelocator::Unsupport;
+}
+
+
+
+// R_HEX_32_PCREL : Word32 : 0xffffffff (S + A - P) : Signed Verify
+HexagonRelocator::Result reloc32PCREL(Relocation& pReloc,
+ HexagonRelocator& pParent)
+{
+ HexagonRelocator::Address S = pReloc.symValue();
+ HexagonRelocator::DWord A = pReloc.addend();
+ HexagonRelocator::DWord P = pReloc.place();
+
+ int64_t result = S + A - P;
+ int32_t range = 1 << 31;
+
+ if (result < range && result > -range) {
+ pReloc.target() = pReloc.target() | ApplyMask(0xffffffff, result);
+ return HexagonRelocator::OK;
+ }
+
+ return HexagonRelocator::Overflow;
+}
diff --git a/lib/Target/Hexagon/HexagonRelocator.h b/lib/Target/Hexagon/HexagonRelocator.h
new file mode 100644
index 0000000..b7347ee
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonRelocator.h
@@ -0,0 +1,66 @@
+//===- HexagonRelocator.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef HEXAGON_RELOCATION_FACTORY_H
+#define HEXAGON_RELOCATION_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/Relocator.h>
+#include <mcld/Target/GOT.h>
+#include <mcld/Target/PLT.h>
+#include <mcld/Target/SymbolEntryMap.h>
+#include "HexagonLDBackend.h"
+
+namespace mcld {
+
+class ResolveInfo;
+
+/** \class HexagonRelocator
+ * \brief HexagonRelocator creates and destroys the Hexagon relocations.
+ *
+ */
+class HexagonRelocator : public Relocator
+{
+public:
+ typedef SymbolEntryMap<PLTEntryBase> SymPLTMap;
+ typedef SymbolEntryMap<HexagonGOTEntry> SymGOTMap;
+
+public:
+ HexagonRelocator(HexagonLDBackend& pParent);
+ ~HexagonRelocator();
+
+ Result applyRelocation(Relocation& pRelocation);
+
+ HexagonLDBackend& getTarget()
+ { return m_Target; }
+
+ const HexagonLDBackend& getTarget() const
+ { return m_Target; }
+
+ const char* getName(Relocation::Type pType) const;
+
+ Size getSize(Relocation::Type pType) const;
+
+ const SymPLTMap& getSymPLTMap() const { return m_SymPLTMap; }
+ SymPLTMap& getSymPLTMap() { return m_SymPLTMap; }
+
+ const SymGOTMap& getSymGOTMap() const { return m_SymGOTMap; }
+ SymGOTMap& getSymGOTMap() { return m_SymGOTMap; }
+
+private:
+ HexagonLDBackend& m_Target;
+ SymPLTMap m_SymPLTMap;
+ SymGOTMap m_SymGOTMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/Hexagon/HexagonTargetMachine.cpp b/lib/Target/Hexagon/HexagonTargetMachine.cpp
new file mode 100644
index 0000000..4e4f1c2
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonTargetMachine.cpp
@@ -0,0 +1,29 @@
+//===- HexagonTargetMachine.cpp -------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "HexagonTargetMachine.h"
+#include "Hexagon.h"
+#include <mcld/Target/TargetMachine.h>
+#include <mcld/Support/TargetRegistry.h>
+
+extern "C" void MCLDInitializeHexagonLDTarget() {
+ // Register createTargetMachine function pointer to mcld::Target
+ mcld::RegisterTargetMachine<mcld::HexagonTargetMachine>
+ X(mcld::TheHexagonTarget);
+}
+
+mcld::HexagonTargetMachine::HexagonTargetMachine(llvm::TargetMachine& pPM,
+ const mcld::Target &pTarget,
+ const std::string& pTriple)
+ : mcld::MCLDTargetMachine(pPM, pTarget, pTriple) {
+}
+
+mcld::HexagonTargetMachine::~HexagonTargetMachine()
+{
+}
+
diff --git a/lib/Target/Hexagon/HexagonTargetMachine.h b/lib/Target/Hexagon/HexagonTargetMachine.h
new file mode 100644
index 0000000..a374475
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonTargetMachine.h
@@ -0,0 +1,28 @@
+//===- HexagonTargetMachine.h ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_HEXAGON_TARGET_MACHINE_H
+#define MCLD_HEXAGON_TARGET_MACHINE_H
+#include "Hexagon.h"
+#include <mcld/Target/TargetMachine.h>
+
+namespace mcld {
+
+class HexagonTargetMachine : public MCLDTargetMachine
+{
+public:
+ HexagonTargetMachine(llvm::TargetMachine &pTM,
+ const mcld::Target &pTarget,
+ const std::string &pTriple);
+
+ virtual ~HexagonTargetMachine();
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp b/lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp
new file mode 100644
index 0000000..0b113aa
--- /dev/null
+++ b/lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp
@@ -0,0 +1,22 @@
+//===- HexagonTargetInfo.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Target/TargetMachine.h>
+#include <mcld/Support/TargetRegistry.h>
+
+namespace mcld {
+
+mcld::Target TheHexagonTarget;
+
+extern "C" void MCLDInitializeHexagonLDTargetInfo() {
+ // register into mcld::TargetRegistry
+ mcld::RegisterTarget X(TheHexagonTarget, "hexagon");
+}
+
+} // namespace of mcld
+
diff --git a/lib/Target/Mips/MipsGNUInfo.h b/lib/Target/Mips/MipsGNUInfo.h
index 9bbc548..a1d8cd2 100644
--- a/lib/Target/Mips/MipsGNUInfo.h
+++ b/lib/Target/Mips/MipsGNUInfo.h
@@ -17,10 +17,36 @@ namespace mcld {
class MipsGNUInfo : public GNUInfo
{
public:
+ enum {
+ // The original o32 abi.
+ E_MIPS_ABI_O32 = 0x00001000,
+ // O32 extended to work on 64 bit architectures.
+ E_MIPS_ABI_O64 = 0x00002000,
+ // EABI in 32 bit mode.
+ E_MIPS_ABI_EABI32 = 0x00003000,
+ // EABI in 64 bit mode.
+ E_MIPS_ABI_EABI64 = 0x00004000
+ };
+
+public:
MipsGNUInfo(const llvm::Triple& pTriple) : GNUInfo(pTriple) { }
uint32_t machine() const { return llvm::ELF::EM_MIPS; }
+ uint64_t defaultTextSegmentAddr() const { return 0x80000; }
+
+ uint64_t flags() const
+ {
+ // TODO: (simon) The correct flag's set depend on command line
+ // arguments and flags from input .o files.
+ return llvm::ELF::EF_MIPS_ARCH_32R2 |
+ llvm::ELF::EF_MIPS_NOREORDER |
+ llvm::ELF::EF_MIPS_PIC |
+ llvm::ELF::EF_MIPS_CPIC |
+ E_MIPS_ABI_O32;
+ }
+
+ uint64_t abiPageSize() const { return 0x10000; }
};
} // namespace of mcld
diff --git a/lib/Target/Mips/MipsLDBackend.cpp b/lib/Target/Mips/MipsLDBackend.cpp
index 59b8d18..0806a2a 100644
--- a/lib/Target/Mips/MipsLDBackend.cpp
+++ b/lib/Target/Mips/MipsLDBackend.cpp
@@ -20,7 +20,6 @@
#include <mcld/IRBuilder.h>
#include <mcld/MC/Attribute.h>
#include <mcld/Fragment/FillFragment.h>
-#include <mcld/Fragment/FragmentLinker.h>
#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/MsgHandling.h>
@@ -28,17 +27,6 @@
#include <mcld/Target/OutputRelocSection.h>
#include <mcld/Object/ObjectBuilder.h>
-enum {
- // The original o32 abi.
- E_MIPS_ABI_O32 = 0x00001000,
- // O32 extended to work on 64 bit architectures.
- E_MIPS_ABI_O64 = 0x00002000,
- // EABI in 32 bit mode.
- E_MIPS_ABI_EABI32 = 0x00003000,
- // EABI in 64 bit mode.
- E_MIPS_ABI_EABI64 = 0x00004000
-};
-
using namespace mcld;
//===----------------------------------------------------------------------===//
@@ -79,13 +67,12 @@ void MipsGNULDBackend::initTargetSections(Module& pModule, ObjectBuilder& pBuild
}
}
-void MipsGNULDBackend::initTargetSymbols(FragmentLinker& pLinker)
+void MipsGNULDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule)
{
// Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
// same name in input
- m_pGOTSymbol = pLinker.defineSymbol<FragmentLinker::AsRefered, FragmentLinker::Resolve>(
+ m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"_GLOBAL_OFFSET_TABLE_",
- false,
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Local,
@@ -94,9 +81,8 @@ void MipsGNULDBackend::initTargetSymbols(FragmentLinker& pLinker)
FragmentRef::Null(), // FragRef
ResolveInfo::Hidden);
- m_pGpDispSymbol = pLinker.defineSymbol<FragmentLinker::AsRefered, FragmentLinker::Resolve>(
+ m_pGpDispSymbol = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"_gp_disp",
- false,
ResolveInfo::Section,
ResolveInfo::Define,
ResolveInfo::Absolute,
@@ -110,11 +96,10 @@ void MipsGNULDBackend::initTargetSymbols(FragmentLinker& pLinker)
}
}
-bool MipsGNULDBackend::initRelocator(const FragmentLinker& pLinker)
+bool MipsGNULDBackend::initRelocator()
{
if (NULL == m_pRelocator) {
m_pRelocator = new MipsRelocator(*this);
- m_pRelocator->setFragmentLinker(pLinker);
}
return true;
}
@@ -126,9 +111,9 @@ Relocator* MipsGNULDBackend::getRelocator()
}
void MipsGNULDBackend::scanRelocation(Relocation& pReloc,
- FragmentLinker& pLinker,
+ IRBuilder& pBuilder,
Module& pModule,
- const LDSection& pSection)
+ LDSection& pSection)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
@@ -142,7 +127,8 @@ void MipsGNULDBackend::scanRelocation(Relocation& pReloc,
pReloc.updateAddend();
- if (0 == (pSection.flag() & llvm::ELF::SHF_ALLOC))
+ assert(NULL != pSection.getLink());
+ if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC))
return;
// We test isLocal or if pInputSym is not a dynamic symbol
@@ -150,47 +136,22 @@ void MipsGNULDBackend::scanRelocation(Relocation& pReloc,
// Don't put undef symbols into local entries.
if ((rsym->isLocal() || !isDynamicSymbol(*rsym) ||
!rsym->isDyn()) && !rsym->isUndef())
- scanLocalReloc(pReloc, pLinker);
+ scanLocalReloc(pReloc, pBuilder, pSection);
else
- scanGlobalReloc(pReloc, pLinker);
+ scanGlobalReloc(pReloc, pBuilder, pSection);
// check if we shoule issue undefined reference for the relocation target
// symbol
if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
fatal(diag::undefined_reference) << rsym->name();
-
- if ((rsym->reserved() & ReserveRel) != 0x0) {
- // set hasTextRelSection if needed
- checkAndSetHasTextRel(pSection);
- }
-}
-
-uint64_t MipsGNULDBackend::flags() const
-{
- // TODO: (simon) The correct flag's set depend on command line
- // arguments and flags from input .o files.
- return llvm::ELF::EF_MIPS_ARCH_32R2 |
- llvm::ELF::EF_MIPS_NOREORDER |
- llvm::ELF::EF_MIPS_PIC |
- llvm::ELF::EF_MIPS_CPIC |
- E_MIPS_ABI_O32;
-}
-
-uint64_t MipsGNULDBackend::defaultTextSegmentAddr() const
-{
- return 0x80000;
}
-uint64_t MipsGNULDBackend::abiPageSize() const
+void MipsGNULDBackend::doPreLayout(IRBuilder& pBuilder)
{
- if (config().options().maxPageSize() > 0)
- return config().options().maxPageSize();
- else
- return static_cast<uint64_t>(0x10000);
-}
+ // initialize .dynamic data
+ if (!config().isCodeStatic() && NULL == m_pDynamic)
+ m_pDynamic = new MipsELFDynamic(*this, config());
-void MipsGNULDBackend::doPreLayout(FragmentLinker& pLinker)
-{
// set .got size
// when building shared object, the .got section is must.
if (LinkerConfig::Object != config().codeGenType()) {
@@ -198,18 +159,21 @@ void MipsGNULDBackend::doPreLayout(FragmentLinker& pLinker)
m_pGOT->hasGOT1() ||
NULL != m_pGOTSymbol) {
m_pGOT->finalizeSectionSize();
- defineGOTSymbol(pLinker);
+ defineGOTSymbol(pBuilder);
}
ELFFileFormat* file_format = getOutputFormat();
// set .rel.dyn size
- if (!m_pRelDyn->empty())
+ if (!m_pRelDyn->empty()) {
+ assert(!config().isCodeStatic() &&
+ "static linkage should not result in a dynamic relocation section");
file_format->getRelDyn().setSize(
m_pRelDyn->numOfRelocs() * getRelEntrySize());
+ }
}
}
-void MipsGNULDBackend::doPostLayout(Module& pModule,
- FragmentLinker& pLinker)
+
+void MipsGNULDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder)
{
}
@@ -217,9 +181,7 @@ void MipsGNULDBackend::doPostLayout(Module& pModule,
/// Use co-variant return type to return its own dynamic section.
MipsELFDynamic& MipsGNULDBackend::dynamic()
{
- if (NULL == m_pDynamic)
- m_pDynamic = new MipsELFDynamic(*this, config());
-
+ assert(NULL != m_pDynamic);
return *m_pDynamic;
}
@@ -227,7 +189,7 @@ MipsELFDynamic& MipsGNULDBackend::dynamic()
/// Use co-variant return type to return its own dynamic section.
const MipsELFDynamic& MipsGNULDBackend::dynamic() const
{
- assert( NULL != m_pDynamic);
+ assert(NULL != m_pDynamic);
return *m_pDynamic;
}
@@ -260,7 +222,7 @@ bool MipsGNULDBackend::isGlobalGOTSymbol(const LDSymbol& pSymbol) const
/// In ELF executable files, regular name pools are .symtab, .strtab,
/// .dynsym, .dynstr, .hash and .shstrtab.
void
-MipsGNULDBackend::sizeNamePools(const Module& pModule, bool pIsStaticLink)
+MipsGNULDBackend::sizeNamePools(Module& pModule, bool pIsStaticLink)
{
// number of entries in symbol tables starts from 1 to hold the special entry
// at index 0 (STN_UNDEF). See ELF Spec Book I, p1-21.
@@ -275,53 +237,37 @@ MipsGNULDBackend::sizeNamePools(const Module& pModule, bool pIsStaticLink)
size_t hash = 0;
// number of local symbol in the .dynsym
+ size_t symtab_local_cnt = 0;
size_t dynsym_local_cnt = 0;
- /// compute the size of .symtab, .dynsym and .strtab
- /// @{
- Module::const_sym_iterator symbol;
const Module::SymbolTable& symbols = pModule.getSymbolTable();
- size_t str_size = 0;
- // compute the size of symbols in Local and File category
- Module::const_sym_iterator symEnd = symbols.localEnd();
- for (symbol = symbols.localBegin(); symbol != symEnd; ++symbol) {
- str_size = (*symbol)->nameSize() + 1;
- if (!pIsStaticLink && isDynamicSymbol(**symbol)) {
- ++dynsym;
- if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol)
- dynstr += str_size;
- }
- ++symtab;
- if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol)
- strtab += str_size;
- }
- // compute the size of symbols in TLS category
- symEnd = symbols.tlsEnd();
- for (symbol = symbols.tlsBegin(); symbol != symEnd; ++symbol) {
- str_size = (*symbol)->nameSize() + 1;
- if (!pIsStaticLink) {
- ++dynsym;
- if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol)
- dynstr += str_size;
- }
+ Module::const_sym_iterator symbol, symEnd;
+ /// Compute the size of .symtab, .strtab, and symtab_local_cnt
+ /// @{
+ symEnd = symbols.end();
+ for (symbol = symbols.begin(); symbol != symEnd; ++symbol) {
++symtab;
- if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol)
- strtab += str_size;
+ if (ResolveInfo::Section != (*symbol)->type() ||
+ *symbol == m_pGpDispSymbol)
+ strtab += (*symbol)->nameSize() + 1;
}
- dynsym_local_cnt = dynsym;
- // compute the size of the reset of symbols
- symEnd = pModule.sym_end();
- for (symbol = symbols.tlsEnd(); symbol != symEnd; ++symbol) {
- str_size = (*symbol)->nameSize() + 1;
- if (!pIsStaticLink && isDynamicSymbol(**symbol)) {
+ symtab_local_cnt = 1 + symbols.numOfFiles() + symbols.numOfLocals() +
+ symbols.numOfLocalDyns();
+ /// @}
+
+ /// Compute the size of .dynsym, .dynstr, and dynsym_local_cnt
+ /// @{
+ if (!pIsStaticLink) {
+ symEnd = symbols.dynamicEnd();
+ for (symbol = symbols.localDynBegin(); symbol != symEnd; ++symbol) {
++dynsym;
- if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol)
- dynstr += str_size;
+ if (ResolveInfo::Section != (*symbol)->type() ||
+ *symbol == m_pGpDispSymbol)
+ dynstr += (*symbol)->nameSize() + 1;
}
- ++symtab;
- if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol)
- strtab += str_size;
+ dynsym_local_cnt = 1 + symbols.numOfLocalDyns();
}
+ /// @}
ELFFileFormat* file_format = getOutputFormat();
@@ -357,6 +303,15 @@ MipsGNULDBackend::sizeNamePools(const Module& pModule, bool pIsStaticLink)
}
}
+ if (!config().options().getRpathList().empty()) {
+ dynamic().reserveNeedEntry();
+ GeneralOptions::const_rpath_iterator rpath,
+ rpathEnd = config().options().rpath_end();
+ for (rpath = config().options().rpath_begin();
+ rpath != rpathEnd; ++rpath)
+ dynstr += (*rpath).size() + 1;
+ }
+
// compute .hash
// Both Elf32_Word and Elf64_Word are 4 bytes
hash = (2 + getHashBucketCount(dynsym, false) + dynsym) *
@@ -385,7 +340,7 @@ MipsGNULDBackend::sizeNamePools(const Module& pModule, bool pIsStaticLink)
// set .symtab sh_info to one greater than the symbol table
// index of the last local symbol
- file_format->getSymTab().setInfo(symbols.numOfLocals() + 1);
+ file_format->getSymTab().setInfo(symtab_local_cnt);
break;
}
default: {
@@ -449,8 +404,7 @@ void MipsGNULDBackend::emitSymbol32(llvm::ELF::Elf32_Sym& pSym,
///
/// the size of these tables should be computed before layout
/// layout should computes the start offset of these tables
-void MipsGNULDBackend::emitDynNamePools(const Module& pModule,
- MemoryArea& pOutput)
+void MipsGNULDBackend::emitDynNamePools(Module& pModule, MemoryArea& pOutput)
{
ELFFileFormat* file_format = getOutputFormat();
if (!file_format->hasDynSymTab() ||
@@ -498,61 +452,14 @@ void MipsGNULDBackend::emitDynNamePools(const Module& pModule,
size_t symtabIdx = 1;
size_t strtabsize = 1;
- // emit of .dynsym, and .dynstr except GOT entries
- Module::const_sym_iterator symbol;
+ // emit .dynsym, and .dynstr (emit LocalDyn and Dynamic category) except GOT
+ // entries
const Module::SymbolTable& symbols = pModule.getSymbolTable();
- // emit symbol in File and Local category if it's dynamic symbol
- Module::const_sym_iterator symEnd = symbols.localEnd();
- for (symbol = symbols.localBegin(); symbol != symEnd; ++symbol) {
- if (!isDynamicSymbol(**symbol))
- continue;
-
+ Module::const_sym_iterator symbol, symEnd = symbols.dynamicEnd();
+ for (symbol = symbols.localDynBegin(); symbol != symEnd; ++symbol) {
if (isGlobalGOTSymbol(**symbol))
continue;
-
- emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize,
- symtabIdx);
-
- // maintain output's symbol and index map
- entry = m_pSymIndexMap->insert(*symbol, sym_exist);
- entry->setValue(symtabIdx);
- // sum up counters
- ++symtabIdx;
- if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol)
- strtabsize += (*symbol)->nameSize() + 1;
- }
-
- // emit symbols in TLS category, all symbols in TLS category shold be emitited
- // directly, except GOT entries
- symEnd = symbols.tlsEnd();
- for (symbol = symbols.tlsBegin(); symbol != symEnd; ++symbol) {
- if (isGlobalGOTSymbol(**symbol))
- continue;
-
- emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize,
- symtabIdx);
-
- // maintain output's symbol and index map
- entry = m_pSymIndexMap->insert(*symbol, sym_exist);
- entry->setValue(symtabIdx);
- // sum up counters
- ++symtabIdx;
- if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol)
- strtabsize += (*symbol)->nameSize() + 1;
- }
-
- // emit the reset of the symbols if the symbol is dynamic symbol
- symEnd = pModule.sym_end();
- for (symbol = symbols.tlsEnd(); symbol != symEnd; ++symbol) {
- if (!isDynamicSymbol(**symbol))
- continue;
-
- if (isGlobalGOTSymbol(**symbol))
- continue;
-
- emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize,
- symtabIdx);
-
+ emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize, symtabIdx);
// maintain output's symbol and index map
entry = m_pSymIndexMap->insert(*symbol, sym_exist);
entry->setValue(symtabIdx);
@@ -566,22 +473,19 @@ void MipsGNULDBackend::emitDynNamePools(const Module& pModule,
for (std::vector<LDSymbol*>::const_iterator symbol = m_GlobalGOTSyms.begin(),
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))
fatal(diag::mips_got_symbol) << (*symbol)->name();
- emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize,
- symtabIdx);
+ emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize, symtabIdx);
// maintain output's symbol and index map
entry = m_pSymIndexMap->insert(*symbol, sym_exist);
entry->setValue(symtabIdx);
-
// sum up counters
++symtabIdx;
- if (ResolveInfo::Section != (*symbol)->type())
+ if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol)
strtabsize += (*symbol)->nameSize() + 1;
}
@@ -614,6 +518,19 @@ void MipsGNULDBackend::emitDynNamePools(const Module& pModule,
} // for
// emit soname
+
+ if (!config().options().getRpathList().empty()) {
+ (*dt_need)->setValue(llvm::ELF::DT_RPATH, strtabsize);
+ ++dt_need;
+ GeneralOptions::const_rpath_iterator rpath,
+ rpathEnd = config().options().rpath_end();
+ for (rpath = config().options().rpath_begin(); rpath != rpathEnd; ++rpath) {
+ memcpy((strtab + strtabsize), (*rpath).data(), (*rpath).size());
+ strtabsize += (*rpath).size();
+ strtab[strtabsize++] = (rpath + 1 == rpathEnd ? '\0' : ':');
+ }
+ }
+
// initialize value of ELF .dynamic section
if (LinkerConfig::DynObj == config().codeGenType())
dynamic().applySoname(strtabsize);
@@ -689,7 +606,7 @@ MipsGNULDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const
}
/// finalizeSymbol - finalize the symbol value
-bool MipsGNULDBackend::finalizeTargetSymbols(FragmentLinker& pLinker)
+bool MipsGNULDBackend::finalizeTargetSymbols()
{
if (NULL != m_pGpDispSymbol)
m_pGpDispSymbol->setValue(m_pGOT->addr() + 0x7FF0);
@@ -704,7 +621,8 @@ bool MipsGNULDBackend::allocateCommonSymbols(Module& pModule)
{
SymbolCategory& symbol_list = pModule.getSymbolTable();
- if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
+ if (symbol_list.emptyCommons() && symbol_list.emptyFiles() &&
+ symbol_list.emptyLocals() && symbol_list.emptyLocalDyns())
return true;
SymbolCategory::iterator com_sym, com_end;
@@ -796,7 +714,8 @@ bool MipsGNULDBackend::allocateCommonSymbols(Module& pModule)
}
void MipsGNULDBackend::scanLocalReloc(Relocation& pReloc,
- FragmentLinker& pLinker)
+ IRBuilder& pBuilder,
+ const LDSection& pSection)
{
ResolveInfo* rsym = pReloc.symInfo();
@@ -812,6 +731,7 @@ void MipsGNULDBackend::scanLocalReloc(Relocation& pReloc,
// 2. Check this condition here.
m_pRelDyn->reserveEntry();
rsym->setReserved(rsym->reserved() | ReserveRel);
+ checkAndSetHasTextRel(*pSection.getLink());
// Remeber this rsym is a local GOT entry (as if it needs an entry).
// Actually we don't allocate an GOT entry.
@@ -846,6 +766,10 @@ void MipsGNULDBackend::scanLocalReloc(Relocation& pReloc,
break;
case llvm::ELF::R_MIPS_GOT16:
case llvm::ELF::R_MIPS_CALL16:
+ case llvm::ELF::R_MIPS_GOT_HI16:
+ case llvm::ELF::R_MIPS_CALL_HI16:
+ case llvm::ELF::R_MIPS_GOT_LO16:
+ case llvm::ELF::R_MIPS_CALL_LO16:
// For got16 section based relocations, we need to reserve got entries.
if (rsym->type() == ResolveInfo::Section) {
m_pGOT->reserveLocalEntry();
@@ -864,12 +788,7 @@ void MipsGNULDBackend::scanLocalReloc(Relocation& pReloc,
case llvm::ELF::R_MIPS_GPREL32:
case llvm::ELF::R_MIPS_GPREL16:
case llvm::ELF::R_MIPS_LITERAL:
- break;
case llvm::ELF::R_MIPS_GOT_DISP:
- case llvm::ELF::R_MIPS_GOT_HI16:
- case llvm::ELF::R_MIPS_CALL_HI16:
- case llvm::ELF::R_MIPS_GOT_LO16:
- case llvm::ELF::R_MIPS_CALL_LO16:
break;
case llvm::ELF::R_MIPS_TLS_DTPMOD32:
case llvm::ELF::R_MIPS_TLS_DTPREL32:
@@ -892,7 +811,8 @@ void MipsGNULDBackend::scanLocalReloc(Relocation& pReloc,
}
void MipsGNULDBackend::scanGlobalReloc(Relocation& pReloc,
- FragmentLinker& pLinker)
+ IRBuilder& pBuilder,
+ const LDSection& pSection)
{
ResolveInfo* rsym = pReloc.symInfo();
@@ -913,9 +833,10 @@ void MipsGNULDBackend::scanGlobalReloc(Relocation& pReloc,
case llvm::ELF::R_MIPS_64:
case llvm::ELF::R_MIPS_HI16:
case llvm::ELF::R_MIPS_LO16:
- if (symbolNeedsDynRel(pLinker, *rsym, false, true)) {
+ if (symbolNeedsDynRel(*rsym, false, true)) {
m_pRelDyn->reserveEntry();
rsym->setReserved(rsym->reserved() | ReserveRel);
+ checkAndSetHasTextRel(*pSection.getLink());
// Remeber this rsym is a global GOT entry (as if it needs an entry).
// Actually we don't allocate an GOT entry.
@@ -982,13 +903,12 @@ void MipsGNULDBackend::scanGlobalReloc(Relocation& pReloc,
}
}
-void MipsGNULDBackend::defineGOTSymbol(FragmentLinker& pLinker)
+void MipsGNULDBackend::defineGOTSymbol(IRBuilder& pBuilder)
{
// define symbol _GLOBAL_OFFSET_TABLE_
if ( m_pGOTSymbol != NULL ) {
- pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Unresolve>(
+ pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
"_GLOBAL_OFFSET_TABLE_",
- false,
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Local,
@@ -998,9 +918,8 @@ void MipsGNULDBackend::defineGOTSymbol(FragmentLinker& pLinker)
ResolveInfo::Hidden);
}
else {
- m_pGOTSymbol = pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Resolve>(
+ m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
"_GLOBAL_OFFSET_TABLE_",
- false,
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Local,
@@ -1013,8 +932,7 @@ void MipsGNULDBackend::defineGOTSymbol(FragmentLinker& pLinker)
/// doCreateProgramHdrs - backend can implement this function to create the
/// target-dependent segments
-void MipsGNULDBackend::doCreateProgramHdrs(Module& pModule,
- const FragmentLinker& pLinker)
+void MipsGNULDBackend::doCreateProgramHdrs(Module& pModule)
{
// TODO
}
diff --git a/lib/Target/Mips/MipsLDBackend.h b/lib/Target/Mips/MipsLDBackend.h
index b9db410..1933751 100644
--- a/lib/Target/Mips/MipsLDBackend.h
+++ b/lib/Target/Mips/MipsLDBackend.h
@@ -15,7 +15,6 @@
namespace mcld {
class LinkerConfig;
-class FragmentLinker;
class OutputRelocSection;
class SectionMap;
class MemoryArea;
@@ -43,10 +42,10 @@ public:
void initTargetSections(Module& pModule, ObjectBuilder& pBuilder);
/// initTargetSymbols - initialize target dependent symbols in output.
- void initTargetSymbols(FragmentLinker& pLinker);
+ void initTargetSymbols(IRBuilder& pBuilder, Module& pModule);
/// initRelocator - create and initialize Relocator.
- bool initRelocator(const FragmentLinker& pLinker);
+ bool initRelocator();
/// getRelocator - return relocator.
Relocator* getRelocator();
@@ -55,23 +54,15 @@ public:
/// create the empty entries if needed.
/// For Mips, the GOT, GP, and dynamic relocation entries are check to create.
void scanRelocation(Relocation& pReloc,
- FragmentLinker& pLinker,
+ IRBuilder& pBuilder,
Module& pModule,
- const LDSection& pSection);
-
- /// flags - the value of ElfXX_Ehdr::e_flags
- uint64_t flags() const;
-
- uint64_t defaultTextSegmentAddr() const;
-
- /// abiPageSize - the abi page size of the target machine
- uint64_t abiPageSize() const;
+ LDSection& pSection);
/// preLayout - Backend can do any needed modification before layout
- void doPreLayout(FragmentLinker& pLinker);
+ void doPreLayout(IRBuilder& pBuilder);
- /// postLayout -Backend can do any needed modification after layout
- void doPostLayout(Module& pModule, FragmentLinker& pLinker);
+ /// postLayout - Backend can do any needed modification after layout
+ void doPostLayout(Module& pModule, IRBuilder& pBuilder);
/// dynamic - the dynamic section of the target machine.
/// Use co-variant return type to return its own dynamic section.
@@ -98,10 +89,10 @@ public:
uint64_t emitSectionData(const LDSection& pSection,
MemoryRegion& pRegion) const;
- void sizeNamePools(const Module& pModule, bool pIsStaticLink);
+ void sizeNamePools(Module& pModule, bool pIsStaticLink);
/// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash
- void emitDynNamePools(const Module& pModule, MemoryArea& pOut);
+ void emitDynNamePools(Module& pModule, MemoryArea& pOut);
MipsGOT& getGOT();
@@ -114,18 +105,22 @@ public:
unsigned int getTargetSectionOrder(const LDSection& pSectHdr) const;
/// finalizeSymbol - finalize the symbol value
- bool finalizeTargetSymbols(FragmentLinker& pLinker);
+ bool finalizeTargetSymbols();
/// allocateCommonSymbols - allocate common symbols in the corresponding
/// sections.
bool allocateCommonSymbols(Module& pModule);
private:
- void scanLocalReloc(Relocation& pReloc, FragmentLinker& pLinker);
+ void scanLocalReloc(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ const LDSection& pSection);
- void scanGlobalReloc(Relocation& pReloc, FragmentLinker& pLinker);
+ void scanGlobalReloc(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ const LDSection& pSection);
- void defineGOTSymbol(FragmentLinker& pLinker);
+ void defineGOTSymbol(IRBuilder& pBuilder);
/// emitSymbol32 - emit an ELF32 symbol, override parent's function
void emitSymbol32(llvm::ELF::Elf32_Sym& pSym32,
@@ -144,8 +139,7 @@ private:
/// doCreateProgramHdrs - backend can implement this function to create the
/// target-dependent segments
- virtual void doCreateProgramHdrs(Module& pModule,
- const FragmentLinker& pLinker);
+ void doCreateProgramHdrs(Module& pModule);
private:
Relocator* m_pRelocator;
diff --git a/lib/Target/Mips/MipsRelocationFunctions.h b/lib/Target/Mips/MipsRelocationFunctions.h
index aad708e..f1461a0 100644
--- a/lib/Target/Mips/MipsRelocationFunctions.h
+++ b/lib/Target/Mips/MipsRelocationFunctions.h
@@ -23,55 +23,55 @@ DECL_MIPS_APPLY_RELOC_FUNC(gothi16) \
DECL_MIPS_APPLY_RELOC_FUNC(gotlo16)
#define DECL_MIPS_APPLY_RELOC_FUNC_PTRS \
- { &none, 0, "R_MIPS_NONE" }, \
- { &none, 1, "R_MIPS_16" }, \
- { &abs32, 2, "R_MIPS_32" }, \
- { &none, 3, "R_MIPS_REL32" }, \
- { &none, 4, "R_MIPS_26" }, \
- { &hi16, 5, "R_MIPS_HI16" }, \
- { &lo16, 6, "R_MIPS_LO16" }, \
- { &none, 7, "R_MIPS_GPREL16" }, \
- { &none, 8, "R_MIPS_LITERAL" }, \
- { &got16, 9, "R_MIPS_GOT16" }, \
- { &none, 10, "R_MIPS_PC16" }, \
- { &call16, 11, "R_MIPS_CALL16" }, \
- { &gprel32, 12, "R_MIPS_GPREL32" }, \
- { &none, 13, "R_MIPS_UNUSED1" }, \
- { &none, 14, "R_MIPS_UNUSED2" }, \
- { &none, 15, "R_MIPS_UNUSED3" }, \
- { &none, 16, "R_MIPS_SHIFT5" }, \
- { &none, 17, "R_MIPS_SHIFT6" }, \
- { &none, 18, "R_MIPS_64" }, \
- { &none, 19, "R_MIPS_GOT_DISP" }, \
- { &none, 20, "R_MIPS_GOT_PAGE" }, \
- { &none, 21, "R_MIPS_GOT_OFST" }, \
- { &gothi16, 22, "R_MIPS_GOT_HI16" }, \
- { &gotlo16, 23, "R_MIPS_GOT_LO16" }, \
- { &none, 24, "R_MIPS_SUB" }, \
- { &none, 25, "R_MIPS_INSERT_A" }, \
- { &none, 26, "R_MIPS_INSERT_B" }, \
- { &none, 27, "R_MIPS_DELETE" }, \
- { &none, 28, "R_MIPS_HIGHER" }, \
- { &none, 29, "R_MIPS_HIGHEST" }, \
- { &gothi16, 30, "R_MIPS_CALL_HI16" }, \
- { &gotlo16, 31, "R_MIPS_CALL_LO16" }, \
- { &none, 32, "R_MIPS_SCN_DISP" }, \
- { &none, 33, "R_MIPS_REL16" }, \
- { &none, 34, "R_MIPS_ADD_IMMEDIATE" }, \
- { &none, 35, "R_MIPS_PJUMP" }, \
- { &none, 36, "R_MIPS_RELGOT" }, \
- { &none, 37, "R_MIPS_JALR" }, \
- { &none, 38, "R_MIPS_TLS_DTPMOD32" }, \
- { &none, 39, "R_MIPS_TLS_DTPREL32" }, \
- { &none, 40, "R_MIPS_TLS_DTPMOD64" }, \
- { &none, 41, "R_MIPS_TLS_DTPREL64" }, \
- { &none, 42, "R_MIPS_TLS_GD" }, \
- { &none, 43, "R_MIPS_TLS_LDM" }, \
- { &none, 44, "R_MIPS_TLS_DTPREL_HI16" }, \
- { &none, 45, "R_MIPS_TLS_DTPREL_LO16" }, \
- { &none, 46, "R_MIPS_TLS_GOTTPREL" }, \
- { &none, 47, "R_MIPS_TLS_TPREL32" }, \
- { &none, 48, "R_MIPS_TLS_TPREL64" }, \
- { &none, 49, "R_MIPS_TLS_TPREL_HI16" }, \
- { &none, 50, "R_MIPS_TLS_TPREL_LO16" }, \
- { &none, 51, "R_MIPS_GLOB_DAT" }
+ { &none, 0, "R_MIPS_NONE", 0}, \
+ { &none, 1, "R_MIPS_16", 16}, \
+ { &abs32, 2, "R_MIPS_32", 32}, \
+ { &none, 3, "R_MIPS_REL32", 32}, \
+ { &none, 4, "R_MIPS_26", 64}, \
+ { &hi16, 5, "R_MIPS_HI16", 16}, \
+ { &lo16, 6, "R_MIPS_LO16", 16}, \
+ { &none, 7, "R_MIPS_GPREL16", 16}, \
+ { &none, 8, "R_MIPS_LITERAL", 16}, \
+ { &got16, 9, "R_MIPS_GOT16", 16}, \
+ { &none, 10, "R_MIPS_PC16", 16}, \
+ { &call16, 11, "R_MIPS_CALL16", 16}, \
+ { &gprel32, 12, "R_MIPS_GPREL32", 32}, \
+ { &none, 13, "R_MIPS_UNUSED1", 0}, \
+ { &none, 14, "R_MIPS_UNUSED2", 0}, \
+ { &none, 15, "R_MIPS_UNUSED3", 0}, \
+ { &none, 16, "R_MIPS_SHIFT5", 32}, \
+ { &none, 17, "R_MIPS_SHIFT6", 32}, \
+ { &none, 18, "R_MIPS_64", 64}, \
+ { &none, 19, "R_MIPS_GOT_DISP", 16}, \
+ { &none, 20, "R_MIPS_GOT_PAGE", 16}, \
+ { &none, 21, "R_MIPS_GOT_OFST", 16}, \
+ { &gothi16, 22, "R_MIPS_GOT_HI16", 16}, \
+ { &gotlo16, 23, "R_MIPS_GOT_LO16", 16}, \
+ { &none, 24, "R_MIPS_SUB", 64}, \
+ { &none, 25, "R_MIPS_INSERT_A", 0}, \
+ { &none, 26, "R_MIPS_INSERT_B", 0}, \
+ { &none, 27, "R_MIPS_DELETE", 0}, \
+ { &none, 28, "R_MIPS_HIGHER", 16}, \
+ { &none, 29, "R_MIPS_HIGHEST", 16}, \
+ { &gothi16, 30, "R_MIPS_CALL_HI16", 16}, \
+ { &gotlo16, 31, "R_MIPS_CALL_LO16", 16}, \
+ { &none, 32, "R_MIPS_SCN_DISP", 32}, \
+ { &none, 33, "R_MIPS_REL16", 0}, \
+ { &none, 34, "R_MIPS_ADD_IMMEDIATE", 0}, \
+ { &none, 35, "R_MIPS_PJUMP", 0}, \
+ { &none, 36, "R_MIPS_RELGOT", 0}, \
+ { &none, 37, "R_MIPS_JALR", 32}, \
+ { &none, 38, "R_MIPS_TLS_DTPMOD32", 32}, \
+ { &none, 39, "R_MIPS_TLS_DTPREL32", 32}, \
+ { &none, 40, "R_MIPS_TLS_DTPMOD64", 0}, \
+ { &none, 41, "R_MIPS_TLS_DTPREL64", 0}, \
+ { &none, 42, "R_MIPS_TLS_GD", 16}, \
+ { &none, 43, "R_MIPS_TLS_LDM", 16}, \
+ { &none, 44, "R_MIPS_TLS_DTPREL_HI16", 16}, \
+ { &none, 45, "R_MIPS_TLS_DTPREL_LO16", 16}, \
+ { &none, 46, "R_MIPS_TLS_GOTTPREL", 16}, \
+ { &none, 47, "R_MIPS_TLS_TPREL32", 32}, \
+ { &none, 48, "R_MIPS_TLS_TPREL64", 0}, \
+ { &none, 49, "R_MIPS_TLS_TPREL_HI16", 16}, \
+ { &none, 50, "R_MIPS_TLS_TPREL_LO16", 16}, \
+ { &none, 51, "R_MIPS_GLOB_DAT", 0}
diff --git a/lib/Target/Mips/MipsRelocator.cpp b/lib/Target/Mips/MipsRelocator.cpp
index ad5de22..ec551ae 100644
--- a/lib/Target/Mips/MipsRelocator.cpp
+++ b/lib/Target/Mips/MipsRelocator.cpp
@@ -9,7 +9,6 @@
#include <llvm/ADT/Twine.h>
#include <llvm/Support/ELF.h>
-#include <mcld/Fragment/FragmentLinker.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Target/OutputRelocSection.h>
@@ -32,6 +31,7 @@ struct ApplyFunctionTriple
ApplyFunctionType func;
unsigned int type;
const char* name;
+ unsigned int size;
};
// declare the table of applying functions
@@ -68,9 +68,13 @@ const char* MipsRelocator::getName(Relocation::Type pType) const
return ApplyFunctions[pType].name;
}
+Relocator::Size MipsRelocator::getSize(Relocation::Type pType) const
+{
+ return ApplyFunctions[pType].size;
+}
+
//===----------------------------------------------------------------------===//
// Relocation helper function
-
//===----------------------------------------------------------------------===//
static const char * const GP_DISP_NAME = "_gp_disp";
diff --git a/lib/Target/Mips/MipsRelocator.h b/lib/Target/Mips/MipsRelocator.h
index 836b7d2..fcb6af9 100644
--- a/lib/Target/Mips/MipsRelocator.h
+++ b/lib/Target/Mips/MipsRelocator.h
@@ -48,6 +48,8 @@ public:
const char* getName(Relocation::Type pType) const;
+ Size getSize(Relocation::Type pType) const;
+
const SymGOTMap& getSymGOTMap() const { return m_SymGOTMap; }
SymGOTMap& getSymGOTMap() { return m_SymGOTMap; }
diff --git a/lib/Target/OutputRelocSection.cpp b/lib/Target/OutputRelocSection.cpp
index 3c1a0ce..2584d13 100644
--- a/lib/Target/OutputRelocSection.cpp
+++ b/lib/Target/OutputRelocSection.cpp
@@ -71,7 +71,7 @@ size_t OutputRelocSection::numOfRelocs()
bool OutputRelocSection::addSymbolToDynSym(LDSymbol& pSymbol)
{
- m_Module.getSymbolTable().changeLocalToTLS(pSymbol);
+ m_Module.getSymbolTable().changeLocalToDynamic(pSymbol);
return true;
}
diff --git a/lib/Target/X86/TargetInfo/X86TargetInfo.cpp b/lib/Target/X86/TargetInfo/X86TargetInfo.cpp
index 0985c02..3c02314 100644
--- a/lib/Target/X86/TargetInfo/X86TargetInfo.cpp
+++ b/lib/Target/X86/TargetInfo/X86TargetInfo.cpp
@@ -11,11 +11,13 @@
namespace mcld {
-mcld::Target TheX86Target;
+mcld::Target TheX86_32Target;
+mcld::Target TheX86_64Target;
extern "C" void MCLDInitializeX86LDTargetInfo() {
// register into mcld::TargetRegistry
- mcld::RegisterTarget X(TheX86Target, "x86");
+ mcld::RegisterTarget X(TheX86_32Target, "x86");
+ mcld::RegisterTarget Y(TheX86_64Target, "x86-64");
}
} // namespace of mcld
diff --git a/lib/Target/X86/X86.h b/lib/Target/X86/X86.h
index 2d07314..0f7d65d 100644
--- a/lib/Target/X86/X86.h
+++ b/lib/Target/X86/X86.h
@@ -14,7 +14,8 @@
namespace mcld {
class TargetLDBackend;
-extern mcld::Target TheX86Target;
+extern mcld::Target TheX86_32Target;
+extern mcld::Target TheX86_64Target;
TargetLDBackend *createX86LDBackend(const llvm::Target&, const std::string&);
diff --git a/lib/Target/X86/X86Diagnostic.cpp b/lib/Target/X86/X86Diagnostic.cpp
index 7191596..9287ca7 100644
--- a/lib/Target/X86/X86Diagnostic.cpp
+++ b/lib/Target/X86/X86Diagnostic.cpp
@@ -33,6 +33,7 @@ DiagnosticLineInfo* createX86DiagLineInfo(const mcld::Target& pTarget,
// InitializeX86Diagnostic
extern "C" void MCLDInitializeX86DiagnosticLineInfo() {
// Register the linker frontend
- mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheX86Target, createX86DiagLineInfo);
+ mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheX86_32Target, createX86DiagLineInfo);
+ mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheX86_64Target, createX86DiagLineInfo);
}
diff --git a/lib/Target/X86/X86Emulation.cpp b/lib/Target/X86/X86Emulation.cpp
index 9343583..753d7cc 100644
--- a/lib/Target/X86/X86Emulation.cpp
+++ b/lib/Target/X86/X86Emulation.cpp
@@ -20,7 +20,17 @@ static bool MCLDEmulateX86ELF(LinkerConfig& pConfig)
// set up bitclass and endian
pConfig.targets().setEndian(TargetOptions::Little);
- pConfig.targets().setBitClass(32);
+ unsigned int bitclass;
+ Triple::ArchType arch = pConfig.targets().triple().getArch();
+ assert (arch == Triple::x86 || arch == Triple::x86_64);
+ if (arch == Triple::x86 ||
+ pConfig.targets().triple().getEnvironment() == Triple::GNUX32) {
+ bitclass = 32;
+ }
+ else {
+ bitclass = 64;
+ }
+ pConfig.targets().setBitClass(bitclass);
// set up target-dependent constraints of attributes
pConfig.attribute().constraint().enableWholeArchive();
@@ -59,6 +69,7 @@ bool emulateX86LD(const std::string& pTriple, LinkerConfig& pConfig)
//===----------------------------------------------------------------------===//
extern "C" void MCLDInitializeX86Emulation() {
// Register the emulation
- mcld::TargetRegistry::RegisterEmulation(mcld::TheX86Target, mcld::emulateX86LD);
+ mcld::TargetRegistry::RegisterEmulation(mcld::TheX86_32Target, mcld::emulateX86LD);
+ mcld::TargetRegistry::RegisterEmulation(mcld::TheX86_64Target, mcld::emulateX86LD);
}
diff --git a/lib/Target/X86/X86GNUInfo.h b/lib/Target/X86/X86GNUInfo.h
index af548f0..65b0451 100644
--- a/lib/Target/X86/X86GNUInfo.h
+++ b/lib/Target/X86/X86GNUInfo.h
@@ -14,13 +14,34 @@
namespace mcld {
-class X86GNUInfo : public GNUInfo
+class X86_32GNUInfo : public GNUInfo
{
public:
- X86GNUInfo(const llvm::Triple& pTriple) : GNUInfo(pTriple) { }
+ X86_32GNUInfo(const llvm::Triple& pTriple) : GNUInfo(pTriple) { }
uint32_t machine() const { return llvm::ELF::EM_386; }
+ uint64_t defaultTextSegmentAddr() const { return 0x08048000; }
+
+ /// flags - the value of ElfXX_Ehdr::e_flags
+ /// FIXME
+ uint64_t flags() const { return 0x0; }
+
+};
+
+class X86_64GNUInfo : public GNUInfo
+{
+public:
+ X86_64GNUInfo(const llvm::Triple& pTriple) : GNUInfo(pTriple) { }
+
+ uint32_t machine() const { return llvm::ELF::EM_X86_64; }
+
+ uint64_t defaultTextSegmentAddr() const { return 0x400000; }
+
+ /// flags - the value of ElfXX_Ehdr::e_flags
+ /// FIXME
+ uint64_t flags() const { return 0x0; }
+
};
} // namespace of mcld
diff --git a/lib/Target/X86/X86GOT.cpp b/lib/Target/X86/X86GOT.cpp
index e734bb3..b77cfd3 100644
--- a/lib/Target/X86/X86GOT.cpp
+++ b/lib/Target/X86/X86GOT.cpp
@@ -16,33 +16,64 @@
using namespace mcld;
//===----------------------------------------------------------------------===//
-// X86GOT
+// X86_32GOT
//===----------------------------------------------------------------------===//
-X86GOT::X86GOT(LDSection& pSection)
+X86_32GOT::X86_32GOT(LDSection& pSection)
: GOT(pSection), m_pLast(NULL)
{
}
-X86GOT::~X86GOT()
+X86_32GOT::~X86_32GOT()
{
}
-void X86GOT::reserve(size_t pNum)
+void X86_32GOT::reserve(size_t pNum)
{
for (size_t i = 0; i < pNum; i++) {
- new X86GOTEntry(0, m_SectionData);
+ new X86_32GOTEntry(0, m_SectionData);
}
}
-X86GOTEntry* X86GOT::consume()
+X86_32GOTEntry* X86_32GOT::consume()
{
if (NULL == m_pLast) {
assert(!empty() && "Consume empty GOT entry!");
- m_pLast = llvm::cast<X86GOTEntry>(&m_SectionData->front());
+ m_pLast = llvm::cast<X86_32GOTEntry>(&m_SectionData->front());
return m_pLast;
}
- m_pLast = llvm::cast<X86GOTEntry>(m_pLast->getNextNode());
+ m_pLast = llvm::cast<X86_32GOTEntry>(m_pLast->getNextNode());
+ return m_pLast;
+}
+
+//===----------------------------------------------------------------------===//
+// X86_64GOT
+//===----------------------------------------------------------------------===//
+X86_64GOT::X86_64GOT(LDSection& pSection)
+ : GOT(pSection), m_pLast(NULL)
+{
+}
+
+X86_64GOT::~X86_64GOT()
+{
+}
+
+void X86_64GOT::reserve(size_t pNum)
+{
+ for (size_t i = 0; i < pNum; i++) {
+ new X86_64GOTEntry(0, m_SectionData);
+ }
+}
+
+X86_64GOTEntry* X86_64GOT::consume()
+{
+ if (NULL == m_pLast) {
+ assert(!empty() && "Consume empty GOT entry!");
+ m_pLast = llvm::cast<X86_64GOTEntry>(&m_SectionData->front());
+ return m_pLast;
+ }
+
+ m_pLast = llvm::cast<X86_64GOTEntry>(m_pLast->getNextNode());
return m_pLast;
}
diff --git a/lib/Target/X86/X86GOT.h b/lib/Target/X86/X86GOT.h
index 66967e1..df557f3 100644
--- a/lib/Target/X86/X86GOT.h
+++ b/lib/Target/X86/X86GOT.h
@@ -19,34 +19,64 @@ namespace mcld {
class LDSection;
class SectionData;
-/** \class X86GOTEntry
+/** \class X86_32GOTEntry
* \brief GOT Entry with size of 4 bytes
*/
-class X86GOTEntry : public GOT::Entry<4>
+class X86_32GOTEntry : public GOT::Entry<4>
{
public:
- X86GOTEntry(uint64_t pContent, SectionData* pParent)
+ X86_32GOTEntry(uint64_t pContent, SectionData* pParent)
: GOT::Entry<4>(pContent, pParent)
{}
};
-/** \class X86GOT
- * \brief X86 Global Offset Table.
+/** \class X86_32GOT
+ * \brief X86_32 Global Offset Table.
*/
-class X86GOT : public GOT
+class X86_32GOT : public GOT
{
public:
- X86GOT(LDSection& pSection);
+ X86_32GOT(LDSection& pSection);
- ~X86GOT();
+ ~X86_32GOT();
void reserve(size_t pNum = 1);
- X86GOTEntry* consume();
+ X86_32GOTEntry* consume();
private:
- X86GOTEntry* m_pLast; ///< the last consumed entry
+ X86_32GOTEntry* m_pLast; ///< the last consumed entry
+};
+
+/** \class X86_64GOTEntry
+ * \brief GOT Entry with size of 8 bytes
+ */
+class X86_64GOTEntry : public GOT::Entry<8>
+{
+public:
+ X86_64GOTEntry(uint64_t pContent, SectionData* pParent)
+ : GOT::Entry<8>(pContent, pParent)
+ {}
+};
+
+/** \class X86_64GOT
+ * \brief X86_64 Global Offset Table.
+ */
+
+class X86_64GOT : public GOT
+{
+public:
+ X86_64GOT(LDSection& pSection);
+
+ ~X86_64GOT();
+
+ void reserve(size_t pNum = 1);
+
+ X86_64GOTEntry* consume();
+
+private:
+ X86_64GOTEntry* m_pLast; ///< the last consumed entry
};
} // namespace of mcld
diff --git a/lib/Target/X86/X86GOTPLT.cpp b/lib/Target/X86/X86GOTPLT.cpp
index b72487e..961e0dc 100644
--- a/lib/Target/X86/X86GOTPLT.cpp
+++ b/lib/Target/X86/X86GOTPLT.cpp
@@ -18,10 +18,10 @@
namespace mcld {
//===----------------------------------------------------------------------===//
-// X86GOTPLT
+// X86_32GOTPLT
//===----------------------------------------------------------------------===//
-X86GOTPLT::X86GOTPLT(LDSection& pSection)
- : GOT(pSection), m_pLast(NULL)
+X86_32GOTPLT::X86_32GOTPLT(LDSection& pSection)
+ : X86_32GOT(pSection)
{
// Create GOT0 entries
reserve(X86GOTPLT0Num);
@@ -32,41 +32,66 @@ X86GOTPLT::X86GOTPLT(LDSection& pSection)
}
}
-X86GOTPLT::~X86GOTPLT()
+X86_32GOTPLT::~X86_32GOTPLT()
{
}
-void X86GOTPLT::reserve(size_t pNum)
+bool X86_32GOTPLT::hasGOT1() const
{
- for (size_t i = 0; i < pNum; i++) {
- new X86GOTPLTEntry(0, m_SectionData);
+ return (m_SectionData->size() > X86GOTPLT0Num);
+}
+
+void X86_32GOTPLT::applyGOT0(uint64_t pAddress)
+{
+ llvm::cast<X86_32GOTEntry>
+ (*(m_SectionData->getFragmentList().begin())).setValue(pAddress);
+}
+
+void X86_32GOTPLT::applyAllGOTPLT(const X86PLT& pPLT)
+{
+ iterator it = begin();
+ // skip GOT0
+ for (size_t i = 0; i < X86GOTPLT0Num; ++i)
+ ++it;
+ // address of corresponding plt entry
+ uint64_t plt_addr = pPLT.addr() + pPLT.getPLT0Size();
+ for (; it != end() ; ++it) {
+ llvm::cast<X86_32GOTEntry>(*it).setValue(plt_addr + 6);
+ plt_addr += pPLT.getPLT1Size();
}
}
-X86GOTPLTEntry* X86GOTPLT::consume()
+//===----------------------------------------------------------------------===//
+// X86_64GOTPLT
+//===----------------------------------------------------------------------===//
+X86_64GOTPLT::X86_64GOTPLT(LDSection& pSection)
+ : X86_64GOT(pSection)
{
- if (NULL == m_pLast) {
- assert(!empty() && "Consume empty GOT entry!");
- m_pLast = llvm::cast<X86GOTPLTEntry>(&m_SectionData->front());
- return m_pLast;
+ // Create GOT0 entries
+ reserve(X86GOTPLT0Num);
+
+ // Skip GOT0 entries
+ for (size_t i = 0; i < X86GOTPLT0Num; ++i) {
+ consume();
}
+}
- m_pLast = llvm::cast<X86GOTPLTEntry>(m_pLast->getNextNode());
- return m_pLast;
+X86_64GOTPLT::~X86_64GOTPLT()
+{
}
-bool X86GOTPLT::hasGOT1() const
+bool X86_64GOTPLT::hasGOT1() const
{
return (m_SectionData->size() > X86GOTPLT0Num);
}
-void X86GOTPLT::applyGOT0(uint64_t pAddress)
+void X86_64GOTPLT::applyGOT0(uint64_t pAddress)
{
- llvm::cast<X86GOTPLTEntry>
+ llvm::cast<X86_64GOTEntry>
(*(m_SectionData->getFragmentList().begin())).setValue(pAddress);
}
-void X86GOTPLT::applyAllGOTPLT(const X86PLT& pPLT)
+void X86_64GOTPLT::applyAllGOTPLT(const X86PLT& pPLT)
{
iterator it = begin();
// skip GOT0
@@ -75,7 +100,7 @@ void X86GOTPLT::applyAllGOTPLT(const X86PLT& pPLT)
// address of corresponding plt entry
uint64_t plt_addr = pPLT.addr() + pPLT.getPLT0Size();
for (; it != end() ; ++it) {
- llvm::cast<X86GOTPLTEntry>(*it).setValue(plt_addr + 6);
+ llvm::cast<X86_64GOTEntry>(*it).setValue(plt_addr + 6);
plt_addr += pPLT.getPLT1Size();
}
}
diff --git a/lib/Target/X86/X86GOTPLT.h b/lib/Target/X86/X86GOTPLT.h
index f288fa4..8e13fac 100644
--- a/lib/Target/X86/X86GOTPLT.h
+++ b/lib/Target/X86/X86GOTPLT.h
@@ -14,7 +14,7 @@
#include <llvm/ADT/DenseMap.h>
-#include <mcld/Target/GOT.h>
+#include "X86GOT.h"
namespace mcld {
@@ -23,27 +23,33 @@ class LDSection;
const unsigned int X86GOTPLT0Num = 3;
-class X86GOTPLTEntry : public GOT::Entry<4>
+/** \class X86_32GOTPLT
+ * \brief X86_32 .got.plt section.
+ */
+class X86_32GOTPLT : public X86_32GOT
{
public:
- X86GOTPLTEntry(uint64_t pContent, SectionData* pParent)
- : GOT::Entry<4>(pContent, pParent)
- {}
+ X86_32GOTPLT(LDSection &pSection);
+
+ ~X86_32GOTPLT();
+
+ // hasGOT1 - return if this section has any GOT1 entry
+ bool hasGOT1() const;
+
+ void applyGOT0(uint64_t pAddress);
+
+ void applyAllGOTPLT(const X86PLT& pPLT);
};
-/** \class X86GOTPLT
- * \brief X86 .got.plt section.
+/** \class X86_64GOTPLT
+ * \brief X86_64 .got.plt section.
*/
-class X86GOTPLT : public GOT
+class X86_64GOTPLT : public X86_64GOT
{
public:
- X86GOTPLT(LDSection &pSection);
+ X86_64GOTPLT(LDSection &pSection);
- ~X86GOTPLT();
-
- void reserve(size_t pNum = 1);
-
- X86GOTPLTEntry* consume();
+ ~X86_64GOTPLT();
// hasGOT1 - return if this section has any GOT1 entry
bool hasGOT1() const;
@@ -51,9 +57,6 @@ public:
void applyGOT0(uint64_t pAddress);
void applyAllGOTPLT(const X86PLT& pPLT);
-
-private:
- X86GOTPLTEntry* m_pLast; ///< the last consumed entry
};
} // namespace of mcld
diff --git a/lib/Target/X86/X86LDBackend.cpp b/lib/Target/X86/X86LDBackend.cpp
index a18fedb..e08120e 100644
--- a/lib/Target/X86/X86LDBackend.cpp
+++ b/lib/Target/X86/X86LDBackend.cpp
@@ -32,79 +32,83 @@ using namespace mcld;
//===----------------------------------------------------------------------===//
// X86GNULDBackend
//===----------------------------------------------------------------------===//
-X86GNULDBackend::X86GNULDBackend(const LinkerConfig& pConfig, X86GNUInfo* pInfo)
+X86GNULDBackend::X86GNULDBackend(const LinkerConfig& pConfig,
+ GNUInfo* pInfo,
+ Relocation::Type pCopyRel)
: GNULDBackend(pConfig, pInfo),
m_pRelocator(NULL),
- m_pGOT(NULL),
m_pPLT(NULL),
- m_pGOTPLT(NULL),
m_pRelDyn(NULL),
m_pRelPLT(NULL),
m_pDynamic(NULL),
- m_pGOTSymbol(NULL) {
+ m_pGOTSymbol(NULL),
+ m_CopyRel(pCopyRel)
+{
+ Triple::ArchType arch = pConfig.targets().triple().getArch();
+ assert (arch == Triple::x86 || arch == Triple::x86_64);
+ if (arch == Triple::x86 ||
+ pConfig.targets().triple().getEnvironment() == Triple::GNUX32) {
+ m_RelEntrySize = 8;
+ m_RelaEntrySize = 12;
+ if (arch == Triple::x86)
+ m_PointerRel = llvm::ELF::R_386_32;
+ else
+ m_PointerRel = llvm::ELF::R_X86_64_32;
+ }
+ else {
+ m_RelEntrySize = 16;
+ m_RelaEntrySize = 24;
+ m_PointerRel = llvm::ELF::R_X86_64_64;
+ }
}
X86GNULDBackend::~X86GNULDBackend()
{
delete m_pRelocator;
- delete m_pGOT;
delete m_pPLT;
- delete m_pGOTPLT;
delete m_pRelDyn;
delete m_pRelPLT;
delete m_pDynamic;
}
-bool X86GNULDBackend::initRelocator(const FragmentLinker& pLinker)
-{
- if (NULL == m_pRelocator) {
- m_pRelocator = new X86Relocator(*this);
- m_pRelocator->setFragmentLinker(pLinker);
- }
- return true;
-}
-
Relocator* X86GNULDBackend::getRelocator()
{
assert(NULL != m_pRelocator);
return m_pRelocator;
}
-void X86GNULDBackend::doPreLayout(FragmentLinker& pLinker)
+void X86GNULDBackend::doPreLayout(IRBuilder& pBuilder)
{
- // set .got.plt size
+ // initialize .dynamic data
+ if (!config().isCodeStatic() && NULL == m_pDynamic)
+ m_pDynamic = new X86ELFDynamic(*this, config());
+
+ // set .got.plt and .got sizes
// when building shared object, the .got section is must
if (LinkerConfig::Object != config().codeGenType()) {
- if (LinkerConfig::DynObj == config().codeGenType() ||
- m_pGOTPLT->hasGOT1() ||
- NULL != m_pGOTSymbol) {
- m_pGOTPLT->finalizeSectionSize();
- defineGOTSymbol(pLinker);
- }
-
- // set .got size
- if (!m_pGOT->empty())
- m_pGOT->finalizeSectionSize();
+ setGOTSectionSize(pBuilder);
// set .plt size
if (m_pPLT->hasPLT1())
m_pPLT->finalizeSectionSize();
- ELFFileFormat* file_format = getOutputFormat();
- // set .rel.dyn size
- if (!m_pRelDyn->empty())
- file_format->getRelDyn().setSize(
- m_pRelDyn->numOfRelocs() * getRelEntrySize());
-
- // set .rel.plt size
- if (!m_pRelPLT->empty())
- file_format->getRelPlt().setSize(
- m_pRelPLT->numOfRelocs() * getRelEntrySize());
+ // set .rel.dyn/.rela.dyn size
+ if (!m_pRelDyn->empty()) {
+ assert(!config().isCodeStatic() &&
+ "static linkage should not result in a dynamic relocation section");
+ setRelDynSize();
+ }
+ // set .rel.plt/.rela.plt size
+ if (!m_pRelPLT->empty()) {
+ assert(!config().isCodeStatic() &&
+ "static linkage should not result in a dynamic relocation section");
+ setRelPLTSize();
+ }
}
}
void X86GNULDBackend::doPostLayout(Module& pModule,
- FragmentLinker& pLinker)
+ IRBuilder& pBuilder)
{
}
@@ -112,9 +116,7 @@ void X86GNULDBackend::doPostLayout(Module& pModule,
/// Use co-variant return type to return its own dynamic section.
X86ELFDynamic& X86GNULDBackend::dynamic()
{
- if (NULL == m_pDynamic)
- m_pDynamic = new X86ELFDynamic(*this, config());
-
+ assert(NULL != m_pDynamic);
return *m_pDynamic;
}
@@ -122,35 +124,34 @@ X86ELFDynamic& X86GNULDBackend::dynamic()
/// Use co-variant return type to return its own dynamic section.
const X86ELFDynamic& X86GNULDBackend::dynamic() const
{
- assert( NULL != m_pDynamic);
+ assert(NULL != m_pDynamic);
return *m_pDynamic;
}
-void X86GNULDBackend::defineGOTSymbol(FragmentLinker& pLinker)
+void X86GNULDBackend::defineGOTSymbol(IRBuilder& pBuilder,
+ Fragment& pFrag)
{
// define symbol _GLOBAL_OFFSET_TABLE_
if (m_pGOTSymbol != NULL) {
- pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Unresolve>(
+ pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
"_GLOBAL_OFFSET_TABLE_",
- false,
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Local,
0x0, // size
0x0, // value
- FragmentRef::Create(*(m_pGOTPLT->begin()), 0x0),
+ FragmentRef::Create(pFrag, 0x0),
ResolveInfo::Hidden);
}
else {
- m_pGOTSymbol = pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Resolve>(
+ m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
"_GLOBAL_OFFSET_TABLE_",
- false,
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Local,
0x0, // size
0x0, // value
- FragmentRef::Create(*(m_pGOTPLT->begin()), 0x0),
+ FragmentRef::Create(pFrag, 0x0),
ResolveInfo::Hidden);
}
}
@@ -158,7 +159,7 @@ void X86GNULDBackend::defineGOTSymbol(FragmentLinker& pLinker)
void X86GNULDBackend::addCopyReloc(ResolveInfo& pSym)
{
Relocation& rel_entry = *m_pRelDyn->consumeEntry();
- rel_entry.setType(llvm::ELF::R_386_COPY);
+ rel_entry.setType(m_CopyRel);
assert(pSym.outSymbol()->hasFragRef());
rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef());
rel_entry.setSymInfo(&pSym);
@@ -169,7 +170,7 @@ void X86GNULDBackend::addCopyReloc(ResolveInfo& pSym)
/// section and all other reference to this symbol should refer to this
/// copy.
/// @note This is executed at `scan relocation' stage.
-LDSymbol& X86GNULDBackend::defineSymbolforCopyReloc(FragmentLinker& pLinker,
+LDSymbol& X86GNULDBackend::defineSymbolforCopyReloc(IRBuilder& pBuilder,
const ResolveInfo& pSym)
{
// get or create corresponding BSS LDSection
@@ -205,10 +206,8 @@ LDSymbol& X86GNULDBackend::defineSymbolforCopyReloc(FragmentLinker& pLinker,
binding = ResolveInfo::Global;
// Define the copy symbol in the bss section and resolve it
- LDSymbol* cpy_sym =
- pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Resolve>(
+ LDSymbol* cpy_sym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
pSym.name(),
- false,
(ResolveInfo::Type)pSym.type(),
ResolveInfo::Define,
binding,
@@ -220,10 +219,204 @@ LDSymbol& X86GNULDBackend::defineSymbolforCopyReloc(FragmentLinker& pLinker,
return *cpy_sym;
}
-void X86GNULDBackend::scanLocalReloc(Relocation& pReloc,
- FragmentLinker& pLinker,
+void X86GNULDBackend::scanRelocation(Relocation& pReloc,
+ IRBuilder& pLinker,
Module& pModule,
- const LDSection& pSection)
+ LDSection& pSection)
+{
+ if (LinkerConfig::Object == config().codeGenType())
+ return;
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ assert(NULL != rsym &&
+ "ResolveInfo of relocation not set while scanRelocation");
+
+ pReloc.updateAddend();
+ assert(NULL != pSection.getLink());
+ if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC))
+ return;
+
+ // Scan relocation type to determine if the GOT/PLT/Dynamic Relocation
+ // entries should be created.
+ if (rsym->isLocal()) // rsym is local
+ scanLocalReloc(pReloc, pLinker, pModule, pSection);
+ else // rsym is external
+ scanGlobalReloc(pReloc, pLinker, pModule, pSection);
+
+ // check if we should issue undefined reference for the relocation target
+ // symbol
+ if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
+ fatal(diag::undefined_reference) << rsym->name();
+}
+
+uint64_t X86GNULDBackend::emitSectionData(const LDSection& pSection,
+ MemoryRegion& pRegion) const
+{
+ assert(pRegion.size() && "Size of MemoryRegion is zero!");
+
+ const ELFFileFormat* FileFormat = getOutputFormat();
+ assert(FileFormat &&
+ "ELFFileFormat is NULL in X86GNULDBackend::emitSectionData!");
+
+ unsigned int EntrySize = 0;
+ uint64_t RegionSize = 0;
+
+ if (&pSection == &(FileFormat->getPLT())) {
+ assert(m_pPLT && "emitSectionData failed, m_pPLT is NULL!");
+
+ unsigned char* buffer = pRegion.getBuffer();
+
+ m_pPLT->applyPLT0();
+ m_pPLT->applyPLT1();
+ X86PLT::iterator it = m_pPLT->begin();
+ unsigned int plt0_size = llvm::cast<PLTEntryBase>((*it)).size();
+
+ memcpy(buffer, llvm::cast<PLTEntryBase>((*it)).getValue(), plt0_size);
+ RegionSize += plt0_size;
+ ++it;
+
+ PLTEntryBase* plt1 = 0;
+ X86PLT::iterator ie = m_pPLT->end();
+ while (it != ie) {
+ plt1 = &(llvm::cast<PLTEntryBase>(*it));
+ EntrySize = plt1->size();
+ memcpy(buffer + RegionSize, plt1->getValue(), EntrySize);
+ RegionSize += EntrySize;
+ ++it;
+ }
+ }
+
+ else if (&pSection == &(FileFormat->getGOT())) {
+ RegionSize += emitGOTSectionData(pRegion);
+ }
+
+ else if (&pSection == &(FileFormat->getGOTPLT())) {
+ RegionSize += emitGOTPLTSectionData(pRegion, FileFormat);
+ }
+
+ else {
+ fatal(diag::unrecognized_output_sectoin)
+ << pSection.name()
+ << "mclinker@googlegroups.com";
+ }
+ return RegionSize;
+}
+
+X86PLT& X86GNULDBackend::getPLT()
+{
+ assert(NULL != m_pPLT && "PLT section not exist");
+ return *m_pPLT;
+}
+
+const X86PLT& X86GNULDBackend::getPLT() const
+{
+ assert(NULL != m_pPLT && "PLT section not exist");
+ return *m_pPLT;
+}
+
+OutputRelocSection& X86GNULDBackend::getRelDyn()
+{
+ assert(NULL != m_pRelDyn && ".rel.dyn/.rela.dyn section not exist");
+ return *m_pRelDyn;
+}
+
+const OutputRelocSection& X86GNULDBackend::getRelDyn() const
+{
+ assert(NULL != m_pRelDyn && ".rel.dyn/.rela.dyn section not exist");
+ return *m_pRelDyn;
+}
+
+OutputRelocSection& X86GNULDBackend::getRelPLT()
+{
+ assert(NULL != m_pRelPLT && ".rel.plt/.rela.plt section not exist");
+ return *m_pRelPLT;
+}
+
+const OutputRelocSection& X86GNULDBackend::getRelPLT() const
+{
+ assert(NULL != m_pRelPLT && ".rel.plt/.rela.plt section not exist");
+ return *m_pRelPLT;
+}
+
+unsigned int
+X86GNULDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const
+{
+ const ELFFileFormat* file_format = getOutputFormat();
+
+ if (&pSectHdr == &file_format->getGOT()) {
+ if (config().options().hasNow())
+ return SHO_RELRO;
+ return SHO_RELRO_LAST;
+ }
+
+ if (&pSectHdr == &file_format->getGOTPLT()) {
+ if (config().options().hasNow())
+ return SHO_RELRO;
+ return SHO_NON_RELRO_FIRST;
+ }
+
+ if (&pSectHdr == &file_format->getPLT())
+ return SHO_PLT;
+
+ return SHO_UNDEFINED;
+}
+
+void X86GNULDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule)
+{
+ if (LinkerConfig::Object != config().codeGenType()) {
+ // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
+ // same name in input
+ m_pGOTSymbol =
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ FragmentRef::Null(), // FragRef
+ ResolveInfo::Hidden);
+ }
+}
+
+/// finalizeSymbol - finalize the symbol value
+bool X86GNULDBackend::finalizeTargetSymbols()
+{
+ return true;
+}
+
+/// doCreateProgramHdrs - backend can implement this function to create the
+/// target-dependent segments
+void X86GNULDBackend::doCreateProgramHdrs(Module& pModule)
+{
+ // TODO
+}
+
+X86_32GNULDBackend::X86_32GNULDBackend(const LinkerConfig& pConfig,
+ GNUInfo* pInfo)
+ : X86GNULDBackend(pConfig, pInfo, llvm::ELF::R_386_COPY),
+ m_pGOT (NULL),
+ m_pGOTPLT (NULL) {
+}
+
+X86_32GNULDBackend::~X86_32GNULDBackend()
+{
+ delete m_pGOT;
+ delete m_pGOTPLT;
+}
+
+bool X86_32GNULDBackend::initRelocator()
+{
+ if (NULL == m_pRelocator) {
+ m_pRelocator = new X86_32Relocator(*this);
+ }
+ return true;
+}
+
+void X86_32GNULDBackend::scanLocalReloc(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
@@ -236,10 +429,11 @@ void X86GNULDBackend::scanLocalReloc(Relocation& pReloc,
// 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 (pLinker.isOutputPIC()) {
+ if (config().isCodeIndep()) {
m_pRelDyn->reserveEntry();
// set Rel bit
rsym->setReserved(rsym->reserved() | ReserveRel);
+ checkAndSetHasTextRel(*pSection.getLink());
}
return;
@@ -255,6 +449,13 @@ void X86GNULDBackend::scanLocalReloc(Relocation& pReloc,
return;
// FIXME: check STT_GNU_IFUNC symbol
m_pGOT->reserve();
+
+ // If the GOT is used in statically linked binaries,
+ // the GOT entry is enough and no relocation is needed.
+ if (config().isCodeStatic()) {
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
+ return;
+ }
// If building shared object or the symbol is undefined, a dynamic
// relocation is needed to relocate this GOT entry. Reserve an
// entry in .rel.dyn
@@ -316,6 +517,11 @@ void X86GNULDBackend::scanLocalReloc(Relocation& pReloc,
if (LinkerConfig::DynObj == config().codeGenType()) {
m_pRelDyn->reserveEntry();
rsym->setReserved(rsym->reserved() | ReserveRel);
+ checkAndSetHasTextRel(*pSection.getLink());
+ } else {
+ // for local sym, we can convert ie to le if not building shared object
+ convertTLSIEtoLE(pReloc, pSection);
+ return;
}
if (rsym->reserved() & GOTRel)
return;
@@ -346,6 +552,7 @@ void X86GNULDBackend::scanLocalReloc(Relocation& pReloc,
if (LinkerConfig::DynObj == config().codeGenType()) {
m_pRelDyn->reserveEntry();
rsym->setReserved(rsym->reserved() | ReserveRel);
+ checkAndSetHasTextRel(*pSection.getLink());
// the target symbol of the dynamic relocation is rsym, so we need to
// emit it into .dynsym
assert(NULL != rsym->outSymbol());
@@ -360,10 +567,10 @@ void X86GNULDBackend::scanLocalReloc(Relocation& pReloc,
} // end switch
}
-void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc,
- FragmentLinker& pLinker,
- Module& pModule,
- const LDSection& pSection)
+void X86_32GNULDBackend::scanGlobalReloc(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
@@ -374,7 +581,7 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc,
case llvm::ELF::R_386_8:
// Absolute relocation type, symbol may needs PLT entry or
// dynamic relocation entry
- if (symbolNeedsPLT(pLinker, *rsym)) {
+ if (symbolNeedsPLT(*rsym)) {
// create plt for this symbol if it does not have one
if (!(rsym->reserved() & ReservePLT)){
// Symbol needs PLT entry, we need to reserve a PLT entry
@@ -389,17 +596,17 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc,
}
}
- if (symbolNeedsDynRel(pLinker, *rsym, (rsym->reserved() & ReservePLT),
- true)) {
+ if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), true)) {
// symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
m_pRelDyn->reserveEntry();
- if (symbolNeedsCopyReloc(pLinker, pReloc, *rsym)) {
- LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym);
+ if (symbolNeedsCopyReloc(pReloc, *rsym)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
addCopyReloc(*cpy_sym.resolveInfo());
}
else {
// set Rel bit
rsym->setReserved(rsym->reserved() | ReserveRel);
+ checkAndSetHasTextRel(pSection);
}
}
return;
@@ -418,7 +625,7 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc,
return;
// if the symbol's value can be decided at link time, then no need plt
- if (symbolFinalValueIsKnown(pLinker, *rsym))
+ if (symbolFinalValueIsKnown(*rsym))
return;
// if symbol is defined in the ouput file and it's not
@@ -445,6 +652,13 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc,
if (rsym->reserved() & (ReserveGOT | GOTRel))
return;
m_pGOT->reserve();
+
+ // If the GOT is used in statically linked binaries,
+ // the GOT entry is enough and no relocation is needed.
+ if (config().isCodeStatic()) {
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
+ return;
+ }
// If building shared object or the symbol is undefined, a dynamic
// relocation is needed to relocate this GOT entry. Reserve an
// entry in .rel.dyn
@@ -463,8 +677,8 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc,
case llvm::ELF::R_386_PC16:
case llvm::ELF::R_386_PC8:
- if (symbolNeedsPLT(pLinker, *rsym) &&
- LinkerConfig::DynObj != config().codeGenType()) {
+ if (symbolNeedsPLT(*rsym) &&
+ LinkerConfig::DynObj != config().codeGenType()) {
// create plt for this symbol if it does not have one
if (!(rsym->reserved() & ReservePLT)){
// Symbol needs PLT entry, we need to reserve a PLT entry
@@ -479,17 +693,17 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc,
}
}
- if (symbolNeedsDynRel(pLinker, *rsym, (rsym->reserved() & ReservePLT),
- false)) {
+ if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), false)) {
// symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
m_pRelDyn->reserveEntry();
- if (symbolNeedsCopyReloc(pLinker, pReloc, *rsym)) {
- LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym);
+ if (symbolNeedsCopyReloc(pReloc, *rsym)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
addCopyReloc(*cpy_sym.resolveInfo());
}
else {
// set Rel bit
rsym->setReserved(rsym->reserved() | ReserveRel);
+ checkAndSetHasTextRel(pSection);
}
}
return;
@@ -519,6 +733,13 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc,
if (LinkerConfig::DynObj == config().codeGenType()) {
m_pRelDyn->reserveEntry();
rsym->setReserved(rsym->reserved() | ReserveRel);
+ checkAndSetHasTextRel(*pSection.getLink());
+ } else {
+ // for global sym, we can convert ie to le if its final value is known
+ if (symbolFinalValueIsKnown(*rsym)) {
+ convertTLSIEtoLE(pReloc, pSection);
+ return;
+ }
}
if (rsym->reserved() & GOTRel)
return;
@@ -547,6 +768,7 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc,
if (LinkerConfig::DynObj == config().codeGenType()) {
m_pRelDyn->reserveEntry();
rsym->setReserved(rsym->reserved() | ReserveRel);
+ checkAndSetHasTextRel(*pSection.getLink());
}
return;
@@ -558,284 +780,557 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc,
} // end switch
}
-void X86GNULDBackend::scanRelocation(Relocation& pReloc,
- FragmentLinker& pLinker,
- Module& pModule,
- const LDSection& pSection)
+void X86_32GNULDBackend::initTargetSections(Module& pModule,
+ ObjectBuilder& pBuilder)
{
- if (LinkerConfig::Object == config().codeGenType())
- return;
- // rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
- assert(NULL != rsym &&
- "ResolveInfo of relocation not set while scanRelocation");
+ if (LinkerConfig::Object != config().codeGenType()) {
+ ELFFileFormat* file_format = getOutputFormat();
+ // initialize .got
+ LDSection& got = file_format->getGOT();
+ m_pGOT = new X86_32GOT(got);
- pReloc.updateAddend();
- if (0 == (pSection.flag() & llvm::ELF::SHF_ALLOC))
- return;
+ // initialize .got.plt
+ LDSection& gotplt = file_format->getGOTPLT();
+ m_pGOTPLT = new X86_32GOTPLT(gotplt);
- // Scan relocation type to determine if the GOT/PLT/Dynamic Relocation
- // entries should be created.
- if (rsym->isLocal()) // rsym is local
- scanLocalReloc(pReloc, pLinker, pModule, pSection);
- else // rsym is external
- scanGlobalReloc(pReloc, pLinker, pModule, pSection);
+ // initialize .plt
+ LDSection& plt = file_format->getPLT();
+ m_pPLT = new X86_32PLT(plt,
+ *m_pGOTPLT,
+ config());
- // check if we shoule issue undefined reference for the relocation target
- // symbol
- if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
- fatal(diag::undefined_reference) << rsym->name();
+ // initialize .rel.plt
+ LDSection& relplt = file_format->getRelPlt();
+ relplt.setLink(&plt);
+ m_pRelPLT = new OutputRelocSection(pModule, relplt);
+
+ // initialize .rel.dyn
+ LDSection& reldyn = file_format->getRelDyn();
+ m_pRelDyn = new OutputRelocSection(pModule, reldyn);
- if ((rsym->reserved() & ReserveRel) != 0x0) {
- // set hasTextRelSection if needed
- checkAndSetHasTextRel(pSection);
}
}
-uint64_t X86GNULDBackend::emitSectionData(const LDSection& pSection,
- MemoryRegion& pRegion) const
+X86_32GOT& X86_32GNULDBackend::getGOT()
{
- assert(pRegion.size() && "Size of MemoryRegion is zero!");
-
- const ELFFileFormat* FileFormat = getOutputFormat();
- assert(FileFormat &&
- "ELFFileFormat is NULL in X86GNULDBackend::emitSectionData!");
+ assert(NULL != m_pGOT);
+ return *m_pGOT;
+}
- unsigned int EntrySize = 0;
- uint64_t RegionSize = 0;
+const X86_32GOT& X86_32GNULDBackend::getGOT() const
+{
+ assert(NULL != m_pGOT);
+ return *m_pGOT;
+}
- if (&pSection == &(FileFormat->getPLT())) {
- assert(m_pPLT && "emitSectionData failed, m_pPLT is NULL!");
+X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT()
+{
+ assert(NULL != m_pGOTPLT);
+ return *m_pGOTPLT;
+}
- unsigned char* buffer = pRegion.getBuffer();
+const X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT() const
+{
+ assert(NULL != m_pGOTPLT);
+ return *m_pGOTPLT;
+}
- m_pPLT->applyPLT0();
- m_pPLT->applyPLT1();
- X86PLT::iterator it = m_pPLT->begin();
- unsigned int plt0_size = llvm::cast<PLTEntryBase>((*it)).size();
+void X86_32GNULDBackend::setRelDynSize()
+{
+ ELFFileFormat* file_format = getOutputFormat();
+ file_format->getRelDyn().setSize
+ (m_pRelDyn->numOfRelocs() * getRelEntrySize());
+}
- memcpy(buffer, llvm::cast<PLTEntryBase>((*it)).getValue(), plt0_size);
- RegionSize += plt0_size;
- ++it;
+void X86_32GNULDBackend::setRelPLTSize()
+{
+ ELFFileFormat* file_format = getOutputFormat();
+ file_format->getRelPlt().setSize
+ (m_pRelPLT->numOfRelocs() * getRelEntrySize());
+}
- PLTEntryBase* plt1 = 0;
- X86PLT::iterator ie = m_pPLT->end();
- while (it != ie) {
- plt1 = &(llvm::cast<PLTEntryBase>(*it));
- EntrySize = plt1->size();
- memcpy(buffer + RegionSize, plt1->getValue(), EntrySize);
- RegionSize += EntrySize;
- ++it;
- }
+void X86_32GNULDBackend::setGOTSectionSize(IRBuilder& pBuilder)
+{
+ // set .got.plt size
+ if (LinkerConfig::DynObj == config().codeGenType() ||
+ m_pGOTPLT->hasGOT1() ||
+ NULL != m_pGOTSymbol) {
+ m_pGOTPLT->finalizeSectionSize();
+ defineGOTSymbol(pBuilder, *(m_pGOTPLT->begin()));
}
- else if (&pSection == &(FileFormat->getGOT())) {
- assert(m_pGOT && "emitSectionData failed, m_pGOT is NULL!");
+ // set .got size
+ if (!m_pGOT->empty())
+ m_pGOT->finalizeSectionSize();
+}
- uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
+uint64_t X86_32GNULDBackend::emitGOTSectionData(MemoryRegion& pRegion) const
+{
+ assert(m_pGOT && "emitGOTSectionData failed, m_pGOT is NULL!");
- X86GOTEntry* got = 0;
- EntrySize = X86GOTEntry::EntrySize;
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
- for (X86GOT::iterator it = m_pGOT->begin(),
- ie = m_pGOT->end(); it != ie; ++it, ++buffer) {
- got = &(llvm::cast<X86GOTEntry>((*it)));
- *buffer = static_cast<uint32_t>(got->getValue());
- RegionSize += EntrySize;
- }
+ X86_32GOTEntry* got = 0;
+ unsigned int EntrySize = X86_32GOTEntry::EntrySize;
+ uint64_t RegionSize = 0;
+
+ for (X86_32GOT::iterator it = m_pGOT->begin(),
+ ie = m_pGOT->end(); it != ie; ++it, ++buffer) {
+ got = &(llvm::cast<X86_32GOTEntry>((*it)));
+ *buffer = static_cast<uint32_t>(got->getValue());
+ RegionSize += EntrySize;
}
- else if (&pSection == &(FileFormat->getGOTPLT())) {
- assert(m_pGOTPLT && "emitSectionData failed, m_pGOTPLT is NULL!");
- m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr());
- m_pGOTPLT->applyAllGOTPLT(*m_pPLT);
+ return RegionSize;
+}
- uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
+uint64_t X86_32GNULDBackend::emitGOTPLTSectionData(MemoryRegion& pRegion,
+ const ELFFileFormat* FileFormat) const
+{
+ assert(m_pGOTPLT && "emitGOTPLTSectionData failed, m_pGOTPLT is NULL!");
+ m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr());
+ m_pGOTPLT->applyAllGOTPLT(*m_pPLT);
- X86GOTEntry* got = 0;
- EntrySize = X86GOTPLTEntry::EntrySize;
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
- for (X86GOTPLT::iterator it = m_pGOTPLT->begin(),
- ie = m_pGOTPLT->end(); it != ie; ++it, ++buffer) {
- got = &(llvm::cast<X86GOTEntry>((*it)));
- *buffer = static_cast<uint32_t>(got->getValue());
- RegionSize += EntrySize;
+ X86_32GOTEntry* got = 0;
+ unsigned int EntrySize = X86_32GOTEntry::EntrySize;
+ uint64_t RegionSize = 0;
+
+ for (X86_32GOTPLT::iterator it = m_pGOTPLT->begin(),
+ ie = m_pGOTPLT->end(); it != ie; ++it, ++buffer) {
+ got = &(llvm::cast<X86_32GOTEntry>((*it)));
+ *buffer = static_cast<uint32_t>(got->getValue());
+ RegionSize += EntrySize;
+ }
+
+ return RegionSize;
+}
+
+/// convert R_386_TLS_IE to R_386_TLS_LE
+void X86_32GNULDBackend::convertTLSIEtoLE(Relocation& pReloc,
+ LDSection& pSection)
+{
+ assert(pReloc.type() == llvm::ELF::R_386_TLS_IE);
+ assert(NULL != pReloc.targetRef().frag());
+
+ // 1. create the fragment references and new relocs
+ uint64_t off = pReloc.targetRef().offset();
+ if (off >= 4)
+ off -= 4;
+ else
+ off = 0;
+
+ FragmentRef* fragref = FragmentRef::Create(*pReloc.targetRef().frag(), off);
+ // TODO: add symbols for R_386_TLS_OPT relocs
+ Relocation* reloc = Relocation::Create(X86_32Relocator::R_386_TLS_OPT,
+ *fragref,
+ 0x0);
+
+ // 2. modify the opcodes to the appropriate ones
+ uint8_t* op = (reinterpret_cast<uint8_t*>(&reloc->target()));
+ off = pReloc.targetRef().offset() - reloc->targetRef().offset() - 1;
+ if (op[off] == 0xa1) {
+ op[off] = 0xb8;
+ } else {
+ switch (op[off - 1]) {
+ case 0x8b:
+ assert((op[off] & 0xc7) == 0x05);
+ op[off - 1] = 0xc7;
+ op[off] = 0xc0 | ((op[off] >> 3) & 7);
+ break;
+ case 0x03:
+ assert((op[off] & 0xc7) == 0x05);
+ op[off - 1] = 0x81;
+ op[off] = 0xc0 | ((op[off] >> 3) & 7);
+ break;
+ default:
+ assert(0);
+ break;
}
}
- else {
- fatal(diag::unrecognized_output_sectoin)
- << pSection.name()
- << "mclinker@googlegroups.com";
+ // 3. insert the new relocs "BEFORE" the original reloc.
+ pSection.getRelocData()->getRelocationList().insert(
+ RelocData::iterator(pReloc), reloc);
+
+ // 4. change the type of the original reloc
+ pReloc.setType(llvm::ELF::R_386_TLS_LE);
+}
+
+// Create a GOT entry for the TLS module index
+X86_32GOTEntry& X86_32GNULDBackend::getTLSModuleID()
+{
+ static X86_32GOTEntry* got_entry = NULL;
+ if (NULL != got_entry)
+ return *got_entry;
+
+ // Allocate 2 got entries and 1 dynamic reloc for R_386_TLS_LDM
+ m_pGOT->reserve(2);
+ got_entry = m_pGOT->consume();
+ m_pGOT->consume()->setValue(0x0);
+
+ m_pRelDyn->reserveEntry();
+ Relocation* rel_entry = m_pRelDyn->consumeEntry();
+ rel_entry->setType(llvm::ELF::R_386_TLS_DTPMOD32);
+ rel_entry->targetRef().assign(*got_entry, 0x0);
+ rel_entry->setSymInfo(NULL);
+
+ return *got_entry;
+}
+
+X86_64GNULDBackend::X86_64GNULDBackend(const LinkerConfig& pConfig,
+ GNUInfo* pInfo)
+ : X86GNULDBackend(pConfig, pInfo, llvm::ELF::R_X86_64_COPY),
+ m_pGOT (NULL),
+ m_pGOTPLT (NULL) {
+}
+
+X86_64GNULDBackend::~X86_64GNULDBackend()
+{
+ delete m_pGOT;
+ delete m_pGOTPLT;
+}
+
+bool X86_64GNULDBackend::initRelocator()
+{
+ if (NULL == m_pRelocator) {
+ m_pRelocator = new X86_64Relocator(*this);
}
- return RegionSize;
+ return true;
}
-X86GOT& X86GNULDBackend::getGOT()
+X86_64GOT& X86_64GNULDBackend::getGOT()
{
assert(NULL != m_pGOT);
return *m_pGOT;
}
-const X86GOT& X86GNULDBackend::getGOT() const
+const X86_64GOT& X86_64GNULDBackend::getGOT() const
{
assert(NULL != m_pGOT);
return *m_pGOT;
}
-X86GOTPLT& X86GNULDBackend::getGOTPLT()
+X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT()
{
assert(NULL != m_pGOTPLT);
return *m_pGOTPLT;
}
-const X86GOTPLT& X86GNULDBackend::getGOTPLT() const
+const X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT() const
{
assert(NULL != m_pGOTPLT);
return *m_pGOTPLT;
}
-X86PLT& X86GNULDBackend::getPLT()
+void X86_64GNULDBackend::setRelDynSize()
{
- assert(NULL != m_pPLT && "PLT section not exist");
- return *m_pPLT;
+ ELFFileFormat* file_format = getOutputFormat();
+ file_format->getRelaDyn().setSize
+ (m_pRelDyn->numOfRelocs() * getRelaEntrySize());
}
-const X86PLT& X86GNULDBackend::getPLT() const
+void X86_64GNULDBackend::setRelPLTSize()
{
- assert(NULL != m_pPLT && "PLT section not exist");
- return *m_pPLT;
+ ELFFileFormat* file_format = getOutputFormat();
+ file_format->getRelaPlt().setSize
+ (m_pRelPLT->numOfRelocs() * getRelaEntrySize());
}
-OutputRelocSection& X86GNULDBackend::getRelDyn()
+void X86_64GNULDBackend::scanLocalReloc(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection)
{
- assert(NULL != m_pRelDyn && ".rel.dyn section not exist");
- return *m_pRelDyn;
-}
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
-const OutputRelocSection& X86GNULDBackend::getRelDyn() const
-{
- assert(NULL != m_pRelDyn && ".rel.dyn section not exist");
- return *m_pRelDyn;
-}
+ switch(pReloc.type()){
+ case llvm::ELF::R_X86_64_64:
+ case llvm::ELF::R_X86_64_32:
+ case llvm::ELF::R_X86_64_16:
+ case llvm::ELF::R_X86_64_8:
+ case llvm::ELF::R_X86_64_32S:
+ // If buiding PIC object (shared library or PIC executable),
+ // a dynamic relocations with RELATIVE type to this location is needed.
+ // Reserve an entry in .rela.dyn
+ if (config().isCodeIndep()) {
+ m_pRelDyn->reserveEntry();
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ checkAndSetHasTextRel(*pSection.getLink());
+ }
+ return;
-// Create a GOT entry for the TLS module index
-X86GOTEntry& X86GNULDBackend::getTLSModuleID()
-{
- static X86GOTEntry* got_entry = NULL;
- if (NULL != got_entry)
- return *got_entry;
+ case llvm::ELF::R_X86_64_PC32:
+ case llvm::ELF::R_X86_64_PC16:
+ case llvm::ELF::R_X86_64_PC8:
+ return;
- // Allocate 2 got entries and 1 dynamic reloc for R_386_TLS_LDM
- m_pGOT->reserve(2);
- got_entry = m_pGOT->consume();
- m_pGOT->consume()->setValue(0x0);
+ case llvm::ELF::R_X86_64_GOTPCREL:
+ // Symbol needs GOT entry, reserve entry in .got
+ // return if we already create GOT for this symbol
+ if (rsym->reserved() & (ReserveGOT | GOTRel))
+ return;
+ m_pGOT->reserve();
- m_pRelDyn->reserveEntry();
- Relocation* rel_entry = m_pRelDyn->consumeEntry();
- rel_entry->setType(llvm::ELF::R_386_TLS_DTPMOD32);
- rel_entry->targetRef().assign(*got_entry, 0x0);
- rel_entry->setSymInfo(NULL);
+ // If the GOT is used in statically linked binaries,
+ // the GOT entry is enough and no relocation is needed.
+ if (config().isCodeStatic()) {
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
+ return;
+ }
+ // If building shared object or the symbol is undefined, a dynamic
+ // relocation is needed to relocate this GOT entry. Reserve an
+ // entry in .rela.dyn
+ if (LinkerConfig::DynObj ==
+ config().codeGenType() || rsym->isUndef() || rsym->isDyn()) {
+ m_pRelDyn->reserveEntry();
+ // set GOTRel bit
+ rsym->setReserved(rsym->reserved() | GOTRel);
+ return;
+ }
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
+ return;
- return *got_entry;
+ default:
+ fatal(diag::unsupported_relocation) << (int)pReloc.type()
+ << "mclinker@googlegroups.com";
+ break;
+ } // end switch
}
-OutputRelocSection& X86GNULDBackend::getRelPLT()
+void X86_64GNULDBackend::scanGlobalReloc(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection)
{
- assert(NULL != m_pRelPLT && ".rel.plt section not exist");
- return *m_pRelPLT;
-}
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
-const OutputRelocSection& X86GNULDBackend::getRelPLT() const
-{
- assert(NULL != m_pRelPLT && ".rel.plt section not exist");
- return *m_pRelPLT;
-}
+ switch(pReloc.type()) {
+ case llvm::ELF::R_X86_64_64:
+ case llvm::ELF::R_X86_64_32:
+ case llvm::ELF::R_X86_64_16:
+ case llvm::ELF::R_X86_64_8:
+ case llvm::ELF::R_X86_64_32S:
+ // Absolute relocation type, symbol may needs PLT entry or
+ // dynamic relocation entry
+ if (symbolNeedsPLT(*rsym)) {
+ // create plt for this symbol if it does not have one
+ if (!(rsym->reserved() & ReservePLT)){
+ // Symbol needs PLT entry, we need to reserve a PLT entry
+ // and the corresponding GOT and dynamic relocation entry
+ // in .got and .rela.plt. (GOT entry will be reserved simultaneously
+ // when calling X86PLT->reserveEntry())
+ m_pPLT->reserveEntry();
+ m_pGOTPLT->reserve();
+ m_pRelPLT->reserveEntry();
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | ReservePLT);
+ }
+ }
-unsigned int
-X86GNULDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const
-{
- const ELFFileFormat* file_format = getOutputFormat();
+ if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), true)) {
+ // symbol needs dynamic relocation entry, reserve an entry in .rela.dyn
+ m_pRelDyn->reserveEntry();
+ if (symbolNeedsCopyReloc(pReloc, *rsym)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
+ addCopyReloc(*cpy_sym.resolveInfo());
+ }
+ else {
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ checkAndSetHasTextRel(*pSection.getLink());
+ }
+ }
+ return;
- if (&pSectHdr == &file_format->getGOT()) {
- if (config().options().hasNow())
- return SHO_RELRO;
- return SHO_RELRO_LAST;
- }
+ case llvm::ELF::R_X86_64_GOTPCREL:
+ // Symbol needs GOT entry, reserve entry in .got
+ // return if we already create GOT for this symbol
+ if (rsym->reserved() & (ReserveGOT | GOTRel))
+ return;
+ m_pGOT->reserve();
- if (&pSectHdr == &file_format->getGOTPLT()) {
- if (config().options().hasNow())
- return SHO_RELRO;
- return SHO_NON_RELRO_FIRST;
- }
+ // If the GOT is used in statically linked binaries,
+ // the GOT entry is enough and no relocation is needed.
+ if (config().isCodeStatic()) {
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
+ return;
+ }
+ // If building shared object or the symbol is undefined, a dynamic
+ // relocation is needed to relocate this GOT entry. Reserve an
+ // entry in .rela.dyn
+ if (LinkerConfig::DynObj ==
+ config().codeGenType() || rsym->isUndef() || rsym->isDyn()) {
+ m_pRelDyn->reserveEntry();
+ // set GOTRel bit
+ rsym->setReserved(rsym->reserved() | GOTRel);
+ return;
+ }
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
+ return;
- if (&pSectHdr == &file_format->getPLT())
- return SHO_PLT;
+ case llvm::ELF::R_X86_64_PLT32:
+ // A PLT entry is needed when building shared library
- return SHO_UNDEFINED;
+ // return if we already create plt for this symbol
+ if (rsym->reserved() & ReservePLT)
+ return;
+
+ // if the symbol's value can be decided at link time, then no need plt
+ if (symbolFinalValueIsKnown(*rsym))
+ return;
+
+ // if symbol is defined in the ouput file and it's not
+ // preemptible, no need plt
+ if (rsym->isDefine() && !rsym->isDyn() &&
+ !isSymbolPreemptible(*rsym)) {
+ return;
+ }
+
+ // 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_pGOTPLT->reserve();
+ m_pRelPLT->reserveEntry();
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | ReservePLT);
+ return;
+
+ case llvm::ELF::R_X86_64_PC32:
+ case llvm::ELF::R_X86_64_PC16:
+ case llvm::ELF::R_X86_64_PC8:
+ if (symbolNeedsPLT(*rsym) &&
+ LinkerConfig::DynObj != config().codeGenType()) {
+ // create plt for this symbol if it does not have one
+ if (!(rsym->reserved() & ReservePLT)){
+ // Symbol needs PLT entry, we need to reserve a PLT entry
+ // 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_pGOTPLT->reserve();
+ m_pRelPLT->reserveEntry();
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | ReservePLT);
+ }
+ }
+
+ // Only PC relative relocation against dynamic symbol needs a
+ // dynamic relocation. Only dynamic copy relocation is allowed
+ // and PC relative relocation will be resolved to the local copy.
+ // All other dynamic relocations may lead to run-time relocation
+ // overflow.
+ if (isDynamicSymbol(*rsym) &&
+ symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), false) &&
+ symbolNeedsCopyReloc(pReloc, *rsym)) {
+ m_pRelDyn->reserveEntry();
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
+ addCopyReloc(*cpy_sym.resolveInfo());
+ }
+ return;
+
+ default:
+ fatal(diag::unsupported_relocation) << (int)pReloc.type()
+ << "mclinker@googlegroups.com";
+ break;
+ } // end switch
}
-void X86GNULDBackend::initTargetSections(Module& pModule, ObjectBuilder& pBuilder)
+void X86_64GNULDBackend::initTargetSections(Module& pModule,
+ ObjectBuilder& pBuilder)
{
if (LinkerConfig::Object != config().codeGenType()) {
ELFFileFormat* file_format = getOutputFormat();
// initialize .got
LDSection& got = file_format->getGOT();
- m_pGOT = new X86GOT(got);
+ m_pGOT = new X86_64GOT(got);
// initialize .got.plt
LDSection& gotplt = file_format->getGOTPLT();
- m_pGOTPLT = new X86GOTPLT(gotplt);
+ m_pGOTPLT = new X86_64GOTPLT(gotplt);
// initialize .plt
LDSection& plt = file_format->getPLT();
- m_pPLT = new X86PLT(plt,
- *m_pGOTPLT,
- config());
+ m_pPLT = new X86_64PLT(plt,
+ *m_pGOTPLT,
+ config());
- // initialize .rel.plt
- LDSection& relplt = file_format->getRelPlt();
+ // initialize .rela.plt
+ LDSection& relplt = file_format->getRelaPlt();
relplt.setLink(&plt);
m_pRelPLT = new OutputRelocSection(pModule, relplt);
- // initialize .rel.dyn
- LDSection& reldyn = file_format->getRelDyn();
+ // initialize .rela.dyn
+ LDSection& reldyn = file_format->getRelaDyn();
m_pRelDyn = new OutputRelocSection(pModule, reldyn);
}
}
-void X86GNULDBackend::initTargetSymbols(FragmentLinker& pLinker)
+void X86_64GNULDBackend::setGOTSectionSize(IRBuilder& pBuilder)
{
- if (LinkerConfig::Object != config().codeGenType()) {
- // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
- // same name in input
- m_pGOTSymbol =
- pLinker.defineSymbol<FragmentLinker::AsRefered,
- FragmentLinker::Resolve>("_GLOBAL_OFFSET_TABLE_",
- false,
- ResolveInfo::Object,
- ResolveInfo::Define,
- ResolveInfo::Local,
- 0x0, // size
- 0x0, // value
- FragmentRef::Null(), // FragRef
- ResolveInfo::Hidden);
+ // set .got.plt size
+ if (LinkerConfig::DynObj == config().codeGenType() ||
+ m_pGOTPLT->hasGOT1() ||
+ NULL != m_pGOTSymbol) {
+ m_pGOTPLT->finalizeSectionSize();
+ defineGOTSymbol(pBuilder, *(m_pGOTPLT->begin()));
}
+
+ // set .got size
+ if (!m_pGOT->empty())
+ m_pGOT->finalizeSectionSize();
}
-/// finalizeSymbol - finalize the symbol value
-bool X86GNULDBackend::finalizeTargetSymbols(FragmentLinker& pLinker)
+uint64_t X86_64GNULDBackend::emitGOTSectionData(MemoryRegion& pRegion) const
{
- return true;
+ assert(m_pGOT && "emitGOTSectionData failed, m_pGOT is NULL!");
+
+ uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.getBuffer());
+
+ X86_64GOTEntry* got = 0;
+ unsigned int EntrySize = X86_64GOTEntry::EntrySize;
+ uint64_t RegionSize = 0;
+
+ for (X86_64GOT::iterator it = m_pGOT->begin(),
+ ie = m_pGOT->end(); it != ie; ++it, ++buffer) {
+ got = &(llvm::cast<X86_64GOTEntry>((*it)));
+ *buffer = static_cast<uint64_t>(got->getValue());
+ RegionSize += EntrySize;
+ }
+
+ return RegionSize;
}
-/// doCreateProgramHdrs - backend can implement this function to create the
-/// target-dependent segments
-void X86GNULDBackend::doCreateProgramHdrs(Module& pModule,
- const FragmentLinker& pLinker)
+uint64_t X86_64GNULDBackend::emitGOTPLTSectionData(MemoryRegion& pRegion,
+ const ELFFileFormat* FileFormat) const
{
- // TODO
+ assert(m_pGOTPLT && "emitGOTPLTSectionData failed, m_pGOTPLT is NULL!");
+ m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr());
+ m_pGOTPLT->applyAllGOTPLT(*m_pPLT);
+
+ uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.getBuffer());
+
+ X86_64GOTEntry* got = 0;
+ unsigned int EntrySize = X86_64GOTEntry::EntrySize;
+ uint64_t RegionSize = 0;
+
+ for (X86_64GOTPLT::iterator it = m_pGOTPLT->begin(),
+ ie = m_pGOTPLT->end(); it != ie; ++it, ++buffer) {
+ got = &(llvm::cast<X86_64GOTEntry>((*it)));
+ *buffer = static_cast<uint64_t>(got->getValue());
+ RegionSize += EntrySize;
+ }
+
+ return RegionSize;
}
namespace mcld {
@@ -862,7 +1357,13 @@ TargetLDBackend* createX86LDBackend(const llvm::Target& pTarget,
createX86COFFObjectWriter);
**/
}
- return new X86GNULDBackend(pConfig, new X86GNUInfo(pConfig.targets().triple()));
+ Triple::ArchType arch = pConfig.targets().triple().getArch();
+ if (arch == Triple::x86)
+ return new X86_32GNULDBackend(pConfig,
+ new X86_32GNUInfo(pConfig.targets().triple()));
+ assert (arch == Triple::x86_64);
+ return new X86_64GNULDBackend(pConfig,
+ new X86_64GNUInfo(pConfig.targets().triple()));
}
} // namespace of mcld
@@ -872,5 +1373,6 @@ TargetLDBackend* createX86LDBackend(const llvm::Target& pTarget,
//===----------------------------------------------------------------------===//
extern "C" void MCLDInitializeX86LDBackend() {
// Register the linker backend
- mcld::TargetRegistry::RegisterTargetLDBackend(TheX86Target, createX86LDBackend);
+ mcld::TargetRegistry::RegisterTargetLDBackend(TheX86_32Target, createX86LDBackend);
+ mcld::TargetRegistry::RegisterTargetLDBackend(TheX86_64Target, createX86LDBackend);
}
diff --git a/lib/Target/X86/X86LDBackend.h b/lib/Target/X86/X86LDBackend.h
index 3f8a626..a008d00 100644
--- a/lib/Target/X86/X86LDBackend.h
+++ b/lib/Target/X86/X86LDBackend.h
@@ -20,7 +20,7 @@
namespace mcld {
class LinkerConfig;
-class X86GNUInfo;
+class GNUInfo;
//===----------------------------------------------------------------------===//
/// X86GNULDBackend - linker backend of X86 target of GNU ELF format
@@ -72,31 +72,23 @@ public:
};
public:
- X86GNULDBackend(const LinkerConfig& pConfig, X86GNUInfo* pInfo);
+ X86GNULDBackend(const LinkerConfig& pConfig,
+ GNUInfo* pInfo,
+ Relocation::Type pCopyRel);
~X86GNULDBackend();
uint32_t machine() const;
- X86GOT& getGOT();
-
- const X86GOT& getGOT() const;
-
- X86GOTPLT& getGOTPLT();
-
- const X86GOTPLT& getGOTPLT() const;
-
X86PLT& getPLT();
const X86PLT& getPLT() const;
- X86GOTEntry& getTLSModuleID();
-
/// preLayout - Backend can do any needed modification before layout
- void doPreLayout(FragmentLinker& pLinker);
+ void doPreLayout(IRBuilder& pBuilder);
/// postLayout -Backend can do any needed modification after layout
- void doPostLayout(Module& pModule, FragmentLinker& pLinker);
+ void doPostLayout(Module& pModule, IRBuilder& pBuilder);
/// dynamic - the dynamic section of the target machine.
/// Use co-variant return type to return its own dynamic section.
@@ -124,23 +116,15 @@ public:
uint64_t emitSectionData(const LDSection& pSection,
MemoryRegion& pRegion) const;
- /// flags - the value of ElfXX_Ehdr::e_flags
- /// FIXME
- uint64_t flags() const
- { return 0x0; }
-
- uint64_t defaultTextSegmentAddr() const
- { return 0x08048000; }
-
/// initRelocator - create and initialize Relocator.
- bool initRelocator(const FragmentLinker& pLinker);
+ virtual bool initRelocator() = 0;
/// getRelocator - return relocator.
Relocator* getRelocator();
- void initTargetSections(Module& pModule, ObjectBuilder& pBuilder);
+ virtual void initTargetSections(Module& pModule, ObjectBuilder& pBuilder) = 0;
- void initTargetSymbols(FragmentLinker& pLinker);
+ void initTargetSymbols(IRBuilder& pBuilder, Module& pModule);
/// scanRelocation - determine the empty entries are needed or not and create
/// the empty entries if needed.
@@ -149,9 +133,9 @@ public:
/// - PLT entry (for .plt section)
/// - dynamin relocation entries (for .rel.plt and .rel.dyn sections)
void scanRelocation(Relocation& pReloc,
- FragmentLinker& pLinker,
+ IRBuilder& pBuilder,
Module& pModule,
- const LDSection& pSection);
+ LDSection& pSection);
OutputRelocSection& getRelDyn();
@@ -165,19 +149,24 @@ public:
unsigned int getTargetSectionOrder(const LDSection& pSectHdr) const;
/// finalizeTargetSymbols - finalize the symbol value
- bool finalizeTargetSymbols(FragmentLinker& pLinker);
+ bool finalizeTargetSymbols();
+
+ /// getPointerRel - get pointer relocation type.
+ Relocation::Type getPointerRel()
+ { return m_PointerRel; }
private:
- void scanLocalReloc(Relocation& pReloc,
- FragmentLinker& pLinker,
- Module& pModule,
- const LDSection& pSection);
+ virtual void scanLocalReloc(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection) = 0;
- void scanGlobalReloc(Relocation& pReloc,
- FragmentLinker& pLinker,
- Module& pModule,
- const LDSection& pSection);
+ virtual void scanGlobalReloc(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection) = 0;
+protected:
/// 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);
@@ -185,29 +174,38 @@ private:
/// 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(FragmentLinker& pLinker,
+ LDSymbol& defineSymbolforCopyReloc(IRBuilder& pLinker,
const ResolveInfo& pSym);
- void defineGOTSymbol(FragmentLinker& pLinker);
+ void defineGOTSymbol(IRBuilder& pBuilder, Fragment&);
+protected:
/// getRelEntrySize - the size in BYTE of rel type relocation
size_t getRelEntrySize()
- { return 8; }
+ { return m_RelEntrySize; }
/// getRelEntrySize - the size in BYTE of rela type relocation
size_t getRelaEntrySize()
- { return 12; }
+ { return m_RelaEntrySize; }
+private:
/// doCreateProgramHdrs - backend can implement this function to create the
/// target-dependent segments
- virtual void doCreateProgramHdrs(Module& pModule,
- const FragmentLinker& pLinker);
+ void doCreateProgramHdrs(Module& pModule);
-private:
+ virtual void setGOTSectionSize(IRBuilder& pBuilder) = 0;
+
+ virtual uint64_t emitGOTSectionData(MemoryRegion& pRegion) const = 0;
+
+ virtual uint64_t emitGOTPLTSectionData(MemoryRegion& pRegion,
+ const ELFFileFormat* FileFormat) const = 0;
+
+ virtual void setRelDynSize() = 0;
+ virtual void setRelPLTSize() = 0;
+
+protected:
Relocator* m_pRelocator;
- 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
@@ -215,25 +213,119 @@ private:
X86ELFDynamic* m_pDynamic;
LDSymbol* m_pGOTSymbol;
+
+ size_t m_RelEntrySize;
+ size_t m_RelaEntrySize;
+
+ Relocation::Type m_CopyRel;
+ Relocation::Type m_PointerRel;
+};
+
+//
+//===----------------------------------------------------------------------===//
+/// X86_32GNULDBackend - linker backend of X86-32 target of GNU ELF format
+///
+class X86_32GNULDBackend : public X86GNULDBackend
+{
+public:
+ X86_32GNULDBackend(const LinkerConfig& pConfig, GNUInfo* pInfo);
+
+ ~X86_32GNULDBackend();
+
+ void initTargetSections(Module& pModule, ObjectBuilder& pBuilder);
+
+ X86_32GOT& getGOT();
+
+ const X86_32GOT& getGOT() const;
+
+ X86_32GOTPLT& getGOTPLT();
+
+ const X86_32GOTPLT& getGOTPLT() const;
+
+ X86_32GOTEntry& getTLSModuleID();
+
+private:
+ void scanLocalReloc(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection);
+
+ void scanGlobalReloc(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection);
+
+ /// initRelocator - create and initialize Relocator.
+ bool initRelocator();
+
+ /// ----- tls optimization ----- ///
+ /// convert R_386_TLS_IE to R_386_TLS_LE
+ void convertTLSIEtoLE(Relocation& pReloc, LDSection& pSection);
+
+ void setGOTSectionSize(IRBuilder& pBuilder);
+
+ uint64_t emitGOTSectionData(MemoryRegion& pRegion) const;
+
+ uint64_t emitGOTPLTSectionData(MemoryRegion& pRegion,
+ const ELFFileFormat* FileFormat) const;
+
+ void setRelDynSize();
+ void setRelPLTSize();
+
+private:
+ X86_32GOT* m_pGOT;
+ X86_32GOTPLT* m_pGOTPLT;
};
+//
//===----------------------------------------------------------------------===//
-/// X86MachOLDBackend - linker backend of X86 target of MachO format
+/// X86_64GNULDBackend - linker backend of X86-64 target of GNU ELF format
///
-/**
-class X86MachOLDBackend : public DarwinX86LDBackend
+class X86_64GNULDBackend : public X86GNULDBackend
{
public:
- X86MachOLDBackend();
- ~X86MachOLDBackend();
+ X86_64GNULDBackend(const LinkerConfig& pConfig, GNUInfo* pInfo);
+
+ ~X86_64GNULDBackend();
+
+ void initTargetSections(Module& pModule, ObjectBuilder& pBuilder);
+
+ X86_64GOT& getGOT();
+
+ const X86_64GOT& getGOT() const;
+
+ X86_64GOTPLT& getGOTPLT();
+
+ const X86_64GOTPLT& getGOTPLT() const;
private:
- MCMachOTargetArchiveReader *createTargetArchiveReader() const;
- MCMachOTargetObjectReader *createTargetObjectReader() const;
- MCMachOTargetObjectWriter *createTargetObjectWriter() const;
+ void scanLocalReloc(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection);
+
+ void scanGlobalReloc(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection);
+
+ /// initRelocator - create and initialize Relocator.
+ bool initRelocator();
+
+ void setGOTSectionSize(IRBuilder& pBuilder);
+ uint64_t emitGOTSectionData(MemoryRegion& pRegion) const;
+
+ uint64_t emitGOTPLTSectionData(MemoryRegion& pRegion,
+ const ELFFileFormat* FileFormat) const;
+
+ void setRelDynSize();
+ void setRelPLTSize();
+
+private:
+ X86_64GOT* m_pGOT;
+ X86_64GOTPLT* m_pGOTPLT;
};
-**/
} // namespace of mcld
#endif
diff --git a/lib/Target/X86/X86MCLinker.cpp b/lib/Target/X86/X86MCLinker.cpp
index e55add3..bad20a9 100644
--- a/lib/Target/X86/X86MCLinker.cpp
+++ b/lib/Target/X86/X86MCLinker.cpp
@@ -34,11 +34,7 @@ MCLinker* createX86MCLinker(const std::string &pTriple,
return NULL;
}
- if (theTriple.isArch32Bit())
- return new X86ELFMCLinker(pConfig, pModule, pOutput);
-
- assert(0 && "X86_64 has not supported yet");
- return NULL;
+ return new X86ELFMCLinker(pConfig, pModule, pOutput);
}
} // namespace of mcld
@@ -48,6 +44,7 @@ MCLinker* createX86MCLinker(const std::string &pTriple,
//===----------------------------------------------------------------------===//
extern "C" void MCLDInitializeX86MCLinker() {
// Register the linker frontend
- mcld::TargetRegistry::RegisterMCLinker(TheX86Target, createX86MCLinker);
+ mcld::TargetRegistry::RegisterMCLinker(TheX86_32Target, createX86MCLinker);
+ mcld::TargetRegistry::RegisterMCLinker(TheX86_64Target, createX86MCLinker);
}
diff --git a/lib/Target/X86/X86PLT.cpp b/lib/Target/X86/X86PLT.cpp
index 25eaab9..669a047 100644
--- a/lib/Target/X86/X86PLT.cpp
+++ b/lib/Target/X86/X86PLT.cpp
@@ -21,23 +21,33 @@ using namespace mcld;
//===----------------------------------------------------------------------===//
// PLT entry data
//===----------------------------------------------------------------------===//
-X86DynPLT0::X86DynPLT0(SectionData& pParent)
- : PLT::Entry<sizeof(x86_dyn_plt0)>(pParent)
+X86_32DynPLT0::X86_32DynPLT0(SectionData& pParent)
+ : PLT::Entry<sizeof(x86_32_dyn_plt0)>(pParent)
{
}
-X86DynPLT1::X86DynPLT1(SectionData& pParent)
- : PLT::Entry<sizeof(x86_dyn_plt1)>(pParent)
+X86_32DynPLT1::X86_32DynPLT1(SectionData& pParent)
+ : PLT::Entry<sizeof(x86_32_dyn_plt1)>(pParent)
{
}
-X86ExecPLT0::X86ExecPLT0(SectionData& pParent)
- : PLT::Entry<sizeof(x86_exec_plt0)>(pParent)
+X86_32ExecPLT0::X86_32ExecPLT0(SectionData& pParent)
+ : PLT::Entry<sizeof(x86_32_exec_plt0)>(pParent)
{
}
-X86ExecPLT1::X86ExecPLT1(SectionData& pParent)
- : PLT::Entry<sizeof(x86_exec_plt1)>(pParent)
+X86_32ExecPLT1::X86_32ExecPLT1(SectionData& pParent)
+ : PLT::Entry<sizeof(x86_32_exec_plt1)>(pParent)
+{
+}
+
+X86_64PLT0::X86_64PLT0(SectionData& pParent)
+ : PLT::Entry<sizeof(x86_64_plt0)>(pParent)
+{
+}
+
+X86_64PLT1::X86_64PLT1(SectionData& pParent)
+ : PLT::Entry<sizeof(x86_64_plt1)>(pParent)
{
}
@@ -45,31 +55,42 @@ X86ExecPLT1::X86ExecPLT1(SectionData& pParent)
// X86PLT
//===----------------------------------------------------------------------===//
X86PLT::X86PLT(LDSection& pSection,
- X86GOTPLT &pGOTPLT,
- const LinkerConfig& pConfig)
+ const LinkerConfig& pConfig,
+ int got_size)
: PLT(pSection),
- m_GOTPLT(pGOTPLT),
m_Config(pConfig)
{
assert(LinkerConfig::DynObj == m_Config.codeGenType() ||
LinkerConfig::Exec == m_Config.codeGenType() ||
LinkerConfig::Binary == m_Config.codeGenType());
- if (LinkerConfig::DynObj == m_Config.codeGenType()) {
- m_PLT0 = x86_dyn_plt0;
- m_PLT1 = x86_dyn_plt1;
- m_PLT0Size = sizeof (x86_dyn_plt0);
- m_PLT1Size = sizeof (x86_dyn_plt1);
- // create PLT0
- new X86DynPLT0(*m_SectionData);
+ if (got_size == 32) {
+ if (LinkerConfig::DynObj == m_Config.codeGenType()) {
+ m_PLT0 = x86_32_dyn_plt0;
+ m_PLT1 = x86_32_dyn_plt1;
+ m_PLT0Size = sizeof (x86_32_dyn_plt0);
+ m_PLT1Size = sizeof (x86_32_dyn_plt1);
+ // create PLT0
+ new X86_32DynPLT0(*m_SectionData);
+ }
+ else {
+ m_PLT0 = x86_32_exec_plt0;
+ m_PLT1 = x86_32_exec_plt1;
+ m_PLT0Size = sizeof (x86_32_exec_plt0);
+ m_PLT1Size = sizeof (x86_32_exec_plt1);
+ // create PLT0
+ new X86_32ExecPLT0(*m_SectionData);
+ }
}
else {
- m_PLT0 = x86_exec_plt0;
- m_PLT1 = x86_exec_plt1;
- m_PLT0Size = sizeof (x86_exec_plt0);
- m_PLT1Size = sizeof (x86_exec_plt1);
+ assert(got_size == 64);
+ m_PLT0 = x86_64_plt0;
+ m_PLT1 = x86_64_plt1;
+ m_PLT0Size = sizeof (x86_64_plt0);
+ m_PLT1Size = sizeof (x86_64_plt1);
// create PLT0
- new X86ExecPLT0(*m_SectionData);
+ new X86_64PLT0(*m_SectionData);
+ m_Last = m_SectionData->begin();
}
m_Last = m_SectionData->begin();
}
@@ -114,9 +135,9 @@ void X86PLT::reserveEntry(size_t pNum)
for (size_t i = 0; i < pNum; ++i) {
if (LinkerConfig::DynObj == m_Config.codeGenType())
- plt1_entry = new X86DynPLT1(*m_SectionData);
+ plt1_entry = new X86_32DynPLT1(*m_SectionData);
else
- plt1_entry = new X86ExecPLT1(*m_SectionData);
+ plt1_entry = new X86_32ExecPLT1(*m_SectionData);
if (NULL == plt1_entry)
fatal(diag::fail_allocate_memory_plt);
@@ -144,8 +165,18 @@ PLTEntryBase* X86PLT::getPLT0() const
return plt0;
}
+//===----------------------------------------------------------------------===//
+// X86_32PLT
+//===----------------------------------------------------------------------===//
+X86_32PLT::X86_32PLT(LDSection& pSection,
+ X86_32GOTPLT& pGOTPLT,
+ const LinkerConfig& pConfig)
+ : X86PLT(pSection, pConfig, 32),
+ m_GOTPLT(pGOTPLT) {
+}
+
// FIXME: It only works on little endian machine.
-void X86PLT::applyPLT0()
+void X86_32PLT::applyPLT0()
{
PLTEntryBase* plt0 = getPLT0();
@@ -157,7 +188,7 @@ void X86PLT::applyPLT0()
memcpy(data, m_PLT0, plt0->size());
- if (m_PLT0 == x86_exec_plt0) {
+ if (m_PLT0 == x86_32_exec_plt0) {
uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2);
*offset = m_GOTPLT.addr() + 4;
offset = reinterpret_cast<uint32_t*>(data + 8);
@@ -168,7 +199,7 @@ void X86PLT::applyPLT0()
}
// FIXME: It only works on little endian machine.
-void X86PLT::applyPLT1()
+void X86_32PLT::applyPLT1()
{
assert(m_Section.addr() && ".plt base address is NULL!");
@@ -176,7 +207,7 @@ void X86PLT::applyPLT1()
X86PLT::iterator ie = m_SectionData->end();
assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
- uint64_t GOTEntrySize = X86GOTPLTEntry::EntrySize;
+ uint64_t GOTEntrySize = X86_32GOTEntry::EntrySize;
// Skip GOT0
uint64_t GOTEntryOffset = GOTEntrySize * X86GOTPLT0Num;
@@ -220,3 +251,96 @@ void X86PLT::applyPLT1()
}
}
+//===----------------------------------------------------------------------===//
+// X86_64PLT
+//===----------------------------------------------------------------------===//
+X86_64PLT::X86_64PLT(LDSection& pSection,
+ X86_64GOTPLT& pGOTPLT,
+ const LinkerConfig& pConfig)
+ : X86PLT(pSection, pConfig, 64),
+ m_GOTPLT(pGOTPLT) {
+}
+
+// FIXME: It only works on little endian machine.
+void X86_64PLT::applyPLT0()
+{
+ PLTEntryBase* plt0 = getPLT0();
+
+ unsigned char* data = 0;
+ data = static_cast<unsigned char*>(malloc(plt0->size()));
+
+ if (!data)
+ fatal(diag::fail_allocate_memory_plt);
+
+ memcpy(data, m_PLT0, plt0->size());
+
+ // pushq GOT + 8(%rip)
+ uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2);
+ *offset = m_GOTPLT.addr() - addr() + 8 - 6;
+ // jmq *GOT + 16(%rip)
+ offset = reinterpret_cast<uint32_t*>(data + 8);
+ *offset = m_GOTPLT.addr() - addr() + 16 - 12;
+
+ plt0->setValue(data);
+}
+
+// FIXME: It only works on little endian machine.
+void X86_64PLT::applyPLT1()
+{
+ assert(m_Section.addr() && ".plt 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 = X86_64GOTEntry::EntrySize;
+
+ // compute sym@GOTPCREL of the PLT1 entry.
+ uint64_t SymGOTPCREL = m_GOTPLT.addr();
+
+ // Skip GOT0
+ SymGOTPCREL += GOTEntrySize * X86GOTPLT0Num;
+
+ // skip PLT0
+ uint64_t PLTEntryOffset = m_PLT0Size;
+ ++it;
+
+ // PC-relative to entry in PLT section.
+ SymGOTPCREL -= addr() + PLTEntryOffset + 6;
+
+ PLTEntryBase* plt1 = 0;
+
+ uint64_t PLTRelIndex = 0;
+
+ while (it != ie) {
+ plt1 = &(llvm::cast<PLTEntryBase>(*it));
+ unsigned char *data;
+ data = static_cast<unsigned char*>(malloc(plt1->size()));
+
+ if (!data)
+ fatal(diag::fail_allocate_memory_plt);
+
+ memcpy(data, m_PLT1, plt1->size());
+
+ uint32_t* offset;
+
+ // jmpq *sym@GOTPCREL(%rip)
+ offset = reinterpret_cast<uint32_t*>(data + 2);
+ *offset = SymGOTPCREL;
+ SymGOTPCREL += GOTEntrySize - m_PLT1Size;
+
+ // pushq $index
+ offset = reinterpret_cast<uint32_t*>(data + 7);
+ *offset = PLTRelIndex;
+ PLTRelIndex++;
+
+ // jmpq plt0
+ offset = reinterpret_cast<uint32_t*>(data + 12);
+ *offset = -(PLTEntryOffset + 12 + 4);
+ PLTEntryOffset += m_PLT1Size;
+
+ plt1->setValue(data);
+ ++it;
+ }
+}
+
diff --git a/lib/Target/X86/X86PLT.h b/lib/Target/X86/X86PLT.h
index 75a72e6..2f4176c 100644
--- a/lib/Target/X86/X86PLT.h
+++ b/lib/Target/X86/X86PLT.h
@@ -13,63 +13,90 @@
namespace {
-const uint8_t x86_dyn_plt0[] = {
+const uint8_t x86_32_dyn_plt0[] = {
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[] = {
+const uint8_t x86_32_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
};
-const uint8_t x86_exec_plt0[] = {
+const uint8_t x86_32_exec_plt0[] = {
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[] = {
+const uint8_t x86_32_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
};
+const uint8_t x86_64_plt0[] = {
+ 0xff, 0x35, 0x8, 0, 0, 0, // pushq GOT + 8(%rip)
+ 0xff, 0x25, 0x16, 0, 0, 0, // jmq *GOT + 16(%rip)
+ 0x0f, 0x1f, 0x40, 0 // nopl 0(%rax)
+};
+
+const uint8_t x86_64_plt1[] = {
+ 0xff, 0x25, 0, 0, 0, 0, // jmpq *sym@GOTPCREL(%rip)
+ 0x68, 0, 0, 0, 0, // pushq $index
+ 0xe9, 0, 0, 0, 0 // jmpq plt0
+};
+
} // anonymous namespace
namespace mcld {
-class X86GOTPLT;
+class X86_32GOTPLT;
class GOTEntry;
class LinkerConfig;
//===----------------------------------------------------------------------===//
-// X86PLT Entry
+// X86_32PLT Entry
//===----------------------------------------------------------------------===//
-class X86DynPLT0 : public PLT::Entry<sizeof(x86_dyn_plt0)>
+class X86_32DynPLT0 : public PLT::Entry<sizeof(x86_32_dyn_plt0)>
{
public:
- X86DynPLT0(SectionData& pParent);
+ X86_32DynPLT0(SectionData& pParent);
};
-class X86DynPLT1 : public PLT::Entry<sizeof(x86_dyn_plt1)>
+class X86_32DynPLT1 : public PLT::Entry<sizeof(x86_32_dyn_plt1)>
{
public:
- X86DynPLT1(SectionData& pParent);
+ X86_32DynPLT1(SectionData& pParent);
};
-class X86ExecPLT0 : public PLT::Entry<sizeof(x86_exec_plt0)>
+class X86_32ExecPLT0 : public PLT::Entry<sizeof(x86_32_exec_plt0)>
{
public:
- X86ExecPLT0(SectionData& pParent);
+ X86_32ExecPLT0(SectionData& pParent);
};
-class X86ExecPLT1 : public PLT::Entry<sizeof(x86_exec_plt1)>
+class X86_32ExecPLT1 : public PLT::Entry<sizeof(x86_32_exec_plt1)>
{
public:
- X86ExecPLT1(SectionData& pParent);
+ X86_32ExecPLT1(SectionData& pParent);
+};
+
+//===----------------------------------------------------------------------===//
+// X86_64PLT Entry
+//===----------------------------------------------------------------------===//
+class X86_64PLT0 : public PLT::Entry<sizeof(x86_64_plt0)>
+{
+public:
+ X86_64PLT0(SectionData& pParent);
+};
+
+class X86_64PLT1 : public PLT::Entry<sizeof(x86_64_plt1)>
+{
+public:
+ X86_64PLT1(SectionData& pParent);
};
//===----------------------------------------------------------------------===//
@@ -82,8 +109,8 @@ class X86PLT : public PLT
{
public:
X86PLT(LDSection& pSection,
- X86GOTPLT& pGOTPLT,
- const LinkerConfig& pConfig);
+ const LinkerConfig& pConfig,
+ int got_size);
~X86PLT();
// finalizeSectionSize - set LDSection size
@@ -96,19 +123,17 @@ public:
PLTEntryBase* consume();
- void applyPLT0();
+ virtual void applyPLT0() = 0;
- void applyPLT1();
+ virtual void applyPLT1() = 0;
unsigned int getPLT0Size() const { return m_PLT0Size; }
unsigned int getPLT1Size() const { return m_PLT1Size; }
-private:
+protected:
PLTEntryBase* getPLT0() const;
-private:
- X86GOTPLT& m_GOTPLT;
-
+protected:
// the last consumed entry.
SectionData::iterator m_Last;
@@ -120,6 +145,48 @@ private:
const LinkerConfig& m_Config;
};
+//===----------------------------------------------------------------------===//
+// X86_32PLT
+//===----------------------------------------------------------------------===//
+/** \class X86_32PLT
+ * \brief X86_32 Procedure Linkage Table
+ */
+class X86_32PLT : public X86PLT
+{
+public:
+ X86_32PLT(LDSection& pSection,
+ X86_32GOTPLT& pGOTPLT,
+ const LinkerConfig& pConfig);
+
+ void applyPLT0();
+
+ void applyPLT1();
+
+private:
+ X86_32GOTPLT& m_GOTPLT;
+};
+
+//===----------------------------------------------------------------------===//
+// X86_64PLT
+//===----------------------------------------------------------------------===//
+/** \class X86_64PLT
+ * \brief X86_64 Procedure Linkage Table
+ */
+class X86_64PLT : public X86PLT
+{
+public:
+ X86_64PLT(LDSection& pSection,
+ X86_64GOTPLT& pGOTPLT,
+ const LinkerConfig& pConfig);
+
+ void applyPLT0();
+
+ void applyPLT1();
+
+private:
+ X86_64GOTPLT& m_GOTPLT;
+};
+
} // namespace of mcld
#endif
diff --git a/lib/Target/X86/X86RelocationFunctions.h b/lib/Target/X86/X86RelocationFunctions.h
index df2e70c..9209242 100644
--- a/lib/Target/X86/X86RelocationFunctions.h
+++ b/lib/Target/X86/X86RelocationFunctions.h
@@ -7,69 +7,122 @@
//
//===----------------------------------------------------------------------===//
-#define DECL_X86_APPLY_RELOC_FUNC(Name) \
-static X86Relocator::Result Name (Relocation& pEntry, \
- X86Relocator& pParent);
+#define DECL_X86_32_APPLY_RELOC_FUNC(Name) \
+static X86Relocator::Result Name(Relocation& pEntry, X86_32Relocator& pParent);
-#define DECL_X86_APPLY_RELOC_FUNCS \
-DECL_X86_APPLY_RELOC_FUNC(none) \
-DECL_X86_APPLY_RELOC_FUNC(abs) \
-DECL_X86_APPLY_RELOC_FUNC(rel) \
-DECL_X86_APPLY_RELOC_FUNC(plt32) \
-DECL_X86_APPLY_RELOC_FUNC(got32) \
-DECL_X86_APPLY_RELOC_FUNC(gotoff32) \
-DECL_X86_APPLY_RELOC_FUNC(gotpc32) \
-DECL_X86_APPLY_RELOC_FUNC(tls_gd) \
-DECL_X86_APPLY_RELOC_FUNC(tls_ie) \
-DECL_X86_APPLY_RELOC_FUNC(tls_gotie) \
-DECL_X86_APPLY_RELOC_FUNC(tls_le) \
-DECL_X86_APPLY_RELOC_FUNC(tls_ldm) \
-DECL_X86_APPLY_RELOC_FUNC(tls_ldo_32) \
-DECL_X86_APPLY_RELOC_FUNC(unsupport)
+#define DECL_X86_32_APPLY_RELOC_FUNCS \
+DECL_X86_32_APPLY_RELOC_FUNC(none) \
+DECL_X86_32_APPLY_RELOC_FUNC(abs) \
+DECL_X86_32_APPLY_RELOC_FUNC(rel) \
+DECL_X86_32_APPLY_RELOC_FUNC(plt32) \
+DECL_X86_32_APPLY_RELOC_FUNC(got32) \
+DECL_X86_32_APPLY_RELOC_FUNC(gotoff32) \
+DECL_X86_32_APPLY_RELOC_FUNC(gotpc32) \
+DECL_X86_32_APPLY_RELOC_FUNC(tls_gd) \
+DECL_X86_32_APPLY_RELOC_FUNC(tls_ie) \
+DECL_X86_32_APPLY_RELOC_FUNC(tls_gotie) \
+DECL_X86_32_APPLY_RELOC_FUNC(tls_le) \
+DECL_X86_32_APPLY_RELOC_FUNC(tls_ldm) \
+DECL_X86_32_APPLY_RELOC_FUNC(tls_ldo_32) \
+DECL_X86_32_APPLY_RELOC_FUNC(unsupport)
-#define DECL_X86_APPLY_RELOC_FUNC_PTRS \
- { &none, 0, "R_386_NONE" }, \
- { &abs, 1, "R_386_32" }, \
- { &rel, 2, "R_386_PC32" }, \
- { &got32, 3, "R_386_GOT32" }, \
- { &plt32, 4, "R_386_PLT32" }, \
- { &none, 5, "R_386_COPY" }, \
- { &none, 6, "R_386_GLOB_DAT" }, \
- { &none, 7, "R_386_JMP_SLOT" }, \
- { &none, 8, "R_386_RELATIVE" }, \
- { &gotoff32, 9, "R_386_GOTOFF" }, \
- { &gotpc32, 10, "R_386_GOTPC" }, \
- { &unsupport, 11, "R_386_32PLT" }, \
- { &unsupport, 12, "" }, \
- { &unsupport, 13, "" }, \
- { &unsupport, 14, "R_386_TLS_TPOFF" }, \
- { &tls_ie, 15, "R_386_TLS_IE" }, \
- { &tls_gotie, 16, "R_386_TLS_GOTIE" }, \
- { &tls_le, 17, "R_386_TLS_LE" }, \
- { &tls_gd, 18, "R_386_TLS_GD" }, \
- { &tls_ldm, 19, "R_386_TLS_LDM" }, \
- { &abs, 20, "R_386_16" }, \
- { &rel, 21, "R_386_PC16" }, \
- { &abs, 22, "R_386_8" }, \
- { &rel, 23, "R_386_PC8" }, \
- { &unsupport, 24, "R_386_TLS_GD_32" }, \
- { &unsupport, 25, "R_386_TLS_GD_PUSH" }, \
- { &unsupport, 26, "R_386_TLS_GD_CALL" }, \
- { &unsupport, 27, "R_386_TLS_GD_POP" }, \
- { &unsupport, 28, "R_386_TLS_LDM_32" }, \
- { &unsupport, 29, "R_386_TLS_LDM_PUSH" }, \
- { &unsupport, 30, "R_386_TLS_LDM_CALL" }, \
- { &unsupport, 31, "R_386_TLS_LDM_POP" }, \
- { &tls_ldo_32, 32, "R_386_TLS_LDO_32" }, \
- { &unsupport, 33, "R_386_TLS_IE_32" }, \
- { &unsupport, 34, "R_386_TLS_LE_32" }, \
- { &unsupport, 35, "R_386_TLS_DTPMOD32" }, \
- { &unsupport, 36, "R_386_TLS_DTPOFF32" }, \
- { &unsupport, 37, "R_386_TLS_TPOFF32" }, \
- { &unsupport, 38, "" }, \
- { &unsupport, 39, "R_386_TLS_GOTDESC" }, \
- { &unsupport, 40, "R_386_TLS_DESC_CALL" }, \
- { &unsupport, 41, "R_386_TLS_DESC" }, \
- { &unsupport, 42, "R_386_IRELATIVE" }, \
- { &unsupport, 43, "R_386_NUM" }
+#define DECL_X86_32_APPLY_RELOC_FUNC_PTRS \
+ { &none, 0, "R_386_NONE", 0 }, \
+ { &abs, 1, "R_386_32", 32 }, \
+ { &rel, 2, "R_386_PC32", 32 }, \
+ { &got32, 3, "R_386_GOT32", 32 }, \
+ { &plt32, 4, "R_386_PLT32", 32 }, \
+ { &none, 5, "R_386_COPY", 0 }, \
+ { &none, 6, "R_386_GLOB_DAT", 0 }, \
+ { &none, 7, "R_386_JMP_SLOT", 0 }, \
+ { &none, 8, "R_386_RELATIVE", 0 }, \
+ { &gotoff32, 9, "R_386_GOTOFF", 32 }, \
+ { &gotpc32, 10, "R_386_GOTPC", 32 }, \
+ { &unsupport, 11, "R_386_32PLT", 0 }, \
+ { &unsupport, 12, "", 0 }, \
+ { &unsupport, 13, "", 0 }, \
+ { &unsupport, 14, "R_386_TLS_TPOFF", 0 }, \
+ { &tls_ie, 15, "R_386_TLS_IE", 0 }, \
+ { &tls_gotie, 16, "R_386_TLS_GOTIE", 0 }, \
+ { &tls_le, 17, "R_386_TLS_LE", 0 }, \
+ { &tls_gd, 18, "R_386_TLS_GD", 0 }, \
+ { &tls_ldm, 19, "R_386_TLS_LDM", 0 }, \
+ { &abs, 20, "R_386_16", 16 }, \
+ { &rel, 21, "R_386_PC16", 16 }, \
+ { &abs, 22, "R_386_8", 8 }, \
+ { &rel, 23, "R_386_PC8", 8 }, \
+ { &unsupport, 24, "R_386_TLS_GD_32", 0 }, \
+ { &unsupport, 25, "R_386_TLS_GD_PUSH", 0 }, \
+ { &unsupport, 26, "R_386_TLS_GD_CALL", 0 }, \
+ { &unsupport, 27, "R_386_TLS_GD_POP", 0 }, \
+ { &unsupport, 28, "R_386_TLS_LDM_32", 0 }, \
+ { &unsupport, 29, "R_386_TLS_LDM_PUSH", 0 }, \
+ { &unsupport, 30, "R_386_TLS_LDM_CALL", 0 }, \
+ { &unsupport, 31, "R_386_TLS_LDM_POP", 0 }, \
+ { &tls_ldo_32, 32, "R_386_TLS_LDO_32", 0 }, \
+ { &unsupport, 33, "R_386_TLS_IE_32", 0 }, \
+ { &unsupport, 34, "R_386_TLS_LE_32", 0 }, \
+ { &unsupport, 35, "R_386_TLS_DTPMOD32", 0 }, \
+ { &unsupport, 36, "R_386_TLS_DTPOFF32", 0 }, \
+ { &unsupport, 37, "R_386_TLS_TPOFF32", 0 }, \
+ { &unsupport, 38, "", 0 }, \
+ { &unsupport, 39, "R_386_TLS_GOTDESC", 0 }, \
+ { &unsupport, 40, "R_386_TLS_DESC_CALL", 0 }, \
+ { &unsupport, 41, "R_386_TLS_DESC", 0 }, \
+ { &unsupport, 42, "R_386_IRELATIVE", 0 }, \
+ { &unsupport, 43, "R_386_NUM", 0 }, \
+ { &none, 44, "R_386_TLS_OPT", 0 }
+
+#define DECL_X86_64_APPLY_RELOC_FUNC(Name) \
+static X86Relocator::Result Name(Relocation& pEntry, X86_64Relocator& pParent);
+
+#define DECL_X86_64_APPLY_RELOC_FUNCS \
+DECL_X86_64_APPLY_RELOC_FUNC(none) \
+DECL_X86_64_APPLY_RELOC_FUNC(abs) \
+DECL_X86_64_APPLY_RELOC_FUNC(signed32) \
+DECL_X86_64_APPLY_RELOC_FUNC(gotpcrel) \
+DECL_X86_64_APPLY_RELOC_FUNC(plt32) \
+DECL_X86_64_APPLY_RELOC_FUNC(rel) \
+DECL_X86_64_APPLY_RELOC_FUNC(unsupport)
+
+#define DECL_X86_64_APPLY_RELOC_FUNC_PTRS \
+ { &none, 0, "R_X86_64_NONE", 0 }, \
+ { &abs, 1, "R_X86_64_64", 64 }, \
+ { &rel, 2, "R_X86_64_PC32", 32 }, \
+ { &unsupport, 3, "R_X86_64_GOT32", 32 }, \
+ { &plt32, 4, "R_X86_64_PLT32", 32 }, \
+ { &none, 5, "R_X86_64_COPY", 0 }, \
+ { &none, 6, "R_X86_64_GLOB_DAT", 0 }, \
+ { &none, 7, "R_X86_64_JMP_SLOT", 0 }, \
+ { &none, 8, "R_X86_64_RELATIVE", 0 }, \
+ { &gotpcrel, 9, "R_X86_64_GOTPCREL", 32 }, \
+ { &abs, 10, "R_X86_64_32", 32 }, \
+ { &signed32, 11, "R_X86_64_32S", 32 }, \
+ { &abs, 12, "R_X86_64_16", 16 }, \
+ { &rel, 13, "R_X86_64_PC16", 16 }, \
+ { &abs, 14, "R_X86_64_8", 8 }, \
+ { &rel, 15, "R_X86_64_PC8", 8 }, \
+ { &none, 16, "R_X86_64_DTPMOD64", 0 }, \
+ { &unsupport, 17, "R_X86_64_DTPOFF64", 0 }, \
+ { &none, 18, "R_X86_64_TPOFF64", 0 }, \
+ { &unsupport, 19, "R_X86_64_TLSGD", 0 }, \
+ { &unsupport, 20, "R_X86_64_TLSLD", 0 }, \
+ { &unsupport, 21, "R_X86_64_DTPOFF32", 0 }, \
+ { &unsupport, 22, "R_X86_64_GOTTPOFF", 0 }, \
+ { &unsupport, 23, "R_X86_64_TPOFF32", 0 }, \
+ { &unsupport, 24, "R_X86_64_PC64", 64 }, \
+ { &unsupport, 25, "R_X86_64_GOTOFF64", 64 }, \
+ { &unsupport, 26, "R_X86_64_GOTPC32", 32 }, \
+ { &unsupport, 27, "R_X86_64_GOT64", 64 }, \
+ { &unsupport, 28, "R_X86_64_GOTPCREL64", 64 }, \
+ { &unsupport, 29, "R_X86_64_GOTPC64", 64 }, \
+ { &unsupport, 30, "R_X86_64_GOTPLT64", 64 }, \
+ { &unsupport, 31, "R_X86_64_PLTOFF64", 64 }, \
+ { &unsupport, 32, "R_X86_64_SIZE32", 32 }, \
+ { &unsupport, 33, "R_X86_64_SIZE64", 64 }, \
+ { &unsupport, 34, "R_X86_64_GOTPC32_TLSDESC", 0 }, \
+ { &unsupport, 35, "R_X86_64_TLSDESC_CALL", 0 }, \
+ { &none, 36, "R_X86_64_TLSDESC", 0 }, \
+ { &none, 37, "R_X86_64_IRELATIVE", 0 }, \
+ { &none, 38, "R_X86_64_RELATIVE64", 0 }
diff --git a/lib/Target/X86/X86Relocator.cpp b/lib/Target/X86/X86Relocator.cpp
index 3b4d389..a4eac66 100644
--- a/lib/Target/X86/X86Relocator.cpp
+++ b/lib/Target/X86/X86Relocator.cpp
@@ -6,68 +6,80 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include "X86Relocator.h"
+#include "X86RelocationFunctions.h"
+
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/LD/LDSymbol.h>
#include <llvm/ADT/Twine.h>
#include <llvm/Support/DataTypes.h>
#include <llvm/Support/ELF.h>
-#include <mcld/Fragment/FragmentLinker.h>
-#include <mcld/Support/MsgHandling.h>
-
-#include "X86Relocator.h"
-#include "X86RelocationFunctions.h"
using namespace mcld;
//===--------------------------------------------------------------------===//
// Relocation Functions and Tables
//===--------------------------------------------------------------------===//
-DECL_X86_APPLY_RELOC_FUNCS
+DECL_X86_32_APPLY_RELOC_FUNCS
/// the prototype of applying function
-typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc,
- X86Relocator& pParent);
+typedef Relocator::Result (*X86_32ApplyFunctionType)(Relocation& pReloc,
+ X86_32Relocator& pParent);
// the table entry of applying functions
-struct ApplyFunctionTriple
+struct X86_32ApplyFunctionTriple
{
- ApplyFunctionType func;
+ X86_32ApplyFunctionType func;
unsigned int type;
const char* name;
+ unsigned int size;
};
// declare the table of applying functions
-static const ApplyFunctionTriple ApplyFunctions[] = {
- DECL_X86_APPLY_RELOC_FUNC_PTRS
+static const X86_32ApplyFunctionTriple X86_32ApplyFunctions[] = {
+ DECL_X86_32_APPLY_RELOC_FUNC_PTRS
};
//===--------------------------------------------------------------------===//
// X86Relocator
//===--------------------------------------------------------------------===//
-X86Relocator::X86Relocator(X86GNULDBackend& pParent)
- : Relocator(),
- m_Target(pParent) {
+X86Relocator::X86Relocator()
+ : Relocator() {
}
X86Relocator::~X86Relocator()
{
}
+//===--------------------------------------------------------------------===//
+// X86_32Relocator
+//===--------------------------------------------------------------------===//
+X86_32Relocator::X86_32Relocator(X86_32GNULDBackend& pParent)
+ : X86Relocator(), m_Target(pParent) {
+}
+
Relocator::Result
-X86Relocator::applyRelocation(Relocation& pRelocation)
+X86_32Relocator::applyRelocation(Relocation& pRelocation)
{
Relocation::Type type = pRelocation.type();
- if (type >= sizeof (ApplyFunctions) / sizeof (ApplyFunctions[0]) ) {
+ if (type >= sizeof (X86_32ApplyFunctions) / sizeof (X86_32ApplyFunctions[0]) ) {
return Unknown;
}
// apply the relocation
- return ApplyFunctions[type].func(pRelocation, *this);
+ return X86_32ApplyFunctions[type].func(pRelocation, *this);
}
-const char* X86Relocator::getName(Relocation::Type pType) const
+const char* X86_32Relocator::getName(Relocation::Type pType) const
{
- return ApplyFunctions[pType].name;
+ return X86_32ApplyFunctions[pType].name;
+}
+
+Relocator::Size X86_32Relocator::getSize(Relocation::Type pType) const
+{
+ return X86_32ApplyFunctions[pType].size;;
}
//===--------------------------------------------------------------------===//
@@ -80,9 +92,9 @@ Relocation& helper_DynRel(ResolveInfo* pSym,
Fragment& pFrag,
uint64_t pOffset,
X86Relocator::Type pType,
- X86Relocator& pParent)
+ X86_32Relocator& pParent)
{
- X86GNULDBackend& ld_backend = pParent.getTarget();
+ X86_32GNULDBackend& ld_backend = pParent.getTarget();
Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
rel_entry.setType(pType);
rel_entry.targetRef().assign(pFrag, pOffset);
@@ -99,7 +111,7 @@ Relocation& helper_DynRel(ResolveInfo* pSym,
/// R_386_RELATIVE
static bool
helper_use_relative_reloc(const ResolveInfo& pSym,
- const X86Relocator& pFactory)
+ const X86_32Relocator& pFactory)
{
// if symbol is dynamic or undefine or preemptible
@@ -111,14 +123,14 @@ helper_use_relative_reloc(const ResolveInfo& pSym,
}
static
-X86GOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
- X86Relocator& pParent)
+X86_32GOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
+ X86_32Relocator& pParent)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
- X86GNULDBackend& ld_backend = pParent.getTarget();
+ X86_32GNULDBackend& ld_backend = pParent.getTarget();
- X86GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
+ X86_32GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
if (NULL != got_entry)
return *got_entry;
@@ -150,27 +162,28 @@ X86GOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
static
-X86Relocator::Address helper_GOT_ORG(X86Relocator& pParent)
+X86Relocator::Address helper_GOT_ORG(X86_32Relocator& pParent)
{
return pParent.getTarget().getGOTPLT().addr();
}
static
-X86Relocator::Address helper_GOT(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Address helper_GOT(Relocation& pReloc, X86_32Relocator& pParent)
{
- X86GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent);
+ X86_32GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent);
X86Relocator::Address got_addr = pParent.getTarget().getGOT().addr();
return got_addr + got_entry.getOffset();
}
static
-PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc, X86Relocator& pParent)
+PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc,
+ X86_32Relocator& pParent)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
- X86GNULDBackend& ld_backend = pParent.getTarget();
+ X86_32GNULDBackend& ld_backend = pParent.getTarget();
PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(*rsym);
if (NULL != plt_entry)
@@ -181,7 +194,7 @@ PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc, X86Relocator& pParent)
pParent.getSymPLTMap().record(*rsym, *plt_entry);
// If we first get this PLT entry, we should initialize it.
if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
- X86GOTPLTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym);
+ X86_32GOTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym);
assert(NULL == gotplt_entry && "PLT entry not exist, but DynRel entry exist!");
gotplt_entry = ld_backend.getGOTPLT().consume();
pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
@@ -200,14 +213,14 @@ PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc, X86Relocator& pParent)
static
-X86Relocator::Address helper_PLT_ORG(X86Relocator& pParent)
+X86Relocator::Address helper_PLT_ORG(X86_32Relocator& pParent)
{
return pParent.getTarget().getPLT().addr();
}
static
-X86Relocator::Address helper_PLT(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Address helper_PLT(Relocation& pReloc, X86_32Relocator& pParent)
{
PLTEntryBase& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
return helper_PLT_ORG(pParent) + plt_entry.getOffset();
@@ -219,7 +232,7 @@ X86Relocator::Address helper_PLT(Relocation& pReloc, X86Relocator& pParent)
//=========================================//
// R_386_NONE
-X86Relocator::Result none(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Result none(Relocation& pReloc, X86_32Relocator& pParent)
{
return X86Relocator::OK;
}
@@ -227,13 +240,12 @@ X86Relocator::Result none(Relocation& pReloc, X86Relocator& pParent)
// R_386_32: S + A
// R_386_16
// R_386_8
-X86Relocator::Result abs(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Result abs(Relocation& pReloc, X86_32Relocator& pParent)
{
ResolveInfo* rsym = pReloc.symInfo();
Relocator::DWord A = pReloc.target() + pReloc.addend();
Relocator::DWord S = pReloc.symValue();
bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel(
- pParent.getFragmentLinker(),
*rsym,
(rsym->reserved() & X86GNULDBackend::ReservePLT),
true);
@@ -292,7 +304,7 @@ X86Relocator::Result abs(Relocation& pReloc, X86Relocator& pParent)
// R_386_PC32: S + A - P
// R_386_PC16
// R_386_PC8
-X86Relocator::Result rel(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Result rel(Relocation& pReloc, X86_32Relocator& pParent)
{
ResolveInfo* rsym = pReloc.symInfo();
Relocator::DWord A = pReloc.target() + pReloc.addend();
@@ -314,7 +326,6 @@ X86Relocator::Result rel(Relocation& pReloc, X86Relocator& pParent)
pReloc.target() = S + A - P;
}
if (pParent.getTarget().symbolNeedsDynRel(
- pParent.getFragmentLinker(),
*rsym,
(rsym->reserved() & X86GNULDBackend::ReservePLT),
false)) {
@@ -336,7 +347,7 @@ X86Relocator::Result rel(Relocation& pReloc, X86Relocator& pParent)
}
// R_386_GOTOFF: S + A - GOT_ORG
-X86Relocator::Result gotoff32(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Result gotoff32(Relocation& pReloc, X86_32Relocator& pParent)
{
Relocator::DWord A = pReloc.target() + pReloc.addend();
X86Relocator::Address GOT_ORG = helper_GOT_ORG(pParent);
@@ -347,7 +358,7 @@ X86Relocator::Result gotoff32(Relocation& pReloc, X86Relocator& pParent)
}
// R_386_GOTPC: GOT_ORG + A - P
-X86Relocator::Result gotpc32(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Result gotpc32(Relocation& pReloc, X86_32Relocator& pParent)
{
Relocator::DWord A = pReloc.target() + pReloc.addend();
X86Relocator::Address GOT_ORG = helper_GOT_ORG(pParent);
@@ -357,7 +368,7 @@ X86Relocator::Result gotpc32(Relocation& pReloc, X86Relocator& pParent)
}
// R_386_GOT32: GOT(S) + A - GOT_ORG
-X86Relocator::Result got32(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Result got32(Relocation& pReloc, X86_32Relocator& pParent)
{
if (!(pReloc.symInfo()->reserved()
& (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) {
@@ -372,7 +383,7 @@ X86Relocator::Result got32(Relocation& pReloc, X86Relocator& pParent)
}
// R_386_PLT32: PLT(S) + A - P
-X86Relocator::Result plt32(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Result plt32(Relocation& pReloc, X86_32Relocator& pParent)
{
// PLT_S depends on if there is a PLT entry.
X86Relocator::Address PLT_S;
@@ -387,7 +398,7 @@ X86Relocator::Result plt32(Relocation& pReloc, X86Relocator& pParent)
}
// R_386_TLS_GD:
-X86Relocator::Result tls_gd(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Result tls_gd(Relocation& pReloc, X86_32Relocator& pParent)
{
// global-dynamic
ResolveInfo* rsym = pReloc.symInfo();
@@ -396,19 +407,19 @@ X86Relocator::Result tls_gd(Relocation& pReloc, X86Relocator& pParent)
return X86Relocator::BadReloc;
}
- X86GNULDBackend& ld_backend = pParent.getTarget();
+ X86_32GNULDBackend& ld_backend = pParent.getTarget();
ELFFileFormat* file_format = pParent.getTarget().getOutputFormat();
// setup corresponding got and dynamic relocatio entries:
// get first got entry, if there is already a got entry for rsym, then apply
// this relocation to the got entry directly. If not, setup the corresponding
// got and dyn relocation entries
- X86GOTEntry* got_entry1 = pParent.getSymGOTMap().lookUp(*rsym);
+ X86_32GOTEntry* got_entry1 = pParent.getSymGOTMap().lookUp(*rsym);
if (NULL == got_entry1) {
// get and init two got entries if not exist
got_entry1 = ld_backend.getGOT().consume();
pParent.getSymGOTMap().record(*rsym, *got_entry1);
- X86GOTEntry* got_entry2 = ld_backend.getGOT().consume();
+ X86_32GOTEntry* got_entry2 = ld_backend.getGOT().consume();
got_entry1->setValue(0x0);
got_entry2->setValue(0x0);
// setup dyn rel for get_entry1
@@ -450,10 +461,10 @@ X86Relocator::Result tls_gd(Relocation& pReloc, X86Relocator& pParent)
}
// R_386_TLS_LDM
-X86Relocator::Result tls_ldm(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Result tls_ldm(Relocation& pReloc, X86_32Relocator& pParent)
{
// FIXME: no linker optimization for TLS relocation
- const X86GOTEntry& got_entry = pParent.getTarget().getTLSModuleID();
+ const X86_32GOTEntry& got_entry = pParent.getTarget().getTLSModuleID();
// All GOT offsets are relative to the end of the GOT.
X86Relocator::SWord GOT_S = got_entry.getOffset() -
@@ -466,7 +477,7 @@ X86Relocator::Result tls_ldm(Relocation& pReloc, X86Relocator& pParent)
}
// R_386_TLS_LDO_32
-X86Relocator::Result tls_ldo_32(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Result tls_ldo_32(Relocation& pReloc, X86_32Relocator& pParent)
{
// FIXME: no linker optimization for TLS relocation
Relocator::DWord A = pReloc.target() + pReloc.addend();
@@ -476,7 +487,7 @@ X86Relocator::Result tls_ldo_32(Relocation& pReloc, X86Relocator& pParent)
}
// R_X86_TLS_IE
-X86Relocator::Result tls_ie(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Result tls_ie(Relocation& pReloc, X86_32Relocator& pParent)
{
ResolveInfo* rsym = pReloc.symInfo();
if (!(rsym->reserved() & X86GNULDBackend::GOTRel)) {
@@ -490,10 +501,10 @@ X86Relocator::Result tls_ie(Relocation& pReloc, X86Relocator& pParent)
}
// set up the got and dynamic relocation entries if not exist
- X86GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
+ X86_32GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
if (NULL == got_entry) {
// set got entry
- X86GNULDBackend& ld_backend = pParent.getTarget();
+ X86_32GNULDBackend& ld_backend = pParent.getTarget();
got_entry = ld_backend.getGOT().consume();
pParent.getSymGOTMap().record(*rsym, *got_entry);
got_entry->setValue(0x0);
@@ -515,7 +526,7 @@ X86Relocator::Result tls_ie(Relocation& pReloc, X86Relocator& pParent)
}
// R_386_TLS_GOTIE
-X86Relocator::Result tls_gotie(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Result tls_gotie(Relocation& pReloc, X86_32Relocator& pParent)
{
ResolveInfo* rsym = pReloc.symInfo();
if (!(rsym->reserved() & X86GNULDBackend::GOTRel)) {
@@ -523,10 +534,10 @@ X86Relocator::Result tls_gotie(Relocation& pReloc, X86Relocator& pParent)
}
// set up the got and dynamic relocation entries if not exist
- X86GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
+ X86_32GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
if (NULL == got_entry) {
// set got entry
- X86GNULDBackend& ld_backend = pParent.getTarget();
+ X86_32GNULDBackend& ld_backend = pParent.getTarget();
got_entry = ld_backend.getGOT().consume();
pParent.getSymGOTMap().record(*rsym, *got_entry);
got_entry->setValue(0x0);
@@ -547,7 +558,7 @@ X86Relocator::Result tls_gotie(Relocation& pReloc, X86Relocator& pParent)
}
// R_X86_TLS_LE
-X86Relocator::Result tls_le(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Result tls_le(Relocation& pReloc, X86_32Relocator& pParent)
{
ResolveInfo* rsym = pReloc.symInfo();
if (pReloc.symInfo()->reserved() & X86GNULDBackend::ReserveRel) {
@@ -569,8 +580,375 @@ X86Relocator::Result tls_le(Relocation& pReloc, X86Relocator& pParent)
return X86Relocator::OK;
}
-X86Relocator::Result unsupport(Relocation& pReloc, X86Relocator& pParent)
+X86Relocator::Result unsupport(Relocation& pReloc, X86_32Relocator& pParent)
{
return X86Relocator::Unsupport;
}
+//===--------------------------------------------------------------------===//
+// Relocation Functions and Tables
+//===--------------------------------------------------------------------===//
+DECL_X86_64_APPLY_RELOC_FUNCS
+
+/// the prototype of applying function
+typedef Relocator::Result (*X86_64ApplyFunctionType)(Relocation& pReloc,
+ X86_64Relocator& pParent);
+
+// the table entry of applying functions
+struct X86_64ApplyFunctionTriple
+{
+ X86_64ApplyFunctionType func;
+ unsigned int type;
+ const char* name;
+ unsigned int size;
+};
+
+// declare the table of applying functions
+static const X86_64ApplyFunctionTriple X86_64ApplyFunctions[] = {
+ DECL_X86_64_APPLY_RELOC_FUNC_PTRS
+};
+
+//===--------------------------------------------------------------------===//
+// X86_64Relocator
+//===--------------------------------------------------------------------===//
+X86_64Relocator::X86_64Relocator(X86_64GNULDBackend& pParent)
+ : X86Relocator(), m_Target(pParent) {
+}
+
+Relocator::Result
+X86_64Relocator::applyRelocation(Relocation& pRelocation)
+{
+ Relocation::Type type = pRelocation.type();
+
+ if (type >= sizeof (X86_64ApplyFunctions) / sizeof (X86_64ApplyFunctions[0]) ) {
+ return Unknown;
+ }
+
+ // apply the relocation
+ return X86_64ApplyFunctions[type].func(pRelocation, *this);
+}
+
+const char* X86_64Relocator::getName(Relocation::Type pType) const
+{
+ return X86_64ApplyFunctions[pType].name;
+}
+
+Relocator::Size X86_64Relocator::getSize(Relocation::Type pType) const
+{
+ return X86_64ApplyFunctions[pType].size;
+}
+
+/// helper_DynRel - Get an relocation entry in .rela.dyn
+static
+Relocation& helper_DynRel(ResolveInfo* pSym,
+ Fragment& pFrag,
+ uint64_t pOffset,
+ X86Relocator::Type pType,
+ X86_64Relocator& pParent)
+{
+ X86_64GNULDBackend& ld_backend = pParent.getTarget();
+ Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
+ rel_entry.setType(pType);
+ rel_entry.targetRef().assign(pFrag, pOffset);
+ if (pType == llvm::ELF::R_X86_64_RELATIVE || NULL == pSym)
+ rel_entry.setSymInfo(0);
+ else
+ rel_entry.setSymInfo(pSym);
+
+ return rel_entry;
+}
+
+
+/// helper_use_relative_reloc - Check if symbol can use relocation
+/// R_X86_64_RELATIVE
+static bool
+helper_use_relative_reloc(const ResolveInfo& pSym,
+ const X86_64Relocator& pFactory)
+
+{
+ // if symbol is dynamic or undefine or preemptible
+ if (pSym.isDyn() ||
+ pSym.isUndef() ||
+ pFactory.getTarget().isSymbolPreemptible(pSym))
+ return false;
+ return true;
+}
+
+static
+X86_64GOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
+ X86_64Relocator& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ X86_64GNULDBackend& ld_backend = pParent.getTarget();
+
+ X86_64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
+ if (NULL != got_entry)
+ return *got_entry;
+
+ // not found
+ got_entry = ld_backend.getGOT().consume();
+ pParent.getSymGOTMap().record(*rsym, *got_entry);
+
+ // If we first get this GOT entry, we should initialize it.
+ if (rsym->reserved() & X86GNULDBackend::ReserveGOT) {
+ // No corresponding dynamic relocation, initialize to the symbol value.
+ got_entry->setValue(pReloc.symValue());
+ }
+ else if (rsym->reserved() & X86GNULDBackend::GOTRel) {
+ // Initialize got_entry content and the corresponding dynamic relocation.
+ if (helper_use_relative_reloc(*rsym, pParent)) {
+ Relocation& rel_entry = helper_DynRel(rsym, *got_entry, 0x0,
+ llvm::ELF::R_X86_64_RELATIVE,
+ pParent);
+ rel_entry.setAddend(pReloc.symValue());
+ }
+ else {
+ helper_DynRel(rsym, *got_entry, 0x0, llvm::ELF::R_X86_64_GLOB_DAT,
+ pParent);
+ }
+ got_entry->setValue(0);
+ }
+ else {
+ fatal(diag::reserve_entry_number_mismatch_got);
+ }
+ return *got_entry;
+}
+
+static
+X86Relocator::Address helper_GOT_ORG(X86_64Relocator& pParent)
+{
+ return pParent.getTarget().getGOT().addr();
+}
+
+static
+X86Relocator::Address helper_GOT(Relocation& pReloc, X86_64Relocator& pParent)
+{
+ X86_64GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent);
+ return got_entry.getOffset();
+}
+
+static
+PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc,
+ X86_64Relocator& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ X86_64GNULDBackend& ld_backend = pParent.getTarget();
+
+ PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(*rsym);
+ if (NULL != plt_entry)
+ return *plt_entry;
+
+ // not found
+ plt_entry = ld_backend.getPLT().consume();
+ pParent.getSymPLTMap().record(*rsym, *plt_entry);
+ // If we first get this PLT entry, we should initialize it.
+ if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
+ X86_64GOTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym);
+ assert(NULL == gotplt_entry && "PLT entry not exist, but DynRel entry exist!");
+ gotplt_entry = ld_backend.getGOTPLT().consume();
+ pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
+ // init the corresponding rel entry in .rel.plt
+ Relocation& rel_entry = *ld_backend.getRelPLT().consumeEntry();
+ rel_entry.setType(llvm::ELF::R_X86_64_JUMP_SLOT);
+ rel_entry.targetRef().assign(*gotplt_entry);
+ rel_entry.setSymInfo(rsym);
+ }
+ else {
+ fatal(diag::reserve_entry_number_mismatch_plt);
+ }
+
+ return *plt_entry;
+}
+
+static
+X86Relocator::Address helper_PLT_ORG(X86_64Relocator& pParent)
+{
+ return pParent.getTarget().getPLT().addr();
+}
+
+static
+X86Relocator::Address helper_PLT(Relocation& pReloc, X86_64Relocator& pParent)
+{
+ PLTEntryBase& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
+ return helper_PLT_ORG(pParent) + plt_entry.getOffset();
+}
+
+//
+// R_X86_64_NONE
+X86Relocator::Result none(Relocation& pReloc, X86_64Relocator& pParent)
+{
+ return X86Relocator::OK;
+}
+
+// R_X86_64_64: S + A
+// R_X86_64_32:
+// R_X86_64_16:
+// R_X86_64_8
+X86Relocator::Result abs(Relocation& pReloc, X86_64Relocator& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ Relocator::DWord A = pReloc.addend();
+ Relocator::DWord S = pReloc.symValue();
+ bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel(
+ *rsym,
+ (rsym->reserved() & X86GNULDBackend::ReservePLT),
+ true);
+
+ LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
+ // If the flag of target section is not ALLOC, we will not scan this relocation
+ // but perform static relocation. (e.g., applying .debug section)
+ if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
+ pReloc.target() = S + A;
+ return X86Relocator::OK;
+ }
+
+ Relocation::Type pointerRel = pParent.getTarget().getPointerRel();
+
+ // A local symbol may need REL Type dynamic relocation
+ if (rsym->isLocal() && has_dyn_rel) {
+ if (pointerRel == pReloc.type()) {
+ Relocation& rel_entry = helper_DynRel(rsym, *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ llvm::ELF::R_X86_64_RELATIVE,
+ pParent);
+ rel_entry.setAddend(S + A);
+ }
+ else {
+ // FIXME: check Section symbol
+ Relocation& rel_entry = helper_DynRel(rsym, *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ pReloc.type(), pParent);
+ rel_entry.setAddend(S + A);
+ }
+ return X86Relocator::OK;
+ }
+
+ // An external symbol may need PLT and dynamic relocation
+ if (!rsym->isLocal()) {
+ // If we generate a dynamic relocation for a place with explicit
+ // addend, there is no need to perform static relocation on it.
+ if (has_dyn_rel) {
+ Relocation& rel_entry = helper_DynRel(rsym, *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ llvm::ELF::R_X86_64_RELATIVE,
+ pParent);
+ // Copy addend.
+ rel_entry.setAddend(A);
+ return X86Relocator::OK;
+ }
+ else if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
+ S = helper_PLT(pReloc, pParent);
+ }
+ }
+
+ // perform static relocation
+ pReloc.target() = S + A;
+ return X86Relocator::OK;
+}
+
+// R_X86_64_32S: S + A
+X86Relocator::Result signed32(Relocation& pReloc, X86_64Relocator& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ Relocator::DWord A = pReloc.addend();
+ Relocator::DWord S = pReloc.symValue();
+ bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel(
+ *rsym,
+ (rsym->reserved() & X86GNULDBackend::ReservePLT),
+ true);
+
+ // There should be no dynamic relocations for R_X86_64_32S.
+ if (has_dyn_rel)
+ return X86Relocator::BadReloc;
+
+ LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
+ // If the flag of target section is not ALLOC, we will not scan this relocation
+ // but perform static relocation. (e.g., applying .debug section)
+ // An external symbol may need PLT and dynamic relocation
+ if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag()) &&
+ !rsym->isLocal() && rsym->reserved() & X86GNULDBackend::ReservePLT)
+ S = helper_PLT(pReloc, pParent);
+
+ // Check 32-bit signed overflow.
+ Relocator::SWord V = S + A;
+ if (V > INT64_C(0x7fffffff) || V < INT64_C(-0x80000000))
+ return X86Relocator::Overflow;
+
+ // perform static relocation
+ pReloc.target() = S + A;
+ return X86Relocator::OK;
+}
+
+// R_X86_64_GOTPCREL: GOT(S) + GOT_ORG + A - P
+X86Relocator::Result gotpcrel(Relocation& pReloc, X86_64Relocator& pParent)
+{
+ if (!(pReloc.symInfo()->reserved()
+ & (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) {
+ return X86Relocator::BadReloc;
+ }
+ X86Relocator::Address GOT_S = helper_GOT(pReloc, pParent);
+ Relocator::DWord A = pReloc.addend();
+ X86Relocator::Address GOT_ORG = helper_GOT_ORG(pParent);
+ // Apply relocation.
+ pReloc.target() = GOT_S + GOT_ORG + A - pReloc.place();
+ return X86Relocator::OK;
+}
+
+// R_X86_64_PLT32: PLT(S) + A - P
+X86Relocator::Result plt32(Relocation& pReloc, X86_64Relocator& pParent)
+{
+ // PLT_S depends on if there is a PLT entry.
+ X86Relocator::Address PLT_S;
+ if ((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT))
+ PLT_S = helper_PLT(pReloc, pParent);
+ else
+ PLT_S = pReloc.symValue();
+ Relocator::DWord A = pReloc.addend();
+ X86Relocator::Address P = pReloc.place();
+ pReloc.target() = PLT_S + A - P;
+ return X86Relocator::OK;
+}
+
+// R_X86_64_PC32: S + A - P
+// R_X86_64_PC16
+// R_X86_64_PC8
+X86Relocator::Result rel(Relocation& pReloc, X86_64Relocator& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ Relocator::DWord A = pReloc.addend();
+ Relocator::DWord S = pReloc.symValue();
+ Relocator::DWord P = pReloc.place();
+
+ LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
+ // If the flag of target section is not ALLOC, we will not scan this relocation
+ // but perform static relocation. (e.g., applying .debug section)
+ if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
+ pReloc.target() = S + A - P;
+ return X86Relocator::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),
+ false)) {
+ return X86Relocator::Overflow;
+ }
+ }
+
+ // perform static relocation
+ pReloc.target() = S + A - P;
+ return X86Relocator::OK;
+}
+
+X86Relocator::Result unsupport(Relocation& pReloc, X86_64Relocator& pParent)
+{
+ return X86Relocator::Unsupport;
+}
diff --git a/lib/Target/X86/X86Relocator.h b/lib/Target/X86/X86Relocator.h
index 7d3c289..922f1f2 100644
--- a/lib/Target/X86/X86Relocator.h
+++ b/lib/Target/X86/X86Relocator.h
@@ -30,25 +30,50 @@ class X86Relocator : public Relocator
{
public:
typedef SymbolEntryMap<PLTEntryBase> SymPLTMap;
- typedef SymbolEntryMap<X86GOTEntry> SymGOTMap;
- typedef SymbolEntryMap<X86GOTPLTEntry> SymGOTPLTMap;
public:
- X86Relocator(X86GNULDBackend& pParent);
+ X86Relocator();
~X86Relocator();
+ virtual Result applyRelocation(Relocation& pRelocation) = 0;
+
+ virtual const char* getName(Relocation::Type pType) const = 0;
+
+ const SymPLTMap& getSymPLTMap() const { return m_SymPLTMap; }
+ SymPLTMap& getSymPLTMap() { return m_SymPLTMap; }
+
+private:
+ SymPLTMap m_SymPLTMap;
+};
+
+/** \class X86_32Relocator
+ * \brief X86_32Relocator creates and destroys the X86-32 relocations.
+ *
+ */
+class X86_32Relocator : public X86Relocator
+{
+public:
+ typedef SymbolEntryMap<X86_32GOTEntry> SymGOTMap;
+ typedef SymbolEntryMap<X86_32GOTEntry> SymGOTPLTMap;
+
+ enum {
+ R_386_TLS_OPT = 44 // mcld internal relocation type
+ };
+
+public:
+ X86_32Relocator(X86_32GNULDBackend& pParent);
+
Result applyRelocation(Relocation& pRelocation);
- X86GNULDBackend& getTarget()
+ X86_32GNULDBackend& getTarget()
{ return m_Target; }
- const X86GNULDBackend& getTarget() const
+ const X86_32GNULDBackend& getTarget() const
{ return m_Target; }
const char* getName(Relocation::Type pType) const;
- const SymPLTMap& getSymPLTMap() const { return m_SymPLTMap; }
- SymPLTMap& getSymPLTMap() { return m_SymPLTMap; }
+ Size getSize(Relocation::Type pType) const;
const SymGOTMap& getSymGOTMap() const { return m_SymGOTMap; }
SymGOTMap& getSymGOTMap() { return m_SymGOTMap; }
@@ -57,8 +82,44 @@ public:
SymGOTPLTMap& getSymGOTPLTMap() { return m_SymGOTPLTMap; }
private:
- X86GNULDBackend& m_Target;
- SymPLTMap m_SymPLTMap;
+ X86_32GNULDBackend& m_Target;
+ SymGOTMap m_SymGOTMap;
+ SymGOTPLTMap m_SymGOTPLTMap;
+};
+
+/** \class X86_64Relocator
+ * \brief X86_64Relocator creates and destroys the X86-64 relocations.
+ *
+ */
+class X86_64Relocator : public X86Relocator
+{
+public:
+ typedef SymbolEntryMap<X86_64GOTEntry> SymGOTMap;
+ typedef SymbolEntryMap<X86_64GOTEntry> SymGOTPLTMap;
+
+public:
+ X86_64Relocator(X86_64GNULDBackend& pParent);
+
+ Result applyRelocation(Relocation& pRelocation);
+
+ X86_64GNULDBackend& getTarget()
+ { return m_Target; }
+
+ const X86_64GNULDBackend& getTarget() const
+ { return m_Target; }
+
+ const char* getName(Relocation::Type pType) const;
+
+ Size getSize(Relocation::Type pType) const;
+
+ const SymGOTMap& getSymGOTMap() const { return m_SymGOTMap; }
+ SymGOTMap& getSymGOTMap() { return m_SymGOTMap; }
+
+ const SymGOTPLTMap& getSymGOTPLTMap() const { return m_SymGOTPLTMap; }
+ SymGOTPLTMap& getSymGOTPLTMap() { return m_SymGOTPLTMap; }
+
+private:
+ X86_64GNULDBackend& m_Target;
SymGOTMap m_SymGOTMap;
SymGOTPLTMap m_SymGOTPLTMap;
};
diff --git a/lib/Target/X86/X86TargetMachine.cpp b/lib/Target/X86/X86TargetMachine.cpp
index 9b5a24e..b419fd1 100644
--- a/lib/Target/X86/X86TargetMachine.cpp
+++ b/lib/Target/X86/X86TargetMachine.cpp
@@ -14,7 +14,8 @@
extern "C" void MCLDInitializeX86LDTarget() {
// Register createTargetMachine function pointer to mcld::Target
- mcld::RegisterTargetMachine<mcld::X86TargetMachine> X(mcld::TheX86Target);
+ mcld::RegisterTargetMachine<mcld::X86TargetMachine> X(mcld::TheX86_32Target);
+ mcld::RegisterTargetMachine<mcld::X86TargetMachine> Y(mcld::TheX86_64Target);
}
mcld::X86TargetMachine::X86TargetMachine(llvm::TargetMachine& pPM,
diff --git a/tools/llvm-mcld/llvm-mcld.cpp b/tools/llvm-mcld/llvm-mcld.cpp
index fc0b99f..8daf65f 100644
--- a/tools/llvm-mcld/llvm-mcld.cpp
+++ b/tools/llvm-mcld/llvm-mcld.cpp
@@ -461,46 +461,6 @@ ArgColor("color",
"surround result strings only if the output is a tty"),
clEnumValEnd));
-/// @{
-/// @name FIXME: begin of unsupported options
-/// @}
-static cl::opt<bool>
-ArgGCSections("gc-sections",
- cl::desc("Enable garbage collection of unused input sections."),
- cl::init(false));
-
-static cl::opt<bool>
-ArgNoGCSections("no-gc-sections",
- cl::desc("disable garbage collection of unused input sections."),
- cl::init(false));
-
-namespace icf {
-enum Mode {
- None,
- All,
- Safe
-};
-} // namespace of icf
-
-static cl::opt<icf::Mode>
-ArgICF("icf",
- cl::desc("Identical Code Folding"),
- cl::init(icf::None),
- cl::values(
- clEnumValN(icf::None, "none",
- "do not perform cold folding"),
- clEnumValN(icf::All, "all",
- "always preform cold folding"),
- clEnumValN(icf::Safe, "safe",
- "Folds ctors, dtors and functions whose pointers are definitely not taken."),
- clEnumValEnd));
-
-// FIXME: add this to target options?
-static cl::opt<bool>
-ArgFIXCA8("fix-cortex-a8",
- cl::desc("Enable Cortex-A8 Thumb-2 branch erratum fix"),
- cl::init(false));
-
static cl::opt<bool>
ArgDiscardLocals("discard-locals",
cl::desc("Delete all temporary local symbols."),
@@ -522,6 +482,26 @@ ArgDiscardAllAlias("x",
cl::aliasopt(ArgDiscardAll));
static cl::opt<bool>
+ArgStripDebug("strip-debug",
+ cl::desc("Omit debugger symbol information from the output file."),
+ cl::init(false));
+
+static cl::alias
+ArgStripDebugAlias("S",
+ cl::desc("alias for --strip-debug"),
+ cl::aliasopt(ArgStripDebug));
+
+static cl::opt<bool>
+ArgStripAll("strip-all",
+ cl::desc("Omit all symbol information from the output file."),
+ cl::init(false));
+
+static cl::alias
+ArgStripAllAlias("s",
+ cl::desc("alias for --strip-all"),
+ cl::aliasopt(ArgStripAll));
+
+static cl::opt<bool>
ArgNMagic("nmagic",
cl::desc("Do not page align data"),
cl::init(false));
@@ -541,15 +521,46 @@ ArgOMagicAlias("N",
cl::desc("alias for --omagic"),
cl::aliasopt(ArgOMagic));
+/// @{
+/// @name FIXME: begin of unsupported options
+/// @}
+static cl::opt<bool>
+ArgGCSections("gc-sections",
+ cl::desc("Enable garbage collection of unused input sections."),
+ cl::init(false));
+
static cl::opt<bool>
-ArgStripDebug("strip-debug",
- cl::desc("Omit debugger symbol information from the output file."),
+ArgNoGCSections("no-gc-sections",
+ cl::desc("disable garbage collection of unused input sections."),
cl::init(false));
-static cl::alias
-ArgStripDebugAlias("S",
- cl::desc("alias for --strip-debug"),
- cl::aliasopt(ArgStripDebug));
+namespace icf {
+enum Mode {
+ None,
+ All,
+ Safe
+};
+} // namespace of icf
+
+static cl::opt<icf::Mode>
+ArgICF("icf",
+ cl::ZeroOrMore,
+ cl::desc("Identical Code Folding"),
+ cl::init(icf::None),
+ cl::values(
+ clEnumValN(icf::None, "none",
+ "do not perform cold folding"),
+ clEnumValN(icf::All, "all",
+ "always preform cold folding"),
+ clEnumValN(icf::Safe, "safe",
+ "Folds ctors, dtors and functions whose pointers are definitely not taken."),
+ clEnumValEnd));
+
+// FIXME: add this to target options?
+static cl::opt<bool>
+ArgFIXCA8("fix-cortex-a8",
+ cl::desc("Enable Cortex-A8 Thumb-2 branch erratum fix"),
+ cl::init(false));
static cl::opt<bool>
ArgExportDynamic("export-dynamic",
@@ -566,13 +577,9 @@ ArgEmulation("m",
cl::desc("Set GNU linker emulation"),
cl::value_desc("emulation"));
-static cl::opt<std::string>
-ArgRuntimePath("rpath",
- cl::desc("Add a directory to the runtime library search path"),
- cl::value_desc("dir"));
-
-static cl::opt<std::string>
+static cl::list<std::string, bool, llvm::cl::SearchDirParser>
ArgRuntimePathLink("rpath-link",
+ cl::ZeroOrMore,
cl::desc("Add a directory to the link time library search path"),
cl::value_desc("dir"));
@@ -603,25 +610,108 @@ ArgVersionScript("version-script",
cl::value_desc("Version script"));
static cl::opt<bool>
-ArgNoStdLib("nostdlib",
- cl::desc("Only search lib dirs explicitly specified on cmdline"),
- cl::init(false));
-
-static cl::opt<bool>
ArgWarnCommon("warn-common",
cl::desc("warn common symbol"),
cl::init(false));
+static cl::opt<mcld::GeneralOptions::HashStyle>
+ArgHashStyle("hash-style", cl::init(mcld::GeneralOptions::SystemV),
+ cl::desc("Set the type of linker's hash table(s)."),
+ cl::values(
+ clEnumValN(mcld::GeneralOptions::SystemV, "sysv",
+ "classic ELF .hash section"),
+ clEnumValN(mcld::GeneralOptions::GNU, "gnu",
+ "new style GNU .gnu.hash section"),
+ clEnumValN(mcld::GeneralOptions::Both, "both",
+ "both the classic ELF and new style GNU hash tables"),
+ clEnumValEnd));
+
+static cl::opt<std::string>
+ArgFilter("F",
+ cl::desc("Filter for shared object symbol table"),
+ cl::value_desc("name"));
+
+static cl::alias
+ArgFilterAlias("filter",
+ cl::desc("alias for -F"),
+ cl::aliasopt(ArgFilterAlias));
+
+static cl::list<std::string>
+ArgAuxiliary("f",
+ cl::ZeroOrMore,
+ cl::desc("Auxiliary filter for shared object symbol table"),
+ cl::value_desc("name"));
+
+static cl::alias
+ArgAuxiliaryAlias("auxiliary",
+ cl::desc("alias for -f"),
+ cl::aliasopt(ArgAuxiliary));
+
static cl::opt<bool>
-ArgFatalWarnings("fatal-warnings",
- cl::desc("turn all warnings into errors"),
- cl::init(false));
+ArgEB("EB",
+ cl::desc("Link big-endian objects. This affects the default output format."),
+ cl::init(false));
+
+static cl::opt<bool>
+ArgEL("EL",
+ cl::desc("Link little-endian objects. This affects the default output format."),
+ cl::init(false));
/// @{
/// @name FIXME: end of unsupported options
/// @}
static cl::opt<bool>
+ArgNoStdlib("nostdlib",
+ cl::desc("Only search lib dirs explicitly specified on cmdline"),
+ cl::init(false));
+
+static cl::list<std::string, bool, llvm::cl::SearchDirParser>
+ArgRuntimePath("rpath",
+ cl::ZeroOrMore,
+ cl::desc("Add a directory to the runtime library search path"),
+ cl::value_desc("dir"));
+
+static cl::alias
+ArgRuntimePathAlias("R",
+ cl::desc("alias for --rpath"),
+ cl::aliasopt(ArgRuntimePath), cl::Prefix);
+
+static cl::opt<bool>
+ArgEnableNewDTags("enable-new-dtags",
+ cl::desc("Enable use of DT_RUNPATH and DT_FLAGS"),
+ cl::init(false));
+
+class FalseParser : public cl::parser<bool> {
+ const char *ArgStr;
+public:
+
+ // parse - Return true on error.
+ bool parse(cl::Option &O, StringRef ArgName, StringRef Arg, bool &Val) {
+ if (cl::parser<bool>::parse(O, ArgName, Arg, Val))
+ return false;
+ Val = false;
+ return false;
+ }
+};
+
+static bool ArgFatalWarnings;
+
+static cl::opt<bool, true, FalseParser>
+ArgNoFatalWarnings("no-fatal-warnings",
+ cl::location(ArgFatalWarnings),
+ cl::desc("do not turn warnings into errors"),
+ cl::init(false),
+ cl::ValueDisallowed);
+
+static cl::opt<bool, true>
+ArgFatalWarnings_("fatal-warnings",
+ cl::location(ArgFatalWarnings),
+ cl::desc("turn all warnings into errors"),
+ cl::init(false),
+ cl::ValueDisallowed);
+
+static cl::opt<bool>
ArgWarnSharedTextrel("warn-shared-textrel",
cl::desc("Warn if adding DT_TEXTREL in a shared object."),
cl::init(false));
@@ -895,8 +985,15 @@ static bool ProcessLinkerOptionsFromCommand(mcld::LinkerConfig& pConfig) {
// set up soname
pConfig.options().setSOName(ArgSOName);
+ // add all rpath entries
+ cl::list<std::string>::iterator rp;
+ cl::list<std::string>::iterator rpEnd = ArgRuntimePath.end();
+ for (rp = ArgRuntimePath.begin(); rp != rpEnd; ++rp) {
+ pConfig.options().getRpathList().push_back(*rp);
+ }
+
// --fatal-warnings
- pConfig.options().setFatalWarnings(ArgFatalWarnings);
+ // pConfig.options().setFatalWarnings(ArgFatalWarnings);
// -shared or -pie
if (true == ArgShared || true == ArgPIE) {
@@ -952,10 +1049,22 @@ static bool ProcessLinkerOptionsFromCommand(mcld::LinkerConfig& pConfig) {
pConfig.options().setEhFrameHdr(ArgEhFrameHdr);
pConfig.options().setNMagic(ArgNMagic);
pConfig.options().setOMagic(ArgOMagic);
- pConfig.options().setStripDebug(ArgStripDebug);
+ pConfig.options().setStripDebug(ArgStripDebug || ArgStripAll);
pConfig.options().setExportDynamic(ArgExportDynamic);
pConfig.options().setWarnSharedTextrel(ArgWarnSharedTextrel);
pConfig.options().setDefineCommon(ArgDefineCommon);
+ pConfig.options().setNewDTags(ArgEnableNewDTags);
+ pConfig.options().setHashStyle(ArgHashStyle);
+ pConfig.options().setNoStdlib(ArgNoStdlib);
+
+ if (ArgStripAll)
+ pConfig.options().setStripSymbols(mcld::GeneralOptions::StripAllSymbols);
+ else if (ArgDiscardAll)
+ pConfig.options().setStripSymbols(mcld::GeneralOptions::StripLocals);
+ else if (ArgDiscardLocals)
+ pConfig.options().setStripSymbols(mcld::GeneralOptions::StripTemporaries);
+ else
+ pConfig.options().setStripSymbols(mcld::GeneralOptions::KeepAllSymbols);
// set up rename map, for --wrap
cl::list<std::string>::iterator wname;
@@ -1034,14 +1143,6 @@ static bool ProcessLinkerOptionsFromCommand(mcld::LinkerConfig& pConfig) {
mcld::warning(mcld::diag::warn_unsupported_option) << ArgFIXCA8.ArgStr;
}
- if (ArgDiscardLocals) {
- mcld::warning(mcld::diag::warn_unsupported_option) << ArgDiscardLocals.ArgStr;
- }
-
- if (ArgDiscardAll) {
- mcld::warning(mcld::diag::warn_unsupported_option) << ArgDiscardAll.ArgStr;
- }
-
// add address mappings
// -Ttext
if (-1U != ArgTextSegAddr) {
@@ -1079,6 +1180,14 @@ static bool ProcessLinkerOptionsFromCommand(mcld::LinkerConfig& pConfig) {
addr_mapping->setValue(address);
}
+ // set up filter/aux filter for shared object
+ pConfig.options().setFilter(ArgFilter);
+
+ cl::list<std::string>::iterator aux;
+ cl::list<std::string>::iterator auxEnd = ArgAuxiliary.end();
+ for (aux = ArgAuxiliary.begin(); aux != auxEnd; ++aux)
+ pConfig.options().getAuxiliaryList().push_back(*aux);
+
return true;
}
diff --git a/tools/mcld/main.cpp b/tools/mcld/main.cpp
index 58a9bb0..968c5e6 100644
--- a/tools/mcld/main.cpp
+++ b/tools/mcld/main.cpp
@@ -31,7 +31,7 @@ using namespace alone;
// Compiler Options
//===----------------------------------------------------------------------===//
#ifdef TARGET_BUILD
-static const std::string OptTargetTripe(DEFAULT_TARGET_TRIPLE_STRING);
+static const std::string OptTargetTriple(DEFAULT_TARGET_TRIPLE_STRING);
#else
static llvm::cl::opt<std::string>
OptTargetTriple("mtriple",
@@ -253,10 +253,6 @@ bool ConfigLinker(Linker &pLinker, const std::string &pOutputFilename) {
config->addSearchDir(*sdir);
}
- // set up default search directories
- config->addSearchDir("=/lib");
- config->addSearchDir("=/usr/lib");
-
// 7. Set up output's type.
config->setShared(OptShared);
diff --git a/unittests/ELFReaderTest.cpp b/unittests/ELFReaderTest.cpp
new file mode 100644
index 0000000..fe7dd39
--- /dev/null
+++ b/unittests/ELFReaderTest.cpp
@@ -0,0 +1,162 @@
+//===- ELFReaderTest.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <cstdio>
+
+#include <llvm/Support/ELF.h>
+#include <mcld/IRBuilder.h>
+#include <mcld/TargetOptions.h>
+#include <mcld/LD/ELFReader.h>
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/Support/Path.h>
+#include <../lib/Target/X86/X86LDBackend.h>
+#include <../lib/Target/X86/X86GNUInfo.h>
+
+#include "ELFReaderTest.h"
+
+using namespace mcld;
+using namespace mcld::sys::fs;
+using namespace mcldtest;
+
+// Constructor can do set-up work for all test here.
+ELFReaderTest::ELFReaderTest()
+ : m_pInput(NULL)
+{
+ m_pConfig = new LinkerConfig("x86_64-linux-gnueabi");
+ m_pConfig->targets().setEndian( TargetOptions::Little );
+ m_pConfig->targets().setBitClass( 64 );
+ Relocation::SetUp( *m_pConfig );
+
+ m_pInfo = new X86_64GNUInfo( m_pConfig->targets().triple() );
+ m_pLDBackend = new X86_64GNULDBackend( *m_pConfig, m_pInfo );
+ m_pELFReader = new ELFReader<64, true>( *m_pLDBackend );
+ m_pModule = new Module();
+ m_pIRBuilder = new IRBuilder( *m_pModule, *m_pConfig);
+ m_pELFObjReader = new ELFObjectReader(*m_pLDBackend,
+ *m_pIRBuilder,
+ *m_pConfig);
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+ELFReaderTest::~ELFReaderTest()
+{
+ delete m_pConfig;
+ delete m_pLDBackend;
+ delete m_pELFReader;
+ delete m_pModule;
+ delete m_pIRBuilder;
+ delete m_pELFObjReader;
+}
+
+// SetUp() will be called immediately before each test.
+void ELFReaderTest::SetUp()
+{
+ Path path(TOPDIR);
+ path.append("unittests/test_x86_64.o");
+
+ m_pInput = m_pIRBuilder->ReadInput("test_x86_64", path);
+ ASSERT_TRUE(NULL!=m_pInput);
+
+ ASSERT_TRUE(m_pInput->hasMemArea());
+ size_t hdr_size = m_pELFReader->getELFHeaderSize();
+ MemoryRegion* region = m_pInput->memArea()->request(m_pInput->fileOffset(),
+ hdr_size);
+ uint8_t* ELF_hdr = region->start();
+ bool shdr_result = m_pELFReader->readSectionHeaders(*m_pInput, ELF_hdr);
+ m_pInput->memArea()->release(region);
+ ASSERT_TRUE(shdr_result);
+}
+
+// TearDown() will be called immediately after each test.
+void ELFReaderTest::TearDown()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// Testcases
+//===----------------------------------------------------------------------===//
+TEST_F( ELFReaderTest, read_section_headers ) {
+ ASSERT_EQ(m_pInput->context()->numOfSections(), 13);
+ LDContext::const_sect_iterator iter = m_pInput->context()->sectBegin();
+ ++iter; /// test section[1]
+ ASSERT_EQ(".text", (*iter)->name());
+ ASSERT_EQ(llvm::ELF::SHT_PROGBITS, (*iter)->type());
+ ASSERT_EQ(0x40, (*iter)->offset());
+ ASSERT_EQ(0x15, (*iter)->size());
+ ASSERT_TRUE(llvm::ELF::SHF_ALLOC & (*iter)->flag()); //AX
+ ASSERT_EQ(0x4, (*iter)->align());
+ ASSERT_EQ(NULL, (*iter)->getLink());
+ ASSERT_EQ(0, (*iter)->getInfo());
+}
+
+TEST_F( ELFReaderTest, read_symbol_and_rela )
+{
+ ASSERT_TRUE(m_pInput->hasMemArea());
+ ASSERT_TRUE(m_pInput->hasContext());
+ m_pInput->setType(Input::Object);
+
+ // -- read symbols
+ LDSection* symtab_shdr = m_pInput->context()->getSection(".symtab");
+ ASSERT_TRUE(NULL!=symtab_shdr);
+
+ LDSection* strtab_shdr = symtab_shdr->getLink();
+ ASSERT_TRUE(NULL!=strtab_shdr);
+
+ MemoryRegion* symtab_region = m_pInput->memArea()->request(
+ m_pInput->fileOffset() + symtab_shdr->offset(),
+ symtab_shdr->size());
+
+ MemoryRegion* strtab_region = m_pInput->memArea()->request(
+ m_pInput->fileOffset() + strtab_shdr->offset(),
+ strtab_shdr->size());
+ char* strtab = reinterpret_cast<char*>(strtab_region->start());
+ bool result = m_pELFReader->readSymbols(*m_pInput, *m_pIRBuilder,
+ *symtab_region, strtab);
+ ASSERT_TRUE(result);
+ ASSERT_EQ("hello.c", std::string(m_pInput->context()->getSymbol(1)->name()));
+ ASSERT_EQ("puts", std::string(m_pInput->context()->getSymbol(10)->name()));
+ ASSERT_TRUE(NULL==m_pInput->context()->getSymbol(11));
+ m_pInput->memArea()->release(symtab_region);
+ m_pInput->memArea()->release(strtab_region);
+
+ // -- read relocations
+ MemoryArea* mem = m_pInput->memArea();
+ LDContext::sect_iterator rs = m_pInput->context()->relocSectBegin();
+ ASSERT_TRUE(rs!=m_pInput->context()->relocSectEnd());
+ ASSERT_EQ(".rela.text", (*rs)->name());
+
+ uint64_t offset = m_pInput->fileOffset() + (*rs)->offset();
+ uint64_t size = (*rs)->size();
+ MemoryRegion* region = mem->request(offset, size);
+ IRBuilder::CreateRelocData(**rs); /// create relocation data for the header
+
+ ASSERT_EQ(llvm::ELF::SHT_RELA, (*rs)->type());
+ ASSERT_TRUE(m_pELFReader->readRela(*m_pInput, **rs, *region));
+ mem->release(region);
+
+ const RelocData::RelocationListType &rRelocs =
+ (*rs)->getRelocData()->getRelocationList();
+ RelocData::const_iterator rReloc = rRelocs.begin();
+ ASSERT_EQ(2, rRelocs.size());
+ ASSERT_TRUE(rRelocs.end()!=rReloc);
+ ++rReloc; /// test rRelocs[1]
+ ASSERT_EQ("puts", std::string(rReloc->symInfo()->name()));
+ ASSERT_EQ(llvm::ELF::R_X86_64_PC32, rReloc->type());
+ ASSERT_EQ(0x0, rReloc->symValue());
+ ASSERT_EQ(-0x4, rReloc->addend());
+}
+
+TEST_F( ELFReaderTest, read_regular_sections ) {
+ ASSERT_TRUE( m_pELFObjReader->readSections(*m_pInput) );
+}
+
+TEST_F( ELFReaderTest, is_my_format ) {
+ ASSERT_TRUE( m_pELFObjReader->isMyFormat(*m_pInput) );
+}
+
+
diff --git a/unittests/ELFReaderTest.h b/unittests/ELFReaderTest.h
new file mode 100644
index 0000000..c977cfb
--- /dev/null
+++ b/unittests/ELFReaderTest.h
@@ -0,0 +1,56 @@
+//===- ELFReaderTest.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELFREADER_TEST_H
+#define MCLD_ELFREADER_TEST_H
+
+#include <gtest.h>
+#include <mcld/LinkerConfig.h>
+#include <mcld/LD/ELFReaderIf.h>
+#include <mcld/LD/ELFReader.h>
+#include <mcld/LD/ELFObjectReader.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/MC/InputBuilder.h>
+
+namespace mcld {
+ class ELFReader<64, true>;
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+class ELFReaderTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ ELFReaderTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~ELFReaderTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ mcld::Input *m_pInput;
+ mcld::LinkerConfig *m_pConfig;
+ mcld::GNUInfo *m_pInfo;
+ mcld::GNULDBackend *m_pLDBackend;
+ mcld::ELFReaderIF *m_pELFReader;
+ mcld::Module *m_pModule;
+ mcld::IRBuilder *m_pIRBuilder;
+ mcld::ELFObjectReader *m_pELFObjReader;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/FileHandleTest.cpp b/unittests/FileHandleTest.cpp
index db6f25f..dc9ecdd 100644
--- a/unittests/FileHandleTest.cpp
+++ b/unittests/FileHandleTest.cpp
@@ -48,6 +48,7 @@ TEST_F(FileHandleTest, open_close) {
ASSERT_TRUE(m_pTestee->open(path, FileHandle::ReadOnly));
ASSERT_TRUE(m_pTestee->isOpened());
ASSERT_TRUE(m_pTestee->isGood());
+ ASSERT_TRUE(m_pTestee->isOwned());
ASSERT_TRUE(27 == m_pTestee->size());
@@ -67,19 +68,19 @@ TEST_F(FileHandleTest, delegate_close) {
ASSERT_TRUE(m_pTestee->delegate(fd, FileHandle::ReadOnly));
ASSERT_TRUE(m_pTestee->isOpened());
ASSERT_TRUE(m_pTestee->isGood());
+ ASSERT_FALSE(m_pTestee->isOwned());
ASSERT_TRUE(27 == m_pTestee->size());
ASSERT_TRUE(m_pTestee->close());
ASSERT_FALSE(m_pTestee->isOpened());
ASSERT_TRUE(m_pTestee->isGood());
+ ASSERT_TRUE(m_pTestee->isOwned());
ASSERT_TRUE(0 == m_pTestee->size());
int close_result = ::close(fd);
- int close_err = errno;
- ASSERT_EQ(-1, close_result);
- ASSERT_EQ(EBADF, close_err);
+ ASSERT_EQ(0, close_result);
}
TEST_F(FileHandleTest, fail_close) {
diff --git a/unittests/LinkerTest.cpp b/unittests/LinkerTest.cpp
index 00ba23b..ab439cb 100644
--- a/unittests/LinkerTest.cpp
+++ b/unittests/LinkerTest.cpp
@@ -84,6 +84,11 @@ TEST_F( LinkerTest, plasma) {
///< --mtriple="armv7-none-linux-gnueabi"
LinkerConfig config("armv7-none-linux-gnueabi");
+ /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
+ Path search_dir(TOPDIR);
+ search_dir.append("test/libs/ARM/Android/android-14");
+ config.options().directories().insert(search_dir);
+
/// To configure linker before setting options. Linker::config sets up
/// default target-dependent configuration to LinkerConfig.
linker.config(config);
@@ -92,11 +97,6 @@ TEST_F( LinkerTest, plasma) {
config.options().setSOName("libplasma.so"); ///< --soname=libplasma.so
config.options().setBsymbolic(); ///< -Bsymbolic
- /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
- Path search_dir(TOPDIR);
- search_dir.append("test/libs/ARM/Android/android-14");
- config.options().directories().insert(search_dir);
-
Module module("libplasma.so");
IRBuilder builder(module, config);
@@ -141,6 +141,11 @@ TEST_F( LinkerTest, plasma_twice) {
///< --mtriple="armv7-none-linux-gnueabi"
LinkerConfig config1("armv7-none-linux-gnueabi");
+ /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
+ Path search_dir(TOPDIR);
+ search_dir.append("test/libs/ARM/Android/android-14");
+ config1.options().directories().insert(search_dir);
+
/// To configure linker before setting options. Linker::config sets up
/// default target-dependent configuration to LinkerConfig.
linker.config(config1);
@@ -149,11 +154,6 @@ TEST_F( LinkerTest, plasma_twice) {
config1.options().setSOName("libplasma.once.so"); ///< --soname=libplasma.twice.so
config1.options().setBsymbolic(false); ///< -Bsymbolic
- /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
- Path search_dir(TOPDIR);
- search_dir.append("test/libs/ARM/Android/android-14");
- config1.options().directories().insert(search_dir);
-
Module module1("libplasma.once.so");
IRBuilder builder1(module1, config1);
@@ -191,6 +191,9 @@ TEST_F( LinkerTest, plasma_twice) {
///< --mtriple="armv7-none-linux-gnueabi"
LinkerConfig config2("armv7-none-linux-gnueabi");
+ /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
+ config2.options().directories().insert(search_dir);
+
/// To configure linker before setting options. Linker::config sets up
/// default target-dependent configuration to LinkerConfig.
linker.config(config2);
@@ -199,9 +202,6 @@ TEST_F( LinkerTest, plasma_twice) {
config2.options().setSOName("libplasma.twice.so"); ///< --soname=libplasma.twice.exe
config2.options().setBsymbolic(); ///< -Bsymbolic
- /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
- config2.options().directories().insert(search_dir);
-
Module module2("libplasma.so");
IRBuilder builder2(module2, config2);
@@ -236,6 +236,11 @@ TEST_F( LinkerTest, plasma_twice_irbuilder_heap) {
///< --mtriple="armv7-none-linux-gnueabi"
LinkerConfig config1("armv7-none-linux-gnueabi");
+ /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
+ Path search_dir(TOPDIR);
+ search_dir.append("test/libs/ARM/Android/android-14");
+ config1.options().directories().insert(search_dir);
+
/// To configure linker before setting options. Linker::config sets up
/// default target-dependent configuration to LinkerConfig.
linker.config(config1);
@@ -244,11 +249,6 @@ TEST_F( LinkerTest, plasma_twice_irbuilder_heap) {
config1.options().setSOName("libplasma.once.so"); ///< --soname=libplasma.twice.so
config1.options().setBsymbolic(false); ///< -Bsymbolic
- /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
- Path search_dir(TOPDIR);
- search_dir.append("test/libs/ARM/Android/android-14");
- config1.options().directories().insert(search_dir);
-
Module module1("libplasma.once.so");
IRBuilder *builder1 = new IRBuilder(module1, config1);
@@ -291,6 +291,9 @@ TEST_F( LinkerTest, plasma_twice_irbuilder_heap) {
///< --mtriple="armv7-none-linux-gnueabi"
LinkerConfig config2("armv7-none-linux-gnueabi");
+ /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
+ config2.options().directories().insert(search_dir);
+
/// To configure linker before setting options. Linker::config sets up
/// default target-dependent configuration to LinkerConfig.
linker.config(config2);
@@ -299,9 +302,6 @@ TEST_F( LinkerTest, plasma_twice_irbuilder_heap) {
config2.options().setSOName("libplasma.twice.so"); ///< --soname=libplasma.twice.exe
config2.options().setBsymbolic(); ///< -Bsymbolic
- /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
- config2.options().directories().insert(search_dir);
-
Module module2("libplasma.so");
IRBuilder* builder2 = new IRBuilder(module2, config2);
diff --git a/unittests/SymbolCategoryTest.cpp b/unittests/SymbolCategoryTest.cpp
index 07f479b..fae146b 100644
--- a/unittests/SymbolCategoryTest.cpp
+++ b/unittests/SymbolCategoryTest.cpp
@@ -80,13 +80,13 @@ TEST_F(SymbolCategoryTest, upward_test) {
++sym;
ASSERT_STREQ("e", (*sym)->name());
- ASSERT_TRUE(2 == m_pTestee->numOfLocals());
+ ASSERT_TRUE(1 == m_pTestee->numOfLocals());
ASSERT_TRUE(1 == m_pTestee->numOfCommons());
- ASSERT_TRUE(2 == m_pTestee->numOfRegulars());
+ ASSERT_TRUE(2 == m_pTestee->numOfDynamics());
ASSERT_TRUE(5 == m_pTestee->numOfSymbols());
}
-TEST_F(SymbolCategoryTest, change_local_to_tls) {
+TEST_F(SymbolCategoryTest, change_local_to_dynamic) {
ResolveInfo* a = ResolveInfo::Create("a");
ResolveInfo* b = ResolveInfo::Create("b");
ResolveInfo* c = ResolveInfo::Create("c");
@@ -129,7 +129,7 @@ TEST_F(SymbolCategoryTest, change_local_to_tls) {
++sym;
ASSERT_STREQ("e", (*sym)->name());
- m_pTestee->changeLocalToTLS(*bb);
+ m_pTestee->changeLocalToDynamic(*bb);
sym = m_pTestee->begin();
ASSERT_STREQ("c", (*sym)->name());
diff --git a/unittests/test b/unittests/test
new file mode 100644
index 0000000..d2a5b5d
--- /dev/null
+++ b/unittests/test
@@ -0,0 +1,8 @@
+0x41, 0x1f, 0x00, 0x00,
+0x00, 0x61, 0x65, 0x61,
+0x62, 0x69, 0x00, 0x01,
+0x15, 0x00, 0x00, 0x00,
+0x06, 0x02, 0x08, 0x01,
+0x09, 0x01, 0x14, 0x01,
+0x15, 0x01, 0x17, 0x03,
+0x18, 0x01, 0x19, 0x01,
diff --git a/unittests/test_x86_64.o b/unittests/test_x86_64.o
new file mode 100644
index 0000000..18389aa
--- /dev/null
+++ b/unittests/test_x86_64.o
Binary files differ