Linkloader improvement: mclinker.
Change-Id: I8805e39ccbc2ee204234fb3e71c70c906f3990bb
diff --git a/lib/Target/ARM/ARM.h b/lib/Target/ARM/ARM.h
new file mode 100644
index 0000000..a128998
--- /dev/null
+++ b/lib/Target/ARM/ARM.h
@@ -0,0 +1,24 @@
+//===- ARM.h --------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ARM_H
+#define MCLD_ARM_H
+#include <string>
+#include "mcld/Target/TargetMachine.h"
+
+namespace mcld {
+class TargetLDBackend;
+
+extern mcld::Target TheARMTarget;
+
+TargetLDBackend *createARMLDBackend(const llvm::Target&, const std::string&);
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/ARMAndroidSectLinker.cpp b/lib/Target/ARM/ARMAndroidSectLinker.cpp
new file mode 100644
index 0000000..a704cfa
--- /dev/null
+++ b/lib/Target/ARM/ARMAndroidSectLinker.cpp
@@ -0,0 +1,35 @@
+//===- ARMAndroidSectLinker.cpp -------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ARMAndroidSectLinker.h"
+
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+ARMAndroidSectLinker::ARMAndroidSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : AndroidSectLinker(pOption,
+ pLDBackend) {
+ MCLDInfo &info = pOption.info();
+ // set up target-dependent constraints of attributes
+ info.attrFactory().constraint().disableWholeArchive();
+ info.attrFactory().constraint().disableAsNeeded();
+ info.attrFactory().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ info.attrFactory().predefined().unsetWholeArchive();
+ info.attrFactory().predefined().setDynamic();
+
+}
+
+ARMAndroidSectLinker::~ARMAndroidSectLinker()
+{
+}
+
diff --git a/lib/Target/ARM/ARMAndroidSectLinker.h b/lib/Target/ARM/ARMAndroidSectLinker.h
new file mode 100644
index 0000000..8a47a94
--- /dev/null
+++ b/lib/Target/ARM/ARMAndroidSectLinker.h
@@ -0,0 +1,40 @@
+//===- ARMAndroidSectLinker.h ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ARM_ANDROIDSECTLINKER_H
+#define ARM_ANDROIDSECTLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Target/AndroidSectLinker.h>
+
+namespace mcld
+{
+
+class MCLDInfo;
+
+/** \class ARMAndroidSectLinker
+ * \brief ARMAndroidSectLinker sets up the environment for linking.
+ *
+ * \see
+ * \author Anders Cheng <Anders.Cheng@mediatek.com>
+ */
+class ARMAndroidSectLinker : public AndroidSectLinker
+{
+public:
+ ARMAndroidSectLinker(SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend);
+
+ ~ARMAndroidSectLinker();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/ARMELFArchiveReader.cpp b/lib/Target/ARM/ARMELFArchiveReader.cpp
new file mode 100644
index 0000000..4c6d775
--- /dev/null
+++ b/lib/Target/ARM/ARMELFArchiveReader.cpp
@@ -0,0 +1,14 @@
+//===- 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
new file mode 100644
index 0000000..b60a12d
--- /dev/null
+++ b/lib/Target/ARM/ARMELFArchiveReader.h
@@ -0,0 +1,29 @@
+//===- ARMELFArchiveReader.h ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef ARMELFARCHIVEREADER_H
+#define ARMELFARCHIVEREADER_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/ARMELFDynamic.cpp b/lib/Target/ARM/ARMELFDynamic.cpp
new file mode 100644
index 0000000..c81a6f3
--- /dev/null
+++ b/lib/Target/ARM/ARMELFDynamic.cpp
@@ -0,0 +1,37 @@
+//===- ARMELFDynamic.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <mcld/LD/ELFFileFormat.h>
+#include "ARMELFDynamic.h"
+
+using namespace mcld;
+
+ARMELFDynamic::ARMELFDynamic(const GNULDBackend& pParent)
+ : ELFDynamic(pParent)
+{
+}
+
+ARMELFDynamic::~ARMELFDynamic()
+{
+}
+
+void ARMELFDynamic::reserveTargetEntries(const ELFFileFormat& pFormat)
+{
+ // reservePLTGOT
+ if (pFormat.hasGOT())
+ reserveOne(llvm::ELF::DT_PLTGOT);
+}
+
+void ARMELFDynamic::applyTargetEntries(const ELFFileFormat& pFormat)
+{
+ // applyPLTGOT
+ if (pFormat.hasGOT())
+ applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOT().addr());
+}
+
diff --git a/lib/Target/ARM/ARMELFDynamic.h b/lib/Target/ARM/ARMELFDynamic.h
new file mode 100644
index 0000000..914dcc4
--- /dev/null
+++ b/lib/Target/ARM/ARMELFDynamic.h
@@ -0,0 +1,31 @@
+//===- ARMELFDynamic.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ARM_ELFDYNAMIC_SECTION_H
+#define MCLD_ARM_ELFDYNAMIC_SECTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Target/ELFDynamic.h>
+
+namespace mcld {
+
+class ARMELFDynamic : public ELFDynamic {
+public:
+ ARMELFDynamic(const GNULDBackend& pParent);
+ ~ARMELFDynamic();
+
+private:
+ void reserveTargetEntries(const ELFFileFormat& pFormat);
+ void applyTargetEntries(const ELFFileFormat& pFormat);
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/ARM/ARMELFSectLinker.cpp b/lib/Target/ARM/ARMELFSectLinker.cpp
new file mode 100644
index 0000000..0395606
--- /dev/null
+++ b/lib/Target/ARM/ARMELFSectLinker.cpp
@@ -0,0 +1,34 @@
+//===- ARMELFSectLinker.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "ARMELFSectLinker.h"
+
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+ARMELFSectLinker::ARMELFSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : SectLinker(pOption,
+ pLDBackend) {
+ MCLDInfo &info = pOption.info();
+ // set up target-dependent constraints of attributes
+ info.attrFactory().constraint().enableWholeArchive();
+ info.attrFactory().constraint().disableAsNeeded();
+ info.attrFactory().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ info.attrFactory().predefined().setWholeArchive();
+ info.attrFactory().predefined().setDynamic();
+
+}
+
+ARMELFSectLinker::~ARMELFSectLinker()
+{
+}
+
diff --git a/lib/Target/ARM/ARMELFSectLinker.h b/lib/Target/ARM/ARMELFSectLinker.h
new file mode 100644
index 0000000..7493d59
--- /dev/null
+++ b/lib/Target/ARM/ARMELFSectLinker.h
@@ -0,0 +1,36 @@
+//===- ARMELFSectLinker.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef ARM_ELFSECTLINKER_H
+#define ARM_ELFSECTLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/CodeGen/SectLinker.h>
+
+namespace mcld
+{
+
+/** \class ARMELFSectLinker
+ * \brief ARMELFSectLinker sets up the environment for linking.
+ *
+ * \see
+ */
+class ARMELFSectLinker : public SectLinker
+{
+public:
+ ARMELFSectLinker(SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend);
+
+ ~ARMELFSectLinker();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/ARMFixupKinds.h b/lib/Target/ARM/ARMFixupKinds.h
new file mode 100644
index 0000000..f42b940
--- /dev/null
+++ b/lib/Target/ARM/ARMFixupKinds.h
@@ -0,0 +1,98 @@
+//===- ARMFixupKinds.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LIB_TARGET_ARM_ARM_FIXUP_KINDS_H_
+#define MCLD_LIB_TARGET_ARM_ARM_FIXUP_KINDS_H_
+
+#include <llvm/MC/MCFixup.h>
+
+namespace mcld {
+namespace ARM {
+
+enum Fixups {
+ // fixup_arm_ldst_pcrel_12 - 12-bit PC relative relocation for symbol
+ // addresses
+ fixup_arm_ldst_pcrel_12 = FirstTargetFixupKind,
+
+ // fixup_t2_ldst_pcrel_12 - Equivalent to fixup_arm_ldst_pcrel_12, with
+ // the 16-bit halfwords reordered.
+ fixup_t2_ldst_pcrel_12,
+
+ // fixup_arm_pcrel_10 - 10-bit PC relative relocation for symbol addresses
+ // used in VFP instructions where the lower 2 bits are not encoded
+ // (so it's encoded as an 8-bit immediate).
+ fixup_arm_pcrel_10,
+ // fixup_t2_pcrel_10 - Equivalent to fixup_arm_pcrel_10, accounting for
+ // the short-swapped encoding of Thumb2 instructions.
+ fixup_t2_pcrel_10,
+ // fixup_thumb_adr_pcrel_10 - 10-bit PC relative relocation for symbol
+ // addresses where the lower 2 bits are not encoded (so it's encoded as an
+ // 8-bit immediate).
+ fixup_thumb_adr_pcrel_10,
+ // fixup_arm_adr_pcrel_12 - 12-bit PC relative relocation for the ADR
+ // instruction.
+ fixup_arm_adr_pcrel_12,
+ // fixup_t2_adr_pcrel_12 - 12-bit PC relative relocation for the ADR
+ // instruction.
+ fixup_t2_adr_pcrel_12,
+ // fixup_arm_condbranch - 24-bit PC relative relocation for conditional branch
+ // instructions.
+ fixup_arm_condbranch,
+ // fixup_arm_uncondbranch - 24-bit PC relative relocation for
+ // branch instructions. (unconditional)
+ fixup_arm_uncondbranch,
+ // fixup_t2_condbranch - 20-bit PC relative relocation for Thumb2 direct
+ // unconditional branch instructions.
+ fixup_t2_condbranch,
+ // fixup_t2_uncondbranch - 20-bit PC relative relocation for Thumb2 direct
+ // branch unconditional branch instructions.
+ fixup_t2_uncondbranch,
+
+ // fixup_arm_thumb_br - 12-bit fixup for Thumb B instructions.
+ fixup_arm_thumb_br,
+
+ // fixup_arm_thumb_bl - Fixup for Thumb BL instructions.
+ fixup_arm_thumb_bl,
+
+ // fixup_arm_thumb_blx - Fixup for Thumb BLX instructions.
+ fixup_arm_thumb_blx,
+
+ // fixup_arm_thumb_cb - Fixup for Thumb branch instructions.
+ fixup_arm_thumb_cb,
+
+ // fixup_arm_thumb_cp - Fixup for Thumb load/store from constant pool instrs.
+ fixup_arm_thumb_cp,
+
+ // fixup_arm_thumb_bcc - Fixup for Thumb conditional branching instructions.
+ fixup_arm_thumb_bcc,
+
+ // The next two are for the movt/movw pair
+ // the 16bit imm field are split into imm{15-12} and imm{11-0}
+ fixup_arm_movt_hi16, // :upper16:
+ fixup_arm_movw_lo16, // :lower16:
+ fixup_t2_movt_hi16, // :upper16:
+ fixup_t2_movw_lo16, // :lower16:
+
+ // It is possible to create an "immediate" that happens to be pcrel.
+ // movw r0, :lower16:Foo-(Bar+8) and movt r0, :upper16:Foo-(Bar+8)
+ // result in different reloc tags than the above two.
+ // Needed to support ELF::R_ARM_MOVT_PREL and ELF::R_ARM_MOVW_PREL_NC
+ fixup_arm_movt_hi16_pcrel, // :upper16:
+ fixup_arm_movw_lo16_pcrel, // :lower16:
+ fixup_t2_movt_hi16_pcrel, // :upper16:
+ fixup_t2_movw_lo16_pcrel, // :lower16:
+
+ // Marker
+ LastTargetFixupKind,
+ NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
+};
+
+} // namespace ARM
+} // namespace mcld
+
+#endif
diff --git a/lib/Target/ARM/ARMGOT.cpp b/lib/Target/ARM/ARMGOT.cpp
new file mode 100644
index 0000000..3eb8e4a
--- /dev/null
+++ b/lib/Target/ARM/ARMGOT.cpp
@@ -0,0 +1,185 @@
+//===- impl.cpp -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "ARMGOT.h"
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <new>
+
+namespace {
+ const size_t ARMGOTEntrySize = 4;
+} // end of anonymous namespace
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// ARMGOT
+ARMGOT::ARMGOT(LDSection& pSection, llvm::MCSectionData& pSectionData)
+ : GOT(pSection, pSectionData, ARMGOTEntrySize),
+ m_NormalGOTIterator(), m_GOTPLTIterator(),
+ m_GOTPLTBegin(), m_GOTPLTEnd()
+{
+ GOTEntry* Entry = 0;
+
+ // Create GOT0 entries.
+ for (int i = 0; i < 3; i++) {
+ Entry = new (std::nothrow) GOTEntry(0, ARMGOTEntrySize,
+ &m_SectionData);
+
+ if (!Entry)
+ llvm::report_fatal_error("Allocating GOT0 entries failed!");
+
+ m_Section.setSize(m_Section.size() + ARMGOTEntrySize);
+ }
+
+ // Skip GOT0 entries.
+ iterator it = m_SectionData.begin();
+ iterator ie = m_SectionData.end();
+
+ for (int i = 1; i < ARMGOT0Num; ++i) {
+ if (it == ie)
+ llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
+
+ ++it;
+ }
+
+ m_NormalGOTIterator = it;
+ m_GOTPLTIterator = it;
+
+ m_GOTPLTBegin = it;
+ m_GOTPLTEnd = it;
+}
+
+ARMGOT::~ARMGOT()
+{
+}
+
+void ARMGOT::reserveEntry(size_t pNum)
+{
+ GOTEntry* Entry = 0;
+
+ for (size_t i = 0; i < pNum; i++) {
+ Entry = new (std::nothrow) GOTEntry(0, ARMGOTEntrySize,
+ &m_SectionData);
+
+ if (!Entry)
+ llvm::report_fatal_error("Allocating new memory for GOTEntry failed");
+
+ m_Section.setSize(m_Section.size() + ARMGOTEntrySize);
+ }
+}
+
+void ARMGOT::reserveGOTPLTEntry()
+{
+ GOTEntry* got_entry = 0;
+
+ got_entry= new GOTEntry(0, getEntrySize(),&(getSectionData()));
+
+ if (!got_entry)
+ llvm::report_fatal_error("Allocating new memory for GOT failed!");
+
+ m_Section.setSize(m_Section.size() + getEntrySize());
+
+ ++m_GOTPLTEnd;
+ ++m_NormalGOTIterator;
+}
+
+GOTEntry* ARMGOT::getEntry(const ResolveInfo& pInfo, bool& pExist)
+{
+ GOTEntry *&Entry = m_NormalGOTMap[&pInfo];
+ pExist = 1;
+
+ if (!Entry) {
+ pExist = 0;
+
+ ++m_NormalGOTIterator;
+ assert(m_NormalGOTIterator != m_SectionData.getFragmentList().end()
+ && "The number of GOT Entries and ResolveInfo doesn't match!");
+
+ Entry = llvm::cast<GOTEntry>(&(*m_NormalGOTIterator));
+ }
+
+ return Entry;
+}
+
+void ARMGOT::applyGOT0(uint64_t pAddress)
+{
+ llvm::cast<GOTEntry>
+ (*(m_SectionData.getFragmentList().begin())).setContent(pAddress);
+}
+
+void ARMGOT::applyAllGOTPLT(uint64_t pPLTBase)
+{
+ iterator begin = getGOTPLTBegin();
+ iterator end = getGOTPLTEnd();
+
+ for (;begin != end ;++begin)
+ llvm::cast<GOTEntry>(*begin).setContent(pPLTBase);
+}
+
+GOTEntry*& ARMGOT::lookupGOTPLTMap(const ResolveInfo& pSymbol)
+{
+ return m_GOTPLTMap[&pSymbol];
+}
+
+ARMGOT::iterator ARMGOT::begin()
+{
+ return m_SectionData.getFragmentList().begin();
+}
+
+ARMGOT::const_iterator ARMGOT::begin() const
+{
+ return m_SectionData.getFragmentList().begin();
+}
+
+ARMGOT::iterator ARMGOT::end()
+{
+ return m_SectionData.getFragmentList().end();
+}
+
+ARMGOT::const_iterator ARMGOT::end() const
+{
+ return m_SectionData.getFragmentList().end();
+}
+
+ARMGOT::iterator ARMGOT::getNextGOTPLTEntry()
+{
+ return ++m_GOTPLTIterator;
+}
+
+ARMGOT::iterator ARMGOT::getGOTPLTBegin()
+{
+ // Move to the first GOTPLT entry from last GOT0 entry.
+ iterator begin = m_GOTPLTBegin;
+ return ++begin;
+}
+
+const ARMGOT::iterator ARMGOT::getGOTPLTEnd()
+{
+ // Move to end or the first normal GOT entry from the last GOTPLT entry.
+ iterator end = m_GOTPLTEnd;
+ return ++end;
+}
+
+uint64_t ARMGOT::emit(MemoryRegion& pRegion)
+{
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
+
+ GOTEntry* got = 0;
+ unsigned int entry_size = getEntrySize();
+ uint64_t result = 0x0;
+ for (iterator it = begin(), ie = end();
+ it != ie; ++it, ++buffer) {
+ got = &(llvm::cast<GOTEntry>((*it)));
+ *buffer = static_cast<uint32_t>(got->getContent());
+ result += entry_size;
+ }
+ return result;
+}
+
diff --git a/lib/Target/ARM/ARMGOT.h b/lib/Target/ARM/ARMGOT.h
new file mode 100644
index 0000000..90f0f53
--- /dev/null
+++ b/lib/Target/ARM/ARMGOT.h
@@ -0,0 +1,92 @@
+//===- ARMGOT.h -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ARM_GOT_H
+#define MCLD_ARM_GOT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Target/GOT.h>
+
+namespace mcld
+{
+class LDSection;
+class MemoryRegion;
+
+/** \class ARMGOT
+ * \brief ARM Global Offset Table.
+ */
+class ARMGOT : public GOT
+{
+ typedef llvm::DenseMap<const ResolveInfo*, GOTEntry*> SymbolIndexMapType;
+
+public:
+ typedef llvm::MCSectionData::iterator iterator;
+ typedef llvm::MCSectionData::const_iterator const_iterator;
+
+ enum {
+ ARMGOT0Num = 3
+ };
+
+public:
+ ARMGOT(LDSection &pSection, llvm::MCSectionData& pSectionData);
+
+ ~ARMGOT();
+
+ iterator begin();
+
+ const_iterator begin() const;
+
+ iterator end();
+
+ const_iterator end() const;
+
+ uint64_t emit(MemoryRegion& pRegion);
+// For GOT0
+public:
+ void applyGOT0(uint64_t pAddress);
+
+// For normal GOT
+public:
+ // Reserve normal GOT entries.
+ void reserveEntry(size_t pNum = 1);
+
+ GOTEntry* getEntry(const ResolveInfo& pSymbol, bool& pExist);
+
+// For GOTPLT
+public:
+ void reserveGOTPLTEntry();
+
+ void applyAllGOTPLT(uint64_t pPLTBase);
+
+ GOTEntry*& lookupGOTPLTMap(const ResolveInfo& pSymbol);
+
+ iterator getNextGOTPLTEntry();
+
+ iterator getGOTPLTBegin();
+
+ const iterator getGOTPLTEnd();
+
+private:
+ // For normal GOT entries
+ iterator m_NormalGOTIterator;
+ SymbolIndexMapType m_NormalGOTMap;
+
+ // For GOTPLT entries
+ iterator m_GOTPLTIterator;
+ SymbolIndexMapType m_GOTPLTMap;
+
+ iterator m_GOTPLTBegin;
+ iterator m_GOTPLTEnd;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/ARMLDBackend.cpp b/lib/Target/ARM/ARMLDBackend.cpp
new file mode 100644
index 0000000..105a957
--- /dev/null
+++ b/lib/Target/ARM/ARMLDBackend.cpp
@@ -0,0 +1,1018 @@
+//===- ARMLDBackend.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 <llvm/ADT/Twine.h>
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/ErrorHandling.h>
+
+#include <mcld/LD/SectionMap.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLDOutput.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/MC/MCRegionFragment.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/TargetRegistry.h>
+
+#include <cstring>
+
+#include "ARM.h"
+#include "ARMELFDynamic.h"
+#include "ARMLDBackend.h"
+#include "ARMRelocationFactory.h"
+
+using namespace mcld;
+
+ARMGNULDBackend::ARMGNULDBackend()
+ : m_pRelocFactory(NULL),
+ m_pGOT(NULL),
+ m_pPLT(NULL),
+ m_pRelDyn(NULL),
+ m_pRelPLT(NULL),
+ m_pDynamic(NULL),
+ m_pEXIDX(NULL),
+ m_pEXTAB(NULL),
+ m_pAttributes(NULL) {
+}
+
+ARMGNULDBackend::~ARMGNULDBackend()
+{
+ if (m_pRelocFactory)
+ delete m_pRelocFactory;
+ if(m_pGOT)
+ delete m_pGOT;
+ if(m_pPLT)
+ delete m_pPLT;
+ if(m_pRelDyn)
+ delete m_pRelDyn;
+ if(m_pRelPLT)
+ delete m_pRelPLT;
+ if(m_pDynamic)
+ delete m_pDynamic;
+}
+
+bool ARMGNULDBackend::initRelocFactory(const MCLinker& pLinker)
+{
+ if (NULL == m_pRelocFactory) {
+ m_pRelocFactory = new ARMRelocationFactory(1024, *this);
+ m_pRelocFactory->setLayout(pLinker.getLayout());
+ }
+ return true;
+}
+
+RelocationFactory* ARMGNULDBackend::getRelocFactory()
+{
+ assert(NULL != m_pRelocFactory);
+ return m_pRelocFactory;
+}
+
+bool ARMGNULDBackend::initTargetSectionMap(SectionMap& pSectionMap)
+{
+ if (!pSectionMap.push_back(".ARM.exidx", ".ARM.exidx") ||
+ !pSectionMap.push_back(".ARM.extab", ".ARM.extab") ||
+ !pSectionMap.push_back(".ARM.attributes", ".ARM.attributes"))
+ return false;
+ return true;
+}
+
+void ARMGNULDBackend::initTargetSections(MCLinker& pLinker)
+{
+ // FIXME: Currently we set exidx and extab to "Exception" and directly emit
+ // them from input
+ m_pEXIDX = &pLinker.getOrCreateOutputSectHdr(".ARM.exidx",
+ LDFileFormat::Exception,
+ llvm::ELF::SHT_ARM_EXIDX,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_LINK_ORDER,
+ bitclass() / 8);
+ m_pEXTAB = &pLinker.getOrCreateOutputSectHdr(".ARM.extab",
+ LDFileFormat::Exception,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ m_pAttributes = &pLinker.getOrCreateOutputSectHdr(".ARM.attributes",
+ LDFileFormat::Target,
+ llvm::ELF::SHT_ARM_ATTRIBUTES,
+ 0x0,
+ 0x1);
+}
+
+void ARMGNULDBackend::initTargetSymbols(MCLinker& pLinker)
+{
+ // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
+ // same name in input
+ m_pGOTSymbol = pLinker.defineSymbol<MCLinker::AsRefered, MCLinker::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Hidden);
+}
+
+void ARMGNULDBackend::doPreLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ // when building shared object, the .got section is must.
+ if(pOutput.type() == Output::DynObj && (NULL == m_pGOT)) {
+ createARMGOT(pLinker, pOutput);
+ }
+}
+
+void ARMGNULDBackend::doPostLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ // emit program headers
+ if(pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec)
+ emitProgramHdrs(pLinker.getLDInfo().output());
+
+ ELFFileFormat *file_format = getOutputFormat(pOutput);
+
+ // apply PLT
+ if (file_format->hasPLT()) {
+ // Since we already have the size of LDSection PLT, m_pPLT should not be
+ // NULL.
+ assert(NULL != m_pPLT);
+ m_pPLT->applyPLT0();
+ m_pPLT->applyPLT1();
+ }
+
+ // apply GOT
+ if (file_format->hasGOT()) {
+ // Since we already have the size of GOT, m_pGOT should not be NULL.
+ assert(NULL != m_pGOT);
+ if (pOutput.type() == Output::DynObj)
+ m_pGOT->applyGOT0(file_format->getDynamic().addr());
+ else {
+ // executable file and object file? should fill with zero.
+ m_pGOT->applyGOT0(0);
+ }
+ }
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+ARMELFDynamic& ARMGNULDBackend::dynamic()
+{
+ if (NULL == m_pDynamic)
+ m_pDynamic = new ARMELFDynamic(*this);
+
+ return *m_pDynamic;
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+const ARMELFDynamic& ARMGNULDBackend::dynamic() const
+{
+ assert( NULL != m_pDynamic);
+ return *m_pDynamic;
+}
+
+bool ARMGNULDBackend::isPIC(const MCLDInfo& pLDInfo, const Output& pOutput) const
+{
+ return (pOutput.type() == Output::DynObj);
+}
+
+void ARMGNULDBackend::createARMGOT(MCLinker& pLinker, const Output& pOutput)
+{
+ // get .got LDSection and create MCSectionData
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ LDSection& got = file_format->getGOT();
+ m_pGOT = new ARMGOT(got, pLinker.getOrCreateSectData(got));
+
+ // define symbol _GLOBAL_OFFSET_TABLE_ when .got create
+ if( m_pGOTSymbol != NULL ) {
+ pLinker.defineSymbol<MCLinker::Force, MCLinker::Unresolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+ else {
+ m_pGOTSymbol = pLinker.defineSymbol<MCLinker::Force, MCLinker::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+
+}
+
+void ARMGNULDBackend::createARMPLTandRelPLT(MCLinker& pLinker,
+ const Output& pOutput)
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ // get .plt and .rel.plt LDSection
+ LDSection& plt = file_format->getPLT();
+ LDSection& relplt = file_format->getRelPlt();
+ // create MCSectionData and ARMPLT
+ m_pPLT = new ARMPLT(plt, pLinker.getOrCreateSectData(plt), *m_pGOT);
+ // set info of .rel.plt to .plt
+ relplt.setLink(&plt);
+ // create MCSectionData and ARMRelDynSection
+ m_pRelPLT = new OutputRelocSection(relplt,
+ pLinker.getOrCreateSectData(relplt),
+ 8);
+}
+
+void ARMGNULDBackend::createARMRelDyn(MCLinker& pLinker,
+ const Output& pOutput)
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ // get .rel.dyn LDSection and create MCSectionData
+ LDSection& reldyn = file_format->getRelDyn();
+ // create MCSectionData and ARMRelDynSection
+ m_pRelDyn = new OutputRelocSection(reldyn,
+ pLinker.getOrCreateSectData(reldyn),
+ 8);
+}
+
+ELFFileFormat* ARMGNULDBackend::getOutputFormat(const Output& pOutput) const
+{
+ switch (pOutput.type()) {
+ case Output::DynObj:
+ return getDynObjFileFormat();
+ case Output::Exec:
+ return getExecFileFormat();
+ // FIXME: We do not support building .o now
+ case Output::Object:
+ default:
+ llvm::report_fatal_error(llvm::Twine("Unsupported output file format: ") +
+ llvm::Twine(pOutput.type()));
+ return NULL;
+ }
+}
+
+bool ARMGNULDBackend::isSymbolNeedsPLT(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ return (Output::DynObj == pOutput.type() &&
+ ResolveInfo::Function == pSym.type() &&
+ (pSym.isDyn() || pSym.isUndef() ||
+ isSymbolPreemptible(pSym, pLDInfo, pOutput)));
+}
+
+bool ARMGNULDBackend::isSymbolNeedsDynRel(const ResolveInfo& pSym,
+ const Output& pOutput,
+ bool isAbsReloc) const
+{
+ if(pSym.isUndef() && (Output::Exec == pOutput.type()))
+ return false;
+ if(pSym.isAbsolute())
+ return false;
+ if(Output::DynObj == pOutput.type() && isAbsReloc)
+ return true;
+ if(pSym.isDyn() || pSym.isUndef())
+ return true;
+
+ return false;
+}
+
+bool ARMGNULDBackend::isSymbolPreemptible(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ if(pSym.other() != ResolveInfo::Default)
+ return false;
+
+ if(Output::DynObj != pOutput.type())
+ return false;
+
+ if(pLDInfo.options().Bsymbolic())
+ return false;
+
+ return true;
+}
+
+/// 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 MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ // If not building a PIC object, no relocation type is invalid
+ if (!isPIC(pLDInfo, pOutput))
+ return;
+
+ switch(pReloc.type()) {
+ case llvm::ELF::R_ARM_RELATIVE:
+ case llvm::ELF::R_ARM_COPY:
+ case llvm::ELF::R_ARM_GLOB_DAT:
+ case llvm::ELF::R_ARM_JUMP_SLOT:
+ case llvm::ELF::R_ARM_ABS32:
+ case llvm::ELF::R_ARM_ABS32_NOI:
+ case llvm::ELF::R_ARM_PC24:
+ case llvm::ELF::R_ARM_TLS_DTPMOD32:
+ case llvm::ELF::R_ARM_TLS_DTPOFF32:
+ case llvm::ELF::R_ARM_TLS_TPOFF32:
+ break;
+
+ default:
+ llvm::report_fatal_error(llvm::Twine("Attempt to generate unsupported") +
+ llvm::Twine(" relocation type ") +
+ llvm::Twine((int)pReloc.type()) +
+ llvm::Twine(" for symbol '") +
+ llvm::Twine(pReloc.symInfo()->name()) +
+ llvm::Twine("', recompile with -fPIC")
+ );
+ break;
+ }
+}
+
+void ARMGNULDBackend::updateAddend(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ const Layout& pLayout) const
+{
+ // Update value keep in addend if we meet a section symbol
+ if(pReloc.symInfo()->type() == ResolveInfo::Section) {
+ pReloc.setAddend(pLayout.getOutputOffset(
+ *pInputSym.fragRef()) + pReloc.addend());
+ }
+}
+
+void ARMGNULDBackend::scanLocalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ updateAddend(pReloc, pInputSym, pLinker.getLayout());
+
+ switch(pReloc.type()){
+
+ // Set R_ARM_TARGET1 to R_ARM_ABS32
+ // Ref: GNU gold 1.11 arm.cc, line 9892
+ case llvm::ELF::R_ARM_TARGET1:
+ pReloc.setType(llvm::ELF::R_ARM_ABS32);
+ case llvm::ELF::R_ARM_ABS32:
+ case llvm::ELF::R_ARM_ABS32_NOI: {
+ // If buiding PIC object (shared library or PIC executable),
+ // a dynamic relocations with RELATIVE type to this location is needed.
+ // Reserve an entry in .rel.dyn
+ if(isPIC(pLDInfo, pOutput)) {
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createARMRelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | 0x1u);
+ }
+ return;
+ }
+
+ case llvm::ELF::R_ARM_ABS16:
+ case llvm::ELF::R_ARM_ABS12:
+ case llvm::ELF::R_ARM_THM_ABS5:
+ case llvm::ELF::R_ARM_ABS8:
+ case llvm::ELF::R_ARM_BASE_ABS:
+ case llvm::ELF::R_ARM_MOVW_ABS_NC:
+ case llvm::ELF::R_ARM_MOVT_ABS:
+ case llvm::ELF::R_ARM_THM_MOVW_ABS_NC:
+ case llvm::ELF::R_ARM_THM_MOVT_ABS: {
+ // Update value keep in relocation place if we meet a section symbol
+ if(rsym->type() == ResolveInfo::Section) {
+ pReloc.target() = pLinker.getLayout().getOutputOffset(
+ *pInputSym.fragRef()) + pReloc.target();
+ }
+
+ // If building PIC object (shared library or PIC executable),
+ // a dynamic relocation for this location is needed.
+ // Reserve an entry in .rel.dyn
+ if(isPIC(pLDInfo, pOutput)) {
+ checkValidReloc(pReloc, pLDInfo, pOutput);
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createARMRelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | 0x1u);
+ }
+ return;
+ }
+ case llvm::ELF::R_ARM_GOTOFF32:
+ case llvm::ELF::R_ARM_GOTOFF12: {
+ // A GOT section is needed
+ if(NULL == m_pGOT)
+ createARMGOT(pLinker, pOutput);
+ return;
+ }
+
+ // Set R_ARM_TARGET2 to R_ARM_GOT_PREL
+ // Ref: GNU gold 1.11 arm.cc, line 9892
+ case llvm::ELF::R_ARM_TARGET2:
+ pReloc.setType(llvm::ELF::R_ARM_GOT_PREL);
+ case llvm::ELF::R_ARM_GOT_BREL:
+ case llvm::ELF::R_ARM_GOT_PREL: {
+ // A GOT entry is needed for these relocation type.
+ // return if we already create GOT for this symbol
+ if(rsym->reserved() & 0x6u)
+ return;
+ if(NULL == m_pGOT)
+ createARMGOT(pLinker, pOutput);
+ m_pGOT->reserveEntry();
+ // If building PIC object, a dynamic relocation with
+ // type RELATIVE is needed to relocate this GOT entry.
+ // Reserve an entry in .rel.dyn
+ if(isPIC(pLDInfo, pOutput)) {
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createARMRelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set GOTRel bit
+ rsym->setReserved(rsym->reserved() | 0x4u);
+ return;
+ }
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | 0x2u);
+ return;
+ }
+
+ case llvm::ELF::R_ARM_BASE_PREL: {
+ // FIXME: Currently we only support R_ARM_BASE_PREL against
+ // symbol _GLOBAL_OFFSET_TABLE_
+ if(rsym != m_pGOTSymbol->resolveInfo()) {
+ llvm::report_fatal_error(llvm::Twine("Do not support relocation '") +
+ llvm::Twine("R_ARM_BASE_PREL' against symbol '") +
+ llvm::Twine(rsym->name()) +
+ llvm::Twine(".'"));
+ }
+ return;
+ }
+ case llvm::ELF::R_ARM_COPY:
+ case llvm::ELF::R_ARM_GLOB_DAT:
+ case llvm::ELF::R_ARM_JUMP_SLOT:
+ case llvm::ELF::R_ARM_RELATIVE: {
+ // These are relocation type for dynamic linker, shold not
+ // appear in object file.
+ llvm::report_fatal_error(llvm::Twine("unexpected reloc ") +
+ llvm::Twine((int)pReloc.type()) +
+ llvm::Twine(" in object file"));
+ break;
+ }
+ default: {
+ break;
+ }
+ } // end switch
+}
+
+void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ switch(pReloc.type()) {
+
+ // Set R_ARM_TARGET1 to R_ARM_ABS32
+ // Ref: GNU gold 1.11 arm.cc, line 9892
+ case llvm::ELF::R_ARM_TARGET1:
+ pReloc.setType(llvm::ELF::R_ARM_ABS32);
+ case llvm::ELF::R_ARM_ABS32:
+ case llvm::ELF::R_ARM_ABS16:
+ case llvm::ELF::R_ARM_ABS12:
+ case llvm::ELF::R_ARM_THM_ABS5:
+ case llvm::ELF::R_ARM_ABS8:
+ case llvm::ELF::R_ARM_BASE_ABS:
+ case llvm::ELF::R_ARM_MOVW_ABS_NC:
+ case llvm::ELF::R_ARM_MOVT_ABS:
+ case llvm::ELF::R_ARM_THM_MOVW_ABS_NC:
+ case llvm::ELF::R_ARM_THM_MOVT_ABS:
+ case llvm::ELF::R_ARM_ABS32_NOI: {
+ // Absolute relocation type, symbol may needs PLT entry or
+ // dynamic relocation entry
+ if(isSymbolNeedsPLT(*rsym, pLDInfo, pOutput)) {
+ // create plt for this symbol if it does not have one
+ if(!(rsym->reserved() & 0x8u)){
+ // Create .got section if it doesn't exist
+ if(NULL == m_pGOT)
+ createARMGOT(pLinker, pOutput);
+ // create .plt and .rel.plt if not exist
+ if(NULL == m_pPLT)
+ createARMPLTandRelPLT(pLinker, pOutput);
+ // Symbol needs PLT entry, we need to reserve a PLT entry
+ // and the corresponding GOT and dynamic relocation entry
+ // in .got and .rel.plt. (GOT entry will be reserved simultaneously
+ // when calling ARMPLT->reserveEntry())
+ m_pPLT->reserveEntry();
+ m_pRelPLT->reserveEntry(*m_pRelocFactory);
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | 0x8u);
+ }
+ }
+
+ if(isSymbolNeedsDynRel(*rsym, pOutput, true)) {
+ checkValidReloc(pReloc, pLDInfo, pOutput);
+ // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createARMRelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | 0x1u);
+ }
+ return;
+ }
+
+ case llvm::ELF::R_ARM_GOTOFF32:
+ case llvm::ELF::R_ARM_GOTOFF12: {
+ // A GOT section is needed
+ if(NULL == m_pGOT)
+ createARMGOT(pLinker, pOutput);
+ return;
+ }
+
+ case llvm::ELF::R_ARM_BASE_PREL:
+ // FIXME: Currently we only support R_ARM_BASE_PREL against
+ // symbol _GLOBAL_OFFSET_TABLE_
+ if(rsym != m_pGOTSymbol->resolveInfo()) {
+ llvm::report_fatal_error(llvm::Twine("Do not support relocation '") +
+ llvm::Twine("R_ARM_BASE_PREL' against symbol '") +
+ llvm::Twine(rsym->name()) +
+ llvm::Twine(".'"));
+ }
+ case llvm::ELF::R_ARM_REL32:
+ case llvm::ELF::R_ARM_LDR_PC_G0:
+ case llvm::ELF::R_ARM_SBREL32:
+ case llvm::ELF::R_ARM_THM_PC8:
+ case llvm::ELF::R_ARM_MOVW_PREL_NC:
+ case llvm::ELF::R_ARM_MOVT_PREL:
+ case llvm::ELF::R_ARM_THM_MOVW_PREL_NC:
+ case llvm::ELF::R_ARM_THM_MOVT_PREL:
+ case llvm::ELF::R_ARM_THM_ALU_PREL_11_0:
+ case llvm::ELF::R_ARM_THM_PC12:
+ case llvm::ELF::R_ARM_REL32_NOI:
+ case llvm::ELF::R_ARM_ALU_PC_G0_NC:
+ case llvm::ELF::R_ARM_ALU_PC_G0:
+ case llvm::ELF::R_ARM_ALU_PC_G1_NC:
+ case llvm::ELF::R_ARM_ALU_PC_G1:
+ case llvm::ELF::R_ARM_ALU_PC_G2:
+ case llvm::ELF::R_ARM_LDR_PC_G1:
+ case llvm::ELF::R_ARM_LDR_PC_G2:
+ case llvm::ELF::R_ARM_LDRS_PC_G0:
+ case llvm::ELF::R_ARM_LDRS_PC_G1:
+ case llvm::ELF::R_ARM_LDRS_PC_G2:
+ case llvm::ELF::R_ARM_LDC_PC_G0:
+ case llvm::ELF::R_ARM_LDC_PC_G1:
+ case llvm::ELF::R_ARM_LDC_PC_G2:
+ case llvm::ELF::R_ARM_ALU_SB_G0_NC:
+ case llvm::ELF::R_ARM_ALU_SB_G0:
+ case llvm::ELF::R_ARM_ALU_SB_G1_NC:
+ case llvm::ELF::R_ARM_ALU_SB_G1:
+ case llvm::ELF::R_ARM_ALU_SB_G2:
+ case llvm::ELF::R_ARM_LDR_SB_G0:
+ case llvm::ELF::R_ARM_LDR_SB_G1:
+ case llvm::ELF::R_ARM_LDR_SB_G2:
+ case llvm::ELF::R_ARM_LDRS_SB_G0:
+ case llvm::ELF::R_ARM_LDRS_SB_G1:
+ case llvm::ELF::R_ARM_LDRS_SB_G2:
+ case llvm::ELF::R_ARM_LDC_SB_G0:
+ case llvm::ELF::R_ARM_LDC_SB_G1:
+ case llvm::ELF::R_ARM_LDC_SB_G2:
+ case llvm::ELF::R_ARM_MOVW_BREL_NC:
+ case llvm::ELF::R_ARM_MOVT_BREL:
+ case llvm::ELF::R_ARM_MOVW_BREL:
+ case llvm::ELF::R_ARM_THM_MOVW_BREL_NC:
+ case llvm::ELF::R_ARM_THM_MOVT_BREL:
+ case llvm::ELF::R_ARM_THM_MOVW_BREL: {
+ // Relative addressing relocation, may needs dynamic relocation
+ if(isSymbolNeedsDynRel(*rsym, pOutput, false)) {
+ checkValidReloc(pReloc, pLDInfo, pOutput);
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createARMRelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | 0x1u);
+ }
+ return;
+ }
+
+ case llvm::ELF::R_ARM_THM_CALL:
+ case llvm::ELF::R_ARM_PLT32:
+ case llvm::ELF::R_ARM_CALL:
+ case llvm::ELF::R_ARM_JUMP24:
+ case llvm::ELF::R_ARM_THM_JUMP24:
+ case llvm::ELF::R_ARM_SBREL31:
+ case llvm::ELF::R_ARM_PREL31:
+ case llvm::ELF::R_ARM_THM_JUMP19:
+ case llvm::ELF::R_ARM_THM_JUMP6:
+ case llvm::ELF::R_ARM_THM_JUMP11:
+ case llvm::ELF::R_ARM_THM_JUMP8: {
+ // These are branch relocation (except PREL31)
+ // A PLT entry is needed when building shared library
+
+ // return if we already create plt for this symbol
+ if(rsym->reserved() & 0x8u)
+ return;
+
+ // if symbol is defined in the ouput file and it's not
+ // preemptible, no need plt
+ if(rsym->isDefine() && !rsym->isDyn() &&
+ !isSymbolPreemptible(*rsym, pLDInfo, pOutput)) {
+ return;
+ }
+
+ // Create .got section if it doesn't exist
+ if(NULL == m_pGOT)
+ createARMGOT(pLinker, pOutput);
+
+ // create .plt and .rel.plt if not exist
+ if(NULL == m_pPLT)
+ createARMPLTandRelPLT(pLinker, pOutput);
+ // Symbol needs PLT entry, we need to reserve a PLT entry
+ // and the corresponding GOT and dynamic relocation entry
+ // in .got and .rel.plt. (GOT entry will be reserved simultaneously
+ // when calling ARMPLT->reserveEntry())
+ m_pPLT->reserveEntry();
+ m_pRelPLT->reserveEntry(*m_pRelocFactory);
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | 0x8u);
+ return;
+ }
+
+ // Set R_ARM_TARGET2 to R_ARM_GOT_PREL
+ // Ref: GNU gold 1.11 arm.cc, line 9892
+ case llvm::ELF::R_ARM_TARGET2:
+ pReloc.setType(llvm::ELF::R_ARM_GOT_PREL);
+ case llvm::ELF::R_ARM_GOT_BREL:
+ case llvm::ELF::R_ARM_GOT_ABS:
+ case llvm::ELF::R_ARM_GOT_PREL: {
+ // Symbol needs GOT entry, reserve entry in .got
+ // return if we already create GOT for this symbol
+ if(rsym->reserved() & 0x6u)
+ return;
+ if(NULL == m_pGOT)
+ createARMGOT(pLinker, pOutput);
+ m_pGOT->reserveEntry();
+ // If building shared object or the symbol is undefined, a dynamic
+ // relocation is needed to relocate this GOT entry. Reserve an
+ // entry in .rel.dyn
+ if(Output::DynObj == pOutput.type() || rsym->isUndef() || rsym->isDyn()) {
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createARMRelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set GOTRel bit
+ rsym->setReserved(rsym->reserved() | 0x4u);
+ return;
+ }
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | 0x2u);
+ return;
+ }
+
+ case llvm::ELF::R_ARM_COPY:
+ case llvm::ELF::R_ARM_GLOB_DAT:
+ case llvm::ELF::R_ARM_JUMP_SLOT:
+ case llvm::ELF::R_ARM_RELATIVE: {
+ // These are relocation type for dynamic linker, shold not
+ // appear in object file.
+ llvm::report_fatal_error(llvm::Twine("Unexpected reloc ") +
+ llvm::Twine((int)pReloc.type()) +
+ llvm::Twine(" in object file"));
+ break;
+ }
+ default: {
+ break;
+ }
+ } // end switch
+}
+
+void ARMGNULDBackend::scanRelocation(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
+
+ // Scan relocation type to determine if an GOT/PLT/Dynamic Relocation
+ // entries should be created.
+ // FIXME: Below judgements concern only .so is generated as output
+ // FIXME: Below judgements concern nothing about TLS related relocation
+
+ // A refernece to symbol _GLOBAL_OFFSET_TABLE_ implies that a .got section
+ // is needed
+ if(NULL == m_pGOT && NULL != m_pGOTSymbol) {
+ if(rsym == m_pGOTSymbol->resolveInfo()) {
+ createARMGOT(pLinker, pOutput);
+ }
+ }
+
+ // rsym is local
+ if(rsym->isLocal())
+ scanLocalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
+
+ // rsym is external
+ else
+ scanGlobalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
+
+}
+
+uint64_t ARMGNULDBackend::emitSectionData(const Output& pOutput,
+ const LDSection& pSection,
+ const MCLDInfo& pInfo,
+ MemoryRegion& pRegion) const
+{
+ assert(pRegion.size() && "Size of MemoryRegion is zero!");
+
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ if (&pSection == m_pAttributes) {
+ // FIXME: Currently Emitting .ARM.attributes directly from the input file.
+ const llvm::MCSectionData* sect_data = pSection.getSectionData();
+ assert(sect_data &&
+ "Emit .ARM.attribute failed, MCSectionData doesn't exist!");
+
+ uint8_t* start =
+ llvm::cast<MCRegionFragment>(
+ sect_data->getFragmentList().front()).getRegion().start();
+
+ memcpy(pRegion.start(), start, pRegion.size());
+ return pRegion.size();
+ }
+
+ if (&pSection == &(file_format->getPLT())) {
+ assert(NULL != m_pPLT && "emitSectionData failed, m_pPLT is NULL!");
+ uint64_t result = m_pPLT->emit(pRegion);
+ return result;
+ }
+
+ if (&pSection == &(file_format->getGOT())) {
+ assert(NULL != m_pGOT && "emitSectionData failed, m_pGOT is NULL!");
+ uint64_t result = m_pGOT->emit(pRegion);
+ return result;
+ }
+
+ llvm::report_fatal_error(llvm::Twine("Unable to emit section `") +
+ pSection.name() +
+ llvm::Twine("'.\n"));
+ return 0x0;
+}
+
+/// finalizeSymbol - finalize the symbol value
+/// If the symbol's reserved field is not zero, MCLinker will call back this
+/// function to ask the final value of the symbol
+bool ARMGNULDBackend::finalizeSymbol(LDSymbol& pSymbol) const
+{
+ return false;
+}
+
+/// allocateCommonSymbols - allocate common symbols in the corresponding
+/// sections.
+/// @refer Google gold linker: common.cc: 214
+bool
+ARMGNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const
+{
+ SymbolCategory& symbol_list = pLinker.getOutputSymbols();
+
+ if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
+ return true;
+
+ // addralign := max value of all common symbols
+ uint64_t addralign = 0x0;
+
+ // Due to the visibility, some common symbols may be forcefully local.
+ SymbolCategory::iterator com_sym, com_end = symbol_list.localEnd();
+ for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+ if (ResolveInfo::Common == (*com_sym)->desc()) {
+ if ((*com_sym)->value() > addralign)
+ addralign = (*com_sym)->value();
+ }
+ }
+
+ // global common symbols.
+ com_end = symbol_list.commonEnd();
+ for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+ if ((*com_sym)->value() > addralign)
+ addralign = (*com_sym)->value();
+ }
+
+ // FIXME: If the order of common symbols is defined, then sort common symbols
+ // com_sym = symbol_list.commonBegin();
+ // std::sort(com_sym, com_end, some kind of order);
+
+ // get or create corresponding BSS LDSection
+ LDSection* bss_sect_hdr = NULL;
+ if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
+ ".tbss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
+ else {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
+
+ // get or create corresponding BSS MCSectionData
+ assert(NULL != bss_sect_hdr);
+ llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(*bss_sect_hdr);
+
+ // allocate all common symbols
+ uint64_t offset = bss_sect_hdr->size();
+
+ // allocate all local common symbols
+ com_end = symbol_list.localEnd();
+ for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+ if (ResolveInfo::Common == (*com_sym)->desc()) {
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ bss_section,
+ (*com_sym)->value());
+ offset += size;
+ }
+ }
+
+ // allocate all global common symbols
+ com_end = symbol_list.commonEnd();
+ for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ bss_section,
+ (*com_sym)->value());
+ offset += size;
+ }
+
+ bss_sect_hdr->setSize(offset);
+ symbol_list.changeCommonsToGlobal();
+ return true;
+}
+
+bool ARMGNULDBackend::readSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr)
+{
+ LDSection& out_sect = pLinker.getOrCreateOutputSectHdr(pInputSectHdr.name(),
+ pInputSectHdr.kind(),
+ pInputSectHdr.type(),
+ pInputSectHdr.flag());
+ // FIXME: (Luba)
+ // Handle ARM attributes in the right way.
+ // In current milestone, MCLinker goes through the shortcut.
+ // It reads input's ARM attributes and copies the first ARM attributes
+ // into the output file. The correct way is merge these sections, not
+ // just copy.
+ if ((0 == out_sect.name().compare(".ARM.attributes")) &&
+ (0 != out_sect.size()))
+ return true;
+
+ MemoryRegion* region = pInput.memArea()->request(pInputSectHdr.offset(),
+ pInputSectHdr.size());
+
+ llvm::MCSectionData& sect_data = pLinker.getOrCreateSectData(pInputSectHdr);
+
+ new MCRegionFragment(*region, §_data);
+
+ out_sect.setSize(out_sect.size() + pInputSectHdr.size());
+ return true;
+}
+
+ARMGOT& ARMGNULDBackend::getGOT()
+{
+ assert(NULL != m_pGOT && "GOT section not exist");
+ return *m_pGOT;
+}
+
+const ARMGOT& ARMGNULDBackend::getGOT() const
+{
+ assert(NULL != m_pGOT && "GOT section not exist");
+ return *m_pGOT;
+}
+
+ARMPLT& ARMGNULDBackend::getPLT()
+{
+ assert(NULL != m_pPLT && "PLT section not exist");
+ return *m_pPLT;
+}
+
+const ARMPLT& ARMGNULDBackend::getPLT() const
+{
+ assert(NULL != m_pPLT && "PLT section not exist");
+ return *m_pPLT;
+}
+
+OutputRelocSection& ARMGNULDBackend::getRelDyn()
+{
+ assert(NULL != m_pRelDyn && ".rel.dyn section not exist");
+ return *m_pRelDyn;
+}
+
+const OutputRelocSection& ARMGNULDBackend::getRelDyn() const
+{
+ assert(NULL != m_pRelDyn && ".rel.dyn section not exist");
+ return *m_pRelDyn;
+}
+
+OutputRelocSection& ARMGNULDBackend::getRelPLT()
+{
+ assert(NULL != m_pRelPLT && ".rel.plt section not exist");
+ return *m_pRelPLT;
+}
+
+const OutputRelocSection& ARMGNULDBackend::getRelPLT() const
+{
+ assert(NULL != m_pRelPLT && ".rel.plt section not exist");
+ return *m_pRelPLT;
+}
+
+unsigned int
+ARMGNULDBackend::getTargetSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ if (&pSectHdr == &file_format->getGOT())
+ return SHO_DATA;
+
+ if (&pSectHdr == &file_format->getPLT())
+ return SHO_PLT;
+
+ return SHO_UNDEFINED;
+}
+
+namespace mcld {
+
+//===----------------------------------------------------------------------===//
+/// createARMLDBackend - the help funtion to create corresponding ARMLDBackend
+///
+TargetLDBackend* createARMLDBackend(const llvm::Target& pTarget,
+ const std::string& pTriple)
+{
+ Triple theTriple(pTriple);
+ if (theTriple.isOSDarwin()) {
+ assert(0 && "MachO linker is not supported yet");
+ /**
+ return new ARMMachOLDBackend(createARMMachOArchiveReader,
+ createARMMachOObjectReader,
+ createARMMachOObjectWriter);
+ **/
+ }
+ if (theTriple.isOSWindows()) {
+ assert(0 && "COFF linker is not supported yet");
+ /**
+ return new ARMCOFFLDBackend(createARMCOFFArchiveReader,
+ createARMCOFFObjectReader,
+ createARMCOFFObjectWriter);
+ **/
+ }
+ return new ARMGNULDBackend();
+}
+
+} // namespace of mcld
+
+//=============================
+// Force static initialization.
+extern "C" void LLVMInitializeARMLDBackend() {
+ // Register the linker backend
+ mcld::TargetRegistry::RegisterTargetLDBackend(TheARMTarget, createARMLDBackend);
+}
+
diff --git a/lib/Target/ARM/ARMLDBackend.h b/lib/Target/ARM/ARMLDBackend.h
new file mode 100644
index 0000000..440d9ee
--- /dev/null
+++ b/lib/Target/ARM/ARMLDBackend.h
@@ -0,0 +1,297 @@
+//===- ARMLDBackend.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ARM_LDBACKEND_H
+#define MCLD_ARM_LDBACKEND_H
+
+#include "ARMELFDynamic.h"
+#include "ARMGOT.h"
+#include "ARMPLT.h"
+#include <mcld/LD/LDSection.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/Target/OutputRelocSection.h>
+
+namespace mcld {
+
+class MCLDInfo;
+class MCLinker;
+class Output;
+class SectionMap;
+
+
+//===----------------------------------------------------------------------===//
+/// ARMGNULDBackend - linker backend of ARM target of GNU ELF format
+///
+class ARMGNULDBackend : public GNULDBackend
+{
+public:
+ ARMGNULDBackend();
+ ~ARMGNULDBackend();
+public:
+ typedef std::vector<llvm::ELF::Elf32_Dyn*> ELF32DynList;
+
+ /** \enum ReservedEntryType
+ * \brief The reserved entry type of reserved space in ResolveInfo.
+ *
+ * This is used for sacnRelocation to record what kinds of entries are
+ * reserved for this resolved symbol
+ *
+ * In ARM, there are three kinds of entries, GOT, PLT, and dynamic reloction.
+ * GOT may needs a corresponding relocation to relocate itself, so we
+ * separate GOT to two situations: GOT and GOTRel. Besides, for the same
+ * symbol, there might be two kinds of entries reserved for different location.
+ * For example, reference to the same symbol, one may use GOT and the other may
+ * use dynamic relocation.
+ *
+ * bit: 3 2 1 0
+ * | PLT | GOTRel | GOT | Rel |
+ *
+ * value Name - Description
+ *
+ * 0000 None - no reserved entry
+ * 0001 ReserveRel - reserve an dynamic relocation entry
+ * 0010 ReserveGOT - reserve an GOT entry
+ * 0011 GOTandRel - For different relocation, we've reserved GOT and
+ * Rel for different location.
+ * 0100 GOTRel - reserve an GOT entry and the corresponding Dyncamic
+ * relocation entry which relocate this GOT entry
+ * 0101 GOTRelandRel - For different relocation, we've reserved GOTRel
+ * and relocation entry for different location.
+ * 1000 ReservePLT - reserve an PLT entry and the corresponding GOT,
+ * Dynamic relocation entries
+ * 1001 PLTandRel - For different relocation, we've reserved PLT and
+ * Rel for different location.
+ */
+ enum ReservedEntryType {
+ None = 0,
+ ReserveRel = 1,
+ ReserveGOT = 2,
+ GOTandRel = 3,
+ GOTRel = 4,
+ GOTRelandRel = 5,
+ ReservePLT = 8,
+ PLTandRel = 9
+ };
+
+public:
+ /// initTargetSectionMap - initialize target dependent section mapping
+ bool initTargetSectionMap(SectionMap& pSectionMap);
+
+ /// initTargetSections - initialize target dependent sections in output.
+ void initTargetSections(MCLinker& pLinker);
+
+ /// initTargetSymbols - initialize target dependent symbols in output.
+ void initTargetSymbols(MCLinker& pLinker);
+
+ /// initRelocFactory - create and initialize RelocationFactory
+ bool initRelocFactory(const MCLinker& pLinker);
+
+ /// getRelocFactory
+ RelocationFactory* getRelocFactory();
+
+ /// scanRelocation - determine the empty entries are needed or not and create
+ /// the empty entries if needed.
+ /// For ARM, following entries are check to create:
+ /// - GOT entry (for .got section)
+ /// - PLT entry (for .plt section)
+ /// - dynamin relocation entries (for .rel.plt and .rel.dyn sections)
+ void scanRelocation(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ uint32_t machine() const
+ { return llvm::ELF::EM_ARM; }
+
+ /// OSABI - the value of e_ident[EI_OSABI]
+ virtual uint8_t OSABI() const
+ { return llvm::ELF::ELFOSABI_NONE; }
+
+ /// ABIVersion - the value of e_ident[EI_ABIVRESION]
+ virtual uint8_t ABIVersion() const
+ { return 0x0; }
+
+ /// flags - the value of ElfXX_Ehdr::e_flags
+ virtual uint64_t flags() const
+ { return (llvm::ELF::EF_ARM_EABIMASK & 0x05000000); }
+
+ bool isLittleEndian() const
+ { return true; }
+
+ unsigned int bitclass() const
+ { return 32; }
+
+ /// doPreLayout - Backend can do any needed modification before layout
+ void doPreLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+ /// doPostLayout -Backend can do any needed modification after layout
+ void doPostLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ ARMELFDynamic& dynamic();
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ const ARMELFDynamic& 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 pOutput - the output file
+ /// @param pSection - the given LDSection
+ /// @param pInfo - all options in the command line.
+ /// @param pRegion - the region to write out data
+ /// @return the size of the table in the file.
+ uint64_t emitSectionData(const Output& pOutput,
+ const LDSection& pSection,
+ const MCLDInfo& pInfo,
+ MemoryRegion& pRegion) const;
+
+ ARMGOT& getGOT();
+
+ const ARMGOT& getGOT() const;
+
+ ARMPLT& getPLT();
+
+ const ARMPLT& getPLT() const;
+
+ OutputRelocSection& getRelDyn();
+
+ const OutputRelocSection& getRelDyn() const;
+
+ OutputRelocSection& getRelPLT();
+
+ const OutputRelocSection& getRelPLT() const;
+
+ /// getTargetSectionOrder - compute the layout order of ARM target sections
+ unsigned int getTargetSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const;
+
+ /// finalizeSymbol - finalize the symbol value
+ /// If the symbol's reserved field is not zero, MCLinker will call back this
+ /// function to ask the final value of the symbol
+ bool finalizeSymbol(LDSymbol& pSymbol) const;
+
+ /// allocateCommonSymbols - allocate common symbols in the corresponding
+ /// sections.
+ bool allocateCommonSymbols(const MCLDInfo& pLDInfo, MCLinker& pLinker) const;
+
+ /// readSection - read target dependent sections
+ bool readSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr);
+
+public:
+ bool isSymbolPreemptible(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const;
+
+ bool isPIC(const MCLDInfo& pLDInfo, const Output& pOutput) const;
+
+private:
+ void scanLocalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ void scanGlobalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ bool isSymbolNeedsPLT(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const;
+
+ bool isSymbolNeedsDynRel(const ResolveInfo& pSym,
+ const Output& pOutput,
+ bool isAbsReloc) const;
+
+
+ void checkValidReloc(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const;
+
+ /// updateAddend - update addend value of the relocation if the
+ /// the target symbol is a section symbol. Addend is the offset
+ /// in the section. This value should be updated after section
+ /// merged.
+ void updateAddend(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ const Layout& pLayout) const;
+
+ void createARMGOT(MCLinker& pLinker, const Output& pOutput);
+
+ /// createARMPLTandRelPLT - create PLT and RELPLT sections.
+ /// Because in ELF sh_info in .rel.plt is the shndx of .plt, these two
+ /// sections should be create together.
+ void createARMPLTandRelPLT(MCLinker& pLinker, const Output& pOutput);
+
+ void createARMRelDyn(MCLinker& pLinker, const Output& pOutput);
+
+ ELFFileFormat* getOutputFormat(const Output& pOutput) const;
+
+private:
+ RelocationFactory* m_pRelocFactory;
+ ARMGOT* m_pGOT;
+ ARMPLT* m_pPLT;
+ /// m_RelDyn - dynamic relocation table of .rel.dyn
+ OutputRelocSection* m_pRelDyn;
+ /// m_RelPLT - dynamic relocation table of .rel.plt
+ OutputRelocSection* m_pRelPLT;
+
+ ARMELFDynamic* m_pDynamic;
+ LDSymbol* m_pGOTSymbol;
+
+ // variable name : ELF
+ LDSection* m_pEXIDX; // .ARM.exidx
+ LDSection* m_pEXTAB; // .ARM.extab
+ LDSection* m_pAttributes; // .ARM.attributes
+// LDSection* m_pPreemptMap; // .ARM.preemptmap
+// 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/ARMPLT.cpp b/lib/Target/ARM/ARMPLT.cpp
new file mode 100644
index 0000000..3a79b52
--- /dev/null
+++ b/lib/Target/ARM/ARMPLT.cpp
@@ -0,0 +1,250 @@
+//===- ARMPLT.cpp -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "ARMGOT.h"
+#include "ARMPLT.h"
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <new>
+
+namespace {
+
+const uint32_t arm_plt0[] = {
+ 0xe52de004, // str lr, [sp, #-4]!
+ 0xe59fe004, // ldr lr, [pc, #4]
+ 0xe08fe00e, // add lr, pc, lr
+ 0xe5bef008, // ldr pc, [lr, #8]!
+ 0x00000000, // &GOT[0] - .
+};
+
+const uint32_t arm_plt1[] = {
+ 0xe28fc600, // add ip, pc, #0xNN00000
+ 0xe28cca00, // add ip, ip, #0xNN000
+ 0xe5bcf000, // ldr pc, [ip, #0xNNN]!
+};
+
+} // anonymous namespace
+
+using namespace mcld;
+
+ARMPLT0::ARMPLT0(llvm::MCSectionData* pParent)
+ : PLTEntry(sizeof(arm_plt0), pParent) {}
+
+ARMPLT1::ARMPLT1(llvm::MCSectionData* pParent)
+ : PLTEntry(sizeof(arm_plt1), pParent) {}
+
+//===----------------------------------------------------------------------===//
+// ARMPLT
+
+ARMPLT::ARMPLT(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ ARMGOT &pGOTPLT)
+ : PLT(pSection, pSectionData), m_GOT(pGOTPLT), m_PLTEntryIterator() {
+ ARMPLT0* plt0_entry = new ARMPLT0(&m_SectionData);
+
+ m_Section.setSize(m_Section.size() + plt0_entry->getEntrySize());
+
+ m_PLTEntryIterator = pSectionData.begin();
+}
+
+ARMPLT::~ARMPLT()
+{
+}
+
+void ARMPLT::reserveEntry(size_t pNum)
+{
+ ARMPLT1* plt1_entry = 0;
+
+ for (size_t i = 0; i < pNum; ++i) {
+ plt1_entry = new (std::nothrow) ARMPLT1(&m_SectionData);
+
+ if (!plt1_entry)
+ llvm::report_fatal_error("Allocating new memory for ARMPLT1 failed!");
+
+ m_Section.setSize(m_Section.size() + plt1_entry->getEntrySize());
+
+ m_GOT.reserveGOTPLTEntry();
+ }
+}
+
+PLTEntry* ARMPLT::getPLTEntry(const ResolveInfo& pSymbol, bool& pExist)
+{
+ ARMPLT1 *&PLTEntry = m_PLTEntryMap[&pSymbol];
+
+ pExist = 1;
+
+ if (!PLTEntry) {
+ GOTEntry *&GOTPLTEntry = m_GOT.lookupGOTPLTMap(pSymbol);
+ assert(!GOTPLTEntry && "PLT entry and got.plt entry doesn't match!");
+
+ pExist = 0;
+
+ // This will skip PLT0.
+ ++m_PLTEntryIterator;
+ assert(m_PLTEntryIterator != m_SectionData.end() &&
+ "The number of PLT Entries and ResolveInfo doesn't match");
+
+ ARMGOT::iterator got_it = m_GOT.getNextGOTPLTEntry();
+ ARMGOT::iterator got_ie = m_GOT.getGOTPLTEnd();
+ assert(got_it != got_ie && "The number of GOTPLT and PLT doesn't match");
+
+ PLTEntry = llvm::cast<ARMPLT1>(&(*m_PLTEntryIterator));
+ GOTPLTEntry = llvm::cast<GOTEntry>(&(*got_it));
+ }
+
+ return PLTEntry;
+}
+
+GOTEntry* ARMPLT::getGOTPLTEntry(const ResolveInfo& pSymbol, bool& pExist)
+{
+ GOTEntry *&GOTPLTEntry = m_GOT.lookupGOTPLTMap(pSymbol);
+
+ pExist = 1;
+
+ if (!GOTPLTEntry) {
+ ARMPLT1 *&PLTEntry = m_PLTEntryMap[&pSymbol];
+ assert(!PLTEntry && "PLT entry and got.plt entry doesn't match!");
+
+ pExist = 0;
+
+ // This will skip PLT0.
+ ++m_PLTEntryIterator;
+ assert(m_PLTEntryIterator != m_SectionData.end() &&
+ "The number of PLT Entries and ResolveInfo doesn't match");
+
+ ARMGOT::iterator got_it = m_GOT.getNextGOTPLTEntry();
+ ARMGOT::iterator got_ie = m_GOT.getGOTPLTEnd();
+ assert(got_it != got_ie && "The number of GOTPLT and PLT doesn't match");
+
+ PLTEntry = llvm::cast<ARMPLT1>(&(*m_PLTEntryIterator));
+ GOTPLTEntry = llvm::cast<GOTEntry>(&(*got_it));
+ }
+
+ return GOTPLTEntry;
+}
+
+ARMPLT0* ARMPLT::getPLT0() const {
+
+ iterator first = m_SectionData.getFragmentList().begin();
+ iterator end = m_SectionData.getFragmentList().end();
+
+ assert(first!=end && "FragmentList is empty, getPLT0 failed!");
+
+ ARMPLT0* plt0 = &(llvm::cast<ARMPLT0>(*first));
+
+ return plt0;
+}
+
+void ARMPLT::applyPLT0() {
+
+ uint64_t plt_base = m_Section.addr();
+ assert(plt_base && ".plt base address is NULL!");
+
+ uint64_t got_base = m_GOT.getSection().addr();
+ assert(got_base && ".got base address is NULL!");
+
+ uint32_t offset = 0;
+
+ if (got_base > plt_base)
+ offset = got_base - (plt_base + 16);
+ else
+ offset = (plt_base + 16) - got_base;
+
+ iterator first = m_SectionData.getFragmentList().begin();
+ iterator end = m_SectionData.getFragmentList().end();
+
+ assert(first!=end && "FragmentList is empty, applyPLT0 failed!");
+
+ ARMPLT0* plt0 = &(llvm::cast<ARMPLT0>(*first));
+
+ uint32_t* data = 0;
+ data = static_cast<uint32_t*>(malloc(plt0->getEntrySize()));
+
+ if (!data)
+ llvm::report_fatal_error("Allocating new memory for plt0 failed!");
+
+ memcpy(data, arm_plt0, plt0->getEntrySize());
+ data[4] = offset;
+
+ plt0->setContent(reinterpret_cast<unsigned char*>(data));
+}
+
+void ARMPLT::applyPLT1() {
+
+ uint64_t plt_base = m_Section.addr();
+ assert(plt_base && ".plt base address is NULL!");
+
+ uint64_t got_base = m_GOT.getSection().addr();
+ assert(got_base && ".got base address is NULL!");
+
+ ARMPLT::iterator it = m_SectionData.begin();
+ ARMPLT::iterator ie = m_SectionData.end();
+ assert(it!=ie && "FragmentList is empty, applyPLT1 failed!");
+
+ uint32_t GOTEntrySize = m_GOT.getEntrySize();
+ uint32_t GOTEntryAddress =
+ got_base + GOTEntrySize * 3;
+
+ uint64_t PLTEntryAddress =
+ plt_base + llvm::cast<ARMPLT0>((*it)).getEntrySize(); //Offset of PLT0
+
+ ++it; //skip PLT0
+ uint64_t PLT1EntrySize = llvm::cast<ARMPLT1>((*it)).getEntrySize();
+ ARMPLT1* plt1 = NULL;
+
+ uint32_t* Out = NULL;
+ while (it != ie) {
+ plt1 = &(llvm::cast<ARMPLT1>(*it));
+ Out = static_cast<uint32_t*>(malloc(plt1->getEntrySize()));
+
+ if (!Out)
+ llvm::report_fatal_error("Allocating new memory for plt1 failed!");
+
+ // Offset is the distance between the last PLT entry and the associated
+ // GOT entry.
+ int32_t Offset = (GOTEntryAddress - (PLTEntryAddress + 8));
+
+ Out[0] = arm_plt1[0] | ((Offset >> 20) & 0xFF);
+ Out[1] = arm_plt1[1] | ((Offset >> 12) & 0xFF);
+ Out[2] = arm_plt1[2] | (Offset & 0xFFF);
+
+ plt1->setContent(reinterpret_cast<unsigned char*>(Out));
+ ++it;
+
+ GOTEntryAddress += GOTEntrySize;
+ PLTEntryAddress += PLT1EntrySize;
+ }
+
+ m_GOT.applyAllGOTPLT(plt_base);
+}
+
+uint64_t ARMPLT::emit(MemoryRegion& pRegion)
+{
+ uint64_t result = 0x0;
+ iterator it = begin();
+ unsigned int plt0_size = llvm::cast<ARMPLT0>((*it)).getEntrySize();
+
+ unsigned char* buffer = pRegion.getBuffer();
+ memcpy(buffer, llvm::cast<ARMPLT0>((*it)).getContent(), plt0_size);
+ result += plt0_size;
+ ++it;
+
+ ARMPLT1* plt1 = 0;
+ ARMPLT::iterator ie = end();
+ unsigned int entry_size = 0;
+ while (it != ie) {
+ plt1 = &(llvm::cast<ARMPLT1>(*it));
+ entry_size = plt1->getEntrySize();
+ memcpy(buffer + result, plt1->getContent(), entry_size);
+ result += entry_size;
+ ++it;
+ }
+ return result;
+}
+
diff --git a/lib/Target/ARM/ARMPLT.h b/lib/Target/ARM/ARMPLT.h
new file mode 100644
index 0000000..f55aaa3
--- /dev/null
+++ b/lib/Target/ARM/ARMPLT.h
@@ -0,0 +1,87 @@
+//===- ARMPLT.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ARM_PLT_H
+#define MCLD_ARM_PLT_H
+
+#include <mcld/Target/PLT.h>
+
+namespace mcld {
+
+class ARMGOT;
+class GOTEntry;
+class MemoryRegion;
+
+class ARMPLT0 : public PLTEntry {
+public:
+ ARMPLT0(llvm::MCSectionData* pParent);
+};
+
+class ARMPLT1 : public PLTEntry {
+public:
+ ARMPLT1(llvm::MCSectionData* pParent);
+};
+
+/** \class ARMPLT
+ * \brief ARM Procedure Linkage Table
+ */
+class ARMPLT : public PLT
+{
+ typedef llvm::DenseMap<const ResolveInfo*, ARMPLT1*> SymbolIndexType;
+
+public:
+ typedef llvm::MCSectionData::iterator iterator;
+ typedef llvm::MCSectionData::const_iterator const_iterator;
+
+public:
+ ARMPLT(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ ARMGOT& pGOTPLT);
+ ~ARMPLT();
+
+// Override virtual function.
+public:
+
+ // reserveEntry is ARMGOT friend function.
+ void reserveEntry(size_t pNum = 1) ;
+
+ PLTEntry* getPLTEntry(const ResolveInfo& pSymbol, bool& pExist) ;
+
+ GOTEntry* getGOTPLTEntry(const ResolveInfo& pSymbol, bool& pExist);
+
+public:
+ iterator begin() { return m_SectionData.begin(); }
+
+ const_iterator begin() const { return m_SectionData.begin(); }
+
+ iterator end() { return m_SectionData.end(); }
+
+ const_iterator end() const { return m_SectionData.end(); }
+
+ ARMPLT0* getPLT0() const;
+
+ void applyPLT0();
+
+ void applyPLT1();
+
+ uint64_t emit(MemoryRegion& pRegion);
+
+private:
+ ARMGOT& m_GOT;
+
+ // Used by getEntry() for mapping a ResolveInfo
+ // instance to a PLT1 Entry.
+ iterator m_PLTEntryIterator;
+
+ SymbolIndexType m_PLTEntryMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/ARMRelocationFactory.cpp b/lib/Target/ARM/ARMRelocationFactory.cpp
new file mode 100644
index 0000000..2763b3b
--- /dev/null
+++ b/lib/Target/ARM/ARMRelocationFactory.cpp
@@ -0,0 +1,861 @@
+//===- ARMRelocationFactory.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/ErrorHandling.h>
+#include <llvm/Support/DataTypes.h>
+#include <llvm/Support/ELF.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/LD/Layout.h>
+
+#include "ARMRelocationFactory.h"
+#include "ARMRelocationFunctions.h"
+
+using namespace mcld;
+
+DECL_ARM_APPLY_RELOC_FUNCS
+
+//===--------------------------------------------------------------------===//
+// ARMRelocationFactory
+ARMRelocationFactory::ARMRelocationFactory(size_t pNum,
+ ARMGNULDBackend& pParent)
+ : RelocationFactory(pNum),
+ m_Target(pParent) {
+}
+
+ARMRelocationFactory::~ARMRelocationFactory()
+{
+}
+
+void ARMRelocationFactory::applyRelocation(Relocation& pRelocation,
+ const MCLDInfo& pLDInfo)
+{
+ Relocation::Type type = pRelocation.type();
+ if (type > 130) { // 131-255 doesn't noted in ARM spec
+ llvm::report_fatal_error(llvm::Twine("Unknown relocation type. "
+ "To symbol `") +
+ pRelocation.symInfo()->name() +
+ llvm::Twine("'."));
+ return;
+ }
+
+ /// the prototype of applying function
+ typedef Result (*ApplyFunctionType)(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent);
+
+ // the table entry of applying functions
+ struct ApplyFunctionTriple {
+ ApplyFunctionType func;
+ unsigned int type;
+ const char* name;
+ };
+
+ // declare the table of applying functions
+ static ApplyFunctionTriple apply_functions[] = {
+ DECL_ARM_APPLY_RELOC_FUNC_PTRS
+ };
+
+ // apply the relocation
+ Result result = apply_functions[type].func(pRelocation, pLDInfo, *this);
+
+ // check result
+ if (OK == result) {
+ return;
+ }
+ if (Overflow == result) {
+ llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
+ llvm::Twine(apply_functions[type].name) +
+ llvm::Twine("' causes overflow. on symbol: `") +
+ llvm::Twine(pRelocation.symInfo()->name()) +
+ llvm::Twine("'."));
+ return;
+ }
+
+ if (BadReloc == result) {
+ llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
+ llvm::Twine(apply_functions[type].name) +
+ llvm::Twine("' encounters unexpected opcode. "
+ "on symbol: `") +
+ llvm::Twine(pRelocation.symInfo()->name()) +
+ llvm::Twine("'."));
+ return;
+ }
+ if (Unsupport == result) {
+ llvm::report_fatal_error(llvm::Twine("Encounter unsupported relocation `") +
+ llvm::Twine(apply_functions[type].name) +
+ llvm::Twine("' on symbol: `") +
+ llvm::Twine(pRelocation.symInfo()->name()) +
+ llvm::Twine("'."));
+ return;
+ }
+}
+
+
+
+//===--------------------------------------------------------------------===//
+// non-member functions
+static RelocationFactory::DWord getThumbBit(const Relocation& pReloc)
+{
+ // Set thumb bit if
+ // - symbol has type of STT_FUNC, is defined and with bit 0 of its value set
+ RelocationFactory::DWord thumbBit =
+ ((pReloc.symInfo()->desc() != ResolveInfo::Undefined) &&
+ (pReloc.symInfo()->type() == ResolveInfo::Function) &&
+ ((pReloc.symValue() & 0x1) != 0))?
+ 1:0;
+ return thumbBit;
+}
+
+
+
+
+//=========================================//
+// Relocation helper function //
+//=========================================//
+
+// Using uint64_t to make sure those complicate operations won't cause
+// undefined behavior.
+static
+uint64_t helper_sign_extend(uint64_t pVal, uint64_t pOri_width)
+{
+ assert(pOri_width <= 64);
+ uint64_t sign_bit = 1 << (pOri_width - 1);
+ return (pVal ^ sign_bit) - sign_bit;
+ // Reverse sign bit, then subtract sign bit.
+}
+
+static
+uint64_t helper_bit_select(uint64_t pA, uint64_t pB, uint64_t pMask)
+{
+ return (pA & ~pMask) | (pB & pMask) ;
+}
+
+// Check if symbol can use relocation R_ARM_RELATIVE
+static bool
+helper_use_relative_reloc(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const ARMRelocationFactory& pFactory)
+{
+ // if symbol is dynamic or undefine or preemptible
+ if(pSym.isDyn() ||
+ pSym.isUndef() ||
+ pFactory.getTarget().isSymbolPreemptible(pSym,
+ pLDInfo,
+ pLDInfo.output()))
+ return false;
+ return true;
+}
+
+static
+GOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMGNULDBackend& ld_backend = pParent.getTarget();
+
+ bool exist;
+ GOTEntry& got_entry = *ld_backend.getGOT().getEntry(*rsym, exist);
+ if (!exist) {
+ // If we first get this GOT entry, we should initialize it.
+ if (rsym->reserved() & ARMGNULDBackend::ReserveGOT) {
+ // No corresponding dynamic relocation, initialize to the symbol value.
+ got_entry.setContent(pReloc.symValue());
+ }
+ else if (rsym->reserved() & ARMGNULDBackend::GOTRel) {
+
+ // Initialize corresponding dynamic relocation.
+ Relocation& rel_entry =
+ *ld_backend.getRelDyn().getEntry(*rsym, true, exist);
+ assert(!exist && "GOT entry not exist, but DynRel entry exist!");
+ if( rsym->isLocal() ||
+ helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
+ // Initialize got entry to target symbol address
+ got_entry.setContent(pReloc.symValue());
+ rel_entry.setType(llvm::ELF::R_ARM_RELATIVE);
+ rel_entry.setSymInfo(0);
+ }
+ else {
+ // Initialize got entry to 0 for corresponding dynamic relocation.
+ got_entry.setContent(0);
+ rel_entry.setType(llvm::ELF::R_ARM_GLOB_DAT);
+ rel_entry.setSymInfo(rsym);
+ }
+ rel_entry.targetRef().assign(got_entry);
+ }
+ else {
+ llvm::report_fatal_error("No GOT entry reserved for GOT type relocation!");
+ }
+ }
+ return got_entry;
+}
+
+static
+ARMRelocationFactory::Address helper_GOT_ORG(ARMRelocationFactory& pParent)
+{
+ return pParent.getTarget().getGOT().getSection().addr();
+}
+
+
+static
+ARMRelocationFactory::Address helper_GOT(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pLDInfo, pParent);
+ return helper_GOT_ORG(pParent) + pParent.getLayout().getOutputOffset(got_entry);
+}
+
+
+static
+PLTEntry& helper_get_PLT_and_init(Relocation& pReloc,
+ ARMRelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMGNULDBackend& ld_backend = pParent.getTarget();
+
+ bool exist;
+ PLTEntry& plt_entry = *ld_backend.getPLT().getPLTEntry(*rsym, exist);
+ if (!exist) {
+ // If we first get this PLT entry, we should initialize it.
+ if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
+ GOTEntry& gotplt_entry =
+ *ld_backend.getPLT().getGOTPLTEntry(*rsym, exist);
+ // Initialize corresponding dynamic relocation.
+ Relocation& rel_entry =
+ *ld_backend.getRelPLT().getEntry(*rsym, true, exist);
+ assert(!exist && "PLT entry not exist, but DynRel entry exist!");
+ rel_entry.setType(llvm::ELF::R_ARM_JUMP_SLOT);
+ rel_entry.targetRef().assign(gotplt_entry);
+ rel_entry.setSymInfo(rsym);
+ }
+ else {
+ llvm::report_fatal_error("No PLT entry reserved for PLT type relocation!");
+ }
+ }
+ return plt_entry;
+}
+
+
+
+static
+ARMRelocationFactory::Address helper_PLT_ORG(ARMRelocationFactory& pParent)
+{
+ return pParent.getTarget().getPLT().getSection().addr();
+}
+
+
+static
+ARMRelocationFactory::Address helper_PLT(Relocation& pReloc,
+ ARMRelocationFactory& pParent)
+{
+ PLTEntry& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
+ return helper_PLT_ORG(pParent) + pParent.getLayout().getOutputOffset(plt_entry);
+}
+
+// Get an relocation entry in .rel.dyn and set its type to pType,
+// its FragmentRef to pReloc->targetFrag() and its ResolveInfo to pReloc->symInfo()
+static
+void helper_DynRel(Relocation& pReloc,
+ ARMRelocationFactory::Type pType,
+ ARMRelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMGNULDBackend& ld_backend = pParent.getTarget();
+ bool exist;
+
+ Relocation& rel_entry =
+ *ld_backend.getRelDyn().getEntry(*rsym, false, exist);
+ rel_entry.setType(pType);
+ rel_entry.targetRef() = pReloc.targetRef();
+
+ if(pType == llvm::ELF::R_ARM_RELATIVE)
+ rel_entry.setSymInfo(0);
+ else
+ rel_entry.setSymInfo(rsym);
+}
+
+static ARMRelocationFactory::DWord
+helper_extract_movw_movt_addend(ARMRelocationFactory::DWord pTarget)
+{
+ // imm16: [19-16][11-0]
+ return helper_sign_extend((((pTarget >> 4)) & 0xf000U) | (pTarget & 0xfffU),
+ 16);
+}
+
+static ARMRelocationFactory::DWord
+helper_insert_val_movw_movt_inst(ARMRelocationFactory::DWord pTarget,
+ ARMRelocationFactory::DWord pImm)
+{
+ // imm16: [19-16][11-0]
+ pTarget &= 0xfff0f000U;
+ pTarget |= pImm & 0x0fffU;
+ pTarget |= (pImm & 0xf000U) << 4;
+ return pTarget;
+}
+
+static ARMRelocationFactory::DWord
+helper_extract_thumb_movw_movt_addend(ARMRelocationFactory::DWord pTarget)
+{
+ // TODO: By the rsloader experience: If we use 32bit, we need to consider
+ // endianness problem. We'd better have a thumb instruction type.
+ // imm16: [19-16][26][14-12][7-0]
+ return helper_sign_extend((((pTarget >> 4) & 0xf000U) |
+ ((pTarget >> 15) & 0x0800U) |
+ ((pTarget >> 4) & 0x0700U) |
+ (pTarget & 0x00ffU)),
+ 16);
+}
+
+static ARMRelocationFactory::DWord
+helper_insert_val_thumb_movw_movt_inst(ARMRelocationFactory::DWord pTarget,
+ ARMRelocationFactory::DWord pImm)
+{
+ // TODO: By the rsloader experience: If we use 32bit, we need to consider
+ // endianness problem. We'd better have a thumb instruction type.
+ // imm16: [19-16][26][14-12][7-0]
+ pTarget &= 0xfbf08f00U;
+ pTarget |= (pImm & 0xf000U) << 4;
+ pTarget |= (pImm & 0x0800U) << 15;
+ pTarget |= (pImm & 0x0700U) << 4;
+ pTarget |= (pImm & 0x00ffU);
+ return pTarget;
+}
+
+static ARMRelocationFactory::DWord
+helper_thumb32_branch_offset(ARMRelocationFactory::DWord pUpper16,
+ ARMRelocationFactory::DWord pLower16)
+{
+ ARMRelocationFactory::DWord s = (pUpper16 & (1U << 10)) >> 10, // 26 bit
+ u = pUpper16 & 0x3ffU, // 25-16
+ l = pLower16 & 0x7ffU, // 10-0
+ j1 = (pLower16 & (1U << 13)) >> 13, // 13
+ j2 = (pLower16 & (1U << 11)) >> 11; // 11
+ ARMRelocationFactory::DWord i1 = j1 ^ s? 0: 1,
+ i2 = j2 ^ s? 0: 1;
+
+ // [31-25][24][23][22][21-12][11-1][0]
+ // 0 s i1 i2 u l 0
+ return helper_sign_extend((s << 24) | (i1 << 23) | (i2 << 22) |
+ (u << 12) | (l << 1),
+ 25);
+}
+
+static ARMRelocationFactory::DWord
+helper_thumb32_branch_upper(ARMRelocationFactory::DWord pUpper16,
+ ARMRelocationFactory::DWord pOffset)
+{
+ uint32_t sign = ((pOffset & 0x80000000U) >> 31);
+ return (pUpper16 & ~0x7ffU) | ((pOffset >> 12) & 0x3ffU) | (sign << 10);
+}
+
+static ARMRelocationFactory::DWord
+helper_thumb32_branch_lower(ARMRelocationFactory::DWord pLower16,
+ ARMRelocationFactory::DWord pOffset)
+{
+ uint32_t sign = ((pOffset & 0x80000000U) >> 31);
+ return ((pLower16 & ~0x2fffU) |
+ ((((pOffset >> 23) & 1) ^ !sign) << 13) |
+ ((((pOffset >> 22) & 1) ^ !sign) << 11) |
+ ((pOffset >> 1) & 0x7ffU));
+}
+
+// Return true if overflow
+static bool
+helper_check_signed_overflow(ARMRelocationFactory::DWord pValue,
+ unsigned bits)
+{
+ int32_t signed_val = static_cast<int32_t>(pValue);
+ int32_t max = (1 << (bits - 1)) - 1;
+ int32_t min = -(1 << (bits - 1));
+ if (signed_val > max || signed_val < min) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+//=========================================//
+// Each relocation function implementation //
+//=========================================//
+
+// R_ARM_NONE
+ARMRelocationFactory::Result none(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_ABS32: (S + A) | T
+ARMRelocationFactory::Result abs32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ ARMRelocationFactory::DWord S = pReloc.symValue();
+
+ if(rsym->isLocal() && (rsym->reserved() & 0x1u)) {
+ helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent);
+ pReloc.target() = (S + A) | T ;
+ return ARMRelocationFactory::OK;
+ }
+ else if(!rsym->isLocal()) {
+ if(rsym->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0 ; // PLT is not thumb
+ pReloc.target() = (S + A) | T;
+ }
+ // If we generate a dynamic relocation (except R_ARM_RELATIVE)
+ // for a place, we should not perform static relocation on it
+ // in order to keep the addend store in the place correct.
+ if(rsym->reserved() & 0x1u) {
+ if(helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
+ helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent);
+ }
+ else {
+ helper_DynRel(pReloc, pReloc.type(), pParent);
+ return ARMRelocationFactory::OK;
+ }
+ }
+ }
+
+ // perform static relocation
+ pReloc.target() = (S + A) | T;
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_REL32: ((S + A) | T) - P
+ARMRelocationFactory::Result rel32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ // perform static relocation
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ pReloc.target() = ((pReloc.symValue() + A) | T)
+ - pReloc.place(pParent.getLayout());
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_BASE_PREL: B(S) + A - P
+ARMRelocationFactory::Result base_prel(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ // perform static relocation
+ ARMRelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ pReloc.target() = pReloc.symValue() + A - pReloc.place(pParent.getLayout());
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_GOTOFF32: ((S + A) | T) - GOT_ORG
+ARMRelocationFactory::Result gotoff32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ ARMRelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
+ ARMRelocationFactory::Address S = pReloc.symValue();
+
+ pReloc.target() = ((S + A) | T) - GOT_ORG;
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_GOT_BREL: GOT(S) + A - GOT_ORG
+ARMRelocationFactory::Result got_brel(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ if(!(pReloc.symInfo()->reserved() & 0x6u)) {
+ return ARMRelocationFactory::BadReloc;
+ }
+ ARMRelocationFactory::Address GOT_S = helper_GOT(pReloc, pLDInfo, pParent);
+ ARMRelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ ARMRelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
+ // Apply relocation.
+ pReloc.target() = GOT_S + A - GOT_ORG;
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_GOT_PREL: GOT(S) + A - P
+ARMRelocationFactory::Result got_prel(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ if(!(pReloc.symInfo()->reserved() & 0x6u)) {
+ return ARMRelocationFactory::BadReloc;
+ }
+ ARMRelocationFactory::Address GOT_S = helper_GOT(pReloc, pLDInfo, pParent);
+ ARMRelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ ARMRelocationFactory::Address P = pReloc.place(pParent.getLayout());
+ // Apply relocation.
+ pReloc.target() = GOT_S + A - P;
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_PLT32: ((S + A) | T) - P
+// R_ARM_JUMP24: ((S + A) | T) - P
+// R_ARM_CALL: ((S + A) | T) - P
+ARMRelocationFactory::Result call(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ // TODO: Some issue have not been considered, e.g. thumb, overflow?
+
+ // If target is undefined weak symbol, we only need to jump to the
+ // next instruction unless it has PLT entry.
+ if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
+ !(pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT)) {
+ // change target to NOP : mov r0, r0
+ pReloc.target() = (pReloc.target() & 0xf0000000U) | 0x01a00000;
+ return ARMRelocationFactory::OK;
+ }
+
+ ARMRelocationFactory::Address S; // S dependent on exist PLT or not.
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A =
+ helper_sign_extend((pReloc.target() & 0x00FFFFFFu) << 2, 26)
+ + pReloc.addend();
+ ARMRelocationFactory::Address P = pReloc.place(pParent.getLayout());
+
+ S = pReloc.symValue();
+ if( pReloc.symInfo()->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0; // PLT is not thumb.
+ }
+
+ ARMRelocationFactory::DWord X = ((S + A) | T) - P;
+
+ if (X & 0x03u) { // Lowest two bit is not zero.
+ llvm::report_fatal_error("Target is thumb, need stub!");
+ }
+ // Check X is 24bit sign int. If not, we should use stub or PLT before apply.
+ assert(!helper_check_signed_overflow(X, 26) && "Jump or Call target too far!");
+ // Make sure the Imm is 0. Result Mask.
+ pReloc.target() = (pReloc.target() & 0xFF000000u) | ((X & 0x03FFFFFEu) >> 2);
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_THM_CALL: ((S + A) | T) - P
+ARMRelocationFactory::Result thm_call(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ // If target is undefined weak symbol, we only need to jump to the
+ // next instruction unless it has PLT entry.
+ if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
+ !(pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT)) {
+ pReloc.target() = (0xe000U << 16) | 0xbf00U;
+ return ARMRelocationFactory::OK;
+ }
+
+ // TODO: By the rsloader experience: If we use 32bit, we need to consider
+ // endianness problem. Here is an ugly solution. We'd better have a thumb
+ // instruction type.
+ //uint16_t upper16 = *(
+ // reinterpret_cast<uint16_t*>(&pReloc.target())
+ // ),
+ // lower16 = *(
+ // reinterpret_cast<uint16_t*>(&pReloc.target()) + 1
+ // );
+ ARMRelocationFactory::DWord upper16 = ((pReloc.target() & 0xffff0000U) >> 16),
+ lower16 = (pReloc.target() & 0xffffU);
+
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A = helper_thumb32_branch_offset(upper16,
+ lower16);
+ ARMRelocationFactory::Address P = pReloc.place(pParent.getLayout());
+ ARMRelocationFactory::Address S;
+
+ S = pReloc.symValue();
+ // if symbol has plt
+ if( pReloc.symInfo()->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0; // PLT is not thumb.
+ }
+
+ // TODO: If the target is not thumb, we should rewrite instruction to BLX.
+
+ ARMRelocationFactory::DWord X = ((S + A) | T) - P;
+ X >>= 1;
+
+ // FIXME: Check bit size is 24(thumb2) or 22?
+ if (helper_check_signed_overflow(X, 24)) {
+ assert(!"Offset is too far. We need stub or PLT for it.");
+ return ARMRelocationFactory::Overflow;
+ }
+
+ // For a BLX instruction, make sure that the relocation is rounded up
+ // to a word boundary. This follows the semantics of the instruction
+ // which specifies that bit 1 of the target address will come from bit
+ // 1 of the base address.
+ if ((X & 0x5000U) == 0x4000U) {
+ X = (X + 2) & ~0x3U;
+ }
+
+ upper16 = helper_thumb32_branch_upper(upper16, X);
+ lower16 = helper_thumb32_branch_lower(lower16, X);
+
+ // TODO: By the rsloader experience: If we use 32bit, we need to consider
+ // endianness problem. Here is an ugly solution. We'd better have a thumb
+ // instruction type.
+ //*(reinterpret_cast<uint16_t*>(&preloc.target())) = upper16;
+ //*(reinterpret_cast<uint16_t*>(&preloc.target()) + 1) = lower16;
+ pReloc.target() = (upper16 << 16);
+ pReloc.target() |= lower16;
+
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_MOVW_ABS_NC: (S + A) | T
+ARMRelocationFactory::Result movw_abs_nc(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A =
+ helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ // use plt
+ if(rsym->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0 ; // PLT is not thumb
+ }
+ X = (S + A) | T ;
+ // perform static relocation
+ pReloc.target() = (S + A) | T;
+ if (helper_check_signed_overflow(X, 16)) {
+ return ARMRelocationFactory::Overflow;
+ } else {
+ pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
+ return ARMRelocationFactory::OK;
+ }
+}
+
+// R_ARM_MOVW_PREL_NC: ((S + A) | T) - P
+ARMRelocationFactory::Result movw_prel_nc(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord P = pReloc.place(pParent.getLayout());
+ ARMRelocationFactory::DWord A =
+ helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ X = ((S + A) | T) - P;
+
+ if (helper_check_signed_overflow(X, 16)) {
+ return ARMRelocationFactory::Overflow;
+ } else {
+ pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
+ return ARMRelocationFactory::OK;
+ }
+}
+
+// R_ARM_MOVT_ABS: S + A
+ARMRelocationFactory::Result movt_abs(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord A =
+ helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ // use plt
+ if(rsym->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ }
+
+ X = S + A;
+ X >>= 16;
+ // perform static relocation
+ pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_MOVT_PREL: S + A - P
+ARMRelocationFactory::Result movt_prel(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord P = pReloc.place(pParent.getLayout());
+ ARMRelocationFactory::DWord A =
+ helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ X = S + A - P;
+ X >>= 16;
+
+ pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_THM_MOVW_ABS_NC: (S + A) | T
+ARMRelocationFactory::Result thm_movw_abs_nc(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A =
+ helper_extract_thumb_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ // use plt
+ if(rsym->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0; // PLT is not thumb
+ }
+ X = (S + A) | T;
+ // check 16-bit overflow
+ if (helper_check_signed_overflow(X, 16)) {
+ return ARMRelocationFactory::Overflow;
+ } else {
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ X);
+ return ARMRelocationFactory::OK;
+ }
+}
+
+// R_ARM_THM_MOVW_PREL_NC: ((S + A) | T) - P
+ARMRelocationFactory::Result thm_movw_prel_nc(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord P = pReloc.place(pParent.getLayout());
+ ARMRelocationFactory::DWord A =
+ helper_extract_thumb_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ X = ((S + A) | T) - P;
+
+ // check 16-bit overflow
+ if (helper_check_signed_overflow(X, 16)) {
+ return ARMRelocationFactory::Overflow;
+ } else {
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ X);
+ return ARMRelocationFactory::OK;
+ }
+}
+
+// R_ARM_THM_MOVT_ABS: S + A
+ARMRelocationFactory::Result thm_movt_abs(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord A =
+ helper_extract_thumb_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ // use plt
+ if(rsym->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ }
+ X = S + A;
+ X >>= 16;
+
+ // check 16-bit overflow
+ if (helper_check_signed_overflow(X, 16)) {
+ return ARMRelocationFactory::Overflow;
+ } else {
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ X);
+ return ARMRelocationFactory::OK;
+ }
+}
+
+// R_ARM_THM_MOVT_PREL: S + A - P
+ARMRelocationFactory::Result thm_movt_prel(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord P = pReloc.place(pParent.getLayout());
+ ARMRelocationFactory::DWord A =
+ helper_extract_thumb_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ X = S + A - P;
+ X >>= 16;
+
+ // check 16-bit overflow
+ if (helper_check_signed_overflow(X, 16)) {
+ return ARMRelocationFactory::Overflow;
+ } else {
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ X);
+ return ARMRelocationFactory::OK;
+ }
+}
+
+// R_ARM_PREL31: (S + A) | T
+ARMRelocationFactory::Result prel31(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ARMRelocationFactory::DWord target = pReloc.target();
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A = helper_sign_extend(target, 31) +
+ pReloc.addend();
+ ARMRelocationFactory::Address S;
+
+ S = pReloc.symValue();
+ // if symbol has plt
+ if( pReloc.symInfo()->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0; // PLT is not thumb.
+ }
+
+ ARMRelocationFactory::DWord X = (S + A) | T ;
+ pReloc.target() = helper_bit_select(target, X, 0x7fffffffU);
+ if(helper_check_signed_overflow(X, 31))
+ return ARMRelocationFactory::Overflow;
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_TLS_GD32: GOT(S) + A - P
+// R_ARM_TLS_IE32: GOT(S) + A - P
+// R_ARM_TLS_LE32: S + A - tp
+ARMRelocationFactory::Result tls(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ llvm::report_fatal_error("We don't support TLS relocation yet.");
+ return ARMRelocationFactory::Unsupport;
+}
+
+ARMRelocationFactory::Result unsupport(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ return ARMRelocationFactory::Unsupport;
+}
diff --git a/lib/Target/ARM/ARMRelocationFactory.h b/lib/Target/ARM/ARMRelocationFactory.h
new file mode 100644
index 0000000..636dbee
--- /dev/null
+++ b/lib/Target/ARM/ARMRelocationFactory.h
@@ -0,0 +1,59 @@
+//===- ARMRelocationFactory.h --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef ARM_RELOCATION_FACTORY_H
+#define ARM_RELOCATION_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/RelocationFactory.h>
+#include <mcld/Target/GOT.h>
+#include "ARMLDBackend.h"
+
+namespace mcld
+{
+
+/** \class ARMRelocationFactory
+ * \brief ARMRelocationFactory creates and destroys the ARM relocations.
+ *
+ */
+class ARMRelocationFactory : public RelocationFactory
+{
+public:
+ /** \enum Reloc
+ * \brief Reloc is the result of applying functions.
+ */
+ enum Result
+ {
+ OK,
+ Overflow,
+ BadReloc,
+ Unsupport
+ };
+
+public:
+ ARMRelocationFactory(size_t pNum, ARMGNULDBackend& pParent);
+ ~ARMRelocationFactory();
+
+ void applyRelocation(Relocation& pRelocation, const MCLDInfo& pLDInfo);
+
+ ARMGNULDBackend& getTarget()
+ { return m_Target; }
+
+ const ARMGNULDBackend& getTarget() const
+ { return m_Target; }
+
+private:
+ ARMGNULDBackend& m_Target;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/ARMRelocationFunctions.h b/lib/Target/ARM/ARMRelocationFunctions.h
new file mode 100644
index 0000000..10d27a4
--- /dev/null
+++ b/lib/Target/ARM/ARMRelocationFunctions.h
@@ -0,0 +1,169 @@
+//===- ARMRelocationFunction.h --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define DECL_ARM_APPLY_RELOC_FUNC(Name) \
+static ARMRelocationFactory::Result Name (Relocation& pEntry, \
+ const MCLDInfo& pLDInfo, \
+ ARMRelocationFactory& pParent);
+
+#define DECL_ARM_APPLY_RELOC_FUNCS \
+DECL_ARM_APPLY_RELOC_FUNC(none) \
+DECL_ARM_APPLY_RELOC_FUNC(abs32) \
+DECL_ARM_APPLY_RELOC_FUNC(rel32) \
+DECL_ARM_APPLY_RELOC_FUNC(gotoff32) \
+DECL_ARM_APPLY_RELOC_FUNC(base_prel) \
+DECL_ARM_APPLY_RELOC_FUNC(got_brel) \
+DECL_ARM_APPLY_RELOC_FUNC(call) \
+DECL_ARM_APPLY_RELOC_FUNC(thm_call) \
+DECL_ARM_APPLY_RELOC_FUNC(movw_prel_nc) \
+DECL_ARM_APPLY_RELOC_FUNC(movw_abs_nc) \
+DECL_ARM_APPLY_RELOC_FUNC(movt_abs) \
+DECL_ARM_APPLY_RELOC_FUNC(movt_prel) \
+DECL_ARM_APPLY_RELOC_FUNC(thm_movw_abs_nc) \
+DECL_ARM_APPLY_RELOC_FUNC(thm_movw_prel_nc) \
+DECL_ARM_APPLY_RELOC_FUNC(thm_movt_abs) \
+DECL_ARM_APPLY_RELOC_FUNC(thm_movt_prel) \
+DECL_ARM_APPLY_RELOC_FUNC(prel31) \
+DECL_ARM_APPLY_RELOC_FUNC(got_prel) \
+DECL_ARM_APPLY_RELOC_FUNC(tls) \
+DECL_ARM_APPLY_RELOC_FUNC(unsupport)
+
+
+#define DECL_ARM_APPLY_RELOC_FUNC_PTRS \
+ { &none, 0, "R_ARM_NONE" }, \
+ { &unsupport, 1, "R_ARM_PC24" }, \
+ { &abs32, 2, "R_ARM_ABS32" }, \
+ { &rel32, 3, "R_ARM_REL32" }, \
+ { &unsupport, 4, "R_ARM_LDR_PC_G0" }, \
+ { &unsupport, 5, "R_ARM_ABS16" }, \
+ { &unsupport, 6, "R_ARM_ABS12" }, \
+ { &unsupport, 7, "R_ARM_THM_ABS5" }, \
+ { &unsupport, 8, "R_ARM_ABS8" }, \
+ { &unsupport, 9, "R_ARM_SBREL32" }, \
+ { &thm_call, 10, "R_ARM_THM_CALL" }, \
+ { &unsupport, 11, "R_ARM_THM_PC8" }, \
+ { &unsupport, 12, "R_ARM_BREL_ADJ" }, \
+ { &unsupport, 13, "R_ARM_TLS_DESC" }, \
+ { &unsupport, 14, "R_ARM_THM_SWI8" }, \
+ { &unsupport, 15, "R_ARM_XPC25" }, \
+ { &unsupport, 16, "R_ARM_THM_XPC22" }, \
+ { &unsupport, 17, "R_ARM_TLS_DTPMOD32" }, \
+ { &unsupport, 18, "R_ARM_TLS_DTPOFF32" }, \
+ { &unsupport, 19, "R_ARM_TLS_TPOFF32" }, \
+ { &unsupport, 20, "R_ARM_COPY" }, \
+ { &unsupport, 21, "R_ARM_GLOB_DAT" }, \
+ { &unsupport, 22, "R_ARM_JUMP_SLOT" }, \
+ { &unsupport, 23, "R_ARM_RELATIVE" }, \
+ { &gotoff32, 24, "R_ARM_GOTOFF32" }, \
+ { &base_prel, 25, "R_ARM_BASE_PREL" }, \
+ { &got_brel, 26, "R_ARM_GOT_BREL" }, \
+ { &call, 27, "R_ARM_PLT32" }, \
+ { &call, 28, "R_ARM_CALL" }, \
+ { &call, 29, "R_ARM_JUMP24" }, \
+ { &unsupport, 30, "R_ARM_THM_JUMP24" }, \
+ { &unsupport, 31, "R_ARM_BASE_ABS" }, \
+ { &unsupport, 32, "R_ARM_ALU_PCREL_7_0" }, \
+ { &unsupport, 33, "R_ARM_ALU_PCREL_15_8" }, \
+ { &unsupport, 34, "R_ARM_ALU_PCREL_23_15" }, \
+ { &unsupport, 35, "R_ARM_LDR_SBREL_11_0_NC" }, \
+ { &unsupport, 36, "R_ARM_ALU_SBREL_19_12_NC"}, \
+ { &unsupport, 37, "R_ARM_ALU_SBREL_27_20_CK"}, \
+ { &abs32, 38, "R_ARM_TARGET1" }, \
+ { &unsupport, 39, "R_ARM_SBREL31" }, \
+ { &unsupport, 40, "R_ARM_V4BX" }, \
+ { &got_prel, 41, "R_ARM_TARGET2" }, \
+ { &prel31, 42, "R_ARM_PREL31" }, \
+ { &movw_abs_nc, 43, "R_ARM_MOVW_ABS_NC" }, \
+ { &movt_abs, 44, "R_ARM_MOVT_ABS" }, \
+ { &movw_prel_nc, 45, "R_ARM_MOVW_PREL_NC" }, \
+ { &movt_prel, 46, "R_ARM_MOVT_PREL" }, \
+ { &thm_movw_abs_nc, 47, "R_ARM_THM_MOVW_ABS_NC" }, \
+ { &thm_movt_abs, 48, "R_ARM_THM_MOVT_ABS" }, \
+ { &thm_movw_prel_nc, 49, "R_ARM_THM_MOVW_PREL_NC" }, \
+ { &thm_movt_prel, 50, "R_ARM_THM_MOVT_PREL" }, \
+ { &unsupport, 51, "R_ARM_THM_JUMP19" }, \
+ { &unsupport, 52, "R_ARM_THM_JUMP6" }, \
+ { &unsupport, 53, "R_ARM_THM_ALU_PREL_11_0" }, \
+ { &unsupport, 54, "R_ARM_THM_PC12" }, \
+ { &unsupport, 55, "R_ARM_ABS32_NOI" }, \
+ { &unsupport, 56, "R_ARM_REL32_NOI" }, \
+ { &unsupport, 57, "R_ARM_ALU_PC_G0_NC" }, \
+ { &unsupport, 58, "R_ARM_ALU_PC_G0" }, \
+ { &unsupport, 59, "R_ARM_ALU_PC_G1_NC" }, \
+ { &unsupport, 60, "R_ARM_ALU_PC_G1" }, \
+ { &unsupport, 61, "R_ARM_ALU_PC_G2" }, \
+ { &unsupport, 62, "R_ARM_LDR_PC_G1" }, \
+ { &unsupport, 63, "R_ARM_LDR_PC_G2" }, \
+ { &unsupport, 64, "R_ARM_LDRS_PC_G0" }, \
+ { &unsupport, 65, "R_ARM_LDRS_PC_G1" }, \
+ { &unsupport, 66, "R_ARM_LDRS_PC_G2" }, \
+ { &unsupport, 67, "R_ARM_LDC_PC_G0" }, \
+ { &unsupport, 68, "R_ARM_LDC_PC_G1" }, \
+ { &unsupport, 69, "R_ARM_LDC_PC_G2" }, \
+ { &unsupport, 70, "R_ARM_ALU_SB_G0_NC" }, \
+ { &unsupport, 71, "R_ARM_ALU_SB_G0" }, \
+ { &unsupport, 72, "R_ARM_ALU_SB_G1_NC" }, \
+ { &unsupport, 73, "R_ARM_ALU_SB_G1" }, \
+ { &unsupport, 74, "R_ARM_ALU_SB_G2" }, \
+ { &unsupport, 75, "R_ARM_LDR_SB_G0" }, \
+ { &unsupport, 76, "R_ARM_LDR_SB_G1" }, \
+ { &unsupport, 77, "R_ARM_LDR_SB_G2" }, \
+ { &unsupport, 78, "R_ARM_LDRS_SB_G0" }, \
+ { &unsupport, 79, "R_ARM_LDRS_SB_G1" }, \
+ { &unsupport, 80, "R_ARM_LDRS_SB_G2" }, \
+ { &unsupport, 81, "R_ARM_LDC_SB_G0" }, \
+ { &unsupport, 82, "R_ARM_LDC_SB_G1" }, \
+ { &unsupport, 83, "R_ARM_LDC_SB_G2" }, \
+ { &unsupport, 84, "R_ARM_MOVW_BREL_NC" }, \
+ { &unsupport, 85, "R_ARM_MOVT_BREL" }, \
+ { &unsupport, 86, "R_ARM_MOVW_BREL" }, \
+ { &unsupport, 87, "R_ARM_THM_MOVW_BREL_NC" }, \
+ { &unsupport, 88, "R_ARM_THM_MOVT_BREL" }, \
+ { &unsupport, 89, "R_ARM_THM_MOVW_BREL" }, \
+ { &unsupport, 90, "R_ARM_TLS_GOTDESC" }, \
+ { &unsupport, 91, "R_ARM_TLS_CALL" }, \
+ { &unsupport, 92, "R_ARM_TLS_DESCSEQ" }, \
+ { &unsupport, 93, "R_ARM_THM_TLS_CALL" }, \
+ { &unsupport, 94, "R_ARM_PLT32_ABS" }, \
+ { &unsupport, 95, "R_ARM_GOT_ABS" }, \
+ { &got_prel, 96, "R_ARM_GOT_PREL" }, \
+ { &unsupport, 97, "R_ARM_GOT_PREL12" }, \
+ { &unsupport, 98, "R_ARM_GOTOFF12" }, \
+ { &unsupport, 99, "R_ARM_GOTRELAX" }, \
+ { &unsupport, 100, "R_ARM_GNU_VTENTRY" }, \
+ { &unsupport, 101, "R_ARM_GNU_VTINERIT" }, \
+ { &unsupport, 102, "R_ARM_THM_JUMP11" }, \
+ { &unsupport, 103, "R_ARM_THM_JUMP8" }, \
+ { &tls, 104, "R_ARM_TLS_GD32" }, \
+ { &unsupport, 105, "R_ARM_TLS_LDM32" }, \
+ { &unsupport, 106, "R_ARM_TLS_LDO32" }, \
+ { &tls, 107, "R_ARM_TLS_IE32" }, \
+ { &tls, 108, "R_ARM_TLS_LE32" }, \
+ { &unsupport, 109, "R_ARM_TLS_LDO12" }, \
+ { &unsupport, 110, "R_ARM_TLS_LE12" }, \
+ { &unsupport, 111, "R_ARM_TLS_IE12GP" }, \
+ { &unsupport, 112, "R_ARM_PRIVATE_0" }, \
+ { &unsupport, 113, "R_ARM_PRIVATE_1" }, \
+ { &unsupport, 114, "R_ARM_PRIVATE_2" }, \
+ { &unsupport, 115, "R_ARM_PRIVATE_3" }, \
+ { &unsupport, 116, "R_ARM_PRIVATE_4" }, \
+ { &unsupport, 117, "R_ARM_PRIVATE_5" }, \
+ { &unsupport, 118, "R_ARM_PRIVATE_6" }, \
+ { &unsupport, 119, "R_ARM_PRIVATE_7" }, \
+ { &unsupport, 120, "R_ARM_PRIVATE_8" }, \
+ { &unsupport, 121, "R_ARM_PRIVATE_9" }, \
+ { &unsupport, 122, "R_ARM_PRIVATE_10" }, \
+ { &unsupport, 123, "R_ARM_PRIVATE_11" }, \
+ { &unsupport, 124, "R_ARM_PRIVATE_12" }, \
+ { &unsupport, 125, "R_ARM_PRIVATE_13" }, \
+ { &unsupport, 126, "R_ARM_PRIVATE_14" }, \
+ { &unsupport, 127, "R_ARM_PRIVATE_15" }, \
+ { &unsupport, 128, "R_ARM_ME_TOO" }, \
+ { &unsupport, 129, "R_ARM_THM_TLS_DESCSEQ16" }, \
+ { &unsupport, 130, "R_ARM_THM_TLS_DESCSEQ32" }
diff --git a/lib/Target/ARM/ARMSectLinker.cpp b/lib/Target/ARM/ARMSectLinker.cpp
new file mode 100644
index 0000000..d686060
--- /dev/null
+++ b/lib/Target/ARM/ARMSectLinker.cpp
@@ -0,0 +1,47 @@
+//===- ARMSectLinker.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 "ARM.h"
+#include "ARMAndroidSectLinker.h"
+#include "ARMELFSectLinker.h"
+
+
+using namespace mcld;
+
+namespace mcld {
+//===----------------------------------------------------------------------===//
+// createARMSectLinker - the help function to create corresponding ARMSectLinker
+//
+SectLinker* createARMSectLinker(const std::string &pTriple,
+ SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend)
+{
+ Triple theTriple(pTriple);
+ if (theTriple.isOSDarwin()) {
+ assert(0 && "MachO linker has not supported yet");
+ }
+ if (theTriple.isOSWindows()) {
+ assert(0 && "COFF linker has not supported yet");
+ }
+
+ // For now, use Android SectLinker directly
+ return new ARMAndroidSectLinker(pOption,
+ pLDBackend);
+}
+
+} // namespace of mcld
+
+//==========================
+// ARMSectLinker
+extern "C" void LLVMInitializeARMSectLinker() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterSectLinker(TheARMTarget, createARMSectLinker);
+}
+
diff --git a/lib/Target/ARM/ARMTargetMachine.cpp b/lib/Target/ARM/ARMTargetMachine.cpp
new file mode 100644
index 0000000..530a610
--- /dev/null
+++ b/lib/Target/ARM/ARMTargetMachine.cpp
@@ -0,0 +1,33 @@
+//===- ARMTargetMachine.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "ARMTargetMachine.h"
+
+#include "mcld/Support/TargetRegistry.h"
+#include "mcld/MC/MCLDInfo.h"
+#include "ARM.h"
+
+extern "C" void LLVMInitializeARMLDTarget() {
+ // Register createTargetMachine function pointer to mcld::Target
+ mcld::RegisterTargetMachine<mcld::ARMBaseTargetMachine> X(mcld::TheARMTarget);
+}
+
+mcld::ARMBaseTargetMachine::ARMBaseTargetMachine(llvm::TargetMachine& pPM,
+ const mcld::Target &pTarget,
+ const std::string& pTriple)
+ : mcld::LLVMTargetMachine(pPM, pTarget, pTriple) {
+ // arg1 - the number of total attributes
+ // arg2 - the most possible number of input files
+ m_pLDInfo = new MCLDInfo(pTriple, 32, 64);
+}
+
+mcld::ARMBaseTargetMachine::~ARMBaseTargetMachine()
+{
+ delete m_pLDInfo;
+}
+
diff --git a/lib/Target/ARM/ARMTargetMachine.h b/lib/Target/ARM/ARMTargetMachine.h
new file mode 100644
index 0000000..19f8aa2
--- /dev/null
+++ b/lib/Target/ARM/ARMTargetMachine.h
@@ -0,0 +1,40 @@
+//===- ARMTargetMachine.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ARM_TARGET_MACHINE_H
+#define MCLD_ARM_TARGET_MACHINE_H
+#include "mcld/Target/TargetMachine.h"
+#include "ARM.h"
+
+namespace mcld
+{
+
+class ARMBaseTargetMachine : public LLVMTargetMachine
+{
+protected:
+ MCLDInfo *m_pLDInfo;
+
+public:
+ ARMBaseTargetMachine(llvm::TargetMachine &pTM,
+ const mcld::Target &pTarget,
+ const std::string &pTriple);
+
+ virtual ~ARMBaseTargetMachine();
+
+ mcld::MCLDInfo& getLDInfo()
+ { return *m_pLDInfo; }
+
+ const mcld::MCLDInfo& getLDInfo() const
+ { return *m_pLDInfo; }
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/Android.mk b/lib/Target/ARM/Android.mk
new file mode 100644
index 0000000..272e9f4
--- /dev/null
+++ b/lib/Target/ARM/Android.mk
@@ -0,0 +1,40 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_arm_target_SRC_FILES := \
+ ARMAndroidSectLinker.cpp \
+ ARMELFDynamic.cpp \
+ ARMELFSectLinker.cpp \
+ ARMGOT.cpp \
+ ARMLDBackend.cpp \
+ ARMPLT.cpp \
+ ARMRelocationFactory.cpp \
+ ARMSectLinker.cpp \
+ ARMTargetMachine.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_arm_target_SRC_FILES)
+LOCAL_MODULE:= libmcldARMTarget
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+ifeq ($(TARGET_ARCH),arm)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_arm_target_SRC_FILES)
+LOCAL_MODULE:= libmcldARMTarget
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/lib/Target/ARM/README b/lib/Target/ARM/README
new file mode 100644
index 0000000..ea88bfe
--- /dev/null
+++ b/lib/Target/ARM/README
@@ -0,0 +1,2 @@
+ARMLDBackend stands like ARMAsmBackend. It's a backend of linker,
+and all target-dependent behavior and data are here.
diff --git a/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp b/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
new file mode 100644
index 0000000..7e6a41a
--- /dev/null
+++ b/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
@@ -0,0 +1,22 @@
+//===- ARMTargetInfo.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 TheARMTarget;
+
+extern "C" void LLVMInitializeARMLDTargetInfo() {
+ // register into mcld::TargetRegistry
+ mcld::RegisterTarget X(TheARMTarget, "arm" );
+}
+
+} // namespace of mcld
+
diff --git a/lib/Target/ARM/TargetInfo/Android.mk b/lib/Target/ARM/TargetInfo/Android.mk
new file mode 100644
index 0000000..c4fffa3
--- /dev/null
+++ b/lib/Target/ARM/TargetInfo/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_arm_info_SRC_FILES := \
+ ARMTargetInfo.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_arm_info_SRC_FILES)
+LOCAL_MODULE:= libmcldARMInfo
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+ifeq ($(TARGET_ARCH),arm)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_arm_info_SRC_FILES)
+LOCAL_MODULE:= libmcldARMInfo
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/lib/Target/Android.mk b/lib/Target/Android.mk
new file mode 100644
index 0000000..8e6e260
--- /dev/null
+++ b/lib/Target/Android.mk
@@ -0,0 +1,36 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_target_SRC_FILES := \
+ AndroidSectLinker.cpp \
+ ELFDynamic.cpp \
+ GNULDBackend.cpp \
+ GOT.cpp \
+ OutputRelocSection.cpp \
+ PLT.cpp \
+ Stub.cpp \
+ Target.cpp \
+ TargetLDBackend.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_target_SRC_FILES)
+LOCAL_MODULE:= libmcldTarget
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_target_SRC_FILES)
+LOCAL_MODULE:= libmcldTarget
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
diff --git a/lib/Target/AndroidSectLinker.cpp b/lib/Target/AndroidSectLinker.cpp
new file mode 100644
index 0000000..8f3acbf
--- /dev/null
+++ b/lib/Target/AndroidSectLinker.cpp
@@ -0,0 +1,45 @@
+//===- AndroidSectLinker.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <mcld/Target/AndroidSectLinker.h>
+
+#include <llvm/Support/ErrorHandling.h>
+#include <mcld/MC/MCLDDirectory.h>
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+//==========================
+// AndroidSectLinker
+
+AndroidSectLinker::AndroidSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : SectLinker(pOption, pLDBackend) {
+}
+
+AndroidSectLinker::~AndroidSectLinker()
+{
+ // SectLinker will delete m_pLDBackend and m_pLDDriver;
+}
+
+void AndroidSectLinker::addTargetOptions(llvm::Module &pM,
+ SectLinkerOption &pOption)
+{
+ // ----- Set up General Options ----- //
+ MCLDInfo &info = pOption.info();
+ MCLDDirectory search_path("=/system/lib");
+ search_path.setSysroot(info.options().sysroot());
+ if (exists(search_path.path()) && is_directory(search_path.path()))
+ info.options().directories().add(search_path);
+ else {
+ // FIXME: need a warning function
+ llvm::errs() << "WARNING: can not open search directory: `-L" << search_path.name() << "'.\n";
+ }
+}
+
diff --git a/lib/Target/DarwinLDBackend.cpp b/lib/Target/DarwinLDBackend.cpp
new file mode 100644
index 0000000..5bd55c3
--- /dev/null
+++ b/lib/Target/DarwinLDBackend.cpp
@@ -0,0 +1,15 @@
+//===- 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
new file mode 100644
index 0000000..b863ab1
--- /dev/null
+++ b/lib/Target/ELFDynamic.cpp
@@ -0,0 +1,257 @@
+//===- ELFDynamic.cpp ------------- ------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/Support/Host.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <mcld/Target/ELFDynamic.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/LD/ELFFileFormat.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/Support/MemoryRegion.h>
+
+using namespace mcld;
+using namespace elf_dynamic;
+
+//===----------------------------------------------------------------------===//
+// elf_dynamic::EntryIF
+EntryIF::EntryIF()
+{
+}
+
+EntryIF::~EntryIF()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// ELFDynamic
+ELFDynamic::ELFDynamic(const GNULDBackend& pParent)
+ : m_pEntryFactory(NULL), m_Idx(0) {
+ if (32 == pParent.bitclass() && pParent.isLittleEndian()) {
+ m_pEntryFactory = new Entry<32, true>();
+ }
+ // FIXME: support big-endian and 64-bit machine.
+}
+
+
+ELFDynamic::~ELFDynamic()
+{
+ if (NULL != m_pEntryFactory)
+ delete m_pEntryFactory;
+
+ EntryListType::iterator entry, entryEnd = m_EntryList.end();
+ for (entry = m_EntryList.begin(); entry != entryEnd; ++entry) {
+ if (NULL != *entry)
+ delete (*entry);
+ }
+
+ entryEnd = m_NeedList.end();
+ for (entry = m_NeedList.begin(); entry != entryEnd; ++entry) {
+ if (NULL != *entry)
+ delete (*entry);
+ }
+}
+
+size_t ELFDynamic::size() const
+{
+ return (m_NeedList.size() + m_EntryList.size());
+}
+
+size_t ELFDynamic::numOfBytes() const
+{
+ return size()*entrySize();
+}
+
+size_t ELFDynamic::entrySize() const
+{
+ return m_pEntryFactory->size();
+}
+
+void ELFDynamic::reserveOne(uint64_t pTag)
+{
+ assert(NULL != m_pEntryFactory);
+ m_EntryList.push_back(new elf_dynamic::Entry<32, true>());
+}
+
+void ELFDynamic::applyOne(uint64_t pTag, uint64_t pValue)
+{
+ assert(m_Idx < m_EntryList.size());
+ m_EntryList[m_Idx]->setValue(pTag, pValue);
+ ++m_Idx;
+}
+
+
+/// reserveEntries - reserve entries
+void ELFDynamic::reserveEntries(const MCLDInfo& pLDInfo,
+ const ELFFileFormat& pFormat)
+{
+ if (pLDInfo.output().type() == Output::DynObj) {
+ reserveOne(llvm::ELF::DT_SONAME); // DT_SONAME
+
+ if (pLDInfo.options().Bsymbolic())
+ reserveOne(llvm::ELF::DT_SYMBOLIC); // DT_SYMBOLIC
+ }
+
+ if (pFormat.hasInit())
+ reserveOne(llvm::ELF::DT_INIT); // DT_INIT
+
+ if (pFormat.hasFini())
+ reserveOne(llvm::ELF::DT_FINI); // DT_FINI
+
+ if (pFormat.hasInitArray()) {
+ reserveOne(llvm::ELF::DT_INIT_ARRAY); // DT_INIT_ARRAY
+ reserveOne(llvm::ELF::DT_INIT_ARRAYSZ); // DT_INIT_ARRAYSZ
+ }
+
+ if (pFormat.hasFiniArray()) {
+ reserveOne(llvm::ELF::DT_FINI_ARRAY); // DT_FINI_ARRAY
+ reserveOne(llvm::ELF::DT_FINI_ARRAYSZ); // DT_FINI_ARRAYSZ
+ }
+
+ if (pFormat.hasHashTab())
+ reserveOne(llvm::ELF::DT_HASH); // DT_HASH
+
+ if (pFormat.hasDynSymTab()) {
+ reserveOne(llvm::ELF::DT_SYMTAB); // DT_SYMTAB
+ reserveOne(llvm::ELF::DT_SYMENT); // DT_SYMENT
+ }
+
+ if (pFormat.hasDynStrTab()) {
+ reserveOne(llvm::ELF::DT_STRTAB); // DT_STRTAB
+ reserveOne(llvm::ELF::DT_STRSZ); // DT_STRSZ
+ }
+
+ reserveTargetEntries(pFormat); // DT_PLTGOT
+
+ if (pFormat.hasRelPlt() || pFormat.hasRelaPlt())
+ reserveOne(llvm::ELF::DT_PLTREL); // DT_PLTREL
+
+ if (pFormat.hasPLT()) {
+ reserveOne(llvm::ELF::DT_JMPREL); // DT_JMPREL
+ reserveOne(llvm::ELF::DT_PLTRELSZ); // DT_PLTRELSZ
+ }
+
+ if (pFormat.hasRelDyn()) {
+ reserveOne(llvm::ELF::DT_REL); // DT_REL
+ reserveOne(llvm::ELF::DT_RELSZ); // DT_RELSZ
+ reserveOne(llvm::ELF::DT_RELENT); // DT_RELENT
+ }
+
+ if (pFormat.hasRelaDyn()) {
+ reserveOne(llvm::ELF::DT_RELA); // DT_RELA
+ reserveOne(llvm::ELF::DT_RELASZ); // DT_RELASZ
+ reserveOne(llvm::ELF::DT_RELAENT); // DT_RELAENT
+ }
+ reserveOne(llvm::ELF::DT_NULL); // for DT_NULL
+}
+
+/// applyEntries - apply entries
+void ELFDynamic::applyEntries(const MCLDInfo& pInfo,
+ const ELFFileFormat& pFormat)
+{
+ if (pInfo.output().type() == Output::DynObj &&
+ pInfo.options().Bsymbolic()) {
+ applyOne(llvm::ELF::DT_SYMBOLIC, 0x0); // DT_SYMBOLIC
+ }
+
+ if (pFormat.hasInit())
+ applyOne(llvm::ELF::DT_INIT, pFormat.getInit().addr()); // DT_INIT
+
+ if (pFormat.hasFini())
+ applyOne(llvm::ELF::DT_FINI, pFormat.getFini().addr()); // DT_FINI
+
+ if (pFormat.hasInitArray()) {
+ // DT_INIT_ARRAY
+ applyOne(llvm::ELF::DT_INIT_ARRAY, pFormat.getInitArray().addr());
+
+ // DT_INIT_ARRAYSZ
+ applyOne(llvm::ELF::DT_INIT_ARRAYSZ, pFormat.getInitArray().size());
+ }
+
+ if (pFormat.hasFiniArray()) {
+ // DT_FINI_ARRAY
+ applyOne(llvm::ELF::DT_FINI_ARRAY, pFormat.getFiniArray().addr());
+
+ // DT_FINI_ARRAYSZ
+ applyOne(llvm::ELF::DT_FINI_ARRAYSZ, pFormat.getFiniArray().size());
+ }
+
+ if (pFormat.hasHashTab())
+ applyOne(llvm::ELF::DT_HASH, pFormat.getHashTab().addr()); // DT_HASH
+
+ if (pFormat.hasDynSymTab()) {
+ applyOne(llvm::ELF::DT_SYMTAB, pFormat.getDynSymTab().addr()); // DT_SYMTAB
+ applyOne(llvm::ELF::DT_SYMENT, symbolSize()); // DT_SYMENT
+ }
+
+ if (pFormat.hasDynStrTab()) {
+ applyOne(llvm::ELF::DT_STRTAB, pFormat.getDynStrTab().addr()); // DT_STRTAB
+ applyOne(llvm::ELF::DT_STRSZ, pFormat.getDynStrTab().size()); // DT_STRSZ
+ }
+
+ 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_JMPREL, pFormat.getRelPlt().addr()); // DT_JMPREL
+ applyOne(llvm::ELF::DT_PLTRELSZ, pFormat.getRelPlt().size()); // DT_PLTRELSZ
+ }
+
+ if (pFormat.hasRelDyn()) {
+ applyOne(llvm::ELF::DT_REL, pFormat.getRelDyn().addr()); // DT_REL
+ applyOne(llvm::ELF::DT_RELSZ, pFormat.getRelDyn().size()); // DT_RELSZ
+ applyOne(llvm::ELF::DT_RELENT, m_pEntryFactory->relSize()); // DT_RELENT
+ }
+
+ if (pFormat.hasRelaDyn()) {
+ applyOne(llvm::ELF::DT_RELA, pFormat.getRelaDyn().addr()); // DT_RELA
+ applyOne(llvm::ELF::DT_RELASZ, pFormat.getRelaDyn().size()); // DT_RELASZ
+ applyOne(llvm::ELF::DT_RELAENT, m_pEntryFactory->relaSize()); // DT_RELAENT
+ }
+
+ applyOne(llvm::ELF::DT_NULL, 0x0); // for DT_NULL
+}
+
+/// symbolSize
+size_t ELFDynamic::symbolSize() const
+{
+ return m_pEntryFactory->symbolSize();
+}
+
+/// reserveNeedEntry - reserve on DT_NEED entry.
+void ELFDynamic::reserveNeedEntry()
+{
+ m_NeedList.push_back(m_pEntryFactory->clone());
+}
+
+/// emit
+void ELFDynamic::emit(const LDSection& pSection, MemoryRegion& pRegion) const
+{
+ if (pRegion.size() < pSection.size()) {
+ llvm::report_fatal_error(llvm::Twine("the given memory is smaller") +
+ llvm::Twine(" than the section's demaind.\n"));
+ }
+
+ uint8_t* address = (uint8_t*)pRegion.start();
+ EntryListType::const_iterator entry, entryEnd = m_NeedList.end();
+ for (entry = m_NeedList.begin(); entry != entryEnd; ++entry)
+ address += (*entry)->emit(address);
+
+ entryEnd = m_EntryList.end();
+ for (entry = m_EntryList.begin(); entry != entryEnd; ++entry)
+ address += (*entry)->emit(address);
+}
+
+void ELFDynamic::applySoname(uint64_t pStrTabIdx)
+{
+ applyOne(llvm::ELF::DT_SONAME, pStrTabIdx); // DT_SONAME
+}
+
diff --git a/lib/Target/GNULDBackend.cpp b/lib/Target/GNULDBackend.cpp
new file mode 100644
index 0000000..b82af73
--- /dev/null
+++ b/lib/Target/GNULDBackend.cpp
@@ -0,0 +1,1021 @@
+//===- GNULDBackend.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/Support/ELF.h>
+#include <mcld/ADT/SizeTraits.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLDOutput.h>
+#include <mcld/MC/MCLDInputTree.h>
+#include <mcld/MC/SymbolCategory.h>
+#include <mcld/LD/LDSymbol.h>
+#include <mcld/LD/Layout.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <string>
+#include <cstring>
+#include <cassert>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// GNULDBackend
+GNULDBackend::GNULDBackend()
+ : m_pArchiveReader(0),
+ m_pObjectReader(0),
+ m_pDynObjReader(0),
+ m_pObjectWriter(0),
+ m_pDynObjWriter(0),
+ m_pDynObjFileFormat(0),
+ m_pExecFileFormat(0),
+ m_ELFSegmentTable(9)// magic number
+{
+ m_pSymIndexMap = new HashTableType(1024);
+}
+
+GNULDBackend::~GNULDBackend()
+{
+ if (m_pArchiveReader)
+ delete m_pArchiveReader;
+ if (m_pObjectReader)
+ delete m_pObjectReader;
+ if (m_pDynObjReader)
+ delete m_pDynObjReader;
+ if (m_pObjectWriter)
+ delete m_pObjectWriter;
+ if (m_pDynObjWriter)
+ delete m_pDynObjWriter;
+ if (m_pDynObjFileFormat)
+ delete m_pDynObjFileFormat;
+ if (m_pExecFileFormat)
+ delete m_pExecFileFormat;
+ if(m_pSymIndexMap)
+ delete m_pSymIndexMap;
+}
+
+size_t GNULDBackend::sectionStartOffset() const
+{
+ // FIXME: use fixed offset, we need 10 segments by default
+ return sizeof(llvm::ELF::Elf64_Ehdr)+10*sizeof(llvm::ELF::Elf64_Phdr);
+}
+
+bool GNULDBackend::initArchiveReader(MCLinker&, MCLDInfo &pInfo)
+{
+ if (0 == m_pArchiveReader)
+ {
+ LDReader::Endian isLittleEndian = LDReader::LittleEndian;
+ m_pArchiveReader = new GNUArchiveReader(pInfo, isLittleEndian);
+ }
+ return true;
+}
+
+bool GNULDBackend::initObjectReader(MCLinker& pLinker)
+{
+ if (0 == m_pObjectReader)
+ m_pObjectReader = new ELFObjectReader(*this, pLinker);
+ return true;
+}
+
+bool GNULDBackend::initDynObjReader(MCLinker& pLinker)
+{
+ if (0 == m_pDynObjReader)
+ m_pDynObjReader = new ELFDynObjReader(*this, pLinker);
+ return true;
+}
+
+bool GNULDBackend::initObjectWriter(MCLinker&)
+{
+ // TODO
+ return true;
+}
+
+bool GNULDBackend::initDynObjWriter(MCLinker& pLinker)
+{
+ if (0 == m_pDynObjWriter)
+ m_pDynObjWriter = new ELFDynObjWriter(*this, pLinker);
+ return true;
+}
+
+bool GNULDBackend::initExecSections(MCLinker& pMCLinker)
+{
+ if (0 == m_pExecFileFormat)
+ m_pExecFileFormat = new ELFExecFileFormat(*this);
+
+ // initialize standard sections
+ m_pExecFileFormat->initStdSections(pMCLinker);
+ return true;
+}
+
+bool GNULDBackend::initDynObjSections(MCLinker& pMCLinker)
+{
+ if (0 == m_pDynObjFileFormat)
+ m_pDynObjFileFormat = new ELFDynObjFileFormat(*this);
+
+ // initialize standard sections
+ m_pDynObjFileFormat->initStdSections(pMCLinker);
+ return true;
+}
+
+bool GNULDBackend::initStandardSymbols(MCLinker& pLinker)
+{
+ return true;
+}
+
+GNUArchiveReader *GNULDBackend::getArchiveReader()
+{
+ assert(0 != m_pArchiveReader);
+ return m_pArchiveReader;
+}
+
+GNUArchiveReader *GNULDBackend::getArchiveReader() const
+{
+ assert(0 != m_pArchiveReader);
+ return m_pArchiveReader;
+}
+
+ELFObjectReader *GNULDBackend::getObjectReader()
+{
+ assert(0 != m_pObjectReader);
+ return m_pObjectReader;
+}
+
+ELFObjectReader *GNULDBackend::getObjectReader() const
+{
+ assert(0 != m_pObjectReader);
+ return m_pObjectReader;
+}
+
+ELFDynObjReader *GNULDBackend::getDynObjReader()
+{
+ assert(0 != m_pDynObjReader);
+ return m_pDynObjReader;
+}
+
+ELFDynObjReader *GNULDBackend::getDynObjReader() const
+{
+ assert(0 != m_pDynObjReader);
+ return m_pDynObjReader;
+}
+
+ELFObjectWriter *GNULDBackend::getObjectWriter()
+{
+ // TODO
+ return NULL;
+}
+
+ELFObjectWriter *GNULDBackend::getObjectWriter() const
+{
+ // TODO
+ return NULL;
+}
+
+ELFDynObjWriter *GNULDBackend::getDynObjWriter()
+{
+ assert(0 != m_pDynObjWriter);
+ return m_pDynObjWriter;
+}
+
+ELFDynObjWriter *GNULDBackend::getDynObjWriter() const
+{
+ assert(0 != m_pDynObjWriter);
+ return m_pDynObjWriter;
+}
+
+ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat()
+{
+ assert(0 != m_pDynObjFileFormat);
+ return m_pDynObjFileFormat;
+}
+
+ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat() const
+{
+ assert(0 != m_pDynObjFileFormat);
+ return m_pDynObjFileFormat;
+}
+
+ELFExecFileFormat* GNULDBackend::getExecFileFormat()
+{
+ assert(0 != m_pExecFileFormat);
+ return m_pExecFileFormat;
+}
+
+ELFExecFileFormat* GNULDBackend::getExecFileFormat() const
+{
+ assert(0 != m_pExecFileFormat);
+ return m_pExecFileFormat;
+}
+
+/// sizeNamePools - compute the size of regular name pools
+/// In ELF executable files, regular name pools are .symtab, .strtab,
+/// .dynsym, .dynstr, and .hash
+void
+GNULDBackend::sizeNamePools(const Output& pOutput,
+ const SymbolCategory& pSymbols,
+ const MCLDInfo& pLDInfo)
+{
+ // size of string tables starts from 1 to hold the null character in their
+ // first byte
+ size_t symtab = 1;
+ size_t dynsym = 1;
+ // 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.
+ size_t strtab = 1;
+ size_t dynstr = 1;
+ size_t hash = 0;
+
+ // compute size of .symtab, .dynsym and .strtab
+ SymbolCategory::const_iterator symbol;
+ SymbolCategory::const_iterator symEnd = pSymbols.end();
+ for (symbol = pSymbols.begin(); symbol != symEnd; ++symbol) {
+ size_t str_size = (*symbol)->nameSize() + 1;
+ if (isDynamicSymbol(**symbol, pOutput)) {
+ ++dynsym;
+ dynstr += str_size;
+ }
+ ++symtab;
+ strtab += str_size;
+ }
+
+ ELFFileFormat* file_format = NULL;
+ switch(pOutput.type()) {
+ // compute size of .dynstr and .hash
+ case Output::DynObj:
+ file_format = getDynObjFileFormat();
+ break;
+ case Output::Exec:
+ file_format = getExecFileFormat();
+ break;
+ case Output::Object:
+ default:
+ // TODO: not support yet
+ return;
+ }
+
+ switch(pOutput.type()) {
+ // compute size of .dynstr and .hash
+ case Output::DynObj:
+ case Output::Exec: {
+ // 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
+ InputTree::const_bfs_iterator input, inputEnd = pLDInfo.inputs().bfs_end();
+ for (input = pLDInfo.inputs().bfs_begin(); input != inputEnd; ++input) {
+ if (Input::DynObj == (*input)->type()) {
+ // --add-needed
+ if ((*input)->attribute()->isAddNeeded()) {
+ // --no-as-needed
+ if (!(*input)->attribute()->isAsNeeded()) {
+ dynstr += (*input)->name().size() + 1;
+ dynamic().reserveNeedEntry();
+ }
+ // --as-needed
+ else if ((*input)->isNeeded()) {
+ dynstr += (*input)->name().size() + 1;
+ dynamic().reserveNeedEntry();
+ }
+ }
+ }
+ } // for
+
+ // compute .hash
+ // Both Elf32_Word and Elf64_Word are 4 bytes
+ hash = (2 + getHashBucketCount(dynsym, false) + dynsym) *
+ sizeof(llvm::ELF::Elf32_Word);
+
+ // set size
+ dynstr += pOutput.name().size() + 1;
+ if (32 == bitclass())
+ 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);
+
+ }
+ /* fall through */
+ case Output::Object: {
+ if (32 == bitclass())
+ file_format->getSymTab().setSize(symtab*sizeof(llvm::ELF::Elf32_Sym));
+ else
+ file_format->getSymTab().setSize(symtab*sizeof(llvm::ELF::Elf64_Sym));
+ file_format->getStrTab().setSize(strtab);
+ break;
+ }
+ } // end of switch
+
+ // reserve fixed entries in the .dynamic section.
+ if (Output::DynObj == pOutput.type() || Output::Exec == pOutput.type()) {
+ // 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(pLDInfo, *file_format);
+ file_format->getDynamic().setSize(dynamic().numOfBytes());
+ }
+}
+
+/// emitRegNamePools - emit regular name pools - .symtab, .strtab
+///
+/// the size of these tables should be computed before layout
+/// layout should computes the start offset of these tables
+void GNULDBackend::emitRegNamePools(Output& pOutput,
+ SymbolCategory& pSymbols,
+ const Layout& pLayout,
+ const MCLDInfo& pLDInfo)
+{
+
+ assert(pOutput.hasMemArea());
+
+ bool sym_exist = false;
+ HashTableType::entry_type* entry = 0;
+
+ ELFFileFormat* file_format = NULL;
+ switch(pOutput.type()) {
+ // compute size of .dynstr and .hash
+ case Output::DynObj:
+ file_format = getDynObjFileFormat();
+ break;
+ case Output::Exec:
+ file_format = getExecFileFormat();
+ break;
+ case Output::Object:
+ default:
+ // add first symbol into m_pSymIndexMap
+ entry = m_pSymIndexMap->insert(NULL, sym_exist);
+ entry->setValue(0);
+
+ // TODO: not support yet
+ return;
+ }
+
+ LDSection& symtab_sect = file_format->getSymTab();
+ LDSection& strtab_sect = file_format->getStrTab();
+
+ MemoryRegion* symtab_region = pOutput.memArea()->request(symtab_sect.offset(),
+ symtab_sect.size());
+ MemoryRegion* strtab_region = pOutput.memArea()->request(strtab_sect.offset(),
+ strtab_sect.size());
+
+ // set up symtab_region
+ llvm::ELF::Elf32_Sym* symtab32 = NULL;
+ llvm::ELF::Elf64_Sym* symtab64 = NULL;
+ if (32 == bitclass())
+ symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region->start();
+ else if (64 == bitclass())
+ symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region->start();
+ else
+ llvm::report_fatal_error(llvm::Twine("unsupported bitclass ") +
+ llvm::Twine(bitclass()) +
+ llvm::Twine(".\n"));
+ // set up strtab_region
+ char* strtab = (char*)strtab_region->start();
+ strtab[0] = '\0';
+
+ // initialize the first ELF symbol
+ if (32 == bitclass()) {
+ 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;
+ }
+
+ size_t symtabIdx = 1;
+ size_t strtabsize = 1;
+ // compute size of .symtab, .dynsym and .strtab
+ SymbolCategory::iterator symbol;
+ SymbolCategory::iterator symEnd = pSymbols.end();
+ for (symbol = pSymbols.begin(); symbol != symEnd; ++symbol) {
+
+ // maintain output's symbol and index map if building .o file
+ if (Output::Object == pOutput.type()) {
+ entry = m_pSymIndexMap->insert(NULL, sym_exist);
+ entry->setValue(symtabIdx);
+ }
+
+ // FIXME: check the endian between host and target
+ // write out symbol
+ if (32 == bitclass()) {
+ symtab32[symtabIdx].st_name = strtabsize;
+ symtab32[symtabIdx].st_value = getSymbolValue(**symbol);
+ symtab32[symtabIdx].st_size = getSymbolSize(**symbol);
+ symtab32[symtabIdx].st_info = getSymbolInfo(**symbol);
+ symtab32[symtabIdx].st_other = (*symbol)->visibility();
+ symtab32[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout);
+ }
+ else { // must 64
+ symtab64[symtabIdx].st_name = strtabsize;
+ symtab64[symtabIdx].st_value = getSymbolValue(**symbol);
+ symtab64[symtabIdx].st_size = getSymbolSize(**symbol);
+ symtab64[symtabIdx].st_info = getSymbolInfo(**symbol);
+ symtab64[symtabIdx].st_other = (*symbol)->visibility();
+ symtab64[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout);
+ }
+ // write out string
+ strcpy((strtab + strtabsize), (*symbol)->name());
+
+ // write out
+ // sum up counters
+ ++symtabIdx;
+ strtabsize += (*symbol)->nameSize() + 1;
+ }
+}
+
+/// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash
+///
+/// the size of these tables should be computed before layout
+/// layout should computes the start offset of these tables
+void GNULDBackend::emitDynNamePools(Output& pOutput,
+ SymbolCategory& pSymbols,
+ const Layout& pLayout,
+ const MCLDInfo& pLDInfo)
+{
+ assert(pOutput.hasMemArea());
+ ELFFileFormat* file_format = NULL;
+
+ bool sym_exist = false;
+ HashTableType::entry_type* entry = 0;
+
+ switch(pOutput.type()) {
+ // compute size of .dynstr and .hash
+ case Output::DynObj:
+ file_format = getDynObjFileFormat();
+ break;
+ case Output::Exec:
+ file_format = getExecFileFormat();
+ break;
+ case Output::Object:
+ default:
+ // TODO: not support yet
+ return;
+ }
+
+ LDSection& symtab_sect = file_format->getDynSymTab();
+ LDSection& strtab_sect = file_format->getDynStrTab();
+ LDSection& hash_sect = file_format->getHashTab();
+ LDSection& dyn_sect = file_format->getDynamic();
+
+ MemoryRegion* symtab_region = pOutput.memArea()->request(symtab_sect.offset(),
+ symtab_sect.size());
+ MemoryRegion* strtab_region = pOutput.memArea()->request(strtab_sect.offset(),
+ strtab_sect.size());
+ MemoryRegion* hash_region = pOutput.memArea()->request(hash_sect.offset(),
+ hash_sect.size());
+ MemoryRegion* dyn_region = pOutput.memArea()->request(dyn_sect.offset(),
+ dyn_sect.size());
+ // set up symtab_region
+ llvm::ELF::Elf32_Sym* symtab32 = NULL;
+ llvm::ELF::Elf64_Sym* symtab64 = NULL;
+ if (32 == bitclass())
+ symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region->start();
+ else if (64 == bitclass())
+ symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region->start();
+ else
+ llvm::report_fatal_error(llvm::Twine("unsupported bitclass ") +
+ llvm::Twine(bitclass()) +
+ llvm::Twine(".\n"));
+
+ // initialize the first ELF symbol
+ if (32 == bitclass()) {
+ 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);
+
+ size_t symtabIdx = 1;
+ size_t strtabsize = 1;
+
+ // emit of .dynsym, and .dynstr
+ SymbolCategory::iterator symbol;
+ SymbolCategory::iterator symEnd = pSymbols.end();
+ for (symbol = pSymbols.begin(); symbol != symEnd; ++symbol) {
+ if (!isDynamicSymbol(**symbol, pOutput))
+ continue;
+
+ // maintain output's symbol and index map
+ entry = m_pSymIndexMap->insert(*symbol, sym_exist);
+ entry->setValue(symtabIdx);
+
+ // FIXME: check the endian between host and target
+ // write out symbol
+ if (32 == bitclass()) {
+ symtab32[symtabIdx].st_name = strtabsize;
+ symtab32[symtabIdx].st_value = (*symbol)->value();
+ symtab32[symtabIdx].st_size = getSymbolSize(**symbol);
+ symtab32[symtabIdx].st_info = getSymbolInfo(**symbol);
+ symtab32[symtabIdx].st_other = (*symbol)->visibility();
+ symtab32[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout);
+ }
+ else { // must 64
+ symtab64[symtabIdx].st_name = strtabsize;
+ symtab64[symtabIdx].st_value = (*symbol)->value();
+ symtab64[symtabIdx].st_size = getSymbolSize(**symbol);
+ symtab64[symtabIdx].st_info = getSymbolInfo(**symbol);
+ symtab64[symtabIdx].st_other = (*symbol)->visibility();
+ symtab64[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout);
+ }
+ // write out string
+ strcpy((strtab + strtabsize), (*symbol)->name());
+
+ // sum up counters
+ ++symtabIdx;
+ 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();
+ InputTree::const_bfs_iterator input, inputEnd = pLDInfo.inputs().bfs_end();
+ for (input = pLDInfo.inputs().bfs_begin(); input != inputEnd; ++input) {
+ if (Input::DynObj == (*input)->type()) {
+ // --add-needed
+ if ((*input)->attribute()->isAddNeeded()) {
+ // --no-as-needed
+ if (!(*input)->attribute()->isAsNeeded()) {
+ strcpy((strtab + strtabsize), (*input)->name().c_str());
+ (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
+ strtabsize += (*input)->name().size() + 1;
+ ++dt_need;
+ }
+ // --as-needed
+ else if ((*input)->isNeeded()) {
+ strcpy((strtab + strtabsize), (*input)->name().c_str());
+ (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
+ strtabsize += (*input)->name().size() + 1;
+ ++dt_need;
+ }
+ }
+ }
+ } // for
+
+ // emit soname
+ // initialize value of ELF .dynamic section
+ dynamic().applySoname(strtabsize);
+ dynamic().applyEntries(pLDInfo, *file_format);
+ dynamic().emit(dyn_sect, *dyn_region);
+
+ strcpy((strtab + strtabsize), pOutput.name().c_str());
+ strtabsize += pOutput.name().size() + 1;
+
+ // emit hash table
+ // FIXME: this verion only emit SVR4 hash section.
+ // Please add GNU new hash section
+
+ // 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;
+
+ uint32_t* bucket = (word_array + 2);
+ uint32_t* chain = (bucket + nbucket);
+
+ // initialize bucket
+ bzero((void*)bucket, nbucket);
+
+ StringHash<ELF> hash_func;
+
+ if (32 == bitclass()) {
+ 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;
+ }
+ }
+ else if (64 == bitclass()) {
+ 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;
+ }
+ }
+}
+
+/// getSectionOrder
+unsigned int GNULDBackend::getSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const
+{
+ // NULL section should be the "1st" section
+ if (LDFileFormat::Null == pSectHdr.kind())
+ return 0;
+
+ // if the section is not ALLOC, lay it out until the last possible moment
+ if (0 == (pSectHdr.flag() & llvm::ELF::SHF_ALLOC))
+ return SHO_UNDEFINED;
+
+ bool is_write = (pSectHdr.flag() & llvm::ELF::SHF_WRITE) != 0;
+ bool is_exec = (pSectHdr.flag() & llvm::ELF::SHF_EXECINSTR) != 0;
+ ELFFileFormat* file_format = NULL;
+ switch (pOutput.type()) {
+ case Output::DynObj:
+ file_format = getDynObjFileFormat();
+ break;
+ case Output::Exec:
+ file_format = getExecFileFormat();
+ break;
+ case Output::Object:
+ default:
+ assert(0 && "Not support yet.\n");
+ break;
+ }
+
+ // TODO: need to take care other possible output sections
+ switch (pSectHdr.kind()) {
+ case LDFileFormat::Regular:
+ if (is_exec) {
+ if (&pSectHdr == &file_format->getInit())
+ return SHO_INIT;
+ if (&pSectHdr == &file_format->getFini())
+ return SHO_FINI;
+ return SHO_TEXT;
+ } else if (!is_write) {
+ return SHO_RO;
+ } else {
+ if (pSectHdr.type() == llvm::ELF::SHT_PREINIT_ARRAY ||
+ pSectHdr.type() == llvm::ELF::SHT_INIT_ARRAY ||
+ pSectHdr.type() == llvm::ELF::SHT_FINI_ARRAY ||
+ &pSectHdr == &file_format->getCtors() ||
+ &pSectHdr == &file_format->getDtors())
+ return SHO_RELRO;
+
+ return SHO_DATA;
+ }
+
+ case LDFileFormat::BSS:
+ return SHO_BSS;
+
+ case LDFileFormat::NamePool:
+ if (&pSectHdr == &file_format->getDynamic())
+ return SHO_RELRO;
+ return SHO_NAMEPOOL;
+
+ case LDFileFormat::Relocation:
+ if (&pSectHdr == &file_format->getRelPlt() ||
+ &pSectHdr == &file_format->getRelaPlt())
+ return SHO_REL_PLT;
+ return SHO_RELOCATION;
+
+ // get the order from target for target specific sections
+ case LDFileFormat::Target:
+ return getTargetSectionOrder(pOutput, pSectHdr);
+
+ // handle .interp
+ case LDFileFormat::Note:
+ return SHO_INTERP;
+
+ case LDFileFormat::Exception:
+ return SHO_EHFRAME;
+
+ case LDFileFormat::MetaData:
+ case LDFileFormat::Debug:
+ default:
+ return SHO_UNDEFINED;
+ }
+}
+
+/// getSymbolSize
+uint64_t GNULDBackend::getSymbolSize(const LDSymbol& pSymbol) const
+{
+ // @ref Google gold linker: symtab.cc: 2780
+ // undefined and dynamic symbols should have zero size.
+ if (pSymbol.isDyn() || pSymbol.desc() == ResolveInfo::Undefined)
+ return 0x0;
+ return pSymbol.resolveInfo()->size();
+}
+
+/// getSymbolInfo
+uint64_t GNULDBackend::getSymbolInfo(const LDSymbol& pSymbol) const
+{
+ // set binding
+ uint8_t bind = 0x0;
+ if (pSymbol.resolveInfo()->isLocal())
+ bind = llvm::ELF::STB_LOCAL;
+ else if (pSymbol.resolveInfo()->isGlobal())
+ bind = llvm::ELF::STB_GLOBAL;
+ else if (pSymbol.resolveInfo()->isWeak())
+ bind = llvm::ELF::STB_WEAK;
+ else if (pSymbol.resolveInfo()->isAbsolute()) {
+ // (Luba) Is a absolute but not global (weak or local) symbol meaningful?
+ bind = llvm::ELF::STB_GLOBAL;
+ }
+
+ if (pSymbol.visibility() == llvm::ELF::STV_INTERNAL ||
+ pSymbol.visibility() == llvm::ELF::STV_HIDDEN)
+ bind = llvm::ELF::STB_LOCAL;
+
+ return (pSymbol.resolveInfo()->type() | (bind << 4));
+}
+
+/// getSymbolValue - this function is called after layout()
+uint64_t GNULDBackend::getSymbolValue(const LDSymbol& pSymbol) const
+{
+ if (pSymbol.isDyn())
+ return 0x0;
+
+ return pSymbol.value();
+}
+
+/// getSymbolShndx - this function is called after layout()
+uint64_t
+GNULDBackend::getSymbolShndx(const LDSymbol& pSymbol, const Layout& pLayout) const
+{
+ if (pSymbol.resolveInfo()->isAbsolute())
+ return llvm::ELF::SHN_ABS;
+ if (pSymbol.resolveInfo()->isCommon())
+ return llvm::ELF::SHN_COMMON;
+ if (pSymbol.resolveInfo()->isUndef() || pSymbol.isDyn())
+ return llvm::ELF::SHN_UNDEF;
+
+ if (pSymbol.resolveInfo()->isLocal()) {
+ switch (pSymbol.type()) {
+ case ResolveInfo::NoType:
+ case ResolveInfo::File:
+ return llvm::ELF::SHN_ABS;
+ }
+ }
+
+ assert(pSymbol.hasFragRef());
+ return pLayout.getOutputLDSection(*pSymbol.fragRef()->frag())->index();
+}
+
+/// getSymbolIdx - called by emitRelocation to get the ouput symbol table index
+size_t GNULDBackend::getSymbolIdx(LDSymbol* pSymbol) const
+{
+ HashTableType::iterator entry = m_pSymIndexMap->find(pSymbol);
+ return entry.getEntry()->value();
+}
+
+/// emitProgramHdrs - emit ELF program headers
+void GNULDBackend::emitProgramHdrs(Output& pOutput)
+{
+ assert(NULL != pOutput.context());
+ createProgramHdrs(*pOutput.context());
+
+ if (32 == bitclass())
+ writeELF32ProgramHdrs(pOutput);
+ else
+ writeELF64ProgramHdrs(pOutput);
+}
+
+/// createProgramHdrs - base on output sections to create the program headers
+void GNULDBackend::createProgramHdrs(LDContext& pContext)
+{
+ // make PT_PHDR
+ m_ELFSegmentTable.produce(llvm::ELF::PT_PHDR);
+
+ // make PT_INTERP
+ LDSection* interp = pContext.getSection(".interp");
+ if (NULL != interp) {
+ ELFSegment* interp_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_INTERP);
+ interp_seg->addSection(interp);
+ interp_seg->setAlign(bitclass() / 8);
+ }
+
+ uint32_t cur_seg_flag, prev_seg_flag = getSegmentFlag(0);
+ uint64_t padding = 0;
+ ELFSegment* load_seg = NULL;
+ // make possible PT_LOAD segments
+ LDContext::sect_iterator sect, sect_end = pContext.sectEnd();
+ for (sect = pContext.sectBegin(); sect != sect_end; ++sect) {
+ if (0 == ((*sect)->flag() & llvm::ELF::SHF_ALLOC) &&
+ LDFileFormat::Null != (*sect)->kind())
+ continue;
+
+ // FIXME: Now only separate writable and non-writable PT_LOAD
+ cur_seg_flag = getSegmentFlag((*sect)->flag());
+ if ((prev_seg_flag & llvm::ELF::PF_W) ^ (cur_seg_flag & llvm::ELF::PF_W) ||
+ LDFileFormat::Null == (*sect)->kind()) {
+ // create new PT_LOAD segment
+ load_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_LOAD);
+ load_seg->setAlign(pagesize());
+
+ // check if this segment needs padding
+ padding = 0;
+ if (((*sect)->offset() & (load_seg->align() - 1)) != 0)
+ padding = load_seg->align();
+ }
+
+ assert(NULL != load_seg);
+ load_seg->addSection(*sect);
+ load_seg->updateFlag(cur_seg_flag);
+
+ // FIXME: set section's vma
+ // need to handle start vma for user-defined one or for executable.
+ (*sect)->setAddr((*sect)->offset() + padding);
+
+ prev_seg_flag = cur_seg_flag;
+ }
+
+ // make PT_DYNAMIC
+ LDSection* dynamic = pContext.getSection(".dynamic");
+ if (NULL != dynamic) {
+ ELFSegment* dyn_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_DYNAMIC);
+ dyn_seg->setFlag(llvm::ELF::PF_R | llvm::ELF::PF_W);
+ dyn_seg->addSection(dynamic);
+ dyn_seg->setAlign(bitclass() / 8);
+ }
+
+ // update segment info
+ uint64_t file_size = 0;
+ ELFSegmentFactory::iterator seg, seg_end = m_ELFSegmentTable.end();
+ for (seg = m_ELFSegmentTable.begin(); seg != seg_end; ++seg) {
+ ELFSegment& segment = *seg;
+
+ // update PT_PHDR
+ if (llvm::ELF::PT_PHDR == segment.type()) {
+ uint64_t offset, phdr_size;
+ if (32 == bitclass()) {
+ offset = sizeof(llvm::ELF::Elf32_Ehdr);
+ phdr_size = sizeof(llvm::ELF::Elf32_Phdr);
+ }
+ else {
+ offset = sizeof(llvm::ELF::Elf64_Ehdr);
+ phdr_size = sizeof(llvm::ELF::Elf64_Phdr);
+ }
+ segment.setOffset(offset);
+ segment.setVaddr(offset);
+ segment.setPaddr(segment.vaddr());
+ segment.setFilesz(numOfSegments() * phdr_size);
+ segment.setMemsz(numOfSegments() * phdr_size);
+ segment.setAlign(bitclass() / 8);
+ continue;
+ }
+
+ assert(NULL != segment.getFirstSection());
+ segment.setOffset(segment.getFirstSection()->offset());
+ segment.setVaddr(segment.getFirstSection()->addr());
+ segment.setPaddr(segment.vaddr());
+
+ const LDSection* last_sect = segment.getLastSection();
+ assert(NULL != last_sect);
+ file_size = last_sect->offset() - segment.offset();
+ if (LDFileFormat::BSS != last_sect->kind())
+ file_size += last_sect->size();
+ segment.setFilesz(file_size);
+
+ segment.setMemsz(last_sect->addr() - segment.vaddr() + last_sect->size());
+ }
+}
+
+/// writeELF32ProgramHdrs - write out the ELF32 program headers
+void GNULDBackend::writeELF32ProgramHdrs(Output& pOutput)
+{
+ assert(pOutput.hasMemArea());
+
+ uint64_t start_offset, phdr_size;
+
+ start_offset = sizeof(llvm::ELF::Elf32_Ehdr);
+ phdr_size = sizeof(llvm::ELF::Elf32_Phdr);
+ // Program header must start directly after ELF header
+ MemoryRegion *region = pOutput.memArea()->request(start_offset,
+ numOfSegments()*phdr_size);
+
+ llvm::ELF::Elf32_Phdr* phdr = (llvm::ELF::Elf32_Phdr*)region->start();
+
+ size_t index = 0;
+ ELFSegmentFactory::iterator seg, segEnd = m_ELFSegmentTable.end();
+ for (seg = m_ELFSegmentTable.begin(); seg != segEnd; ++seg, ++index) {
+ phdr[index].p_type = (*seg).type();
+ phdr[index].p_flags = (*seg).flag();
+ phdr[index].p_offset = (*seg).offset();
+ phdr[index].p_vaddr = (*seg).vaddr();
+ phdr[index].p_paddr = (*seg).paddr();
+ phdr[index].p_filesz = (*seg).filesz();
+ phdr[index].p_memsz = (*seg).memsz();
+ phdr[index].p_align = (*seg).align();
+ }
+}
+
+/// writeELF64ProgramHdrs - write out the ELF64 program headers
+void GNULDBackend::writeELF64ProgramHdrs(Output& pOutput)
+{
+ assert(pOutput.hasMemArea());
+
+ uint64_t start_offset, phdr_size;
+
+ start_offset = sizeof(llvm::ELF::Elf64_Ehdr);
+ phdr_size = sizeof(llvm::ELF::Elf64_Phdr);
+ // Program header must start directly after ELF header
+ MemoryRegion *region = pOutput.memArea()->request(start_offset,
+ numOfSegments() *phdr_size);
+ llvm::ELF::Elf64_Phdr* phdr = (llvm::ELF::Elf64_Phdr*)region->start();
+
+ size_t index = 0;
+ ELFSegmentFactory::iterator seg, segEnd = m_ELFSegmentTable.end();
+ for (seg = m_ELFSegmentTable.begin(); seg != segEnd; ++seg, ++index) {
+ phdr[index].p_type = (*seg).type();
+ phdr[index].p_flags = (*seg).flag();
+ phdr[index].p_offset = (*seg).offset();
+ phdr[index].p_vaddr = (*seg).vaddr();
+ phdr[index].p_paddr = (*seg).paddr();
+ phdr[index].p_filesz = (*seg).filesz();
+ phdr[index].p_memsz = (*seg).memsz();
+ phdr[index].p_align = (*seg).align();
+ }
+}
+
+/// preLayout - Backend can do any needed modification before layout
+void GNULDBackend::preLayout(const Output& pOutput,
+ const MCLDInfo& pLDInfo,
+ MCLinker& pLinker)
+{
+ // prelayout target first
+ doPreLayout(pOutput, pLDInfo, pLinker);
+}
+
+/// postLayout -Backend can do any needed modification after layout
+void GNULDBackend::postLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ // post layout target first
+ doPostLayout(pOutput, pInfo, pLinker);
+}
+
+/// getHashBucketCount - calculate hash bucket count.
+/// @ref Google gold linker, dynobj.cc:791
+unsigned GNULDBackend::getHashBucketCount(unsigned pNumOfSymbols,
+ bool pIsGNUStyle)
+{
+ // @ref Google gold, dynobj.cc:loc 791
+ static const unsigned int buckets[] =
+ {
+ 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209,
+ 16411, 32771, 65537, 131101, 262147
+ };
+ const unsigned buckets_count = sizeof buckets / sizeof buckets[0];
+
+ unsigned int result = 1;
+ for (unsigned i = 0; i < buckets_count; ++i) {
+ if (pNumOfSymbols < buckets[i])
+ break;
+ result = buckets[i];
+ }
+
+ if (pIsGNUStyle && result < 2)
+ result = 2;
+
+ return result;
+}
+
+/// isDynamicSymbol
+/// @ref Google gold linker: symtab.cc:311
+bool GNULDBackend::isDynamicSymbol(const LDSymbol& pSymbol,
+ const Output& pOutput)
+{
+ // If a local symbol is in the LDContext's symbol table, it's a real local
+ // symbol. We should not add it
+ if (pSymbol.binding() == ResolveInfo::Local)
+ return false;
+
+ // If we are building shared object, and the visibility is external, we
+ // need to add it.
+ if (Output::DynObj == pOutput.type())
+ if (pSymbol.resolveInfo()->visibility() == ResolveInfo::Default ||
+ pSymbol.resolveInfo()->visibility() == ResolveInfo::Protected)
+ return true;
+
+ return false;
+}
diff --git a/lib/Target/GOT.cpp b/lib/Target/GOT.cpp
new file mode 100644
index 0000000..a05b574
--- /dev/null
+++ b/lib/Target/GOT.cpp
@@ -0,0 +1,45 @@
+//===- GOT.cpp ------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Target/GOT.h>
+#include <cstring>
+#include <cstdlib>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// GOTEntry
+GOTEntry::GOTEntry(uint64_t pContent, size_t pEntrySize,
+ llvm::MCSectionData* pParent)
+ : MCTargetFragment(llvm::MCFragment::FT_Target, pParent),
+ f_Content(pContent), m_EntrySize(pEntrySize) {
+}
+
+GOTEntry::~GOTEntry()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// GOT
+GOT::GOT(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ size_t pEntrySize)
+ : m_Section(pSection),
+ m_SectionData(pSectionData),
+ f_EntrySize(pEntrySize) {
+}
+
+GOT::~GOT()
+{
+}
+
+size_t GOT::getEntrySize() const
+{
+ return f_EntrySize;
+}
+
diff --git a/lib/Target/Mips/Android.mk b/lib/Target/Mips/Android.mk
new file mode 100644
index 0000000..cc5a211
--- /dev/null
+++ b/lib/Target/Mips/Android.mk
@@ -0,0 +1,39 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_mips_target_SRC_FILES := \
+ MipsAndroidSectLinker.cpp \
+ MipsELFDynamic.cpp \
+ MipsELFSectLinker.cpp \
+ MipsGOT.cpp \
+ MipsLDBackend.cpp \
+ MipsRelocationFactory.cpp \
+ MipsSectLinker.cpp \
+ MipsTargetMachine.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_mips_target_SRC_FILES)
+LOCAL_MODULE:= libmcldMipsTarget
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+ifeq ($(TARGET_ARCH),mips)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_mips_target_SRC_FILES)
+LOCAL_MODULE:= libmcldMipsTarget
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/lib/Target/Mips/Mips.h b/lib/Target/Mips/Mips.h
new file mode 100644
index 0000000..a63be45
--- /dev/null
+++ b/lib/Target/Mips/Mips.h
@@ -0,0 +1,20 @@
+//===- Mips.h -------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MIPS_H
+#define MCLD_MIPS_H
+
+#include "mcld/Support/TargetRegistry.h"
+
+namespace mcld {
+
+extern mcld::Target TheMipselTarget;
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Mips/MipsAndroidSectLinker.cpp b/lib/Target/Mips/MipsAndroidSectLinker.cpp
new file mode 100644
index 0000000..e697fbc
--- /dev/null
+++ b/lib/Target/Mips/MipsAndroidSectLinker.cpp
@@ -0,0 +1,33 @@
+//===- MipsAndroidSectLinker.cpp ------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsAndroidSectLinker.h"
+
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+MipsAndroidSectLinker::MipsAndroidSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : AndroidSectLinker(pOption,
+ pLDBackend) {
+ MCLDInfo &info = pOption.info();
+ // set up target-dependent constraints of attibutes
+ info.attrFactory().constraint().disableWholeArchive();
+ info.attrFactory().constraint().disableAsNeeded();
+ info.attrFactory().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ info.attrFactory().predefined().unsetWholeArchive();
+ info.attrFactory().predefined().setDynamic();
+}
+
+MipsAndroidSectLinker::~MipsAndroidSectLinker()
+{
+}
diff --git a/lib/Target/Mips/MipsAndroidSectLinker.h b/lib/Target/Mips/MipsAndroidSectLinker.h
new file mode 100644
index 0000000..ba216e4
--- /dev/null
+++ b/lib/Target/Mips/MipsAndroidSectLinker.h
@@ -0,0 +1,36 @@
+//===- MipsAndroidSectLinker.h --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MIPS_ANDROIDSECTLINKER_H
+#define MIPS_ANDROIDSECTLINKER_H
+
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/Target/AndroidSectLinker.h"
+
+namespace mcld
+{
+
+/** \class MipsAndroidSectLinker
+ * \brief MipsAndroidSectLinker sets up the environment for linking.
+ *
+ */
+class MipsAndroidSectLinker : public AndroidSectLinker
+{
+public:
+ MipsAndroidSectLinker(SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend);
+
+ ~MipsAndroidSectLinker();
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Mips/MipsELFDynamic.cpp b/lib/Target/Mips/MipsELFDynamic.cpp
new file mode 100644
index 0000000..cd692ac
--- /dev/null
+++ b/lib/Target/Mips/MipsELFDynamic.cpp
@@ -0,0 +1,90 @@
+//===- MipsELFDynamic.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <mcld/LD/ELFFileFormat.h>
+#include <mcld/Target/GNULDBackend.h>
+#include "MipsELFDynamic.h"
+#include "MipsLDBackend.h"
+
+using namespace mcld;
+
+// MIPS mandatory dynamic section entries
+enum {
+ MIPS_RLD_VERSION = 0x70000001,
+ MIPS_FLAGS = 0x70000005,
+ MIPS_BASE_ADDRESS = 0x70000006,
+ MIPS_LOCAL_GOTNO = 0x7000000a,
+ MIPS_SYMTABNO = 0x70000011,
+ MIPS_GOTSYM = 0x70000013,
+};
+
+MipsELFDynamic::MipsELFDynamic(const MipsGNULDBackend& pParent)
+ : ELFDynamic(pParent),
+ m_pParent(pParent)
+{
+}
+
+MipsELFDynamic::~MipsELFDynamic()
+{
+}
+
+void MipsELFDynamic::reserveTargetEntries(const ELFFileFormat& pFormat)
+{
+ // reservePLTGOT
+ if (pFormat.hasGOT())
+ reserveOne(llvm::ELF::DT_PLTGOT);
+
+ reserveOne(MIPS_RLD_VERSION);
+ reserveOne(MIPS_FLAGS);
+ reserveOne(MIPS_BASE_ADDRESS);
+ reserveOne(MIPS_LOCAL_GOTNO);
+ reserveOne(MIPS_SYMTABNO);
+ reserveOne(MIPS_GOTSYM);
+}
+
+void MipsELFDynamic::applyTargetEntries(const ELFFileFormat& pFormat)
+{
+ // applyPLTGOT
+ if (pFormat.hasGOT())
+ applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOT().addr());
+
+ applyOne(MIPS_RLD_VERSION, 1);
+ applyOne(MIPS_FLAGS, 0);
+ applyOne(MIPS_BASE_ADDRESS, 0);
+ applyOne(MIPS_LOCAL_GOTNO, getLocalGotNum(pFormat));
+ applyOne(MIPS_SYMTABNO, getSymTabNum(pFormat));
+ applyOne(MIPS_GOTSYM, getGotSym(pFormat));
+}
+
+size_t MipsELFDynamic::getSymTabNum(const ELFFileFormat& pFormat) const
+{
+ if (!pFormat.hasDynSymTab())
+ return 0;
+
+ const LDSection& dynsym = pFormat.getDynSymTab();
+ return dynsym.size() / symbolSize();
+}
+
+size_t MipsELFDynamic::getGotSym(const ELFFileFormat& pFormat) const
+{
+ if (!pFormat.hasGOT())
+ return 0;
+
+ return getSymTabNum(pFormat) -
+ m_pParent.getGOT().getTotalNum() +
+ m_pParent.getGOT().getLocalNum();
+}
+
+size_t MipsELFDynamic::getLocalGotNum(const ELFFileFormat& pFormat) const
+{
+ if (!pFormat.hasGOT())
+ return 0;
+
+ return m_pParent.getGOT().getLocalNum();
+}
diff --git a/lib/Target/Mips/MipsELFDynamic.h b/lib/Target/Mips/MipsELFDynamic.h
new file mode 100644
index 0000000..118e4f9
--- /dev/null
+++ b/lib/Target/Mips/MipsELFDynamic.h
@@ -0,0 +1,41 @@
+//===- MipsELFDynamic.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_Mips_ELFDYNAMIC_SECTION_H
+#define MCLD_Mips_ELFDYNAMIC_SECTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Target/ELFDynamic.h>
+
+namespace mcld {
+
+class MipsGNULDBackend;
+
+class MipsELFDynamic : public ELFDynamic
+{
+public:
+ MipsELFDynamic(const MipsGNULDBackend& pParent);
+ ~MipsELFDynamic();
+
+private:
+ const MipsGNULDBackend& m_pParent;
+
+private:
+ void reserveTargetEntries(const ELFFileFormat& pFormat);
+ void applyTargetEntries(const ELFFileFormat& pFormat);
+
+ size_t getSymTabNum(const ELFFileFormat& pFormat) const;
+ size_t getGotSym(const ELFFileFormat& pFormat) const;
+ size_t getLocalGotNum(const ELFFileFormat& pFormat) const;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Mips/MipsELFSectLinker.cpp b/lib/Target/Mips/MipsELFSectLinker.cpp
new file mode 100644
index 0000000..aa41f36
--- /dev/null
+++ b/lib/Target/Mips/MipsELFSectLinker.cpp
@@ -0,0 +1,33 @@
+//===- MipsELFSectLinker.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsELFSectLinker.h"
+
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+MipsELFSectLinker::MipsELFSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : SectLinker(pOption,
+ pLDBackend) {
+ MCLDInfo &info = pOption.info();
+ // set up target-dependent constraints of attibutes
+ info.attrFactory().constraint().enableWholeArchive();
+ info.attrFactory().constraint().disableAsNeeded();
+ info.attrFactory().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ info.attrFactory().predefined().setWholeArchive();
+ info.attrFactory().predefined().setDynamic();
+}
+
+MipsELFSectLinker::~MipsELFSectLinker()
+{
+}
diff --git a/lib/Target/Mips/MipsELFSectLinker.h b/lib/Target/Mips/MipsELFSectLinker.h
new file mode 100644
index 0000000..82bec4c
--- /dev/null
+++ b/lib/Target/Mips/MipsELFSectLinker.h
@@ -0,0 +1,34 @@
+//===- MipsELFSectLinker.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MIPS_ELFSECTLINKER_H
+#define MIPS_ELFSECTLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/CodeGen/SectLinker.h>
+
+namespace mcld
+{
+
+/** \class MipsELFSectLinker
+ * \brief MipsELFSectLinker sets up the environment for linking.
+ */
+class MipsELFSectLinker : public SectLinker
+{
+public:
+ MipsELFSectLinker(SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend);
+
+ ~MipsELFSectLinker();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/Mips/MipsGOT.cpp b/lib/Target/Mips/MipsGOT.cpp
new file mode 100644
index 0000000..f9d5bb4
--- /dev/null
+++ b/lib/Target/Mips/MipsGOT.cpp
@@ -0,0 +1,148 @@
+//===- MipsGOT.cpp --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <llvm/Support/ErrorHandling.h>
+#include <mcld/LD/ResolveInfo.h>
+#include <mcld/Support/MemoryRegion.h>
+#include "MipsGOT.h"
+
+namespace {
+ const size_t MipsGOTEntrySize = 4;
+ const size_t MipsGOT0Num = 1;
+}
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// MipsGOT
+MipsGOT::MipsGOT(LDSection& pSection, llvm::MCSectionData& pSectionData)
+ : GOT(pSection, pSectionData, MipsGOTEntrySize),
+ m_pLocalNum(0)
+{
+ // Create GOT0 entries.
+ for (size_t i = 0; i < MipsGOT0Num; ++i) {
+ GOTEntry* entry =
+ new (std::nothrow) GOTEntry(0, MipsGOTEntrySize, &m_SectionData);
+
+ if (NULL == entry)
+ llvm::report_fatal_error("Allocating GOT0 entries failed!");
+
+ m_Section.setSize(m_Section.size() + MipsGOTEntrySize);
+ }
+
+ // Skip GOT0 entries.
+ iterator it = m_SectionData.begin();
+ iterator ie = m_SectionData.end();
+
+ for (size_t i = 1; i < MipsGOT0Num; ++i) {
+ if (it == ie)
+ llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
+
+ ++it;
+ }
+
+ m_LocalGOTIterator = it;
+ m_GlobalGOTIterator = it;
+ m_pLocalNum = MipsGOT0Num;
+}
+
+MipsGOT::iterator MipsGOT::begin()
+{
+ return m_SectionData.getFragmentList().begin();
+}
+
+MipsGOT::iterator MipsGOT::end()
+{
+ return m_SectionData.getFragmentList().end();
+}
+
+MipsGOT::const_iterator MipsGOT::begin() const
+{
+ return m_SectionData.getFragmentList().begin();
+}
+
+MipsGOT::const_iterator MipsGOT::end() const
+{
+ return m_SectionData.getFragmentList().end();
+}
+
+uint64_t MipsGOT::emit(MemoryRegion& pRegion)
+{
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
+
+ size_t entry_size = getEntrySize();
+
+ uint64_t result = 0;
+ for (iterator it = begin(), ie = end();
+ it != ie; ++it, ++buffer) {
+ GOTEntry* got = &(llvm::cast<GOTEntry>((*it)));
+ *buffer = static_cast<uint32_t>(got->getContent());
+ result += entry_size;
+ }
+ return result;
+}
+
+void MipsGOT::reserveEntry(size_t pNum)
+{
+ for (size_t i = 0; i < pNum; ++i) {
+ GOTEntry* entry =
+ new (std::nothrow) GOTEntry(0, MipsGOTEntrySize, &m_SectionData);
+
+ if (NULL == entry)
+ llvm::report_fatal_error("Allocating new GOTEntry failed");
+
+ m_Section.setSize(m_Section.size() + MipsGOTEntrySize);
+ }
+}
+
+void MipsGOT::reserveLocalEntry()
+{
+ reserveEntry(1);
+ ++m_pLocalNum;
+
+ // Move global entries iterator forward.
+ // We need to put global GOT entries after all local ones.
+ ++m_GlobalGOTIterator;
+}
+
+void MipsGOT::reserveGlobalEntry()
+{
+ reserveEntry(1);
+}
+
+GOTEntry* MipsGOT::getEntry(const ResolveInfo& pInfo, bool& pExist)
+{
+ GOTEntry*& entry = m_GeneralGOTMap[&pInfo];
+
+ pExist = NULL != entry;
+
+ if (!pExist) {
+ iterator& it = pInfo.isLocal() ? m_LocalGOTIterator : m_GlobalGOTIterator;
+
+ ++it;
+
+ assert(it != m_SectionData.getFragmentList().end() &&
+ "The number of GOT Entries and ResolveInfo doesn't match");
+
+ entry = llvm::cast<GOTEntry>(&(*it));
+ }
+
+ return entry;
+}
+
+size_t MipsGOT::getTotalNum() const
+{
+ return m_SectionData.getFragmentList().size();
+}
+
+size_t MipsGOT::getLocalNum() const
+{
+ return m_pLocalNum;
+}
+
diff --git a/lib/Target/Mips/MipsGOT.h b/lib/Target/Mips/MipsGOT.h
new file mode 100644
index 0000000..dccc7ac
--- /dev/null
+++ b/lib/Target/Mips/MipsGOT.h
@@ -0,0 +1,67 @@
+//===- MipsGOT.h ----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MIPS_GOT_H
+#define MCLD_MIPS_GOT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Target/GOT.h>
+
+namespace mcld
+{
+class LDSection;
+class MemoryRegion;
+
+/** \class MipsGOT
+ * \brief Mips Global Offset Table.
+ */
+class MipsGOT : public GOT
+{
+private:
+ typedef llvm::DenseMap<const ResolveInfo*, GOTEntry*> SymbolIndexMapType;
+
+public:
+ typedef llvm::MCSectionData::iterator iterator;
+ typedef llvm::MCSectionData::const_iterator const_iterator;
+
+public:
+ MipsGOT(LDSection& pSection, llvm::MCSectionData& pSectionData);
+
+ iterator begin();
+ iterator end();
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ uint64_t emit(MemoryRegion& pRegion);
+
+ void reserveLocalEntry();
+ void reserveGlobalEntry();
+
+ GOTEntry* getEntry(const ResolveInfo& pInfo, bool& pExist);
+
+ size_t getTotalNum() const;
+ size_t getLocalNum() const;
+
+private:
+ SymbolIndexMapType m_GeneralGOTMap;
+ iterator m_LocalGOTIterator; // last local GOT entries
+ iterator m_GlobalGOTIterator; // last global GOT entries
+ size_t m_pLocalNum;
+
+private:
+ // Use reserveLocalEntry()/reserveGlobalEntry() instead of this routine.
+ void reserveEntry(size_t pNum = 1);
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/Mips/MipsLDBackend.cpp b/lib/Target/Mips/MipsLDBackend.cpp
new file mode 100644
index 0000000..c7a6b23
--- /dev/null
+++ b/lib/Target/Mips/MipsLDBackend.cpp
@@ -0,0 +1,894 @@
+//===- MipsLDBackend.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 <llvm/Support/ELF.h>
+
+#include <mcld/LD/SectionMap.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/Target/OutputRelocSection.h>
+
+#include "Mips.h"
+#include "MipsELFDynamic.h"
+#include "MipsLDBackend.h"
+#include "MipsRelocationFactory.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
+};
+
+namespace mcld {
+
+MipsGNULDBackend::MipsGNULDBackend()
+ : m_pRelocFactory(NULL),
+ m_pGOT(NULL),
+ m_pRelDyn(NULL),
+ m_pDynamic(NULL),
+ m_pGOTSymbol(NULL),
+ m_pGpDispSymbol(NULL)
+{
+}
+
+MipsGNULDBackend::~MipsGNULDBackend()
+{
+ if (NULL != m_pRelocFactory)
+ delete m_pRelocFactory;
+ if (NULL != m_pGOT)
+ delete m_pGOT;
+ if (NULL != m_pRelDyn)
+ delete m_pRelDyn;
+ if (NULL != m_pDynamic)
+ delete m_pDynamic;
+}
+
+bool MipsGNULDBackend::initTargetSectionMap(SectionMap& pSectionMap)
+{
+ // Nothing to do because we do not support
+ // any MIPS specific sections now.
+ return true;
+}
+
+void MipsGNULDBackend::initTargetSections(MCLinker& pLinker)
+{
+ // Nothing to do because we do not support
+ // any MIPS specific sections now.
+}
+
+void MipsGNULDBackend::initTargetSymbols(MCLinker& pLinker)
+{
+ // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
+ // same name in input
+ m_pGOTSymbol = pLinker.defineSymbol<MCLinker::AsRefered, MCLinker::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Hidden);
+
+ m_pGpDispSymbol = pLinker.defineSymbol<MCLinker::AsRefered, MCLinker::Resolve>(
+ "_gp_disp",
+ false,
+ ResolveInfo::Section,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+
+ if (NULL != m_pGpDispSymbol) {
+ m_pGpDispSymbol->resolveInfo()->setReserved(ReserveGpDisp);
+ }
+}
+
+bool MipsGNULDBackend::initRelocFactory(const MCLinker& pLinker)
+{
+ if (NULL == m_pRelocFactory) {
+ m_pRelocFactory = new MipsRelocationFactory(1024, *this);
+ m_pRelocFactory->setLayout(pLinker.getLayout());
+ }
+ return true;
+}
+
+RelocationFactory* MipsGNULDBackend::getRelocFactory()
+{
+ assert(NULL != m_pRelocFactory);
+ return m_pRelocFactory;
+}
+
+void MipsGNULDBackend::scanRelocation(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
+
+ // A refernece to symbol _GLOBAL_OFFSET_TABLE_ implies
+ // that a .got section is needed.
+ if (NULL == m_pGOT && NULL != m_pGOTSymbol) {
+ if (rsym == m_pGOTSymbol->resolveInfo()) {
+ createGOT(pLinker, pOutput);
+ }
+ }
+
+ if (rsym->isLocal())
+ scanLocalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
+ else
+ scanGlobalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
+}
+
+uint32_t MipsGNULDBackend::machine() const
+{
+ return llvm::ELF::EM_MIPS;
+}
+
+uint8_t MipsGNULDBackend::OSABI() const
+{
+ return llvm::ELF::ELFOSABI_NONE;
+}
+
+uint8_t MipsGNULDBackend::ABIVersion() const
+{
+ return 0;
+}
+
+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;
+}
+
+bool MipsGNULDBackend::isLittleEndian() const
+{
+ // Now we support little endian (mipsel) target only.
+ return true;
+}
+
+unsigned int MipsGNULDBackend::bitclass() const
+{
+ return 32;
+}
+
+void MipsGNULDBackend::doPreLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ // when building shared object, the .got section is must.
+ if (pOutput.type() == Output::DynObj && NULL == m_pGOT) {
+ createGOT(pLinker, pOutput);
+ }
+}
+
+void MipsGNULDBackend::doPostLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ // emit program headers
+ if (pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec)
+ emitProgramHdrs(pLinker.getLDInfo().output());
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+MipsELFDynamic& MipsGNULDBackend::dynamic()
+{
+ if (NULL == m_pDynamic)
+ m_pDynamic = new MipsELFDynamic(*this);
+
+ return *m_pDynamic;
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+const MipsELFDynamic& MipsGNULDBackend::dynamic() const
+{
+ assert( NULL != m_pDynamic);
+ return *m_pDynamic;
+}
+
+uint64_t MipsGNULDBackend::emitSectionData(const Output& pOutput,
+ const LDSection& pSection,
+ const MCLDInfo& pInfo,
+ MemoryRegion& pRegion) const
+{
+ assert(pRegion.size() && "Size of MemoryRegion is zero!");
+
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ if (&pSection == &(file_format->getGOT())) {
+ assert(NULL != m_pGOT && "emitSectionData failed, m_pGOT is NULL!");
+ uint64_t result = m_pGOT->emit(pRegion);
+ return result;
+ }
+
+ llvm::report_fatal_error(llvm::Twine("Unable to emit section `") +
+ pSection.name() +
+ llvm::Twine("'.\n"));
+ return 0;
+}
+/// isGOTSymbol - return true if the symbol is the GOT entry.
+bool MipsGNULDBackend::isGOTSymbol(const LDSymbol& pSymbol) const
+{
+ return std::find(m_LocalGOTSyms.begin(),
+ m_LocalGOTSyms.end(), &pSymbol) != m_LocalGOTSyms.end() ||
+ std::find(m_GlobalGOTSyms.begin(),
+ m_GlobalGOTSyms.end(), &pSymbol) != m_GlobalGOTSyms.end();
+}
+
+/// emitDynamicSymbol - emit dynamic symbol.
+void MipsGNULDBackend::emitDynamicSymbol(llvm::ELF::Elf32_Sym& sym32,
+ Output& pOutput,
+ LDSymbol& pSymbol,
+ const Layout& pLayout,
+ char* strtab,
+ size_t strtabsize,
+ size_t symtabIdx)
+{
+ // maintain output's symbol and index map
+ bool sym_exist = false;
+ HashTableType::entry_type* entry = 0;
+ entry = m_pSymIndexMap->insert(&pSymbol, sym_exist);
+ entry->setValue(symtabIdx);
+
+ // FIXME: check the endian between host and target
+ // write out symbol
+ sym32.st_name = strtabsize;
+ sym32.st_value = pSymbol.value();
+ sym32.st_size = getSymbolSize(pSymbol);
+ sym32.st_info = getSymbolInfo(pSymbol);
+ sym32.st_other = pSymbol.visibility();
+ sym32.st_shndx = getSymbolShndx(pSymbol, pLayout);
+ // write out string
+ strcpy((strtab + strtabsize), pSymbol.name());
+}
+
+/// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash
+///
+/// the size of these tables should be computed before layout
+/// layout should computes the start offset of these tables
+void MipsGNULDBackend::emitDynNamePools(Output& pOutput,
+ SymbolCategory& pSymbols,
+ const Layout& pLayout,
+ const MCLDInfo& pLDInfo)
+{
+ assert(pOutput.hasMemArea());
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ 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.memArea()->request(symtab_sect.offset(),
+ symtab_sect.size());
+ MemoryRegion* strtab_region = pOutput.memArea()->request(strtab_sect.offset(),
+ strtab_sect.size());
+ MemoryRegion* hash_region = pOutput.memArea()->request(hash_sect.offset(),
+ hash_sect.size());
+ MemoryRegion* dyn_region = pOutput.memArea()->request(dyn_sect.offset(),
+ dyn_sect.size());
+ // set up symtab_region
+ llvm::ELF::Elf32_Sym* symtab32 = NULL;
+ symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region->start();
+
+ 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;
+
+ // set up strtab_region
+ char* strtab = (char*)strtab_region->start();
+ strtab[0] = '\0';
+
+ bool sym_exist = false;
+ HashTableType::entry_type* entry = 0;
+
+ // add index 0 symbol into SymIndexMap
+ entry = m_pSymIndexMap->insert(NULL, sym_exist);
+ entry->setValue(0);
+
+ size_t symtabIdx = 1;
+ size_t strtabsize = 1;
+
+ // emit of .dynsym, and .dynstr except GOT entries
+ for (SymbolCategory::iterator symbol = pSymbols.begin(),
+ sym_end = pSymbols.end(); symbol != sym_end; ++symbol) {
+ if (!isDynamicSymbol(**symbol, pOutput))
+ continue;
+
+ if (isGOTSymbol(**symbol))
+ continue;
+
+ emitDynamicSymbol(symtab32[symtabIdx], pOutput, **symbol, pLayout, strtab,
+ strtabsize, symtabIdx);
+
+ // sum up counters
+ ++symtabIdx;
+ strtabsize += (*symbol)->nameSize() + 1;
+ }
+
+ // emit global GOT
+ for (std::vector<LDSymbol*>::const_iterator symbol = m_GlobalGOTSyms.begin(),
+ symbol_end = m_GlobalGOTSyms.end();
+ symbol != symbol_end; ++symbol) {
+
+ emitDynamicSymbol(symtab32[symtabIdx], pOutput, **symbol, pLayout, strtab,
+ strtabsize, symtabIdx);
+
+ // sum up counters
+ ++symtabIdx;
+ 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();
+ InputTree::const_bfs_iterator input, inputEnd = pLDInfo.inputs().bfs_end();
+ for (input = pLDInfo.inputs().bfs_begin(); input != inputEnd; ++input) {
+ if (Input::DynObj == (*input)->type()) {
+ // --add-needed
+ if ((*input)->attribute()->isAddNeeded()) {
+ // --no-as-needed
+ if (!(*input)->attribute()->isAsNeeded()) {
+ strcpy((strtab + strtabsize), (*input)->name().c_str());
+ (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
+ strtabsize += (*input)->name().size() + 1;
+ ++dt_need;
+ }
+ // --as-needed
+ else if ((*input)->isNeeded()) {
+ strcpy((strtab + strtabsize), (*input)->name().c_str());
+ (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
+ strtabsize += (*input)->name().size() + 1;
+ ++dt_need;
+ }
+ }
+ }
+ } // for
+
+ // emit soname
+ // initialize value of ELF .dynamic section
+ dynamic().applySoname(strtabsize);
+ dynamic().applyEntries(pLDInfo, *file_format);
+ dynamic().emit(dyn_sect, *dyn_region);
+
+ strcpy((strtab + strtabsize), pOutput.name().c_str());
+ strtabsize += pOutput.name().size() + 1;
+
+ // emit hash table
+ // FIXME: this verion only emit SVR4 hash section.
+ // Please add GNU new hash section
+
+ // 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;
+
+ uint32_t* bucket = (word_array + 2);
+ uint32_t* chain = (bucket + nbucket);
+
+ // initialize bucket
+ bzero((void*)bucket, nbucket);
+
+ StringHash<ELF> hash_func;
+
+ 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;
+ }
+
+}
+
+MipsGOT& MipsGNULDBackend::getGOT()
+{
+ assert(NULL != m_pGOT);
+ return *m_pGOT;
+}
+
+const MipsGOT& MipsGNULDBackend::getGOT() const
+{
+ assert(NULL != m_pGOT);
+ return *m_pGOT;
+}
+
+OutputRelocSection& MipsGNULDBackend::getRelDyn()
+{
+ assert(NULL != m_pRelDyn);
+ return *m_pRelDyn;
+}
+
+const OutputRelocSection& MipsGNULDBackend::getRelDyn() const
+{
+ assert(NULL != m_pRelDyn);
+ return *m_pRelDyn;
+}
+
+unsigned int
+MipsGNULDBackend::getTargetSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ if (&pSectHdr == &file_format->getGOT())
+ return SHO_DATA;
+
+ return SHO_UNDEFINED;
+}
+
+/// finalizeSymbol - finalize the symbol value
+/// If the symbol's reserved field is not zero, MCLinker will call back this
+/// function to ask the final value of the symbol
+bool MipsGNULDBackend::finalizeSymbol(LDSymbol& pSymbol) const
+{
+ if (&pSymbol == m_pGpDispSymbol) {
+ m_pGpDispSymbol->setValue(m_pGOT->getSection().addr() + 0x7FF0);
+ return true;
+ }
+ return false;
+}
+
+/// allocateCommonSymbols - allocate common symbols in the corresponding
+/// sections.
+/// @refer Google gold linker: common.cc: 214
+/// FIXME: Mips needs to allocate small common symbol
+bool
+MipsGNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const
+{
+ // SymbolCategory contains all symbols that must emit to the output files.
+ // We are not like Google gold linker, we don't remember symbols before symbol
+ // resolution. All symbols in SymbolCategory are already resolved. Therefore, we
+ // don't need to care about some symbols may be changed its category due to symbol
+ // resolution.
+ SymbolCategory& symbol_list = pLinker.getOutputSymbols();
+
+ if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
+ return true;
+
+ // addralign := max value of all common symbols
+ uint64_t addralign = 0x0;
+
+ // Due to the visibility, some common symbols may be forcefully local.
+ SymbolCategory::iterator com_sym, com_end = symbol_list.localEnd();
+ for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+ if (ResolveInfo::Common == (*com_sym)->desc()) {
+ if ((*com_sym)->value() > addralign)
+ addralign = (*com_sym)->value();
+ }
+ }
+
+ // global common symbols.
+ com_end = symbol_list.commonEnd();
+ for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+ if ((*com_sym)->value() > addralign)
+ addralign = (*com_sym)->value();
+ }
+
+ // FIXME: If the order of common symbols is defined, then sort common symbols
+ // com_sym = symbol_list.commonBegin();
+ // std::sort(com_sym, com_end, some kind of order);
+
+ // get or create corresponding BSS LDSection
+ LDSection* bss_sect_hdr = NULL;
+ if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
+ ".tbss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
+ else {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
+
+ // get or create corresponding BSS MCSectionData
+ assert(NULL != bss_sect_hdr);
+ llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(*bss_sect_hdr);
+
+ // allocate all common symbols
+ uint64_t offset = bss_sect_hdr->size();
+
+ // allocate all local common symbols
+ com_end = symbol_list.localEnd();
+ for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+ if (ResolveInfo::Common == (*com_sym)->desc()) {
+ alignAddress(offset, (*com_sym)->value());
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size(), &bss_section);
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+ offset += (*com_sym)->size();
+ }
+ }
+
+ // allocate all global common symbols
+ com_end = symbol_list.commonEnd();
+ for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+ alignAddress(offset, (*com_sym)->value());
+
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size(), &bss_section);
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+ offset += (*com_sym)->size();
+ }
+
+ bss_sect_hdr->setSize(offset);
+ symbol_list.changeCommonsToGlobal();
+ return true;
+}
+
+void MipsGNULDBackend::updateAddend(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ const Layout& pLayout) const
+{
+ // Update value keep in addend if we meet a section symbol
+ if(pReloc.symInfo()->type() == ResolveInfo::Section) {
+ pReloc.setAddend(pLayout.getOutputOffset(
+ *pInputSym.fragRef()) + pReloc.addend());
+ }
+}
+
+void MipsGNULDBackend::scanLocalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ updateAddend(pReloc, pInputSym, pLinker.getLayout());
+
+ switch (pReloc.type()){
+ case llvm::ELF::R_MIPS_NONE:
+ case llvm::ELF::R_MIPS_16:
+ break;
+ case llvm::ELF::R_MIPS_32:
+ if (Output::DynObj == pOutput.type()) {
+ // TODO: (simon) The gold linker does not create an entry in .rel.dyn
+ // section if the symbol section flags contains SHF_EXECINSTR.
+ // 1. Find the reason of this condition.
+ // 2. Check this condition here.
+ if (NULL == m_pRelDyn)
+ createRelDyn(pLinker, pOutput);
+
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
+ break;
+ case llvm::ELF::R_MIPS_REL32:
+ case llvm::ELF::R_MIPS_26:
+ case llvm::ELF::R_MIPS_HI16:
+ case llvm::ELF::R_MIPS_LO16:
+ case llvm::ELF::R_MIPS_PC16:
+ case llvm::ELF::R_MIPS_SHIFT5:
+ case llvm::ELF::R_MIPS_SHIFT6:
+ case llvm::ELF::R_MIPS_64:
+ case llvm::ELF::R_MIPS_GOT_PAGE:
+ case llvm::ELF::R_MIPS_GOT_OFST:
+ case llvm::ELF::R_MIPS_SUB:
+ case llvm::ELF::R_MIPS_INSERT_A:
+ case llvm::ELF::R_MIPS_INSERT_B:
+ case llvm::ELF::R_MIPS_DELETE:
+ case llvm::ELF::R_MIPS_HIGHER:
+ case llvm::ELF::R_MIPS_HIGHEST:
+ case llvm::ELF::R_MIPS_SCN_DISP:
+ case llvm::ELF::R_MIPS_REL16:
+ case llvm::ELF::R_MIPS_ADD_IMMEDIATE:
+ case llvm::ELF::R_MIPS_PJUMP:
+ case llvm::ELF::R_MIPS_RELGOT:
+ case llvm::ELF::R_MIPS_JALR:
+ case llvm::ELF::R_MIPS_GLOB_DAT:
+ case llvm::ELF::R_MIPS_COPY:
+ case llvm::ELF::R_MIPS_JUMP_SLOT:
+ break;
+ case llvm::ELF::R_MIPS_GOT16:
+ case llvm::ELF::R_MIPS_CALL16:
+ if (NULL == m_pGOT)
+ createGOT(pLinker, pOutput);
+
+ if (!(rsym->reserved() & MipsGNULDBackend::ReserveGot)) {
+ m_pGOT->reserveLocalEntry();
+ rsym->setReserved(rsym->reserved() | ReserveGot);
+ m_LocalGOTSyms.push_back(rsym->outSymbol());
+ }
+ break;
+ 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:
+ case llvm::ELF::R_MIPS_TLS_DTPMOD64:
+ case llvm::ELF::R_MIPS_TLS_DTPREL64:
+ case llvm::ELF::R_MIPS_TLS_GD:
+ case llvm::ELF::R_MIPS_TLS_LDM:
+ case llvm::ELF::R_MIPS_TLS_DTPREL_HI16:
+ case llvm::ELF::R_MIPS_TLS_DTPREL_LO16:
+ case llvm::ELF::R_MIPS_TLS_GOTTPREL:
+ case llvm::ELF::R_MIPS_TLS_TPREL32:
+ case llvm::ELF::R_MIPS_TLS_TPREL64:
+ case llvm::ELF::R_MIPS_TLS_TPREL_HI16:
+ case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
+ break;
+ default:
+ llvm::report_fatal_error(llvm::Twine("Unknown relocation ") +
+ llvm::Twine(pReloc.type()) +
+ llvm::Twine("for the local symbol `") +
+ pReloc.symInfo()->name() +
+ llvm::Twine("'."));
+ }
+}
+
+void MipsGNULDBackend::scanGlobalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ switch (pReloc.type()){
+ case llvm::ELF::R_MIPS_NONE:
+ case llvm::ELF::R_MIPS_INSERT_A:
+ case llvm::ELF::R_MIPS_INSERT_B:
+ case llvm::ELF::R_MIPS_DELETE:
+ case llvm::ELF::R_MIPS_TLS_DTPMOD64:
+ case llvm::ELF::R_MIPS_TLS_DTPREL64:
+ case llvm::ELF::R_MIPS_REL16:
+ case llvm::ELF::R_MIPS_ADD_IMMEDIATE:
+ case llvm::ELF::R_MIPS_PJUMP:
+ case llvm::ELF::R_MIPS_RELGOT:
+ case llvm::ELF::R_MIPS_TLS_TPREL64:
+ break;
+ case llvm::ELF::R_MIPS_32:
+ case llvm::ELF::R_MIPS_64:
+ case llvm::ELF::R_MIPS_HI16:
+ case llvm::ELF::R_MIPS_LO16:
+ if (isSymbolNeedsDynRel(*rsym, pOutput)) {
+ if (NULL == m_pRelDyn)
+ createRelDyn(pLinker, pOutput);
+
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
+ break;
+ case llvm::ELF::R_MIPS_GOT16:
+ case llvm::ELF::R_MIPS_CALL16:
+ 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:
+ case llvm::ELF::R_MIPS_GOT_PAGE:
+ case llvm::ELF::R_MIPS_GOT_OFST:
+ if (NULL == m_pGOT)
+ createGOT(pLinker, pOutput);
+
+ if (!(rsym->reserved() & MipsGNULDBackend::ReserveGot)) {
+ m_pGOT->reserveGlobalEntry();
+ rsym->setReserved(rsym->reserved() | ReserveGot);
+ m_GlobalGOTSyms.push_back(rsym->outSymbol());
+ }
+ break;
+ case llvm::ELF::R_MIPS_LITERAL:
+ case llvm::ELF::R_MIPS_GPREL32:
+ llvm::report_fatal_error(llvm::Twine("Relocation ") +
+ llvm::Twine(pReloc.type()) +
+ llvm::Twine(" is not defined for the "
+ "global symbol `") +
+ pReloc.symInfo()->name() +
+ llvm::Twine("'."));
+ break;
+ case llvm::ELF::R_MIPS_GPREL16:
+ break;
+ case llvm::ELF::R_MIPS_26:
+ case llvm::ELF::R_MIPS_PC16:
+ break;
+ case llvm::ELF::R_MIPS_16:
+ case llvm::ELF::R_MIPS_SHIFT5:
+ case llvm::ELF::R_MIPS_SHIFT6:
+ case llvm::ELF::R_MIPS_SUB:
+ case llvm::ELF::R_MIPS_HIGHER:
+ case llvm::ELF::R_MIPS_HIGHEST:
+ case llvm::ELF::R_MIPS_SCN_DISP:
+ break;
+ case llvm::ELF::R_MIPS_TLS_DTPREL32:
+ case llvm::ELF::R_MIPS_TLS_GD:
+ case llvm::ELF::R_MIPS_TLS_LDM:
+ case llvm::ELF::R_MIPS_TLS_DTPREL_HI16:
+ case llvm::ELF::R_MIPS_TLS_DTPREL_LO16:
+ case llvm::ELF::R_MIPS_TLS_GOTTPREL:
+ case llvm::ELF::R_MIPS_TLS_TPREL32:
+ case llvm::ELF::R_MIPS_TLS_TPREL_HI16:
+ case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
+ break;
+ case llvm::ELF::R_MIPS_REL32:
+ break;
+ case llvm::ELF::R_MIPS_JALR:
+ break;
+ case llvm::ELF::R_MIPS_COPY:
+ case llvm::ELF::R_MIPS_GLOB_DAT:
+ case llvm::ELF::R_MIPS_JUMP_SLOT:
+ llvm::report_fatal_error(llvm::Twine("Relocation ") +
+ llvm::Twine(pReloc.type()) +
+ llvm::Twine("for the global symbol `") +
+ pReloc.symInfo()->name() +
+ llvm::Twine("' should only be seen "
+ "by the dynamic linker"));
+ break;
+ default:
+ llvm::report_fatal_error(llvm::Twine("Unknown relocation ") +
+ llvm::Twine(pReloc.type()) +
+ llvm::Twine("for the global symbol `") +
+ pReloc.symInfo()->name() +
+ llvm::Twine("'."));
+ }
+}
+
+bool MipsGNULDBackend::isSymbolNeedsPLT(ResolveInfo& pSym,
+ const Output& pOutput) const
+{
+ return (Output::DynObj == pOutput.type() &&
+ ResolveInfo::Function == pSym.type() &&
+ (pSym.isDyn() || pSym.isUndef()));
+}
+
+bool MipsGNULDBackend::isSymbolNeedsDynRel(ResolveInfo& pSym,
+ const Output& pOutput) const
+{
+ if(pSym.isUndef() && Output::Exec == pOutput.type())
+ return false;
+ if(pSym.isAbsolute())
+ return false;
+ if(Output::DynObj == pOutput.type())
+ return true;
+ if(pSym.isDyn() || pSym.isUndef())
+ return true;
+
+ return false;
+}
+
+void MipsGNULDBackend::createGOT(MCLinker& pLinker, const Output& pOutput)
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ LDSection& got = file_format->getGOT();
+ m_pGOT = new MipsGOT(got, pLinker.getOrCreateSectData(got));
+
+ // define symbol _GLOBAL_OFFSET_TABLE_ when .got create
+ if( m_pGOTSymbol != NULL ) {
+ pLinker.defineSymbol<MCLinker::Force, MCLinker::Unresolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+ else {
+ m_pGOTSymbol = pLinker.defineSymbol<MCLinker::Force, MCLinker::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+}
+
+void MipsGNULDBackend::createRelDyn(MCLinker& pLinker, const Output& pOutput)
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ // get .rel.dyn LDSection and create MCSectionData
+ LDSection& reldyn = file_format->getRelDyn();
+ // create MCSectionData and ARMRelDynSection
+ m_pRelDyn = new OutputRelocSection(reldyn,
+ pLinker.getOrCreateSectData(reldyn),
+ 8);
+}
+
+ELFFileFormat* MipsGNULDBackend::getOutputFormat(const Output& pOutput) const
+{
+ switch (pOutput.type()) {
+ case Output::DynObj:
+ return getDynObjFileFormat();
+ case Output::Exec:
+ return getExecFileFormat();
+ case Output::Object:
+ return NULL;
+ default:
+ llvm::report_fatal_error(llvm::Twine("Unsupported output file format: ") +
+ llvm::Twine(pOutput.type()));
+ return NULL;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+/// createMipsLDBackend - the help funtion to create corresponding MipsLDBackend
+///
+static TargetLDBackend* createMipsLDBackend(const llvm::Target& pTarget,
+ const std::string& pTriple)
+{
+ llvm::Triple theTriple(pTriple);
+ if (theTriple.isOSDarwin()) {
+ assert(0 && "MachO linker is not supported yet");
+ }
+ if (theTriple.isOSWindows()) {
+ assert(0 && "COFF linker is not supported yet");
+ }
+ return new MipsGNULDBackend();
+}
+
+} // namespace of mcld
+
+//=============================
+// Force static initialization.
+extern "C" void LLVMInitializeMipsLDBackend() {
+ // Register the linker backend
+ mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheMipselTarget,
+ mcld::createMipsLDBackend);
+}
diff --git a/lib/Target/Mips/MipsLDBackend.h b/lib/Target/Mips/MipsLDBackend.h
new file mode 100644
index 0000000..cd9e3cd
--- /dev/null
+++ b/lib/Target/Mips/MipsLDBackend.h
@@ -0,0 +1,200 @@
+//===- MipsLDBackend.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MIPS_LDBACKEND_H
+#define MIPS_LDBACKEND_H
+#include "mcld/Target/GNULDBackend.h"
+#include "MipsELFDynamic.h"
+#include "MipsGOT.h"
+
+namespace mcld {
+
+class MCLinker;
+class OutputRelocSection;
+class SectionMap;
+
+//===----------------------------------------------------------------------===//
+/// MipsGNULDBackend - linker backend of Mips target of GNU ELF format
+///
+class MipsGNULDBackend : public GNULDBackend
+{
+public:
+ enum ReservedEntryType {
+ None = 0, // no reserved entry
+ ReserveRel = 1, // reserve a dynamic relocation entry
+ ReserveGot = 2, // reserve a GOT entry
+ ReserveGpDisp = 8 // reserve _gp_disp symbol
+ };
+
+public:
+ MipsGNULDBackend();
+ ~MipsGNULDBackend();
+
+public:
+ /// initTargetSectionMap - initialize target dependent section mapping.
+ bool initTargetSectionMap(SectionMap& pSectionMap);
+
+ /// initTargetSections - initialize target dependent sections in output
+ void initTargetSections(MCLinker& pLinker);
+
+ /// initTargetSymbols - initialize target dependent symbols in output.
+ void initTargetSymbols(MCLinker& pLinker);
+
+ /// initRelocFactory - create and initialize RelocationFactory.
+ bool initRelocFactory(const MCLinker& pLinker);
+
+ /// getRelocFactory - return relocation factory.
+ RelocationFactory* getRelocFactory();
+
+ /// scanRelocation - determine the empty entries are needed or not and
+ /// create the empty entries if needed.
+ /// For Mips, the GOT, GP, and dynamic relocation entries are check to create.
+ void scanRelocation(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ uint32_t machine() const;
+
+ /// OSABI - the value of e_ident[EI_OSABI]
+ uint8_t OSABI() const;
+
+ /// ABIVersion - the value of e_ident[EI_ABIVRESION]
+ uint8_t ABIVersion() const;
+
+ /// flags - the value of ElfXX_Ehdr::e_flags
+ uint64_t flags() const;
+
+ bool isLittleEndian() const;
+
+ unsigned int bitclass() const;
+
+ /// preLayout - Backend can do any needed modification before layout
+ void doPreLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+ /// postLayout -Backend can do any needed modification after layout
+ void doPostLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ MipsELFDynamic& dynamic();
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ const MipsELFDynamic& 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 pOutput - the output file
+ /// @param pSection - the given LDSection
+ /// @param pInfo - all options in the command line.
+ /// @param pRegion - the region to write out data
+ /// @return the size of the table in the file.
+ uint64_t emitSectionData(const Output& pOutput,
+ const LDSection& pSection,
+ const MCLDInfo& pInfo,
+ MemoryRegion& pRegion) const;
+
+ /// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash
+ virtual void emitDynNamePools(Output& pOutput,
+ SymbolCategory& pSymbols,
+ const Layout& pLayout,
+ const MCLDInfo& pLDInfo);
+
+ MipsGOT& getGOT();
+ const MipsGOT& getGOT() const;
+
+ OutputRelocSection& getRelDyn();
+ const OutputRelocSection& getRelDyn() const;
+
+ /// getTargetSectionOrder - compute the layout order of ARM target sections
+ unsigned int getTargetSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const;
+
+ /// finalizeSymbol - finalize the symbol value
+ /// If the symbol's reserved field is not zero, MCLinker will call back this
+ /// function to ask the final value of the symbol
+ bool finalizeSymbol(LDSymbol& pSymbol) const;
+
+ /// allocateCommonSymbols - allocate common symbols in the corresponding
+ /// sections.
+ bool allocateCommonSymbols(const MCLDInfo& pLDInfo, MCLinker& pLinker) const;
+
+private:
+ void scanLocalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ void scanGlobalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ bool isSymbolNeedsPLT(ResolveInfo& pSym, const Output& pOutput) const;
+ bool isSymbolNeedsDynRel(ResolveInfo& pSym, const Output& pOutput) const;
+
+ void createGOT(MCLinker& pLinker, const Output& pOutput);
+ void createRelDyn(MCLinker& pLinker, const Output& pOutput);
+
+ ELFFileFormat* getOutputFormat(const Output& pOutput) const;
+
+ /// updateAddend - update addend value of the relocation if the
+ /// the target symbol is a section symbol. Addend is the offset
+ /// in the section. This value should be updated after section
+ /// merged.
+ void updateAddend(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ const Layout& pLayout) const;
+
+private:
+ RelocationFactory* m_pRelocFactory;
+
+ MipsGOT* m_pGOT; // .got
+ OutputRelocSection* m_pRelDyn; // .rel.dyn
+
+ MipsELFDynamic* m_pDynamic;
+ LDSymbol* m_pGOTSymbol;
+ LDSymbol* m_pGpDispSymbol;
+
+ std::vector<LDSymbol*> m_LocalGOTSyms;
+ std::vector<LDSymbol*> m_GlobalGOTSyms;
+
+private:
+ /// isGOTSymbol - return true if the symbol is the GOT entry.
+ bool isGOTSymbol(const LDSymbol& pSymbol) const;
+ /// emitDynamicSymbol - emit dynamic symbol.
+ void emitDynamicSymbol(llvm::ELF::Elf32_Sym& sym32,
+ Output& pOutput,
+ LDSymbol& pSymbol,
+ const Layout& pLayout,
+ char* strtab,
+ size_t strtabsize,
+ size_t symtabIdx);
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/Mips/MipsRelocationFactory.cpp b/lib/Target/Mips/MipsRelocationFactory.cpp
new file mode 100644
index 0000000..e3a7793
--- /dev/null
+++ b/lib/Target/Mips/MipsRelocationFactory.cpp
@@ -0,0 +1,363 @@
+//===- MipsRelocationFactory.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/ELF.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <mcld/LD/Layout.h>
+#include <mcld/Target/OutputRelocSection.h>
+
+#include "MipsRelocationFactory.h"
+#include "MipsRelocationFunctions.h"
+
+using namespace mcld;
+
+DECL_MIPS_APPLY_RELOC_FUNCS
+
+//==========================
+// MipsRelocationFactory
+MipsRelocationFactory::MipsRelocationFactory(size_t pNum,
+ MipsGNULDBackend& pParent)
+ : RelocationFactory(pNum),
+ m_Target(pParent),
+ m_AHL(0)
+{
+}
+
+void MipsRelocationFactory::applyRelocation(Relocation& pRelocation,
+ const MCLDInfo& pLDInfo)
+
+{
+ /// the prototype of applying function
+ typedef Result (*ApplyFunctionType)(Relocation&,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory&);
+
+ // the table entry of applying functions
+ struct ApplyFunctionTriple {
+ ApplyFunctionType func;
+ unsigned int type;
+ const char* name;
+ };
+
+ // declare the table of applying functions
+ static ApplyFunctionTriple apply_functions[] = {
+ DECL_MIPS_APPLY_RELOC_FUNC_PTRS
+ };
+
+ Relocation::Type type = pRelocation.type();
+
+ if (type >= sizeof(apply_functions) / sizeof(apply_functions[0])) {
+ llvm::report_fatal_error(llvm::Twine("Unknown relocation type. "
+ "To symbol `") +
+ pRelocation.symInfo()->name() +
+ llvm::Twine("'."));
+ }
+
+ // apply the relocation
+ Result result = apply_functions[type].func(pRelocation, pLDInfo, *this);
+
+ // check result
+ if (Overflow == result) {
+ llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
+ llvm::Twine(apply_functions[type].name) +
+ llvm::Twine("' causes overflow. on symbol: `") +
+ llvm::Twine(pRelocation.symInfo()->name()) +
+ llvm::Twine("'."));
+ return;
+ }
+
+ if (BadReloc == result) {
+ llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
+ llvm::Twine(apply_functions[type].name) +
+ llvm::Twine("' encounters unexpected opcode. "
+ "on symbol: `") +
+ llvm::Twine(pRelocation.symInfo()->name()) +
+ llvm::Twine("'."));
+ return;
+ }
+}
+
+//=========================================//
+// Relocation helper function //
+//=========================================//
+
+static const char * const GP_DISP_NAME = "_gp_disp";
+
+// Get an relocation entry in .rel.dyn and set its type to R_MIPS_REL32,
+// its FragmentRef to pReloc->targetFrag() and its ResolveInfo
+// to pReloc->symInfo()
+static
+void helper_SetRelDynEntry(Relocation& pReloc,
+ MipsRelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ MipsGNULDBackend& ld_backend = pParent.getTarget();
+
+ bool exist;
+ Relocation& rel_entry =
+ *ld_backend.getRelDyn().getEntry(*rsym, false, exist);
+
+ rel_entry.setType(llvm::ELF::R_MIPS_REL32);
+ rel_entry.targetRef() = pReloc.targetRef();
+ rel_entry.setSymInfo(0);
+}
+
+// Find next R_MIPS_LO16 relocation paired to pReloc.
+static
+Relocation* helper_FindLo16Reloc(Relocation& pReloc)
+{
+ Relocation* reloc = static_cast<Relocation*>(pReloc.getNextNode());
+ while (NULL != reloc)
+ {
+ if (llvm::ELF::R_MIPS_LO16 == reloc->type() &&
+ reloc->symInfo() == pReloc.symInfo())
+ return reloc;
+
+ reloc = static_cast<Relocation*>(reloc->getNextNode());
+ }
+ return NULL;
+}
+
+// Check the symbol is _gp_disp.
+static
+bool helper_isGpDisp(const Relocation& pReloc)
+{
+ const ResolveInfo* rsym = pReloc.symInfo();
+ return 0 == strcmp(GP_DISP_NAME, rsym->name());
+}
+
+static
+RelocationFactory::Address helper_GetGP(MipsRelocationFactory& pParent)
+{
+ return pParent.getTarget().getGOT().getSection().addr() + 0x7FF0;
+}
+
+static
+GOTEntry& helper_GetGOTEntry(Relocation& pReloc,
+ MipsRelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ MipsGNULDBackend& ld_backend = pParent.getTarget();
+
+ bool exist;
+ GOTEntry& got_entry = *ld_backend.getGOT().getEntry(*rsym, exist);
+
+ if (exist)
+ return got_entry;
+
+ // If we first get this GOT entry, we should initialize it.
+ if (rsym->reserved() & MipsGNULDBackend::ReserveGot) {
+ got_entry.setContent(pReloc.symValue());
+ }
+ else {
+ llvm::report_fatal_error("No GOT entry reserved for GOT type relocation!");
+ }
+
+ return got_entry;
+}
+
+static
+RelocationFactory::Address helper_GetGOTOffset(Relocation& pReloc,
+ MipsRelocationFactory& pParent)
+{
+ GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent);
+ return pParent.getLayout().getOutputOffset(got_entry) - 0x7FF0;
+}
+
+static
+int32_t helper_CalcAHL(const Relocation& pHiReloc, const Relocation& pLoReloc)
+{
+ assert((pHiReloc.type() == llvm::ELF::R_MIPS_HI16 ||
+ pHiReloc.type() == llvm::ELF::R_MIPS_GOT16) &&
+ pLoReloc.type() == llvm::ELF::R_MIPS_LO16 &&
+ "Incorrect type of relocation for AHL calculation");
+
+ // Note the addend is section symbol offset here
+ assert (pHiReloc.addend() == pLoReloc.addend());
+
+ int32_t AHI = pHiReloc.target();
+ int32_t ALO = pLoReloc.target();
+ int32_t AHL = ((AHI & 0xFFFF) << 16) + (int16_t)(ALO & 0xFFFF) + pLoReloc.addend();
+ return AHL;
+}
+
+static
+void helper_DynRel(Relocation& pReloc,
+ MipsRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ MipsGNULDBackend& ld_backend = pParent.getTarget();
+
+ bool exist;
+ Relocation& rel_entry =
+ *ld_backend.getRelDyn().getEntry(*rsym, false, exist);
+
+ rel_entry.setType(llvm::ELF::R_MIPS_REL32);
+ rel_entry.targetRef() = pReloc.targetRef();
+ rel_entry.setSymInfo(rsym->isLocal() ? NULL : rsym);
+}
+
+//=========================================//
+// Relocation functions implementation //
+//=========================================//
+
+// R_MIPS_NONE and those unsupported/deprecated relocation type
+static
+MipsRelocationFactory::Result none(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory& pParent)
+{
+ return MipsRelocationFactory::OK;
+}
+
+// R_MIPS_32: S + A
+static
+MipsRelocationFactory::Result abs32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ if (rsym->reserved() & MipsGNULDBackend::ReserveRel) {
+ helper_DynRel(pReloc, pParent);
+ }
+
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ RelocationFactory::DWord S = pReloc.symValue();
+
+ pReloc.target() |= (S + A);
+
+ return MipsRelocationFactory::OK;
+}
+
+// R_MIPS_HI16:
+// local/external: ((AHL + S) - (short)(AHL + S)) >> 16
+// _gp_disp : ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16
+static
+MipsRelocationFactory::Result hi16(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory& pParent)
+{
+ Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
+ assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_HI16");
+
+ int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc);
+ int32_t res = 0;
+
+ pParent.setAHL(AHL);
+
+ if (helper_isGpDisp(pReloc)) {
+ int32_t P = pReloc.place(pParent.getLayout());
+ int32_t GP = helper_GetGP(pParent);
+ res = ((AHL + GP - P) - (int16_t)(AHL + GP - P)) >> 16;
+ }
+ else {
+ int32_t S = pReloc.symValue();
+ res = ((AHL + S) - (int16_t)(AHL + S)) >> 16;
+ }
+
+ pReloc.target() &= 0xFFFF0000;
+ pReloc.target() |= (res & 0xFFFF);
+
+ return MipsRelocationFactory::OK;
+}
+
+// R_MIPS_LO16:
+// local/external: AHL + S
+// _gp_disp : AHL + GP - P + 4
+static
+MipsRelocationFactory::Result lo16(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory& pParent)
+{
+ int32_t AHL = pParent.getAHL();
+ int32_t res = 0;
+
+ if (helper_isGpDisp(pReloc)) {
+ int32_t P = pReloc.place(pParent.getLayout());
+ int32_t GP = helper_GetGP(pParent);
+ res = AHL + GP - P + 4;
+ }
+ else {
+ int32_t S = pReloc.symValue();
+ res = AHL + S;
+ }
+
+ pReloc.target() &= 0xFFFF0000;
+ pReloc.target() |= (res & 0xFFFF);
+
+ return MipsRelocationFactory::OK;
+}
+
+// R_MIPS_GOT16:
+// local : G (calculate AHL and put high 16 bit to GOT)
+// external: G
+static
+MipsRelocationFactory::Result got16(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ if (rsym->isLocal()) {
+ Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
+ assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_GOT16");
+
+ int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc);
+ int32_t S = pReloc.symValue();
+
+ pParent.setAHL(AHL);
+
+ GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent);
+
+ int32_t res = (AHL + S + 0x8000) & 0xFFFF0000;
+ got_entry.setContent(res);
+ }
+
+ RelocationFactory::Address G = helper_GetGOTOffset(pReloc, pParent);
+
+ pReloc.target() &= 0xFFFF0000;
+ pReloc.target() |= (G & 0xFFFF);
+
+ return MipsRelocationFactory::OK;
+}
+
+// R_MIPS_CALL16: G
+static
+MipsRelocationFactory::Result call16(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory& pParent)
+{
+ RelocationFactory::Address G = helper_GetGOTOffset(pReloc, pParent);
+
+ pReloc.target() &= 0xFFFF0000;
+ pReloc.target() |= (G & 0xFFFF);
+
+ return MipsRelocationFactory::OK;
+}
+
+// R_MIPS_GPREL32: A + S + GP0 - GP
+static
+MipsRelocationFactory::Result gprel32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory& pParent)
+{
+ int32_t A = pReloc.target();
+ int32_t S = pReloc.symValue();
+ int32_t GP = helper_GetGP(pParent);
+
+ // llvm does not emits SHT_MIPS_REGINFO section.
+ // Assume that GP0 is zero.
+ pReloc.target() = (A + S - GP) & 0xFFFFFFFF;
+
+ return MipsRelocationFactory::OK;
+}
diff --git a/lib/Target/Mips/MipsRelocationFactory.h b/lib/Target/Mips/MipsRelocationFactory.h
new file mode 100644
index 0000000..8f3bf93
--- /dev/null
+++ b/lib/Target/Mips/MipsRelocationFactory.h
@@ -0,0 +1,64 @@
+//===- MipsRelocationFactory.h --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MIPS_RELOCATION_FACTORY_H
+#define MIPS_RELOCATION_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/RelocationFactory.h>
+#include <mcld/Support/GCFactory.h>
+#include "MipsLDBackend.h"
+
+namespace mcld
+{
+
+/** \class MipsRelocationFactory
+ * \brief MipsRelocationFactory creates and destroys the Mips relocations.
+ */
+class MipsRelocationFactory : public RelocationFactory
+{
+public:
+ /** \enum Reloc
+ * \brief Reloc is the result of applying functions.
+ */
+ enum Result
+ {
+ OK,
+ Overflow,
+ BadReloc
+ };
+
+public:
+ MipsRelocationFactory(size_t pNum, MipsGNULDBackend& pParent);
+
+ void applyRelocation(Relocation& pRelocation, const MCLDInfo& pLDInfo);
+
+ MipsGNULDBackend& getTarget()
+ { return m_Target; }
+
+ const MipsGNULDBackend& getTarget() const
+ { return m_Target; }
+
+ // Get last calculated AHL.
+ int32_t getAHL() const
+ { return m_AHL; }
+
+ // Set last calculated AHL.
+ void setAHL(int32_t pAHL)
+ { m_AHL = pAHL; }
+
+private:
+ MipsGNULDBackend& m_Target;
+ int32_t m_AHL;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Mips/MipsRelocationFunctions.h b/lib/Target/Mips/MipsRelocationFunctions.h
new file mode 100644
index 0000000..4b60d10
--- /dev/null
+++ b/lib/Target/Mips/MipsRelocationFunctions.h
@@ -0,0 +1,76 @@
+//===- MipsRelocationFunction.h -------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define DECL_MIPS_APPLY_RELOC_FUNC(Name) \
+static MipsRelocationFactory::Result Name(Relocation& pEntry, \
+ const MCLDInfo& pLDInfo, \
+ MipsRelocationFactory& pParent);
+
+#define DECL_MIPS_APPLY_RELOC_FUNCS \
+DECL_MIPS_APPLY_RELOC_FUNC(none) \
+DECL_MIPS_APPLY_RELOC_FUNC(abs32) \
+DECL_MIPS_APPLY_RELOC_FUNC(hi16) \
+DECL_MIPS_APPLY_RELOC_FUNC(lo16) \
+DECL_MIPS_APPLY_RELOC_FUNC(got16) \
+DECL_MIPS_APPLY_RELOC_FUNC(call16) \
+DECL_MIPS_APPLY_RELOC_FUNC(gprel32)
+
+#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" }, \
+ { &none, 22, "R_MIPS_GOT_HI16" }, \
+ { &none, 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" }, \
+ { &none, 30, "R_MIPS_CALL_HI16" }, \
+ { &none, 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" }
diff --git a/lib/Target/Mips/MipsSectLinker.cpp b/lib/Target/Mips/MipsSectLinker.cpp
new file mode 100644
index 0000000..af543c9
--- /dev/null
+++ b/lib/Target/Mips/MipsSectLinker.cpp
@@ -0,0 +1,47 @@
+//===- MipsSectLinker.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 "Mips.h"
+#include "MipsAndroidSectLinker.h"
+
+using namespace mcld;
+
+namespace mcld {
+//===----------------------------------------------------------------------===//
+/// createMipsSectLinker - the help funtion to create
+/// corresponding MipsSectLinker
+///
+SectLinker* createMipsSectLinker(const std::string &pTriple,
+ SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend)
+{
+ llvm::Triple theTriple(pTriple);
+ if (theTriple.isOSDarwin()) {
+ assert(0 && "MachO linker has not supported yet");
+ }
+ if (theTriple.isOSWindows()) {
+ assert(0 && "COFF linker has not supported yet");
+ }
+
+ // For now, use Android SectLinker directly
+ return new MipsAndroidSectLinker(pOption,
+ pLDBackend);
+}
+
+} // namespace of mcld
+
+//==========================
+// MipsSectLinker
+extern "C" void LLVMInitializeMipsSectLinker() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterSectLinker(TheMipselTarget,
+ createMipsSectLinker);
+}
diff --git a/lib/Target/Mips/MipsTargetMachine.cpp b/lib/Target/Mips/MipsTargetMachine.cpp
new file mode 100644
index 0000000..0987585
--- /dev/null
+++ b/lib/Target/Mips/MipsTargetMachine.cpp
@@ -0,0 +1,34 @@
+//===- MipsTargetMachine.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsTargetMachine.h"
+#include "mcld/Target/TargetMachine.h"
+#include "mcld/Support/TargetRegistry.h"
+#include "mcld/MC/MCLDInfo.h"
+#include "Mips.h"
+
+extern "C" void LLVMInitializeMipsLDTarget() {
+ // Register createTargetMachine function pointer to mcld::Target
+ mcld::RegisterTargetMachine<mcld::MipsBaseTargetMachine>
+ X(mcld::TheMipselTarget);
+}
+
+mcld::MipsBaseTargetMachine::MipsBaseTargetMachine(llvm::TargetMachine& pPM,
+ const mcld::Target &pTarget,
+ const std::string& pTriple)
+ : mcld::LLVMTargetMachine(pPM, pTarget, pTriple) {
+ // arg1 - the number of total attributes
+ // arg2 - the most possible number of input files
+ m_pLDInfo = new MCLDInfo(pTriple, 32, 64);
+}
+
+mcld::MipsBaseTargetMachine::~MipsBaseTargetMachine()
+{
+ delete m_pLDInfo;
+}
diff --git a/lib/Target/Mips/MipsTargetMachine.h b/lib/Target/Mips/MipsTargetMachine.h
new file mode 100644
index 0000000..e9bd5da
--- /dev/null
+++ b/lib/Target/Mips/MipsTargetMachine.h
@@ -0,0 +1,38 @@
+//===- MipsTargetMachine.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MIPS_TARGET_MACHINE_H
+#define MIPS_TARGET_MACHINE_H
+#include "mcld/Target/TargetMachine.h"
+#include "Mips.h"
+
+namespace mcld
+{
+
+class MipsBaseTargetMachine : public LLVMTargetMachine
+{
+protected:
+ MCLDInfo *m_pLDInfo;
+
+public:
+ MipsBaseTargetMachine(llvm::TargetMachine &pTM,
+ const mcld::Target &pTarget,
+ const std::string &pTriple);
+
+ virtual ~MipsBaseTargetMachine();
+
+ mcld::MCLDInfo& getLDInfo()
+ { return *m_pLDInfo; }
+
+ const mcld::MCLDInfo& getLDInfo() const
+ { return *m_pLDInfo; }
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Mips/TargetInfo/Android.mk b/lib/Target/Mips/TargetInfo/Android.mk
new file mode 100644
index 0000000..cf8ae38
--- /dev/null
+++ b/lib/Target/Mips/TargetInfo/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_mips_info_SRC_FILES := \
+ MipsTargetInfo.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_mips_info_SRC_FILES)
+LOCAL_MODULE:= libmcldMipsInfo
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+ifeq ($(TARGET_ARCH),mips)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_mips_info_SRC_FILES)
+LOCAL_MODULE:= libmcldMipsInfo
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp b/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp
new file mode 100644
index 0000000..0889973
--- /dev/null
+++ b/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp
@@ -0,0 +1,21 @@
+//===- MipsTargetInfo.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 TheMipselTarget;
+
+extern "C" void LLVMInitializeMipsLDTargetInfo() {
+ // register into mcld::TargetRegistry
+ mcld::RegisterTarget X(TheMipselTarget, "mipsel");
+}
+
+} // namespace of mcld
diff --git a/lib/Target/OutputRelocSection.cpp b/lib/Target/OutputRelocSection.cpp
new file mode 100644
index 0000000..89b4f52
--- /dev/null
+++ b/lib/Target/OutputRelocSection.cpp
@@ -0,0 +1,84 @@
+//===- OutputRelocSection.cpp ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/LDSection.h>
+#include <mcld/Target/OutputRelocSection.h>
+
+using namespace mcld;
+
+//==========================
+// OutputRelocSection
+
+
+OutputRelocSection::OutputRelocSection(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ unsigned int pEntrySize)
+ : m_pSection(&pSection),
+ m_pSectionData(&pSectionData),
+ m_EntryBytes(pEntrySize),
+ m_isVisit(false),
+ m_ValidEntryIterator(){
+}
+
+OutputRelocSection::~OutputRelocSection()
+{
+}
+
+void OutputRelocSection::reserveEntry(RelocationFactory& pRelFactory,
+ size_t pNum)
+{
+ for(size_t i=0; i<pNum; i++) {
+ m_pSectionData->getFragmentList().push_back(pRelFactory.produceEmptyEntry());
+ // update section size
+ m_pSection->setSize(m_pSection->size() + m_EntryBytes);
+ }
+}
+
+Relocation* OutputRelocSection::getEntry(const ResolveInfo& pSymbol,
+ bool isForGOT,
+ bool& pExist)
+{
+ // first time visit this function, set m_ValidEntryIterator to
+ // Fragments.begin()
+ if(!m_isVisit) {
+ assert( !m_pSectionData->getFragmentList().empty() &&
+ "DynRelSection contains no entries.");
+ m_ValidEntryIterator = m_pSectionData->getFragmentList().begin();
+ m_isVisit = true;
+ }
+
+ assert(m_ValidEntryIterator != m_pSectionData->end() &&
+ "No empty relocation entry for the incoming symbol.");
+
+ // if this relocation is used to relocate GOT (.got or .got.plt),
+ // check if we've gotten an entry for this symbol before. If yes,
+ // return the found entry in map.
+ // Otherwise, this relocation is used to relocate general section
+ // (data or text section), return an empty entry directly.
+ Relocation* result;
+
+ if(isForGOT) {
+ // get or create entry in m_SymRelMap
+ Relocation *&Entry = m_SymRelMap[&pSymbol];
+ pExist = 1;
+
+ if(!Entry) {
+ pExist = 0;
+ Entry = llvm::cast<Relocation>(&(*m_ValidEntryIterator));
+ ++m_ValidEntryIterator;
+ }
+ result = Entry;
+ }
+ else {
+ pExist = 0;
+ result = llvm::cast<Relocation>(&(*m_ValidEntryIterator));
+ ++m_ValidEntryIterator;
+ }
+ return result;
+}
+
diff --git a/lib/Target/PLT.cpp b/lib/Target/PLT.cpp
new file mode 100644
index 0000000..a29dfd8
--- /dev/null
+++ b/lib/Target/PLT.cpp
@@ -0,0 +1,42 @@
+//===- PLT.cpp ------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Target/PLT.h>
+
+using namespace mcld;
+
+class GOT;
+
+//===--------------------------------------------------------------------===//
+// PLTEntry
+PLTEntry::PLTEntry(size_t pSize, llvm::MCSectionData* pParent)
+ : MCTargetFragment(llvm::MCFragment::FT_Target, pParent),
+ m_EntrySize(pSize), m_pContent(NULL)
+{
+}
+
+PLTEntry::~PLTEntry()
+{
+ if (m_pContent) {
+ free(m_pContent);
+ m_pContent = NULL;
+ }
+}
+
+//===--------------------------------------------------------------------===//
+// PLT
+PLT::PLT(LDSection& pSection, llvm::MCSectionData& pSectionData)
+ :m_Section(pSection),
+ m_SectionData(pSectionData)
+{
+}
+
+PLT::~PLT()
+{
+}
+
diff --git a/lib/Target/Stub.cpp b/lib/Target/Stub.cpp
new file mode 100644
index 0000000..4b59acf
--- /dev/null
+++ b/lib/Target/Stub.cpp
@@ -0,0 +1,15 @@
+//===- Stub.cpp -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Target/Stub.h"
+
+using namespace mcld;
+
+//==========================
+// Stub
+
diff --git a/lib/Target/Target.cpp b/lib/Target/Target.cpp
new file mode 100644
index 0000000..58178ec
--- /dev/null
+++ b/lib/Target/Target.cpp
@@ -0,0 +1,25 @@
+//===- Target.cpp ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Support/TargetRegistry.h"
+#include "mcld/Target/TargetMachine.h"
+#include <llvm/Support/TargetRegistry.h>
+#include <llvm/Target/TargetMachine.h>
+
+using namespace llvm;
+using namespace mcld;
+
+/* ** */
+mcld::Target::Target()
+ : TargetMachineCtorFn(0),
+ SectLinkerCtorFn(0),
+ TargetLDBackendCtorFn(0),
+ m_pT(0)
+{
+}
+
diff --git a/lib/Target/TargetLDBackend.cpp b/lib/Target/TargetLDBackend.cpp
new file mode 100644
index 0000000..1a8ab6b
--- /dev/null
+++ b/lib/Target/TargetLDBackend.cpp
@@ -0,0 +1,23 @@
+//===- TargetLDBackend.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/Relocation.h"
+#include "mcld/LD/Layout.h"
+#include "mcld/Target/TargetLDBackend.h"
+
+using namespace mcld;
+
+/* ** */
+TargetLDBackend::TargetLDBackend()
+{
+}
+
+TargetLDBackend::~TargetLDBackend()
+{
+}
+
diff --git a/lib/Target/X86/Android.mk b/lib/Target/X86/Android.mk
new file mode 100644
index 0000000..e9a051b
--- /dev/null
+++ b/lib/Target/X86/Android.mk
@@ -0,0 +1,41 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_x86_target_SRC_FILES := \
+ X86AndroidSectLinker.cpp \
+ X86ELFDynamic.cpp \
+ X86ELFSectLinker.cpp \
+ X86GOT.cpp \
+ X86GOTPLT.cpp \
+ X86LDBackend.cpp \
+ X86PLT.cpp \
+ X86RelocationFactory.cpp \
+ X86SectLinker.cpp \
+ X86TargetMachine.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_x86_target_SRC_FILES)
+LOCAL_MODULE:= libmcldX86Target
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+ifeq ($(TARGET_ARCH),x86)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_x86_target_SRC_FILES)
+LOCAL_MODULE:= libmcldX86Target
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/lib/Target/X86/TargetInfo/Android.mk b/lib/Target/X86/TargetInfo/Android.mk
new file mode 100644
index 0000000..3664933
--- /dev/null
+++ b/lib/Target/X86/TargetInfo/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_x86_info_SRC_FILES := \
+ X86TargetInfo.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_x86_info_SRC_FILES)
+LOCAL_MODULE:= libmcldX86Info
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+ifeq ($(TARGET_ARCH),x86)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_x86_info_SRC_FILES)
+LOCAL_MODULE:= libmcldX86Info
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/lib/Target/X86/TargetInfo/X86TargetInfo.cpp b/lib/Target/X86/TargetInfo/X86TargetInfo.cpp
new file mode 100644
index 0000000..afe349e
--- /dev/null
+++ b/lib/Target/X86/TargetInfo/X86TargetInfo.cpp
@@ -0,0 +1,22 @@
+//===- X86TargetInfo.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 TheX86Target;
+
+extern "C" void LLVMInitializeX86LDTargetInfo() {
+ // register into mcld::TargetRegistry
+ mcld::RegisterTarget X(TheX86Target, "x86");
+}
+
+} // namespace of mcld
+
diff --git a/lib/Target/X86/X86.h b/lib/Target/X86/X86.h
new file mode 100644
index 0000000..2d07314
--- /dev/null
+++ b/lib/Target/X86/X86.h
@@ -0,0 +1,24 @@
+//===- X86.h --------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_X86_H
+#define MCLD_X86_H
+#include <string>
+#include "mcld/Target/TargetMachine.h"
+
+namespace mcld {
+class TargetLDBackend;
+
+extern mcld::Target TheX86Target;
+
+TargetLDBackend *createX86LDBackend(const llvm::Target&, const std::string&);
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/X86/X86AndroidSectLinker.cpp b/lib/Target/X86/X86AndroidSectLinker.cpp
new file mode 100644
index 0000000..91b466c
--- /dev/null
+++ b/lib/Target/X86/X86AndroidSectLinker.cpp
@@ -0,0 +1,35 @@
+//===- X86AndroidSectLinker.cpp -------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86AndroidSectLinker.h"
+
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+X86AndroidSectLinker::X86AndroidSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : AndroidSectLinker(pOption,
+ pLDBackend) {
+ MCLDInfo &info = pOption.info();
+ // set up target-dependent constraints of attibutes
+ info.attrFactory().constraint().disableWholeArchive();
+ info.attrFactory().constraint().disableAsNeeded();
+ info.attrFactory().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ info.attrFactory().predefined().unsetWholeArchive();
+ info.attrFactory().predefined().setDynamic();
+
+}
+
+X86AndroidSectLinker::~X86AndroidSectLinker()
+{
+}
+
diff --git a/lib/Target/X86/X86AndroidSectLinker.h b/lib/Target/X86/X86AndroidSectLinker.h
new file mode 100644
index 0000000..b275aca
--- /dev/null
+++ b/lib/Target/X86/X86AndroidSectLinker.h
@@ -0,0 +1,38 @@
+//===- X86AndroidSectLinker.h ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef X86_ANDROIDSECTLINKER_H
+#define X86_ANDROIDSECTLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Target/AndroidSectLinker.h>
+
+namespace mcld
+{
+
+/** \class X86AndroidSectLinker
+ * \brief X86AndroidSectLinker sets up the environment for linking.
+ *
+ * \see
+ * \author Anders Cheng <Anders.Cheng@mediatek.com>
+ */
+class X86AndroidSectLinker : public AndroidSectLinker
+{
+public:
+ X86AndroidSectLinker(SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend);
+
+ ~X86AndroidSectLinker();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/X86/X86ELFDynamic.cpp b/lib/Target/X86/X86ELFDynamic.cpp
new file mode 100644
index 0000000..c32cfa8
--- /dev/null
+++ b/lib/Target/X86/X86ELFDynamic.cpp
@@ -0,0 +1,41 @@
+//===- X86ELFDynamic.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <mcld/LD/ELFFileFormat.h>
+#include "X86ELFDynamic.h"
+
+using namespace mcld;
+
+X86ELFDynamic::X86ELFDynamic(const GNULDBackend& pParent)
+ : ELFDynamic(pParent), m_HasGOTPLT(false)
+{
+}
+
+X86ELFDynamic::~X86ELFDynamic()
+{
+}
+
+void X86ELFDynamic::reserveTargetEntries(const ELFFileFormat& pFormat)
+{
+ // reservePLTGOT
+ if (m_HasGOTPLT ? pFormat.hasGOTPLT() : pFormat.hasGOT())
+ reserveOne(llvm::ELF::DT_PLTGOT);
+}
+
+void X86ELFDynamic::applyTargetEntries(const ELFFileFormat& pFormat)
+{
+ // applyPLTGOT
+ if (m_HasGOTPLT) {
+ if (pFormat.hasGOTPLT())
+ applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOTPLT().addr());
+ }
+ else if (pFormat.hasGOT())
+ applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOT().addr());
+}
+
diff --git a/lib/Target/X86/X86ELFDynamic.h b/lib/Target/X86/X86ELFDynamic.h
new file mode 100644
index 0000000..b9e70ce
--- /dev/null
+++ b/lib/Target/X86/X86ELFDynamic.h
@@ -0,0 +1,38 @@
+//===- X86ELFDynamic.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_X86_ELFDYNAMIC_SECTION_H
+#define MCLD_X86_ELFDYNAMIC_SECTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Target/ELFDynamic.h>
+
+namespace mcld {
+
+class X86ELFDynamic : public ELFDynamic
+{
+public:
+ X86ELFDynamic(const GNULDBackend& pParent);
+ ~X86ELFDynamic();
+
+private:
+ void reserveTargetEntries(const ELFFileFormat& pFormat);
+ void applyTargetEntries(const ELFFileFormat& pFormat);
+
+private:
+ // True if we have .got.plt section, which will avoid GOT0 entries
+ // when PLT isn't used. To support .got.plt section, we must combine
+ // .got section and .got.plt section into a single GOT.
+ bool m_HasGOTPLT;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/X86/X86ELFSectLinker.cpp b/lib/Target/X86/X86ELFSectLinker.cpp
new file mode 100644
index 0000000..009293c
--- /dev/null
+++ b/lib/Target/X86/X86ELFSectLinker.cpp
@@ -0,0 +1,34 @@
+//===- X86ELFSectLinker.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "X86ELFSectLinker.h"
+
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+X86ELFSectLinker::X86ELFSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : SectLinker(pOption,
+ pLDBackend) {
+ MCLDInfo &info = pOption.info();
+ // set up target-dependent constraints of attibutes
+ info.attrFactory().constraint().enableWholeArchive();
+ info.attrFactory().constraint().disableAsNeeded();
+ info.attrFactory().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ info.attrFactory().predefined().setWholeArchive();
+ info.attrFactory().predefined().setDynamic();
+
+}
+
+X86ELFSectLinker::~X86ELFSectLinker()
+{
+}
+
diff --git a/lib/Target/X86/X86ELFSectLinker.h b/lib/Target/X86/X86ELFSectLinker.h
new file mode 100644
index 0000000..5e7abfd
--- /dev/null
+++ b/lib/Target/X86/X86ELFSectLinker.h
@@ -0,0 +1,36 @@
+//===- X86ELFSectLinker.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_ELFSECTLINKER_H
+#define X86_ELFSECTLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/CodeGen/SectLinker.h>
+
+namespace mcld
+{
+
+/** \class X86ELFSectLinker
+ * \brief X86ELFSectLinker sets up the environment for linking.
+ *
+ * \see
+ */
+class X86ELFSectLinker : public SectLinker
+{
+public:
+ X86ELFSectLinker(SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend);
+
+ ~X86ELFSectLinker();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/X86/X86GOT.cpp b/lib/Target/X86/X86GOT.cpp
new file mode 100644
index 0000000..2784989
--- /dev/null
+++ b/lib/Target/X86/X86GOT.cpp
@@ -0,0 +1,129 @@
+//===- impl.cpp -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "X86GOT.h"
+#include <mcld/LD/LDFileFormat.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <new>
+
+namespace {
+ const size_t X86GOTEntrySize = 4;
+}
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// X86GOT
+X86GOT::X86GOT(LDSection& pSection, llvm::MCSectionData& pSectionData)
+ : GOT(pSection, pSectionData, X86GOTEntrySize),
+ m_GeneralGOTNum(0), m_GOTPLTNum(0), m_GeneralGOTIterator(),
+ m_GOTPLTIterator(), m_LastGOT0()
+{
+ GOTEntry* Entry = 0;
+
+ // Create GOT0 entries.
+ for (unsigned int i = 0; i < X86GOT0Num; i++) {
+ Entry = new (std::nothrow) GOTEntry(0, X86GOTEntrySize,
+ &m_SectionData);
+
+ if (!Entry)
+ llvm::report_fatal_error("Allocating GOT0 entries failed!");
+
+ m_Section.setSize(m_Section.size() + X86GOTEntrySize);
+ }
+
+ // Skip GOT0 entries.
+ iterator it = m_SectionData.begin();
+ iterator ie = m_SectionData.end();
+
+ for (unsigned int i = 1; i < X86GOT0Num; ++i) {
+ if (it == ie)
+ llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
+
+ ++it;
+ }
+
+ m_LastGOT0 = it;
+ m_GeneralGOTIterator = it;
+ m_GOTPLTIterator = it;
+}
+
+X86GOT::~X86GOT()
+{
+}
+
+void X86GOT::reserveEntry(size_t pNum)
+{
+ GOTEntry* Entry = 0;
+
+ for (size_t i = 0; i < pNum; i++) {
+ Entry = new (std::nothrow) GOTEntry(0, X86GOTEntrySize,
+ &m_SectionData);
+
+ if (!Entry)
+ llvm::report_fatal_error("Allocating new memory for GOTEntry failed");
+
+ m_Section.setSize(m_Section.size() + X86GOTEntrySize);
+ ++m_GeneralGOTNum;
+ }
+}
+
+
+GOTEntry* X86GOT::getEntry(const ResolveInfo& pInfo, bool& pExist)
+{
+ GOTEntry *&Entry = m_GeneralGOTMap[&pInfo];
+ pExist = 1;
+
+ if (!Entry) {
+ pExist = 0;
+
+ ++m_GeneralGOTIterator;
+ assert(m_GeneralGOTIterator != m_SectionData.getFragmentList().end()
+ && "The number of GOT Entries and ResolveInfo doesn't match!");
+
+ Entry = llvm::cast<GOTEntry>(&(*m_GeneralGOTIterator));
+ }
+
+ return Entry;
+}
+
+void X86GOT::applyGOT0(uint64_t pAddress)
+{
+ llvm::cast<GOTEntry>
+ (*(m_SectionData.getFragmentList().begin())).setContent(pAddress);
+}
+
+X86GOT::iterator X86GOT::begin()
+{
+ return m_SectionData.getFragmentList().begin();
+}
+
+X86GOT::const_iterator X86GOT::begin() const
+{
+ return m_SectionData.getFragmentList().begin();
+}
+
+X86GOT::iterator X86GOT::end()
+{
+ return m_SectionData.getFragmentList().end();
+}
+
+X86GOT::const_iterator X86GOT::end() const
+{
+ return m_SectionData.getFragmentList().end();
+}
+
+unsigned int X86GOT::getGOTPLTNum() const
+{ return m_GOTPLTNum; }
+
+X86GOT::iterator X86GOT::getLastGOT0()
+{ return m_LastGOT0; }
+
+const X86GOT::iterator X86GOT::getLastGOT0() const
+{ return m_LastGOT0; }
+
diff --git a/lib/Target/X86/X86GOT.h b/lib/Target/X86/X86GOT.h
new file mode 100644
index 0000000..018aa24
--- /dev/null
+++ b/lib/Target/X86/X86GOT.h
@@ -0,0 +1,91 @@
+//===- X86GOT.h -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_X86_GOT_H
+#define MCLD_X86_GOT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "X86PLT.h"
+#include <mcld/Target/GOT.h>
+
+namespace mcld
+{
+class LDSection;
+
+/** \class X86GOT
+ * \brief X86 Global Offset Table.
+ */
+
+const unsigned int X86GOT0Num = 3;
+
+class X86GOT : public GOT
+{
+ friend void mcld::X86PLT::reserveEntry(size_t pNum);
+
+ friend mcld::PLTEntry* mcld::X86PLT::getPLTEntry(
+ const mcld::ResolveInfo& pSymbol,bool& pExist);
+
+ friend mcld::GOTEntry* mcld::X86PLT::getGOTPLTEntry(
+ const mcld::ResolveInfo& pSymbol,bool& pExist);
+
+ typedef llvm::DenseMap<const ResolveInfo*, GOTEntry*> SymbolIndexMapType;
+
+public:
+ typedef llvm::MCSectionData::iterator iterator;
+ typedef llvm::MCSectionData::const_iterator const_iterator;
+
+public:
+ X86GOT(LDSection& pSection, llvm::MCSectionData& pSectionData);
+
+ ~X86GOT();
+
+ //Reserve general GOT entries.
+ void reserveEntry(size_t pNum = 1);
+
+ GOTEntry* getEntry(const ResolveInfo& pSymbol, bool& pExist);
+
+ void applyGOT0(uint64_t pAddress);
+
+ iterator begin();
+
+ const_iterator begin() const;
+
+ iterator end();
+
+ const_iterator end() const;
+
+ unsigned int getGOTPLTNum() const;
+
+ iterator getLastGOT0();
+
+ const iterator getLastGOT0() const;
+
+private:
+
+ unsigned int m_GeneralGOTNum;
+ unsigned int m_GOTPLTNum;
+
+ // Used by getGeneralGOTEntry()
+ iterator m_GeneralGOTIterator;
+
+ // Used by getGOTPLTEntry()
+ iterator m_GOTPLTIterator;
+
+ // The last GOT0 entry
+ iterator m_LastGOT0;
+
+ SymbolIndexMapType m_GOTPLTMap;
+ SymbolIndexMapType m_GeneralGOTMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/X86/X86GOTPLT.cpp b/lib/Target/X86/X86GOTPLT.cpp
new file mode 100644
index 0000000..55596e3
--- /dev/null
+++ b/lib/Target/X86/X86GOTPLT.cpp
@@ -0,0 +1,113 @@
+//===- X86GOTPLT.cpp ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "X86GOTPLT.h"
+#include "mcld/LD/LDFileFormat.h"
+#include <llvm/Support/ErrorHandling.h>
+#include <new>
+
+namespace {
+ const uint64_t X86GOTPLTEntrySize = 4;
+}
+
+namespace mcld {
+
+//===----------------------------------------------------------------------===//
+// X86GOTPLT
+X86GOTPLT::X86GOTPLT(LDSection& pSection, llvm::MCSectionData& pSectionData)
+ : GOT(pSection, pSectionData, X86GOTPLTEntrySize), m_GOTPLTIterator()
+{
+ GOTEntry* Entry = 0;
+
+ // Create GOT0 entries.
+ for (int i = 0; i < 3; i++) {
+ Entry = new (std::nothrow) GOTEntry(0, X86GOTPLTEntrySize,
+ &m_SectionData);
+
+ if (!Entry)
+ llvm::report_fatal_error("Allocating GOT0 entries failed!");
+
+ m_Section.setSize(m_Section.size() + X86GOTPLTEntrySize);
+ }
+
+ // Skip GOT0 entries.
+ iterator it = m_SectionData.begin();
+ iterator ie = m_SectionData.end();
+
+ for (size_t i = 1; i < X86GOT0Num; ++i) {
+ if (it == ie)
+ llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
+
+ ++it;
+ }
+
+ m_GOTPLTIterator = it;
+}
+
+X86GOTPLT::~X86GOTPLT()
+{
+}
+
+X86GOTPLT::iterator X86GOTPLT::begin()
+{
+ return m_SectionData.begin();
+}
+
+X86GOTPLT::const_iterator X86GOTPLT::begin() const
+{
+ return m_SectionData.begin();
+}
+
+X86GOTPLT::iterator X86GOTPLT::end()
+{
+ return m_SectionData.end();
+}
+
+X86GOTPLT::const_iterator X86GOTPLT::end() const
+{
+ return m_SectionData.end();
+}
+
+void X86GOTPLT::applyGOT0(const uint64_t pAddress)
+{
+ llvm::cast<GOTEntry>
+ (*(m_SectionData.getFragmentList().begin())).setContent(pAddress);
+}
+
+void X86GOTPLT::reserveGOTPLTEntry()
+{
+ GOTEntry* got_entry = 0;
+
+ got_entry= new GOTEntry(0, getEntrySize(),&(getSectionData()));
+
+ if (!got_entry)
+ llvm::report_fatal_error("Allocating new memory for GOT failed!");
+
+ m_Section.setSize(m_Section.size() + getEntrySize());
+}
+
+void X86GOTPLT::applyAllGOTPLT(const uint64_t pPLTBase)
+{
+ iterator gotplt_it = begin();
+ iterator gotplt_ie = end();
+
+ for (; gotplt_it != gotplt_ie; ++gotplt_it)
+ llvm::cast<GOTEntry>(*gotplt_it).setContent(pPLTBase);
+}
+
+GOTEntry*& X86GOTPLT::lookupGOTPLTMap(const ResolveInfo& pSymbol)
+{
+ return m_GOTPLTMap[&pSymbol];
+}
+
+X86GOTPLT::iterator X86GOTPLT::getNextGOTPLTEntry()
+{
+ return ++m_GOTPLTIterator;
+}
+
+} //end mcld namespace
diff --git a/lib/Target/X86/X86GOTPLT.h b/lib/Target/X86/X86GOTPLT.h
new file mode 100644
index 0000000..9882cc4
--- /dev/null
+++ b/lib/Target/X86/X86GOTPLT.h
@@ -0,0 +1,70 @@
+//===- X86GOTPLT.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_X86_GOTPLT_H
+#define MCLD_X86_GOTPLT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/Target/GOT.h"
+
+namespace mcld
+{
+class LDSection;
+
+/** \class X86GOTPLT
+ * \brief X86 .got.plt section.
+ */
+
+const unsigned int X86GOT0Num = 3;
+
+class X86GOTPLT : public GOT
+{
+ typedef llvm::DenseMap<const ResolveInfo*, GOTEntry*> SymbolIndexMapType;
+
+public:
+ typedef llvm::MCSectionData::iterator iterator;
+ typedef llvm::MCSectionData::const_iterator const_iterator;
+
+public:
+ X86GOTPLT(LDSection &pSection, llvm::MCSectionData& pSectionData);
+
+ ~X86GOTPLT();
+
+ iterator begin();
+
+ const_iterator begin() const;
+
+ iterator end();
+
+ const_iterator end() const;
+
+// For GOT0
+public:
+ void applyGOT0(const uint64_t pAddress);
+
+// For GOTPLT
+public:
+ void reserveGOTPLTEntry();
+
+ void applyAllGOTPLT(const uint64_t pPLTBase);
+
+ GOTEntry*& lookupGOTPLTMap(const ResolveInfo& pSymbol);
+
+ iterator getNextGOTPLTEntry();
+
+private:
+ iterator m_GOTPLTIterator;
+ SymbolIndexMapType m_GOTPLTMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/X86/X86LDBackend.cpp b/lib/Target/X86/X86LDBackend.cpp
new file mode 100644
index 0000000..354cd51
--- /dev/null
+++ b/lib/Target/X86/X86LDBackend.cpp
@@ -0,0 +1,752 @@
+//===- X86LDBackend.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86.h"
+#include "X86ELFDynamic.h"
+#include "X86LDBackend.h"
+#include "X86RelocationFactory.h"
+
+#include <llvm/ADT/Triple.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLDOutput.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/LD/SectionMap.h>
+#include <mcld/MC/MCRegionFragment.h>
+
+#include <cstring>
+
+using namespace mcld;
+
+X86GNULDBackend::X86GNULDBackend()
+ : m_pRelocFactory(NULL),
+ m_pGOT(NULL),
+ m_pPLT(NULL),
+ m_pRelDyn(NULL),
+ m_pRelPLT(NULL),
+ m_pDynamic(NULL) {
+}
+
+X86GNULDBackend::~X86GNULDBackend()
+{
+ if (NULL != m_pRelocFactory)
+ delete m_pRelocFactory;
+ if (NULL != m_pGOT)
+ delete m_pGOT;
+ if (NULL != m_pPLT)
+ delete m_pPLT;
+ if (NULL !=m_pRelDyn)
+ delete m_pRelDyn;
+ if (NULL != m_pRelPLT)
+ delete m_pRelPLT;
+ if (NULL != m_pDynamic)
+ delete m_pDynamic;
+}
+
+RelocationFactory* X86GNULDBackend::getRelocFactory()
+{
+ assert(NULL != m_pRelocFactory);
+ return m_pRelocFactory;
+}
+
+bool X86GNULDBackend::initRelocFactory(const MCLinker& pLinker)
+{
+ if (NULL == m_pRelocFactory) {
+ m_pRelocFactory = new X86RelocationFactory(1024, *this);
+ m_pRelocFactory->setLayout(pLinker.getLayout());
+ }
+ return true;
+}
+
+void X86GNULDBackend::doPreLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ // when building shared object, the .got section is needed
+ if(pOutput.type() == Output::DynObj && (NULL == m_pGOT))
+ createX86GOT(pLinker, pOutput);
+}
+
+void X86GNULDBackend::doPostLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ // emit program headers
+ if(pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec)
+ emitProgramHdrs(pLinker.getLDInfo().output());
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+X86ELFDynamic& X86GNULDBackend::dynamic()
+{
+ if (NULL == m_pDynamic)
+ m_pDynamic = new X86ELFDynamic(*this);
+
+ return *m_pDynamic;
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+const X86ELFDynamic& X86GNULDBackend::dynamic() const
+{
+ assert( NULL != m_pDynamic);
+ return *m_pDynamic;
+}
+
+void X86GNULDBackend::createX86GOT(MCLinker& pLinker, const Output& pOutput)
+{
+ // get .got LDSection and create MCSectionData
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ LDSection& got = file_format->getGOT();
+ m_pGOT = new X86GOT(got, pLinker.getOrCreateSectData(got));
+
+ // define symbol _GLOBAL_OFFSET_TABLE_ when .got create
+ if( m_pGOTSymbol != NULL ) {
+ pLinker.defineSymbol<MCLinker::Force, MCLinker::Unresolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+ else {
+ m_pGOTSymbol = pLinker.defineSymbol<MCLinker::Force, MCLinker::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+}
+
+void X86GNULDBackend::createX86PLTandRelPLT(MCLinker& pLinker,
+ const Output& pOutput)
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ LDSection& plt = file_format->getPLT();
+ LDSection& relplt = file_format->getRelPlt();
+ // create MCSectionData and X86PLT
+ m_pPLT = new X86PLT(plt, pLinker.getOrCreateSectData(plt), *m_pGOT, pOutput);
+
+ // set info of .rel.plt to .plt
+ relplt.setLink(&plt);
+ // create MCSectionData and X86RelDynSection
+ m_pRelPLT = new OutputRelocSection(relplt,
+ pLinker.getOrCreateSectData(relplt),
+ 8);
+}
+
+void X86GNULDBackend::createX86RelDyn(MCLinker& pLinker,
+ const Output& pOutput)
+{
+ // get .rel.dyn LDSection and create MCSectionData
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ LDSection& reldyn = file_format->getRelDyn();
+ // create MCSectionData and X86RelDynSection
+ m_pRelDyn = new OutputRelocSection(reldyn,
+ pLinker.getOrCreateSectData(reldyn),
+ 8);
+}
+
+ELFFileFormat* X86GNULDBackend::getOutputFormat(const Output& pOutput) const
+{
+ switch (pOutput.type()) {
+ case Output::DynObj:
+ return getDynObjFileFormat();
+ case Output::Exec:
+ return getExecFileFormat();
+ // FIXME: We do not support building .o now
+ case Output::Object:
+ default:
+ llvm::report_fatal_error(llvm::Twine("Unsupported output file format: ") +
+ llvm::Twine(pOutput.type()));
+ return NULL;
+ }
+}
+
+bool X86GNULDBackend::isSymbolNeedsPLT(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ return((Output::DynObj == pOutput.type())
+ &&(ResolveInfo::Function == pSym.type())
+ &&(pSym.isDyn() || pSym.isUndef() ||
+ isSymbolPreemptible(pSym, pLDInfo, pOutput))
+ );
+}
+
+bool X86GNULDBackend::isSymbolNeedsDynRel(const ResolveInfo& pSym,
+ const Output& pOutput,
+ bool isAbsReloc) const
+{
+ if(pSym.isUndef() && (pOutput.type()==Output::Exec))
+ return false;
+ if(pSym.isAbsolute())
+ return false;
+ if(pOutput.type()==Output::DynObj && isAbsReloc)
+ return true;
+ if(pSym.isDyn() || pSym.isUndef())
+ return true;
+
+ return false;
+}
+
+bool X86GNULDBackend::isSymbolPreemptible(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ if(pSym.other() != ResolveInfo::Default)
+ return false;
+
+ if(pOutput.type() != Output::DynObj)
+ return false;
+
+ if(pLDInfo.options().Bsymbolic())
+ return false;
+
+ return true;
+}
+
+void X86GNULDBackend::updateAddend(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ const Layout& pLayout) const
+{
+ // Update value keep in addend if we meet a section symbol
+ if(pReloc.symInfo()->type() == ResolveInfo::Section) {
+ pReloc.setAddend(pLayout.getOutputOffset(
+ *pInputSym.fragRef()) + pReloc.addend());
+ }
+}
+
+void X86GNULDBackend::scanLocalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ updateAddend(pReloc, pInputSym, pLinker.getLayout());
+
+ switch(pReloc.type()){
+
+ case llvm::ELF::R_386_32:
+ // If buiding PIC object (shared library or PIC executable),
+ // a dynamic relocations with RELATIVE type to this location is needed.
+ // Reserve an entry in .rel.dyn
+ if(Output::DynObj == pOutput.type()) {
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createX86RelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
+ return;
+
+ case llvm::ELF::R_386_GOTOFF:
+ case llvm::ELF::R_386_GOTPC:
+ // A GOT section is needed
+ if(NULL == m_pGOT)
+ createX86GOT(pLinker, pOutput);
+ return;
+
+ case llvm::ELF::R_386_PC32:
+ return;
+
+ default:
+ llvm::report_fatal_error(llvm::Twine("unexpected reloc ") +
+ llvm::Twine((int) pReloc.type()) +
+ llvm::Twine(" in object file"));
+ break;
+ } // end switch
+}
+
+void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ switch(pReloc.type()) {
+ case llvm::ELF::R_386_32:
+ // Absolute relocation type, symbol may needs PLT entry or
+ // dynamic relocation entry
+ if(isSymbolNeedsPLT(*rsym, pLDInfo, pOutput)) {
+ // create plt for this symbol if it does not have one
+ if(!(rsym->reserved() & ReservePLT)){
+ // Create .got section if it dosen't exist
+ if(NULL == m_pGOT)
+ createX86GOT(pLinker, pOutput);
+ // create .plt and .rel.plt if not exist
+ if(NULL == m_pPLT)
+ createX86PLTandRelPLT(pLinker, pOutput);
+ // Symbol needs PLT entry, we need to reserve a PLT entry
+ // and the corresponding GOT and dynamic relocation entry
+ // in .got and .rel.plt. (GOT entry will be reserved simultaneously
+ // when calling X86PLT->reserveEntry())
+ m_pPLT->reserveEntry();
+ m_pRelPLT->reserveEntry(*m_pRelocFactory);
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | ReservePLT);
+ }
+ }
+
+ if(isSymbolNeedsDynRel(*rsym, pOutput, true)) {
+ // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createX86RelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
+ return;
+
+ case llvm::ELF::R_386_GOTOFF:
+ case llvm::ELF::R_386_GOTPC: {
+ // A GOT section is needed
+ if(NULL == m_pGOT)
+ createX86GOT(pLinker, pOutput);
+ return;
+ }
+
+ case llvm::ELF::R_386_PLT32:
+ // A PLT entry is needed when building shared library
+
+ // return if we already create plt for this symbol
+ if(rsym->reserved() & ReservePLT)
+ return;
+
+ // if symbol is defined in the ouput file and it's not
+ // preemptible, no need plt
+ if(rsym->isDefine() && !rsym->isDyn() &&
+ !isSymbolPreemptible(*rsym, pLDInfo, pOutput)) {
+ return;
+ }
+
+ // Create .got section if it dosen't exist
+ if(NULL == m_pGOT)
+ createX86GOT(pLinker, pOutput);
+ // create .plt and .rel.plt if not exist
+ if(NULL == m_pPLT)
+ createX86PLTandRelPLT(pLinker, pOutput);
+ // Symbol needs PLT entry, we need to reserve a PLT entry
+ // and the corresponding GOT and dynamic relocation entry
+ // in .got and .rel.plt. (GOT entry will be reserved simultaneously
+ // when calling X86PLT->reserveEntry())
+ m_pPLT->reserveEntry();
+ m_pRelPLT->reserveEntry(*m_pRelocFactory);
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | ReservePLT);
+ return;
+
+ case llvm::ELF::R_386_GOT32:
+ // Symbol needs GOT entry, reserve entry in .got
+ // return if we already create GOT for this symbol
+ if(rsym->reserved() & (ReserveGOT | GOTRel))
+ return;
+ if(NULL == m_pGOT)
+ createX86GOT(pLinker, pOutput);
+ m_pGOT->reserveEntry();
+ // If building shared object or the symbol is undefined, a dynamic
+ // relocation is needed to relocate this GOT entry. Reserve an
+ // entry in .rel.dyn
+ if(Output::DynObj == pOutput.type() || rsym->isUndef() || rsym->isDyn()) {
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createX86RelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set GOTRel bit
+ rsym->setReserved(rsym->reserved() | GOTRel);
+ return;
+ }
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
+ return;
+
+ case llvm::ELF::R_386_PC32:
+ // We allow R_386_PC32 only if it isn't preemptible. Otherwise
+ // we will generate writable text section in output.
+ if (!isSymbolPreemptible(*rsym, pLDInfo, pOutput))
+ return;
+
+ default: {
+ llvm::report_fatal_error(llvm::Twine("Unexpected reloc ") +
+ llvm::Twine((int) pReloc.type()) +
+ llvm::Twine(" in object file"));
+ break;
+ }
+ } // end switch
+}
+
+void X86GNULDBackend::scanRelocation(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
+
+ // Scan relocation type to determine if an GOT/PLT/Dynamic Relocation
+ // entries should be created.
+ // FIXME: Below judgements concern only .so is generated as output
+ // FIXME: Below judgements concren nothing about TLS related relocation
+
+ // A refernece to symbol _GLOBAL_OFFSET_TABLE_ implies that a .got section
+ // is needed
+ if(NULL == m_pGOT && NULL != m_pGOTSymbol) {
+ if(rsym == m_pGOTSymbol->resolveInfo()) {
+ createX86GOT(pLinker, pOutput);
+ }
+ }
+
+ // rsym is local
+ if(rsym->isLocal())
+ scanLocalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
+
+ // rsym is external
+ else
+ scanGlobalReloc(pReloc, pInputSym ,pLinker, pLDInfo, pOutput);
+
+}
+
+uint64_t X86GNULDBackend::emitSectionData(const Output& pOutput,
+ const LDSection& pSection,
+ const MCLDInfo& pInfo,
+ MemoryRegion& pRegion) const
+{
+ assert(pRegion.size() && "Size of MemoryRegion is zero!");
+
+ ELFFileFormat* FileFormat = getOutputFormat(pOutput);
+ 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<X86PLT0>((*it)).getEntrySize();
+
+ memcpy(buffer, llvm::cast<X86PLT0>((*it)).getContent(), plt0_size);
+ RegionSize += plt0_size;
+ ++it;
+
+ X86PLT1* plt1 = 0;
+ X86PLT::iterator ie = m_pPLT->end();
+ while (it != ie) {
+ plt1 = &(llvm::cast<X86PLT1>(*it));
+ EntrySize = plt1->getEntrySize();
+ memcpy(buffer + RegionSize, plt1->getContent(), EntrySize);
+ RegionSize += EntrySize;
+ ++it;
+ }
+ }
+
+ else if (&pSection == &(FileFormat->getGOT())) {
+ assert(m_pGOT && "emitSectionData failed, m_pGOT is NULL!");
+
+ m_pGOT->applyGOT0(FileFormat->getDynamic().addr());
+
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
+
+ GOTEntry* got = 0;
+ EntrySize = m_pGOT->getEntrySize();
+
+ for (X86GOT::iterator it = m_pGOT->begin(),
+ ie = m_pGOT->end(); it != ie; ++it, ++buffer) {
+ got = &(llvm::cast<GOTEntry>((*it)));
+ *buffer = static_cast<uint32_t>(got->getContent());
+ RegionSize += EntrySize;
+ }
+ }
+
+ else
+ llvm::report_fatal_error("unsupported section name "
+ + pSection.name() + " !");
+
+ return RegionSize;
+}
+uint32_t X86GNULDBackend::machine() const
+{
+ return llvm::ELF::EM_386;
+}
+
+X86GOT& X86GNULDBackend::getGOT()
+{
+ assert(NULL != m_pGOT);
+ return *m_pGOT;
+}
+
+const X86GOT& X86GNULDBackend::getGOT() const
+{
+ assert(NULL != m_pGOT);
+ return *m_pGOT;
+}
+
+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 section not exist");
+ return *m_pRelDyn;
+}
+
+const OutputRelocSection& X86GNULDBackend::getRelDyn() const
+{
+ assert(NULL != m_pRelDyn && ".rel.dyn section not exist");
+ return *m_pRelDyn;
+}
+
+OutputRelocSection& X86GNULDBackend::getRelPLT()
+{
+ assert(NULL != m_pRelPLT && ".rel.plt section not exist");
+ return *m_pRelPLT;
+}
+
+const OutputRelocSection& X86GNULDBackend::getRelPLT() const
+{
+ assert(NULL != m_pRelPLT && ".rel.plt section not exist");
+ return *m_pRelPLT;
+}
+
+unsigned int
+X86GNULDBackend::getTargetSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ // FIXME: if command line option, "-z now", is given, we can let the order of
+ // .got and .got.plt be the same as RELRO sections
+ if (&pSectHdr == &file_format->getGOT())
+ return SHO_RELRO_LAST;
+
+ if (&pSectHdr == &file_format->getGOTPLT())
+ return SHO_NON_RELRO_FIRST;
+
+ if (&pSectHdr == &file_format->getPLT())
+ return SHO_PLT;
+
+ return SHO_UNDEFINED;
+}
+
+unsigned int X86GNULDBackend::bitclass() const
+{
+ return 32;
+}
+
+bool X86GNULDBackend::initTargetSectionMap(SectionMap& pSectionMap)
+{
+ return true;
+}
+
+void X86GNULDBackend::initTargetSections(MCLinker& pLinker)
+{
+}
+
+void X86GNULDBackend::initTargetSymbols(MCLinker& pLinker)
+{
+ // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
+ // same name in input
+ m_pGOTSymbol = pLinker.defineSymbol<MCLinker::AsRefered, MCLinker::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Hidden);
+}
+
+/// finalizeSymbol - finalize the symbol value
+/// If the symbol's reserved field is not zero, MCLinker will call back this
+/// function to ask the final value of the symbol
+bool X86GNULDBackend::finalizeSymbol(LDSymbol& pSymbol) const
+{
+ return false;
+}
+
+/// allocateCommonSymbols - allocate common symbols in the corresponding
+/// sections.
+/// @refer Google gold linker: common.cc: 214
+bool
+X86GNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const
+{
+ // SymbolCategory contains all symbols that must emit to the output files.
+ // We are not like Google gold linker, we don't remember symbols before symbol
+ // resolution. All symbols in SymbolCategory are already resolved. Therefore, we
+ // don't need to care about some symbols may be changed its category due to symbol
+ // resolution.
+ SymbolCategory& symbol_list = pLinker.getOutputSymbols();
+
+ if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
+ return true;
+
+ // addralign := max value of all common symbols
+ uint64_t addralign = 0x0;
+
+ // Due to the visibility, some common symbols may be forcefully local.
+ SymbolCategory::iterator com_sym, com_end = symbol_list.localEnd();
+ for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+ if (ResolveInfo::Common == (*com_sym)->desc()) {
+ if ((*com_sym)->value() > addralign)
+ addralign = (*com_sym)->value();
+ }
+ }
+
+ // global common symbols.
+ com_end = symbol_list.commonEnd();
+ for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+ if ((*com_sym)->value() > addralign)
+ addralign = (*com_sym)->value();
+ }
+
+ // FIXME: If the order of common symbols is defined, then sort common symbols
+ // com_sym = symbol_list.commonBegin();
+ // std::sort(com_sym, com_end, some kind of order);
+
+ // get or create corresponding BSS LDSection
+ LDSection* bss_sect_hdr = NULL;
+ if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
+ ".tbss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
+ else {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
+
+ // get or create corresponding BSS MCSectionData
+ assert(NULL != bss_sect_hdr);
+ llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(*bss_sect_hdr);
+
+ // allocate all common symbols
+ uint64_t offset = bss_sect_hdr->size();
+
+ // allocate all local common symbols
+ com_end = symbol_list.localEnd();
+ for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+ if (ResolveInfo::Common == (*com_sym)->desc()) {
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ bss_section,
+ (*com_sym)->value());
+ offset += size;
+ }
+ }
+
+ // allocate all global common symbols
+ com_end = symbol_list.commonEnd();
+ for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ bss_section,
+ (*com_sym)->value());
+ offset += size;
+ }
+
+ bss_sect_hdr->setSize(offset);
+ symbol_list.changeCommonsToGlobal();
+ return true;
+}
+
+namespace mcld {
+
+//===----------------------------------------------------------------------===//
+/// createX86LDBackend - the help funtion to create corresponding X86LDBackend
+///
+TargetLDBackend* createX86LDBackend(const llvm::Target& pTarget,
+ const std::string& pTriple)
+{
+ Triple theTriple(pTriple);
+ if (theTriple.isOSDarwin()) {
+ assert(0 && "MachO linker is not supported yet");
+ /**
+ return new X86MachOLDBackend(createX86MachOArchiveReader,
+ createX86MachOObjectReader,
+ createX86MachOObjectWriter);
+ **/
+ }
+ if (theTriple.isOSWindows()) {
+ assert(0 && "COFF linker is not supported yet");
+ /**
+ return new X86COFFLDBackend(createX86COFFArchiveReader,
+ createX86COFFObjectReader,
+ createX86COFFObjectWriter);
+ **/
+ }
+ return new X86GNULDBackend();
+}
+
+} // namespace of mcld
+
+//=============================
+// Force static initialization.
+extern "C" void LLVMInitializeX86LDBackend() {
+ // Register the linker backend
+ mcld::TargetRegistry::RegisterTargetLDBackend(TheX86Target, createX86LDBackend);
+}
diff --git a/lib/Target/X86/X86LDBackend.h b/lib/Target/X86/X86LDBackend.h
new file mode 100644
index 0000000..d9a4d56
--- /dev/null
+++ b/lib/Target/X86/X86LDBackend.h
@@ -0,0 +1,257 @@
+//===- X86LDBackend.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_LDBACKEND_H
+#define X86_LDBACKEND_H
+
+#include "X86ELFDynamic.h"
+#include "X86GOT.h"
+#include "X86PLT.h"
+#include <mcld/LD/LDSection.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/Target/OutputRelocSection.h>
+
+namespace mcld {
+
+//===----------------------------------------------------------------------===//
+/// X86GNULDBackend - linker backend of X86 target of GNU ELF format
+///
+class X86GNULDBackend : public GNULDBackend
+{
+public:
+ /** \enum ReservedEntryType
+ * \brief The reserved entry type of reserved space in ResolveInfo.
+ *
+ * This is used for sacnRelocation to record what kinds of entries are
+ * reserved for this resolved symbol
+ *
+ * In X86, there are three kinds of entries, GOT, PLT, and dynamic reloction.
+ * GOT may needs a corresponding relocation to relocate itself, so we
+ * separate GOT to two situations: GOT and GOTRel. Besides, for the same
+ * symbol, there might be two kinds of entries reserved for different location.
+ * For example, reference to the same symbol, one may use GOT and the other may
+ * use dynamic relocation.
+ *
+ * bit: 3 2 1 0
+ * | PLT | GOTRel | GOT | Rel |
+ *
+ * value Name - Description
+ *
+ * 0000 None - no reserved entry
+ * 0001 ReserveRel - reserve an dynamic relocation entry
+ * 0010 ReserveGOT - reserve an GOT entry
+ * 0011 GOTandRel - For different relocation, we've reserved GOT and
+ * Rel for different location.
+ * 0100 GOTRel - reserve an GOT entry and the corresponding Dyncamic
+ * relocation entry which relocate this GOT entry
+ * 0101 GOTRelandRel - For different relocation, we've reserved GOTRel
+ * and relocation entry for different location.
+ * 1000 ReservePLT - reserve an PLT entry and the corresponding GOT,
+ * Dynamic relocation entries
+ * 1001 PLTandRel - For different relocation, we've reserved PLT and
+ * Rel for different location.
+ */
+ enum ReservedEntryType {
+ None = 0,
+ ReserveRel = 1,
+ ReserveGOT = 2,
+ GOTandRel = 3,
+ GOTRel = 4,
+ GOTRelandRel = 5,
+ ReservePLT = 8,
+ PLTandRel = 9
+ };
+
+ X86GNULDBackend();
+
+ ~X86GNULDBackend();
+
+ RelocationFactory* getRelocFactory();
+
+ uint32_t machine() const;
+
+ bool isLittleEndian() const
+ { return true; }
+
+ X86GOT& getGOT();
+
+ const X86GOT& getGOT() const;
+
+ X86PLT& getPLT();
+
+ const X86PLT& getPLT() const;
+
+ unsigned int bitclass() const;
+
+ /// preLayout - Backend can do any needed modification before layout
+ void doPreLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+ /// postLayout -Backend can do any needed modification after layout
+ void doPostLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ X86ELFDynamic& dynamic();
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ const X86ELFDynamic& 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 pOutput - the output file
+ /// @param pSection - the given LDSection
+ /// @param pInfo - all options in the command line.
+ /// @param pRegion - the region to write out data
+ /// @return the size of the table in the file.
+ uint64_t emitSectionData(const Output& pOutput,
+ const LDSection& pSection,
+ const MCLDInfo& pInfo,
+ MemoryRegion& pRegion) const;
+
+ /// OSABI - the value of e_ident[EI_OSABI]
+ /// FIXME
+ uint8_t OSABI() const
+ { return llvm::ELF::ELFOSABI_NONE; }
+
+ /// ABIVersion - the value of e_ident[EI_ABIVRESION]
+ /// FIXME
+ uint8_t ABIVersion() const
+ { return 0x0; }
+
+ /// flags - the value of ElfXX_Ehdr::e_flags
+ /// FIXME
+ uint64_t flags() const
+ { return 0x0; }
+
+ /// initTargetSectionMap - initialize target dependent section mapping
+ bool initTargetSectionMap(SectionMap& pSectionMap);
+
+ // initRelocFactory - create and initialize RelocationFactory
+ bool initRelocFactory(const MCLinker& pLinker);
+
+ void initTargetSections(MCLinker& pLinker);
+
+ void initTargetSymbols(MCLinker& pLinker);
+
+ /// scanRelocation - determine the empty entries are needed or not and create
+ /// the empty entries if needed.
+ /// For X86, 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,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ OutputRelocSection& getRelDyn();
+
+ const OutputRelocSection& getRelDyn() const;
+
+ OutputRelocSection& getRelPLT();
+
+ const OutputRelocSection& getRelPLT() const;
+
+ /// getTargetSectionOrder - compute the layout order of X86 target sections
+ unsigned int getTargetSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const;
+
+ /// finalizeSymbol - finalize the symbol value
+ /// If the symbol's reserved field is not zero, MCLinker will call back this
+ /// function to ask the final value of the symbol
+ bool finalizeSymbol(LDSymbol& pSymbol) const;
+
+ /// allocateCommonSymbols - allocate common symbols in the corresponding
+ /// sections.
+ bool allocateCommonSymbols(const MCLDInfo& pLDInfo, MCLinker& pLinker) const;
+
+public:
+ bool isSymbolPreemptible(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const;
+
+private:
+ void scanLocalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ void scanGlobalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ bool isSymbolNeedsPLT(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const;
+
+ bool isSymbolNeedsDynRel(const ResolveInfo& pSym,
+ const Output& pOutput,
+ bool isAbsReloc) const;
+
+ void updateAddend(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ const Layout& pLayout) const;
+
+ void createX86GOT(MCLinker& pLinker, const Output& pOutput);
+ void createX86PLTandRelPLT(MCLinker& pLinker, const Output& pOutput);
+ void createX86RelDyn(MCLinker& pLinker, const Output& pOutput);
+
+ ELFFileFormat* getOutputFormat(const Output& pOutput) const;
+
+private:
+ RelocationFactory* m_pRelocFactory;
+ X86GOT* m_pGOT;
+ X86PLT* m_pPLT;
+ /// m_RelDyn - dynamic relocation table of .rel.dyn
+ OutputRelocSection* m_pRelDyn;
+ /// m_RelPLT - dynamic relocation table of .rel.plt
+ OutputRelocSection* m_pRelPLT;
+
+ X86ELFDynamic* m_pDynamic;
+ LDSymbol* m_pGOTSymbol;
+};
+
+//===----------------------------------------------------------------------===//
+/// X86MachOLDBackend - linker backend of X86 target of MachO format
+///
+/**
+class X86MachOLDBackend : public DarwinX86LDBackend
+{
+public:
+ X86MachOLDBackend();
+ ~X86MachOLDBackend();
+
+private:
+ MCMachOTargetArchiveReader *createTargetArchiveReader() const;
+ MCMachOTargetObjectReader *createTargetObjectReader() const;
+ MCMachOTargetObjectWriter *createTargetObjectWriter() const;
+
+};
+**/
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/X86/X86PLT.cpp b/lib/Target/X86/X86PLT.cpp
new file mode 100644
index 0000000..c5e05f9
--- /dev/null
+++ b/lib/Target/X86/X86PLT.cpp
@@ -0,0 +1,279 @@
+//===- X86PLT.cpp -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "X86GOT.h"
+#include "X86PLT.h"
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <llvm/Support/ELF.h>
+#include <mcld/MC/MCLDOutput.h>
+#include <new>
+
+namespace {
+
+const uint8_t x86_dyn_plt0[] = {
+ 0xff, 0xb3, 0x04, 0, 0, 0, // pushl 0x4(%ebx)
+ 0xff, 0xa3, 0x08, 0, 0, 0, // jmp *0x8(%ebx)
+ 0xf, 0x1f, 0x4, 0 // nopl 0(%eax)
+};
+
+const uint8_t x86_dyn_plt1[] = {
+ 0xff, 0xa3, 0, 0, 0, 0, // jmp *sym@GOT(%ebx)
+ 0x68, 0, 0, 0, 0, // pushl $offset
+ 0xe9, 0, 0, 0, 0 // jmp plt0
+};
+
+const uint8_t x86_exec_plt0[] = {
+ 0xff, 0x35, 0, 0, 0, 0, // pushl .got + 4
+ 0xff, 0x25, 0, 0, 0, 0, // jmp *(.got + 8)
+ 0xf, 0x1f, 0x4, 0 // nopl 0(%eax)
+};
+
+const uint8_t x86_exec_plt1[] = {
+ 0xff, 0x25, 0, 0, 0, 0, // jmp *(sym in .got)
+ 0x68, 0, 0, 0, 0, // pushl $offset
+ 0xe9, 0, 0, 0, 0 // jmp plt0
+};
+
+}
+
+namespace mcld {
+
+X86PLT0::X86PLT0(llvm::MCSectionData* pParent, unsigned int pSize)
+ : PLTEntry(pSize, pParent) { }
+
+X86PLT1::X86PLT1(llvm::MCSectionData* pParent, unsigned int pSize)
+ : PLTEntry(pSize, pParent) { }
+
+//===----------------------------------------------------------------------===//
+// X86PLT
+
+X86PLT::X86PLT(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ X86GOT &pGOTPLT,
+ const Output& pOutput)
+ : PLT(pSection, pSectionData), m_GOT(pGOTPLT), m_PLTEntryIterator()
+{
+ assert (Output::DynObj == pOutput.type() || Output::Exec == pOutput.type());
+ if (Output::DynObj == pOutput.type()) {
+ m_PLT0 = x86_dyn_plt0;
+ m_PLT1 = x86_dyn_plt1;
+ m_PLT0Size = sizeof (x86_dyn_plt0);
+ m_PLT1Size = sizeof (x86_dyn_plt1);
+ }
+ else {
+ m_PLT0 = x86_exec_plt0;
+ m_PLT1 = x86_exec_plt1;
+ m_PLT0Size = sizeof (x86_exec_plt0);
+ m_PLT1Size = sizeof (x86_exec_plt1);
+ }
+ X86PLT0* plt0_entry = new X86PLT0(&m_SectionData, m_PLT0Size);
+
+ m_Section.setSize(m_Section.size() + plt0_entry->getEntrySize());
+
+ m_PLTEntryIterator = pSectionData.begin();
+}
+
+X86PLT::~X86PLT()
+{
+}
+
+void X86PLT::reserveEntry(size_t pNum)
+{
+ X86PLT1* plt1_entry = 0;
+ GOTEntry* got_entry = 0;
+
+ for (size_t i = 0; i < pNum; ++i) {
+ plt1_entry = new (std::nothrow) X86PLT1(&m_SectionData, m_PLT1Size);
+
+ if (!plt1_entry)
+ llvm::report_fatal_error("Allocating new memory for X86PLT1 failed!");
+
+ m_Section.setSize(m_Section.size() + plt1_entry->getEntrySize());
+
+ got_entry= new (std::nothrow) GOTEntry(0, m_GOT.getEntrySize(),
+ &(m_GOT.m_SectionData));
+
+ if (!got_entry)
+ llvm::report_fatal_error("Allocating new memory for GOT failed!");
+
+ m_GOT.m_Section.setSize(m_GOT.m_Section.size() + m_GOT.f_EntrySize);
+
+ ++(m_GOT.m_GOTPLTNum);
+ ++(m_GOT.m_GeneralGOTIterator);
+ }
+}
+
+PLTEntry* X86PLT::getPLTEntry(const ResolveInfo& pSymbol, bool& pExist)
+{
+ X86PLT1 *&PLTEntry = m_PLTEntryMap[&pSymbol];
+
+ pExist = 1;
+
+ if (!PLTEntry) {
+ GOTEntry *&GOTPLTEntry = m_GOT.m_GOTPLTMap[&pSymbol];
+ assert(!GOTPLTEntry && "PLT entry and got.plt entry doesn't match!");
+
+ pExist = 0;
+
+ // This will skip PLT0.
+ ++m_PLTEntryIterator;
+ assert(m_PLTEntryIterator != m_SectionData.end() &&
+ "The number of PLT Entries and ResolveInfo doesn't match");
+ ++(m_GOT.m_GOTPLTIterator);
+
+ PLTEntry = llvm::cast<X86PLT1>(&(*m_PLTEntryIterator));
+ GOTPLTEntry = llvm::cast<GOTEntry>(&(*(m_GOT.m_GOTPLTIterator)));
+ }
+
+ return PLTEntry;
+}
+
+GOTEntry* X86PLT::getGOTPLTEntry(const ResolveInfo& pSymbol, bool& pExist)
+{
+ GOTEntry *&GOTPLTEntry = m_GOT.m_GOTPLTMap[&pSymbol];
+
+ pExist = 1;
+
+ if (!GOTPLTEntry) {
+ X86PLT1 *&PLTEntry = m_PLTEntryMap[&pSymbol];
+ assert(!PLTEntry && "PLT entry and got.plt entry doesn't match!");
+
+ pExist = 0;
+
+ // This will skip PLT0.
+ ++m_PLTEntryIterator;
+ assert(m_PLTEntryIterator != m_SectionData.end() &&
+ "The number of PLT Entries and ResolveInfo doesn't match");
+ ++(m_GOT.m_GOTPLTIterator);
+
+ PLTEntry = llvm::cast<X86PLT1>(&(*m_PLTEntryIterator));
+ GOTPLTEntry = llvm::cast<GOTEntry>(&(*(m_GOT.m_GOTPLTIterator)));
+ }
+
+ return GOTPLTEntry;
+}
+
+X86PLT0* X86PLT::getPLT0() const {
+
+ iterator first = m_SectionData.getFragmentList().begin();
+ iterator end = m_SectionData.getFragmentList().end();
+
+ assert(first!=end && "FragmentList is empty, getPLT0 failed!");
+
+ X86PLT0* plt0 = &(llvm::cast<X86PLT0>(*first));
+
+ return plt0;
+}
+
+// FIXME: It only works on little endian machine.
+void X86PLT::applyPLT0() {
+
+ iterator first = m_SectionData.getFragmentList().begin();
+ iterator end = m_SectionData.getFragmentList().end();
+
+ assert(first!=end && "FragmentList is empty, applyPLT0 failed!");
+
+ X86PLT0* plt0 = &(llvm::cast<X86PLT0>(*first));
+
+ unsigned char* data = 0;
+ data = static_cast<unsigned char*>(malloc(plt0->getEntrySize()));
+
+ if (!data)
+ llvm::report_fatal_error("Allocating new memory for plt0 failed!");
+
+ memcpy(data, m_PLT0, plt0->getEntrySize());
+
+ if (m_PLT0 == x86_exec_plt0) {
+ uint64_t got_base = m_GOT.getSection().addr();
+ assert(got_base && ".got base address is NULL!");
+ uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2);
+ *offset = got_base + 4;
+ offset = reinterpret_cast<uint32_t*>(data + 8);
+ *offset = got_base + 8;
+ }
+
+ plt0->setContent(data);
+}
+
+// FIXME: It only works on little endian machine.
+void X86PLT::applyPLT1() {
+
+ uint64_t plt_base = m_Section.addr();
+ assert(plt_base && ".plt base address is NULL!");
+
+ uint64_t got_base = m_GOT.getSection().addr();
+ assert(got_base && ".got base address is NULL!");
+
+ X86PLT::iterator it = m_SectionData.begin();
+ X86PLT::iterator ie = m_SectionData.end();
+ assert(it!=ie && "FragmentList is empty, applyPLT1 failed!");
+
+ uint64_t GOTEntrySize = m_GOT.getEntrySize();
+
+ // Skip GOT0
+ uint64_t GOTEntryOffset = GOTEntrySize * X86GOT0Num;
+
+ //skip PLT0
+ uint64_t PLTEntryOffset = m_PLT0Size;
+ ++it;
+
+ X86PLT1* plt1 = 0;
+
+ uint64_t PLTRelOffset = 0;
+
+ while (it != ie) {
+ plt1 = &(llvm::cast<X86PLT1>(*it));
+ unsigned char *data;
+ data = static_cast<unsigned char*>(malloc(plt1->getEntrySize()));
+
+ if (!data)
+ llvm::report_fatal_error("Allocating new memory for plt1 failed!");
+
+ memcpy(data, m_PLT1, plt1->getEntrySize());
+
+ uint32_t* offset;
+
+ offset = reinterpret_cast<uint32_t*>(data + 2);
+ *offset = GOTEntryOffset;
+ GOTEntryOffset += GOTEntrySize;
+
+ offset = reinterpret_cast<uint32_t*>(data + 7);
+ *offset = PLTRelOffset;
+ PLTRelOffset += sizeof (llvm::ELF::Elf32_Rel);
+
+ offset = reinterpret_cast<uint32_t*>(data + 12);
+ *offset = -(PLTEntryOffset + 12 + 4);
+ PLTEntryOffset += m_PLT1Size;
+
+ plt1->setContent(data);
+ ++it;
+ }
+
+ unsigned int GOTPLTNum = m_GOT.getGOTPLTNum();
+
+ if (GOTPLTNum != 0) {
+ X86GOT::iterator gotplt_it = m_GOT.getLastGOT0();
+ X86GOT::iterator list_ie = m_GOT.getSectionData().getFragmentList().end();
+
+ ++gotplt_it;
+ uint64_t PLTEntryAddress = plt_base + m_PLT0Size;
+ for (unsigned int i = 0; i < GOTPLTNum; ++i) {
+ if (gotplt_it == list_ie)
+ llvm::report_fatal_error(
+ "The number of got.plt entries is inconsistent!");
+
+ llvm::cast<GOTEntry>(*gotplt_it).setContent(PLTEntryAddress + 6);
+ PLTEntryAddress += m_PLT1Size;
+ ++gotplt_it;
+ }
+ }
+}
+
+} // end namespace mcld
+
diff --git a/lib/Target/X86/X86PLT.h b/lib/Target/X86/X86PLT.h
new file mode 100644
index 0000000..dd72f52
--- /dev/null
+++ b/lib/Target/X86/X86PLT.h
@@ -0,0 +1,91 @@
+//===- X86PLT.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_PLT_H
+#define X86_PLT_H
+
+#include <mcld/Target/PLT.h>
+
+namespace mcld {
+
+class X86GOT;
+class GOTEntry;
+class Output;
+
+class X86PLT0 : public PLTEntry {
+public:
+ X86PLT0(llvm::MCSectionData* pParent, unsigned int pSize);
+};
+
+class X86PLT1 : public PLTEntry {
+public:
+ X86PLT1(llvm::MCSectionData* pParent, unsigned int pSize);
+};
+
+/** \class X86PLT
+ * \brief X86 Procedure Linkage Table
+ */
+class X86PLT : public PLT
+{
+ typedef llvm::DenseMap<const ResolveInfo*, X86PLT1*> SymbolIndexType;
+
+public:
+ typedef llvm::MCSectionData::iterator iterator;
+ typedef llvm::MCSectionData::const_iterator const_iterator;
+
+public:
+ X86PLT(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ X86GOT& pGOTPLT,
+ const Output& pOutput);
+ ~X86PLT();
+
+// Override virtual function.
+public:
+
+ // reserveEntry is X86GOT friend function.
+ void reserveEntry(size_t pNum = 1) ;
+
+ PLTEntry* getPLTEntry(const ResolveInfo& pSymbol, bool& pExist) ;
+
+ GOTEntry* getGOTPLTEntry(const ResolveInfo& pSymbol, bool& pExist);
+
+public:
+
+ iterator begin() { return m_SectionData.begin(); }
+
+ const_iterator begin() const { return m_SectionData.begin(); }
+
+ iterator end() { return m_SectionData.end(); }
+
+ const_iterator end() const { return m_SectionData.end(); }
+
+ X86PLT0* getPLT0() const;
+
+ void applyPLT0();
+
+ void applyPLT1();
+
+private:
+ X86GOT& m_GOT;
+
+ // Used by getEntry() for mapping a ResolveInfo
+ // instance to a PLT1 Entry.
+ iterator m_PLTEntryIterator;
+
+ SymbolIndexType m_PLTEntryMap;
+
+ const uint8_t *m_PLT0;
+ const uint8_t *m_PLT1;
+ unsigned int m_PLT0Size;
+ unsigned int m_PLT1Size;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/X86/X86RelocationFactory.cpp b/lib/Target/X86/X86RelocationFactory.cpp
new file mode 100644
index 0000000..15b9a6b
--- /dev/null
+++ b/lib/Target/X86/X86RelocationFactory.cpp
@@ -0,0 +1,361 @@
+//===- X86RelocationFactory.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/ErrorHandling.h>
+#include <llvm/Support/DataTypes.h>
+#include <llvm/Support/ELF.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/LD/Layout.h>
+
+#include "X86RelocationFactory.h"
+#include "X86RelocationFunctions.h"
+
+using namespace mcld;
+
+DECL_X86_APPLY_RELOC_FUNCS
+
+//===--------------------------------------------------------------------===//
+// X86RelocationFactory
+X86RelocationFactory::X86RelocationFactory(size_t pNum,
+ X86GNULDBackend& pParent)
+ : RelocationFactory(pNum),
+ m_Target(pParent) {
+}
+
+X86RelocationFactory::~X86RelocationFactory()
+{
+}
+
+void X86RelocationFactory::applyRelocation(Relocation& pRelocation,
+ const MCLDInfo& pLDInfo)
+{
+ Relocation::Type type = pRelocation.type();
+
+ /// the prototype of applying function
+ typedef Result (*ApplyFunctionType)(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent);
+
+ // the table entry of applying functions
+ struct ApplyFunctionTriple {
+ ApplyFunctionType func;
+ unsigned int type;
+ const char* name;
+ };
+
+ // declare the table of applying functions
+ static ApplyFunctionTriple apply_functions[] = {
+ DECL_X86_APPLY_RELOC_FUNC_PTRS
+ };
+
+ if (type >= sizeof (apply_functions) / sizeof (apply_functions[0]) ) {
+ llvm::report_fatal_error(llvm::Twine("Unknown relocation type ") +
+ llvm::Twine((int) type) +
+ llvm::Twine(" to symbol `") +
+ pRelocation.symInfo()->name() +
+ llvm::Twine("'."));
+ return;
+ }
+
+ // apply the relocation
+ Result result = apply_functions[type].func(pRelocation, pLDInfo, *this);
+
+ // check result
+ if (Overflow == result) {
+ llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
+ llvm::Twine(apply_functions[type].name) +
+ llvm::Twine("' causes overflow. on symbol: `") +
+ llvm::Twine(pRelocation.symInfo()->name()) +
+ llvm::Twine("'."));
+ return;
+ }
+
+ if (BadReloc == result) {
+ llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
+ llvm::Twine(apply_functions[type].name) +
+ llvm::Twine("' encounters unexpected opcode. "
+ "on symbol: `") +
+ llvm::Twine(pRelocation.symInfo()->name()) +
+ llvm::Twine("'."));
+ return;
+ }
+}
+
+
+
+// non-member functions
+
+//=========================================//
+// Relocation helper function //
+//=========================================//
+
+// Check if symbol can use relocation R_386_RELATIVE
+static bool
+helper_use_relative_reloc(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const X86RelocationFactory& pFactory)
+
+{
+ // if symbol is dynamic or undefine or preemptible
+ if(pSym.isDyn() ||
+ pSym.isUndef() ||
+ pFactory.getTarget().isSymbolPreemptible(pSym, pLDInfo, pLDInfo.output()))
+ return false;
+ return true;
+}
+
+static
+GOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ X86GNULDBackend& ld_backend = pParent.getTarget();
+
+ bool exist;
+ GOTEntry& got_entry = *ld_backend.getGOT().getEntry(*rsym, exist);
+ if (!exist) {
+ // 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.setContent(pReloc.symValue());
+ }
+ else if (rsym->reserved() & X86GNULDBackend::GOTRel) {
+ // Initialize corresponding dynamic relocation.
+ Relocation& rel_entry =
+ *ld_backend.getRelDyn().getEntry(*rsym, true, exist);
+ assert(!exist && "GOT entry not exist, but DynRel entry exist!");
+ if(helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
+ // Initialize got entry to target symbol address
+ got_entry.setContent(pReloc.symValue());
+ rel_entry.setType(llvm::ELF::R_386_RELATIVE);
+ rel_entry.setSymInfo(0);
+ }
+ else {
+ got_entry.setContent(0);
+ rel_entry.setType(llvm::ELF::R_386_GLOB_DAT);
+ rel_entry.setSymInfo(rsym);
+ }
+ rel_entry.targetRef().assign(got_entry);
+ }
+ else {
+ llvm::report_fatal_error("No GOT entry reserved for GOT type relocation!");
+ }
+ }
+ return got_entry;
+}
+
+
+static
+X86RelocationFactory::Address helper_GOT_ORG(X86RelocationFactory& pParent)
+{
+ return pParent.getTarget().getGOT().getSection().addr();
+}
+
+
+static
+X86RelocationFactory::Address helper_GOT(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pLDInfo, pParent);
+ return helper_GOT_ORG(pParent) + pParent.getLayout().getOutputOffset(got_entry);
+}
+
+
+static
+PLTEntry& helper_get_PLT_and_init(Relocation& pReloc,
+ X86RelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ X86GNULDBackend& ld_backend = pParent.getTarget();
+
+ bool exist;
+ PLTEntry& plt_entry = *ld_backend.getPLT().getPLTEntry(*rsym, exist);
+ if (!exist) {
+ // If we first get this PLT entry, we should initialize it.
+ if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
+ GOTEntry& gotplt_entry =
+ *ld_backend.getPLT().getGOTPLTEntry(*rsym, exist);
+ // Initialize corresponding dynamic relocation.
+ Relocation& rel_entry =
+ *ld_backend.getRelPLT().getEntry(*rsym, true, exist);
+ assert(!exist && "PLT entry not exist, but DynRel entry exist!");
+ rel_entry.setType(llvm::ELF::R_386_JUMP_SLOT);
+ rel_entry.targetRef().assign(gotplt_entry);
+ rel_entry.setSymInfo(rsym);
+ }
+ else {
+ llvm::report_fatal_error("No PLT entry reserved for PLT type relocation!");
+ }
+ }
+ return plt_entry;
+}
+
+
+
+static
+X86RelocationFactory::Address helper_PLT_ORG(X86RelocationFactory& pParent)
+{
+ return pParent.getTarget().getPLT().getSection().addr();
+}
+
+
+static
+X86RelocationFactory::Address helper_PLT(Relocation& pReloc,
+ X86RelocationFactory& pParent)
+{
+ PLTEntry& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
+ return helper_PLT_ORG(pParent) + pParent.getLayout().getOutputOffset(plt_entry);
+}
+
+// Get an relocation entry in .rel.dyn and set its type to pType,
+// its FragmentRef to pReloc->targetFrag() and its ResolveInfo to pReloc->symInfo()
+static
+void helper_DynRel(Relocation& pReloc,
+ X86RelocationFactory::Type pType,
+ X86RelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ X86GNULDBackend& ld_backend = pParent.getTarget();
+ bool exist;
+
+ Relocation& rel_entry =
+ *ld_backend.getRelDyn().getEntry(*rsym, false, exist);
+ rel_entry.setType(pType);
+ rel_entry.targetRef() = pReloc.targetRef();
+
+ if(pType == llvm::ELF::R_386_RELATIVE)
+ rel_entry.setSymInfo(0);
+ else
+ rel_entry.setSymInfo(rsym);
+}
+
+
+//=========================================//
+// Each relocation function implementation //
+//=========================================//
+
+// R_386_NONE
+X86RelocationFactory::Result none(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ return X86RelocationFactory::OK;
+}
+
+// R_386_32: S + A
+X86RelocationFactory::Result abs32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ RelocationFactory::DWord S = pReloc.symValue();
+
+ if(rsym->isLocal() && (rsym->reserved() & X86GNULDBackend::ReserveRel)) {
+ helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
+ pReloc.target() = S + A;
+ return X86RelocationFactory::OK;
+ }
+ else if(!rsym->isLocal()) {
+ if(rsym->reserved() & X86GNULDBackend::ReservePLT) {
+ S = helper_PLT(pReloc, pParent);
+ pReloc.target() = S + A;
+ }
+ if(rsym->reserved() & X86GNULDBackend::ReserveRel) {
+ if(helper_use_relative_reloc(*rsym, pLDInfo, pParent) ) {
+ helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
+ }
+ else {
+ helper_DynRel(pReloc, pReloc.type(), pParent);
+ return X86RelocationFactory::OK;
+ }
+ }
+ }
+
+ // perform static relocation
+ pReloc.target() = S + A;
+ return X86RelocationFactory::OK;
+}
+
+// R_386_PC32: S + A - P
+X86RelocationFactory::Result rel32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ // perform static relocation
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ pReloc.target() = pReloc.symValue() + A
+ - pReloc.place(pParent.getLayout());
+ return X86RelocationFactory::OK;
+}
+
+// R_386_GOTOFF: S + A - GOT_ORG
+X86RelocationFactory::Result gotoff32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
+ X86RelocationFactory::Address S = pReloc.symValue();
+
+ pReloc.target() = S + A - GOT_ORG;
+ return X86RelocationFactory::OK;
+}
+
+// R_386_GOTPC: GOT_ORG + A - P
+X86RelocationFactory::Result gotpc32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
+ // Apply relocation.
+ pReloc.target() = GOT_ORG + A - pReloc.place(pParent.getLayout());
+ return X86RelocationFactory::OK;
+}
+
+// R_386_GOT32: GOT(S) + A - GOT_ORG
+X86RelocationFactory::Result got32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ if(!(pReloc.symInfo()->reserved()
+ & (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) {
+ return X86RelocationFactory::BadReloc;
+ }
+ X86RelocationFactory::Address GOT_S = helper_GOT(pReloc, pLDInfo, pParent);
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
+ // Apply relocation.
+ pReloc.target() = GOT_S + A - GOT_ORG;
+ return X86RelocationFactory::OK;
+}
+
+// R_386_PLT32: PLT(S) + A - P
+X86RelocationFactory::Result plt32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ // PLT_S depends on if there is a PLT entry.
+ X86RelocationFactory::Address PLT_S;
+ if((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT))
+ PLT_S = helper_PLT(pReloc, pParent);
+ else
+ PLT_S = pReloc.symValue();
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ X86RelocationFactory::Address P = pReloc.place(pParent.getLayout());
+ pReloc.target() = PLT_S + A - P;
+ return X86RelocationFactory::OK;
+}
diff --git a/lib/Target/X86/X86RelocationFactory.h b/lib/Target/X86/X86RelocationFactory.h
new file mode 100644
index 0000000..6a6c372
--- /dev/null
+++ b/lib/Target/X86/X86RelocationFactory.h
@@ -0,0 +1,58 @@
+//===- X86RelocationFactory.h --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_RELOCATION_FACTORY_H
+#define X86_RELOCATION_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/RelocationFactory.h>
+#include <mcld/Target/GOT.h>
+#include "X86LDBackend.h"
+
+namespace mcld
+{
+
+/** \class X86RelocationFactory
+ * \brief X86RelocationFactory creates and destroys the X86 relocations.
+ *
+ */
+class X86RelocationFactory : public RelocationFactory
+{
+public:
+ /** \enum Reloc
+ * \brief Reloc is the result of applying functions.
+ */
+ enum Result
+ {
+ OK,
+ Overflow,
+ BadReloc
+ };
+
+public:
+ X86RelocationFactory(size_t pNum, X86GNULDBackend& pParent);
+ ~X86RelocationFactory();
+
+ void applyRelocation(Relocation& pRelocation, const MCLDInfo& pLDInfo);
+
+ X86GNULDBackend& getTarget()
+ { return m_Target; }
+
+ const X86GNULDBackend& getTarget() const
+ { return m_Target; }
+
+private:
+ X86GNULDBackend& m_Target;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/X86/X86RelocationFunctions.h b/lib/Target/X86/X86RelocationFunctions.h
new file mode 100644
index 0000000..46d4f34
--- /dev/null
+++ b/lib/Target/X86/X86RelocationFunctions.h
@@ -0,0 +1,36 @@
+//===- X86RelocationFunction.h --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define DECL_X86_APPLY_RELOC_FUNC(Name) \
+static X86RelocationFactory::Result Name (Relocation& pEntry, \
+ const MCLDInfo& pLDInfo, \
+ X86RelocationFactory& pParent);
+
+#define DECL_X86_APPLY_RELOC_FUNCS \
+DECL_X86_APPLY_RELOC_FUNC(none) \
+DECL_X86_APPLY_RELOC_FUNC(abs32) \
+DECL_X86_APPLY_RELOC_FUNC(rel32) \
+DECL_X86_APPLY_RELOC_FUNC(plt32) \
+DECL_X86_APPLY_RELOC_FUNC(got32) \
+DECL_X86_APPLY_RELOC_FUNC(gotoff32) \
+DECL_X86_APPLY_RELOC_FUNC(gotpc32)
+
+
+#define DECL_X86_APPLY_RELOC_FUNC_PTRS \
+ { &none, 0, "R_386_NONE" }, \
+ { &abs32, 1, "R_386_32" }, \
+ { &rel32, 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" }
diff --git a/lib/Target/X86/X86SectLinker.cpp b/lib/Target/X86/X86SectLinker.cpp
new file mode 100644
index 0000000..793b97b
--- /dev/null
+++ b/lib/Target/X86/X86SectLinker.cpp
@@ -0,0 +1,47 @@
+//===- X86SectLinker.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 "X86.h"
+#include "X86AndroidSectLinker.h"
+#include "X86ELFSectLinker.h"
+
+using namespace mcld;
+
+namespace mcld {
+//===----------------------------------------------------------------------===//
+/// createX86SectLinker - the help funtion to create corresponding X86SectLinker
+///
+SectLinker* createX86SectLinker(const std::string &pTriple,
+ SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend)
+{
+ Triple theTriple(pTriple);
+ if (theTriple.isOSDarwin()) {
+ assert(0 && "MachO linker has not supported yet");
+ }
+ if (theTriple.isOSWindows()) {
+ assert(0 && "COFF linker has not supported yet");
+ }
+
+ // For now, use Android SectLinker directly
+ return new X86AndroidSectLinker(pOption,
+ pLDBackend);
+}
+
+} // namespace of mcld
+
+//==========================
+// X86SectLinker
+extern "C" void LLVMInitializeX86SectLinker() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterSectLinker(TheX86Target, createX86SectLinker);
+}
+
diff --git a/lib/Target/X86/X86TargetMachine.cpp b/lib/Target/X86/X86TargetMachine.cpp
new file mode 100644
index 0000000..b036137
--- /dev/null
+++ b/lib/Target/X86/X86TargetMachine.cpp
@@ -0,0 +1,34 @@
+//===- X86TargetMachine.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "X86TargetMachine.h"
+
+#include "mcld/Target/TargetMachine.h"
+#include "mcld/Support/TargetRegistry.h"
+#include "mcld/MC/MCLDInfo.h"
+#include "X86.h"
+
+extern "C" void LLVMInitializeX86LDTarget() {
+ // Register createTargetMachine function pointer to mcld::Target
+ mcld::RegisterTargetMachine<mcld::X86TargetMachine> X(mcld::TheX86Target);
+}
+
+mcld::X86TargetMachine::X86TargetMachine(llvm::TargetMachine& pPM,
+ const mcld::Target &pTarget,
+ const std::string& pTriple)
+ : mcld::LLVMTargetMachine(pPM, pTarget, pTriple) {
+ // arg1 - the number of total attributes
+ // arg2 - the most possible number of input files
+ m_pLDInfo = new MCLDInfo(pTriple, 32, 64);
+}
+
+mcld::X86TargetMachine::~X86TargetMachine()
+{
+ delete m_pLDInfo;
+}
+
diff --git a/lib/Target/X86/X86TargetMachine.h b/lib/Target/X86/X86TargetMachine.h
new file mode 100644
index 0000000..3ba9e59
--- /dev/null
+++ b/lib/Target/X86/X86TargetMachine.h
@@ -0,0 +1,40 @@
+//===- X86TargetMachine.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_X86_TARGET_MACHINE_H
+#define MCLD_X86_TARGET_MACHINE_H
+#include "mcld/Target/TargetMachine.h"
+#include "X86.h"
+
+namespace mcld
+{
+
+class X86TargetMachine : public LLVMTargetMachine
+{
+protected:
+ MCLDInfo *m_pLDInfo;
+
+public:
+ X86TargetMachine(llvm::TargetMachine &pTM,
+ const mcld::Target &pTarget,
+ const std::string &pTriple);
+
+ virtual ~X86TargetMachine();
+
+ mcld::MCLDInfo& getLDInfo()
+ { return *m_pLDInfo; }
+
+ const mcld::MCLDInfo& getLDInfo() const
+ { return *m_pLDInfo; }
+
+};
+
+} // namespace of mcld
+
+#endif
+