summaryrefslogtreecommitdiff
path: root/lib/Target/AArch64
diff options
context:
space:
mode:
authorStephen Hines <srhines@google.com>2014-04-24 14:41:24 -0700
committerStephen Hines <srhines@google.com>2014-04-24 15:22:31 -0700
commit551ae4ebd3e9d137ea668fb83ae4a55b8cfba451 (patch)
treec4ea60679a6fe2630e21bf6d46177b2c4fcab33b /lib/Target/AArch64
parent334c6f83c1265eabd58ac7c8b860898038831eab (diff)
downloadmclinker-551ae4ebd3e9d137ea668fb83ae4a55b8cfba451.tar.gz
Update MCLinker for LLVM 3.5.
Change-Id: Ib07513d0eb2f8b7d3516a7dd8823f98820943cc9
Diffstat (limited to 'lib/Target/AArch64')
-rw-r--r--lib/Target/AArch64/AArch64.h30
-rw-r--r--lib/Target/AArch64/AArch64Diagnostic.cpp36
-rw-r--r--lib/Target/AArch64/AArch64ELFDynamic.cpp51
-rw-r--r--lib/Target/AArch64/AArch64ELFDynamic.h31
-rw-r--r--lib/Target/AArch64/AArch64ELFMCLinker.cpp25
-rw-r--r--lib/Target/AArch64/AArch64ELFMCLinker.h37
-rw-r--r--lib/Target/AArch64/AArch64Emulation.cpp71
-rw-r--r--lib/Target/AArch64/AArch64GNUInfo.h35
-rw-r--r--lib/Target/AArch64/AArch64GOT.cpp141
-rw-r--r--lib/Target/AArch64/AArch64GOT.h103
-rw-r--r--lib/Target/AArch64/AArch64LDBackend.cpp458
-rw-r--r--lib/Target/AArch64/AArch64LDBackend.h167
-rw-r--r--lib/Target/AArch64/AArch64MCLinker.cpp51
-rw-r--r--lib/Target/AArch64/AArch64PLT.cpp171
-rw-r--r--lib/Target/AArch64/AArch64PLT.h86
-rw-r--r--lib/Target/AArch64/AArch64RelocationFunctions.h110
-rw-r--r--lib/Target/AArch64/AArch64RelocationHelpers.h212
-rw-r--r--lib/Target/AArch64/AArch64Relocator.cpp694
-rw-r--r--lib/Target/AArch64/AArch64Relocator.h151
-rw-r--r--lib/Target/AArch64/AArch64TargetMachine.cpp30
-rw-r--r--lib/Target/AArch64/AArch64TargetMachine.h29
-rw-r--r--lib/Target/AArch64/Android.mk38
-rw-r--r--lib/Target/AArch64/TargetInfo/AArch64TargetInfo.cpp22
-rw-r--r--lib/Target/AArch64/TargetInfo/Android.mk28
24 files changed, 2807 insertions, 0 deletions
diff --git a/lib/Target/AArch64/AArch64.h b/lib/Target/AArch64/AArch64.h
new file mode 100644
index 0000000..df389e8
--- /dev/null
+++ b/lib/Target/AArch64/AArch64.h
@@ -0,0 +1,30 @@
+//===- AArch64.h ----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TARGET_AARCH64_AARCH64_H
+#define TARGET_AARCH64_AARCH64_H
+#include <string>
+
+namespace llvm {
+class Target;
+} // namespace of llvm
+
+namespace mcld {
+
+class Target;
+class TargetLDBackend;
+
+extern mcld::Target TheAArch64Target;
+
+TargetLDBackend *createAArch64LDBackend(const llvm::Target&,
+ const std::string&);
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/AArch64/AArch64Diagnostic.cpp b/lib/Target/AArch64/AArch64Diagnostic.cpp
new file mode 100644
index 0000000..6fddce4
--- /dev/null
+++ b/lib/Target/AArch64/AArch64Diagnostic.cpp
@@ -0,0 +1,36 @@
+//===- AArch64Diagnostic.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/LD/DWARFLineInfo.h>
+#include "AArch64.h"
+
+using namespace mcld;
+
+namespace mcld {
+//===----------------------------------------------------------------------===//
+// createAArch64Diagnostic - the help function to create corresponding
+// AArch64Diagnostic
+//===----------------------------------------------------------------------===//
+DiagnosticLineInfo* createAArch64DiagLineInfo(const mcld::Target& pTarget,
+ const std::string &pTriple)
+{
+ return new DWARFLineInfo();
+}
+
+} // namespace of mcld
+
+//===----------------------------------------------------------------------===//
+// InitializeAArch64Diagnostic
+//===----------------------------------------------------------------------===//
+extern "C" void MCLDInitializeAArch64DiagnosticLineInfo() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheAArch64Target,
+ createAArch64DiagLineInfo);
+}
+
diff --git a/lib/Target/AArch64/AArch64ELFDynamic.cpp b/lib/Target/AArch64/AArch64ELFDynamic.cpp
new file mode 100644
index 0000000..3aa572a
--- /dev/null
+++ b/lib/Target/AArch64/AArch64ELFDynamic.cpp
@@ -0,0 +1,51 @@
+//===- AArch64ELFDynamic.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "AArch64ELFDynamic.h"
+
+#include <mcld/LD/ELFFileFormat.h>
+#include <mcld/LinkerConfig.h>
+
+using namespace mcld;
+
+AArch64ELFDynamic::AArch64ELFDynamic(const GNULDBackend& pParent,
+ const LinkerConfig& pConfig)
+ : ELFDynamic(pParent, pConfig)
+{
+}
+
+AArch64ELFDynamic::~AArch64ELFDynamic()
+{
+}
+
+void AArch64ELFDynamic::reserveTargetEntries(const ELFFileFormat& pFormat)
+{
+ // reservePLTGOT
+ if (config().options().hasNow()) {
+ if (pFormat.hasGOT())
+ reserveOne(llvm::ELF::DT_PLTGOT);
+ }
+ else {
+ if (pFormat.hasGOTPLT())
+ reserveOne(llvm::ELF::DT_PLTGOT);
+ }
+}
+
+void AArch64ELFDynamic::applyTargetEntries(const ELFFileFormat& pFormat)
+{
+ // applyPLTGOT
+ if (config().options().hasNow()) {
+ if (pFormat.hasGOT())
+ applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOT().addr());
+ }
+ else {
+ if (pFormat.hasGOTPLT())
+ applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOTPLT().addr());
+ }
+}
+
diff --git a/lib/Target/AArch64/AArch64ELFDynamic.h b/lib/Target/AArch64/AArch64ELFDynamic.h
new file mode 100644
index 0000000..04060ac
--- /dev/null
+++ b/lib/Target/AArch64/AArch64ELFDynamic.h
@@ -0,0 +1,31 @@
+//===- AArch64ELFDynamic.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TARGET_AARCH64_AARCH64ELFDYNAMIC_H
+#define TARGET_AARCH64_AARCH64ELFDYNAMIC_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Target/ELFDynamic.h>
+
+namespace mcld {
+
+class AArch64ELFDynamic : public ELFDynamic {
+public:
+ AArch64ELFDynamic(const GNULDBackend& pParent, const LinkerConfig& pConfig);
+ ~AArch64ELFDynamic();
+
+private:
+ void reserveTargetEntries(const ELFFileFormat& pFormat);
+ void applyTargetEntries(const ELFFileFormat& pFormat);
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/AArch64/AArch64ELFMCLinker.cpp b/lib/Target/AArch64/AArch64ELFMCLinker.cpp
new file mode 100644
index 0000000..a311435
--- /dev/null
+++ b/lib/Target/AArch64/AArch64ELFMCLinker.cpp
@@ -0,0 +1,25 @@
+//===- AArch64ELFMCLinker.cpp ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "AArch64ELFMCLinker.h"
+
+#include <mcld/LinkerConfig.h>
+#include <mcld/Object/SectionMap.h>
+
+using namespace mcld;
+
+AArch64ELFMCLinker::AArch64ELFMCLinker(LinkerConfig& pConfig,
+ mcld::Module &pModule,
+ FileHandle& pFileHandle)
+ : ELFMCLinker(pConfig, pModule, pFileHandle) {
+}
+
+AArch64ELFMCLinker::~AArch64ELFMCLinker()
+{
+}
+
diff --git a/lib/Target/AArch64/AArch64ELFMCLinker.h b/lib/Target/AArch64/AArch64ELFMCLinker.h
new file mode 100644
index 0000000..36e4a5c
--- /dev/null
+++ b/lib/Target/AArch64/AArch64ELFMCLinker.h
@@ -0,0 +1,37 @@
+//===- AArch64ELFMCLinker.h -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TARGET_AARCH64_AARCH64ELFMCLINKER_H
+#define TARGET_AARCH64_AARCH64ELFMCLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Target/ELFMCLinker.h>
+
+namespace mcld {
+
+class Module;
+class FileHandle;
+
+/** \class AArch64ELFMCLinker
+ * \brief AArch64ELFMCLinker sets up the environment for linking.
+ */
+class AArch64ELFMCLinker : public ELFMCLinker
+{
+public:
+ AArch64ELFMCLinker(LinkerConfig& pConfig,
+ mcld::Module& pModule,
+ FileHandle& pFileHandle);
+
+ ~AArch64ELFMCLinker();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/AArch64/AArch64Emulation.cpp b/lib/Target/AArch64/AArch64Emulation.cpp
new file mode 100644
index 0000000..02f4b01
--- /dev/null
+++ b/lib/Target/AArch64/AArch64Emulation.cpp
@@ -0,0 +1,71 @@
+//===- AArch64Emulation.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "AArch64.h"
+#include <mcld/LinkerConfig.h>
+#include <mcld/LinkerScript.h>
+#include <mcld/Target/ELFEmulation.h>
+#include <mcld/Support/TargetRegistry.h>
+
+namespace mcld {
+
+static bool MCLDEmulateAArch64ELF(LinkerScript& pScript, LinkerConfig& pConfig)
+{
+ if (!MCLDEmulateELF(pScript, pConfig))
+ return false;
+
+ // set up bitclass and endian
+ pConfig.targets().setEndian(TargetOptions::Little);
+ pConfig.targets().setBitClass(64);
+
+ // set up target-dependent constraints of attributes
+ pConfig.attribute().constraint().enableWholeArchive();
+ pConfig.attribute().constraint().enableAsNeeded();
+ pConfig.attribute().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ pConfig.attribute().predefined().unsetWholeArchive();
+ pConfig.attribute().predefined().unsetAsNeeded();
+ pConfig.attribute().predefined().setDynamic();
+
+ // set up section map
+ if (pConfig.options().getScriptList().empty() &&
+ pConfig.codeGenType() != LinkerConfig::Object) {
+ pScript.sectionMap().insert(".ARM.attributes*", ".ARM.attributes");
+ }
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// emulateAArch64LD - the help function to emulate AArch64 ld
+//===----------------------------------------------------------------------===//
+bool emulateAArch64LD(LinkerScript& pScript, LinkerConfig& pConfig)
+{
+ if (pConfig.targets().triple().isOSDarwin()) {
+ assert(0 && "MachO linker has not supported yet");
+ return false;
+ }
+ if (pConfig.targets().triple().isOSWindows()) {
+ assert(0 && "COFF linker has not supported yet");
+ return false;
+ }
+
+ return MCLDEmulateAArch64ELF(pScript, pConfig);
+}
+
+} // namespace of mcld
+
+//===----------------------------------------------------------------------===//
+// AArch64Emulation
+//===----------------------------------------------------------------------===//
+extern "C" void MCLDInitializeAArch64Emulation() {
+ // Register the emulation
+ mcld::TargetRegistry::RegisterEmulation(mcld::TheAArch64Target,
+ mcld::emulateAArch64LD);
+}
+
diff --git a/lib/Target/AArch64/AArch64GNUInfo.h b/lib/Target/AArch64/AArch64GNUInfo.h
new file mode 100644
index 0000000..554b27c
--- /dev/null
+++ b/lib/Target/AArch64/AArch64GNUInfo.h
@@ -0,0 +1,35 @@
+//===- AArch64GNUInfo.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TARGET_AARCH64_AARCH64GNUINFO_H
+#define TARGET_AARCH64_AARCH64GNUINFO_H
+#include <mcld/Target/GNUInfo.h>
+
+#include <llvm/Support/ELF.h>
+
+namespace mcld {
+
+class AArch64GNUInfo : public GNUInfo
+{
+public:
+ AArch64GNUInfo(const llvm::Triple& pTriple) : GNUInfo(pTriple) { }
+
+ uint32_t machine() const { return llvm::ELF::EM_AARCH64; }
+
+ uint64_t abiPageSize() const { return 0x10000; }
+
+ uint64_t defaultTextSegmentAddr() const { return 0x400000; }
+
+ // There are no processor-specific flags so this field shall contain zero.
+ uint64_t flags() const { return 0x0; }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/AArch64/AArch64GOT.cpp b/lib/Target/AArch64/AArch64GOT.cpp
new file mode 100644
index 0000000..4864c07
--- /dev/null
+++ b/lib/Target/AArch64/AArch64GOT.cpp
@@ -0,0 +1,141 @@
+//===- AArch64GOT.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "AArch64GOT.h"
+
+#include <llvm/Support/Casting.h>
+
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/Support/MsgHandling.h>
+
+namespace {
+ const unsigned int AArch64GOT0Num = 3;
+} // end of anonymous namespace
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// AArch64GOT
+AArch64GOT::AArch64GOT(LDSection& pSection)
+ : GOT(pSection), m_pGOTPLTFront(NULL), m_pGOTFront(NULL)
+{
+}
+
+AArch64GOT::~AArch64GOT()
+{
+}
+
+void AArch64GOT::createGOT0()
+{
+ // create GOT0, and put them into m_SectionData immediately
+ for (unsigned int i = 0; i < AArch64GOT0Num; ++i)
+ new AArch64GOTEntry(0, m_SectionData);
+}
+
+bool AArch64GOT::hasGOT1() const
+{
+ return ((!m_GOT.empty()) || (!m_GOTPLT.empty()));
+}
+
+AArch64GOTEntry* AArch64GOT::createGOT()
+{
+ AArch64GOTEntry* entry = new AArch64GOTEntry(0, NULL);
+ m_GOT.push_back(entry);
+ return entry;
+}
+
+AArch64GOTEntry* AArch64GOT::createGOTPLT()
+{
+ AArch64GOTEntry* entry = new AArch64GOTEntry(0, NULL);
+ m_GOTPLT.push_back(entry);
+ return entry;
+}
+
+void AArch64GOT::finalizeSectionSize()
+{
+ uint32_t offset = 0;
+ SectionData::FragmentListType& frag_list = m_SectionData->getFragmentList();
+ // setup GOT0 offset
+ SectionData::iterator frag, fragEnd = m_SectionData->end();
+ for (frag = m_SectionData->begin(); frag != fragEnd; ++frag) {
+ frag->setOffset(offset);
+ offset += frag->size();
+ }
+
+ // push GOTPLT into the SectionData and setup the offset
+ if (!m_GOTPLT.empty()) {
+ m_pGOTPLTFront = m_GOTPLT.front();
+ entry_iterator it, end = m_GOTPLT.end();
+ for (it = m_GOTPLT.begin(); it != end; ++it) {
+ AArch64GOTEntry* entry = *it;
+ frag_list.push_back(entry);
+ entry->setParent(m_SectionData);
+ entry->setOffset(offset);
+ offset += entry->size();
+
+ }
+ }
+ m_GOTPLT.clear();
+
+ // push GOT into the SectionData and setup the offset
+ if (!m_GOT.empty()) {
+ m_pGOTFront = m_GOT.front();
+ entry_iterator it, end = m_GOT.end();
+ for (it = m_GOT.begin(); it != end; ++it) {
+ AArch64GOTEntry* entry = *it;
+ frag_list.push_back(entry);
+ entry->setParent(m_SectionData);
+ entry->setOffset(offset);
+ offset += entry->size();
+ }
+ }
+ m_GOT.clear();
+
+ // set section size
+ m_Section.setSize(offset);
+}
+
+void AArch64GOT::applyGOT0(uint64_t pAddress)
+{
+ llvm::cast<AArch64GOTEntry>
+ (*(m_SectionData->getFragmentList().begin())).setValue(pAddress);
+}
+
+void AArch64GOT::applyGOTPLT(uint64_t pPLTBase)
+{
+ if (NULL == m_pGOTPLTFront)
+ return;
+
+ SectionData::iterator entry(m_pGOTPLTFront);
+ SectionData::iterator e_end;
+ if (NULL == m_pGOTFront)
+ e_end = m_SectionData->end();
+ else
+ e_end = SectionData::iterator(m_pGOTFront);
+
+ while (entry != e_end) {
+ llvm::cast<AArch64GOTEntry>(entry)->setValue(pPLTBase);
+ ++entry;
+ }
+}
+
+uint64_t AArch64GOT::emit(MemoryRegion& pRegion)
+{
+ uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.begin());
+
+ AArch64GOTEntry* got = NULL;
+ uint64_t result = 0x0;
+ for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) {
+ got = &(llvm::cast<AArch64GOTEntry>((*it)));
+ *buffer = static_cast<uint64_t>(got->getValue());
+ result += AArch64GOTEntry::EntrySize;
+ }
+ return result;
+}
+
diff --git a/lib/Target/AArch64/AArch64GOT.h b/lib/Target/AArch64/AArch64GOT.h
new file mode 100644
index 0000000..87d91eb
--- /dev/null
+++ b/lib/Target/AArch64/AArch64GOT.h
@@ -0,0 +1,103 @@
+//===- AArch64GOT.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TARGET_AARCH64_AARCH64GOT_H
+#define TARGET_AARCH64_AARCH64GOT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Target/GOT.h>
+
+#include <llvm/ADT/DenseMap.h>
+
+#include <vector>
+
+namespace mcld {
+
+class LDSection;
+
+/** \class AArch64GOTEntry
+ * \brief GOT Entry with size of 8 bytes
+ */
+class AArch64GOTEntry : public GOT::Entry<8>
+{
+public:
+ AArch64GOTEntry(uint64_t pContent, SectionData* pParent)
+ : GOT::Entry<8>(pContent, pParent)
+ {}
+};
+
+/** \class AArch64GOT
+ * \brief AArch64 Global Offset Table.
+ *
+ * AArch64 GOT integrates traditional .got.plt and .got sections into one.
+ * Traditional .got.plt is placed in the front part of GOT (PLTGOT), and
+ * traditional .got is placed in the rear part of GOT (GOT). When -z now and
+ * -z relro are given, the got section layout will be as below. Otherwise,
+ * there will be two seperated sections, .got and .got.plt.
+ *
+ * This class may be used as .got (with no GOTPLT entry), .got.plt (with only
+ * GOTPLT entries) or .got (with GOTPLT and normal GOT entries)
+ *
+ * AArch64 .got
+ * +--------------+
+ * | GOT0 |
+ * +--------------+
+ * | GOTPLT |
+ * +--------------+
+ * | GOT |
+ * +--------------+
+ *
+ */
+class AArch64GOT : public GOT
+{
+public:
+ AArch64GOT(LDSection &pSection);
+
+ ~AArch64GOT();
+
+ /// createGOT0 - create the defualt GOT0 entries. This function called when
+ /// it's a .got section (with GOTPLT entries and normal GOT entry) or it's a
+ /// .got.plt section
+ void createGOT0();
+
+ AArch64GOTEntry* createGOT();
+ AArch64GOTEntry* createGOTPLT();
+
+ void finalizeSectionSize();
+
+ uint64_t emit(MemoryRegion& pRegion);
+
+ void applyGOT0(uint64_t pAddress);
+
+ void applyGOTPLT(uint64_t pPLTBase);
+
+ bool hasGOT1() const;
+
+private:
+ typedef std::vector<AArch64GOTEntry*> EntryListType;
+ typedef EntryListType::iterator entry_iterator;
+ typedef EntryListType::const_iterator const_entry_iterator;
+
+private:
+ AArch64GOTEntry* m_pGOTPLTFront;
+ AArch64GOTEntry* m_pGOTFront;
+
+ /// m_GOTPLTEntries - a list of gotplt entries
+ EntryListType m_GOTPLT;
+
+ /// m_GOTEntris - a list of got entries
+ EntryListType m_GOT;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/AArch64/AArch64LDBackend.cpp b/lib/Target/AArch64/AArch64LDBackend.cpp
new file mode 100644
index 0000000..254b912
--- /dev/null
+++ b/lib/Target/AArch64/AArch64LDBackend.cpp
@@ -0,0 +1,458 @@
+//===- AArch64LDBackend.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "AArch64.h"
+#include "AArch64ELFDynamic.h"
+#include "AArch64GNUInfo.h"
+#include "AArch64LDBackend.h"
+#include "AArch64Relocator.h"
+
+#include <cstring>
+
+#include <llvm/ADT/Triple.h>
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/Casting.h>
+
+#include <mcld/IRBuilder.h>
+#include <mcld/LinkerConfig.h>
+#include <mcld/Fragment/FillFragment.h>
+#include <mcld/Fragment/AlignFragment.h>
+#include <mcld/Fragment/RegionFragment.h>
+#include <mcld/Fragment/Stub.h>
+#include <mcld/Fragment/NullFragment.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/LD/BranchIslandFactory.h>
+#include <mcld/LD/StubFactory.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/LD/ELFFileFormat.h>
+#include <mcld/LD/ELFSegmentFactory.h>
+#include <mcld/LD/ELFSegment.h>
+#include <mcld/Target/ELFAttribute.h>
+#include <mcld/Target/GNUInfo.h>
+#include <mcld/Object/ObjectBuilder.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// AArch64GNULDBackend
+//===----------------------------------------------------------------------===//
+AArch64GNULDBackend::AArch64GNULDBackend(const LinkerConfig& pConfig,
+ GNUInfo* pInfo)
+ : GNULDBackend(pConfig, pInfo),
+ m_pRelocator(NULL),
+ m_pGOT(NULL),
+ m_pGOTPLT(NULL),
+ m_pPLT(NULL),
+ m_pRelaDyn(NULL),
+ m_pRelaPLT(NULL),
+ // m_pAttrData(NULL),
+ m_pDynamic(NULL),
+ m_pGOTSymbol(NULL),
+ m_pAttributes(NULL) {
+}
+
+AArch64GNULDBackend::~AArch64GNULDBackend()
+{
+ if (m_pRelocator != NULL)
+ delete m_pRelocator;
+ if (m_pGOT == m_pGOTPLT) {
+ if (m_pGOT != NULL)
+ delete m_pGOT;
+ } else {
+ if (m_pGOT != NULL)
+ delete m_pGOT;
+ if (m_pGOTPLT != NULL)
+ delete m_pGOTPLT;
+ }
+ if (m_pPLT != NULL)
+ delete m_pPLT;
+ if (m_pRelaDyn != NULL)
+ delete m_pRelaDyn;
+ if (m_pRelaPLT != NULL)
+ delete m_pRelaPLT;
+ if (m_pDynamic != NULL)
+ delete m_pDynamic;
+}
+
+void AArch64GNULDBackend::initTargetSections(Module& pModule,
+ ObjectBuilder& pBuilder)
+{
+ // TODO
+
+ if (LinkerConfig::Object != config().codeGenType()) {
+ ELFFileFormat* file_format = getOutputFormat();
+
+ // initialize .got
+ LDSection& got = file_format->getGOT();
+ m_pGOT = new AArch64GOT(got);
+ if (config().options().hasNow()) {
+ // when -z now is given, there will be only one .got section (contains
+ // both GOTPLT and normal GOT entries), create GOT0 for .got section and
+ // set m_pGOTPLT to the same .got
+ m_pGOT->createGOT0();
+ m_pGOTPLT = m_pGOT;
+ }
+ else {
+ // Otherwise, got should be seperated to two sections, .got and .got.plt
+ // initialize .got.plt
+ LDSection& gotplt = file_format->getGOTPLT();
+ m_pGOTPLT = new AArch64GOT(gotplt);
+ m_pGOTPLT->createGOT0();
+ }
+
+ // initialize .plt
+ LDSection& plt = file_format->getPLT();
+ m_pPLT = new AArch64PLT(plt, *m_pGOTPLT);
+
+ // initialize .rela.plt
+ LDSection& relaplt = file_format->getRelaPlt();
+ relaplt.setLink(&plt);
+ m_pRelaPLT = new OutputRelocSection(pModule, relaplt);
+
+ // initialize .rela.dyn
+ LDSection& reladyn = file_format->getRelaDyn();
+ m_pRelaDyn = new OutputRelocSection(pModule, reladyn);
+ }
+}
+
+void AArch64GNULDBackend::initTargetSymbols(IRBuilder& pBuilder,
+ Module& pModule)
+{
+ // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
+ // same name in input
+ if (LinkerConfig::Object != config().codeGenType()) {
+ m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ FragmentRef::Null(),
+ ResolveInfo::Hidden);
+ }
+ // TODO
+}
+
+bool AArch64GNULDBackend::initRelocator()
+{
+ if (NULL == m_pRelocator) {
+ m_pRelocator = new AArch64Relocator(*this, config());
+ }
+ return true;
+}
+
+Relocator* AArch64GNULDBackend::getRelocator()
+{
+ assert(NULL != m_pRelocator);
+ return m_pRelocator;
+}
+
+void AArch64GNULDBackend::defineGOTSymbol(IRBuilder& pBuilder)
+{
+ // define symbol _GLOBAL_OFFSET_TABLE_ when .got create
+ if (m_pGOTSymbol != NULL) {
+ pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ FragmentRef::Create(*(m_pGOTPLT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+ else {
+ m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ FragmentRef::Create(*(m_pGOTPLT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+}
+
+void AArch64GNULDBackend::doPreLayout(IRBuilder& pBuilder)
+{
+ // initialize .dynamic data
+ if (!config().isCodeStatic() && NULL == m_pDynamic)
+ m_pDynamic = new AArch64ELFDynamic(*this, config());
+
+ if (LinkerConfig::Object != config().codeGenType()) {
+ // set .got size
+ if (config().options().hasNow()) {
+ // when building shared object, the GOTPLT section is must
+ if (LinkerConfig::DynObj == config().codeGenType() ||
+ m_pGOT->hasGOT1() ||
+ NULL != m_pGOTSymbol) {
+ m_pGOT->finalizeSectionSize();
+ defineGOTSymbol(pBuilder);
+ }
+ }
+ else {
+ // when building shared object, the GOTPLT section is must
+ if (LinkerConfig::DynObj == config().codeGenType() ||
+ m_pGOTPLT->hasGOT1() ||
+ NULL != m_pGOTSymbol) {
+ m_pGOTPLT->finalizeSectionSize();
+ defineGOTSymbol(pBuilder);
+ }
+ if (m_pGOT->hasGOT1())
+ m_pGOT->finalizeSectionSize();
+ }
+
+ // set .plt size
+ if (m_pPLT->hasPLT1())
+ m_pPLT->finalizeSectionSize();
+
+ ELFFileFormat* file_format = getOutputFormat();
+ // set .rela.dyn size
+ if (!m_pRelaDyn->empty()) {
+ assert(!config().isCodeStatic() &&
+ "static linkage should not result in a dynamic relocation section");
+ file_format->getRelaDyn().setSize(
+ m_pRelaDyn->numOfRelocs() * getRelaEntrySize());
+ }
+
+ // set .rela.plt size
+ if (!m_pRelaPLT->empty()) {
+ assert(!config().isCodeStatic() &&
+ "static linkage should not result in a dynamic relocation section");
+ file_format->getRelaPlt().setSize(
+ m_pRelaPLT->numOfRelocs() * getRelaEntrySize());
+ }
+ }
+}
+
+void AArch64GNULDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder)
+{
+ const ELFFileFormat *file_format = getOutputFormat();
+
+ // apply PLT
+ if (file_format->hasPLT()) {
+ assert(NULL != m_pPLT);
+ m_pPLT->applyPLT0();
+ m_pPLT->applyPLT1();
+ }
+
+ // apply GOTPLT
+ if ((config().options().hasNow() && file_format->hasGOT()) ||
+ file_format->hasGOTPLT()) {
+ assert(NULL != m_pGOTPLT);
+ if (LinkerConfig::DynObj == config().codeGenType())
+ m_pGOTPLT->applyGOT0(file_format->getDynamic().addr());
+ else {
+ // executable file and object file? should fill with zero.
+ m_pGOTPLT->applyGOT0(0);
+ }
+ }
+}
+
+AArch64ELFDynamic& AArch64GNULDBackend::dynamic()
+{
+ assert(NULL != m_pDynamic);
+ return *m_pDynamic;
+}
+
+const AArch64ELFDynamic& AArch64GNULDBackend::dynamic() const
+{
+ assert(NULL != m_pDynamic);
+ return *m_pDynamic;
+}
+
+uint64_t AArch64GNULDBackend::emitSectionData(const LDSection& pSection,
+ MemoryRegion& pRegion) const
+{
+ assert(pRegion.size() && "Size of MemoryRegion is zero!");
+
+ const ELFFileFormat* file_format = getOutputFormat();
+
+ if (file_format->hasPLT() && (&pSection == &(file_format->getPLT()))) {
+ uint64_t result = m_pPLT->emit(pRegion);
+ return result;
+ }
+
+ if (file_format->hasGOT() && (&pSection == &(file_format->getGOT()))) {
+ uint64_t result = m_pGOT->emit(pRegion);
+ return result;
+ }
+
+ if (file_format->hasGOTPLT() && (&pSection == &(file_format->getGOTPLT()))) {
+ uint64_t result = m_pGOT->emit(pRegion);
+ return result;
+ }
+
+ // TODO
+ return pRegion.size();
+}
+
+unsigned int
+AArch64GNULDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const
+{
+ const ELFFileFormat* file_format = getOutputFormat();
+
+ if (file_format->hasGOT() && (&pSectHdr == &file_format->getGOT())) {
+ if (config().options().hasNow())
+ return SHO_RELRO;
+ return SHO_RELRO_LAST;
+ }
+
+ if (file_format->hasGOTPLT() && (&pSectHdr == &file_format->getGOTPLT()))
+ return SHO_NON_RELRO_FIRST;
+
+ if (file_format->hasPLT() && (&pSectHdr == &file_format->getPLT()))
+ return SHO_PLT;
+
+ return SHO_UNDEFINED;
+}
+
+bool AArch64GNULDBackend::doRelax(Module& pModule,
+ IRBuilder& pBuilder,
+ bool& pFinished)
+{
+ // TODO
+ return false;
+}
+
+bool AArch64GNULDBackend::initTargetStubs()
+{
+ // TODO
+ return true;
+}
+
+void AArch64GNULDBackend::doCreateProgramHdrs(Module& pModule)
+{
+ // TODO
+}
+
+bool AArch64GNULDBackend::finalizeTargetSymbols()
+{
+ // TODO
+ return true;
+}
+
+bool AArch64GNULDBackend::mergeSection(Module& pModule,
+ const Input& pInput,
+ LDSection& pSection)
+{
+ // TODO
+ return true;
+}
+
+bool AArch64GNULDBackend::readSection(Input& pInput, SectionData& pSD)
+{
+ // TODO
+ return true;
+}
+
+AArch64GOT& AArch64GNULDBackend::getGOT()
+{
+ assert(NULL != m_pGOT && "GOT section not exist");
+ return *m_pGOT;
+}
+
+const AArch64GOT& AArch64GNULDBackend::getGOT() const
+{
+ assert(NULL != m_pGOT && "GOT section not exist");
+ return *m_pGOT;
+}
+
+AArch64GOT& AArch64GNULDBackend::getGOTPLT()
+{
+ assert(NULL != m_pGOTPLT && "GOTPLT section not exist");
+ return *m_pGOTPLT;
+}
+
+const AArch64GOT& AArch64GNULDBackend::getGOTPLT() const
+{
+ assert(NULL != m_pGOTPLT && "GOTPLT section not exist");
+ return *m_pGOTPLT;
+}
+
+AArch64PLT& AArch64GNULDBackend::getPLT()
+{
+ assert(NULL != m_pPLT && "PLT section not exist");
+ return *m_pPLT;
+}
+
+const AArch64PLT& AArch64GNULDBackend::getPLT() const
+{
+ assert(NULL != m_pPLT && "PLT section not exist");
+ return *m_pPLT;
+}
+
+OutputRelocSection& AArch64GNULDBackend::getRelaDyn()
+{
+ assert(NULL != m_pRelaDyn && ".rela.dyn section not exist");
+ return *m_pRelaDyn;
+}
+
+const OutputRelocSection& AArch64GNULDBackend::getRelaDyn() const
+{
+ assert(NULL != m_pRelaDyn && ".rela.dyn section not exist");
+ return *m_pRelaDyn;
+}
+
+OutputRelocSection& AArch64GNULDBackend::getRelaPLT()
+{
+ assert(NULL != m_pRelaPLT && ".rela.plt section not exist");
+ return *m_pRelaPLT;
+}
+
+const OutputRelocSection& AArch64GNULDBackend::getRelaPLT() const
+{
+ assert(NULL != m_pRelaPLT && ".rela.plt section not exist");
+ return *m_pRelaPLT;
+}
+
+namespace mcld {
+
+//===----------------------------------------------------------------------===//
+// createAArch64LDBackend - the help funtion to create corresponding
+// AArch64LDBackend
+//===----------------------------------------------------------------------===//
+TargetLDBackend* createAArch64LDBackend(const LinkerConfig& pConfig)
+{
+ if (pConfig.targets().triple().isOSDarwin()) {
+ assert(0 && "MachO linker is not supported yet");
+ /**
+ return new AArch64MachOLDBackend(createAArch64MachOArchiveReader,
+ createAArch64MachOObjectReader,
+ createAArch64MachOObjectWriter);
+ **/
+ }
+ if (pConfig.targets().triple().isOSWindows()) {
+ assert(0 && "COFF linker is not supported yet");
+ /**
+ return new AArch64COFFLDBackend(createAArch64COFFArchiveReader,
+ createAArch64COFFObjectReader,
+ createAArch64COFFObjectWriter);
+ **/
+ }
+ return new AArch64GNULDBackend(pConfig,
+ new AArch64GNUInfo(pConfig.targets().triple()));
+}
+
+} // namespace of mcld
+
+//===----------------------------------------------------------------------===//
+// Force static initialization.
+//===----------------------------------------------------------------------===//
+extern "C" void MCLDInitializeAArch64LDBackend() {
+ // Register the linker backend
+ mcld::TargetRegistry::RegisterTargetLDBackend(TheAArch64Target,
+ createAArch64LDBackend);
+}
+
diff --git a/lib/Target/AArch64/AArch64LDBackend.h b/lib/Target/AArch64/AArch64LDBackend.h
new file mode 100644
index 0000000..1735043
--- /dev/null
+++ b/lib/Target/AArch64/AArch64LDBackend.h
@@ -0,0 +1,167 @@
+//===- AArch64LDBackend.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TARGET_AARCH64_AARCH64LDBACKEND_H
+#define TARGET_AARCH64_AARCH64LDBACKEND_H
+
+#include "AArch64ELFDynamic.h"
+#include "AArch64GOT.h"
+#include "AArch64PLT.h"
+#include <mcld/LD/LDSection.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/Target/OutputRelocSection.h>
+
+namespace mcld {
+
+class LinkerConfig;
+class GNUInfo;
+
+//===----------------------------------------------------------------------===//
+/// AArch64GNULDBackend - linker backend of AArch64 target of GNU ELF format
+///
+class AArch64GNULDBackend : public GNULDBackend
+{
+public:
+ AArch64GNULDBackend(const LinkerConfig& pConfig, GNUInfo* pInfo);
+ ~AArch64GNULDBackend();
+
+public:
+ /// initTargetSections - initialize target dependent sections in output.
+ void initTargetSections(Module& pModule, ObjectBuilder& pBuilder);
+
+ /// initTargetSymbols - initialize target dependent symbols in output.
+ void initTargetSymbols(IRBuilder& pBuilder, Module& pModule);
+
+ /// initRelocator - create and initialize Relocator.
+ bool initRelocator();
+
+ /// getRelocator - return relocator.
+ Relocator* getRelocator();
+
+
+ /// doPreLayout - Backend can do any needed modification before layout
+ void doPreLayout(IRBuilder& pBuilder);
+
+ /// doPostLayout -Backend can do any needed modification after layout
+ void doPostLayout(Module& pModule, IRBuilder& pBuilder);
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ AArch64ELFDynamic& dynamic();
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ const AArch64ELFDynamic& 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 SectionData directly
+ /// - LDSection.getSectionData can get the section data.
+ /// Or, backend can put the data into special data structure
+ /// - backend can maintain its own map<LDSection, table> to get the table
+ /// from given LDSection.
+ ///
+ /// @param pSection - the given LDSection
+ /// @param pConfig - 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 LDSection& pSection,
+ MemoryRegion& pRegion) const;
+
+ AArch64GOT& getGOT();
+ const AArch64GOT& getGOT() const;
+
+ AArch64GOT& getGOTPLT();
+ const AArch64GOT& getGOTPLT() const;
+
+ AArch64PLT& getPLT();
+ const AArch64PLT& getPLT() const;
+
+ OutputRelocSection& getRelaDyn();
+ const OutputRelocSection& getRelaDyn() const;
+
+ OutputRelocSection& getRelaPLT();
+ const OutputRelocSection& getRelaPLT() const;
+
+ LDSymbol* getGOTSymbol() { return m_pGOTSymbol; }
+ const LDSymbol* getGOTSymbol() const { return m_pGOTSymbol; }
+
+ /// getTargetSectionOrder - compute the layout order of AArch64 target sections
+ unsigned int getTargetSectionOrder(const LDSection& pSectHdr) const;
+
+ /// finalizeTargetSymbols - finalize the symbol value
+ bool finalizeTargetSymbols();
+
+ /// mergeSection - merge target dependent sections
+ bool mergeSection(Module& pModule, const Input& pInput, LDSection& pSection);
+
+ /// readSection - read target dependent sections
+ bool readSection(Input& pInput, SectionData& pSD);
+
+private:
+ void defineGOTSymbol(IRBuilder& pBuilder);
+
+ /// maxBranchOffset
+ /// FIXME:
+ uint64_t maxBranchOffset() { return 0x0; }
+
+ /// mayRelax - Backends should override this function if they need relaxation
+ bool mayRelax() { return true; }
+
+ /// doRelax - Backend can orevride this function to add its relaxation
+ /// implementation. Return true if the output (e.g., .text) is "relaxed"
+ /// (i.e. layout is changed), and set pFinished to true if everything is fit,
+ /// otherwise set it to false.
+ bool doRelax(Module& pModule, IRBuilder& pBuilder, bool& pFinished);
+
+ /// initTargetStubs
+ bool initTargetStubs();
+
+ /// getRelEntrySize - the size in BYTE of rel type relocation
+ size_t getRelEntrySize()
+ { return 16; }
+
+ /// getRelEntrySize - the size in BYTE of rela type relocation
+ size_t getRelaEntrySize()
+ { return 24; }
+
+ /// doCreateProgramHdrs - backend can implement this function to create the
+ /// target-dependent segments
+ virtual void doCreateProgramHdrs(Module& pModule);
+
+private:
+ Relocator* m_pRelocator;
+
+ AArch64GOT* m_pGOT;
+ AArch64GOT* m_pGOTPLT;
+ AArch64PLT* m_pPLT;
+ /// m_RelDyn - dynamic relocation table of .rel.dyn
+ OutputRelocSection* m_pRelaDyn;
+ /// m_RelPLT - dynamic relocation table of .rel.plt
+ OutputRelocSection* m_pRelaPLT;
+
+ /// m_pAttrData - attribute data in public ("aeabi") attribute subsection
+ // AArch64ELFAttributeData* m_pAttrData;
+
+ AArch64ELFDynamic* m_pDynamic;
+ LDSymbol* m_pGOTSymbol;
+
+ // variable name : ELF
+ LDSection* m_pAttributes; // .ARM.attributes
+// LDSection* m_pPreemptMap; // .AArch64.preemptmap
+// LDSection* m_pDebugOverlay; // .AArch64.debug_overlay
+// LDSection* m_pOverlayTable; // .AArch64.overlay_table
+};
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/AArch64/AArch64MCLinker.cpp b/lib/Target/AArch64/AArch64MCLinker.cpp
new file mode 100644
index 0000000..538461a
--- /dev/null
+++ b/lib/Target/AArch64/AArch64MCLinker.cpp
@@ -0,0 +1,51 @@
+//===- AArch64MCLinker.cpp-------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "AArch64ELFMCLinker.h"
+
+#include "AArch64.h"
+#include <llvm/ADT/Triple.h>
+#include <mcld/Module.h>
+#include <mcld/Support/TargetRegistry.h>
+
+using namespace mcld;
+
+namespace mcld {
+//===----------------------------------------------------------------------===//
+// createAArch64MCLinker - the help function to create corresponding
+// AArch64MCLinker
+//===----------------------------------------------------------------------===//
+MCLinker* createAArch64MCLinker(const std::string& pTriple,
+ LinkerConfig& pConfig,
+ mcld::Module& pModule,
+ FileHandle& pFileHandle)
+{
+ llvm::Triple theTriple(pTriple);
+ if (theTriple.isOSDarwin()) {
+ assert(0 && "MachO linker has not supported yet");
+ return NULL;
+ }
+ if (theTriple.isOSWindows()) {
+ assert(0 && "COFF linker has not supported yet");
+ return NULL;
+ }
+
+ return new AArch64ELFMCLinker(pConfig, pModule, pFileHandle);
+}
+
+} // namespace of mcld
+
+//===----------------------------------------------------------------------===//
+// AArch64MCLinker
+//===----------------------------------------------------------------------===//
+extern "C" void MCLDInitializeAArch64MCLinker() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterMCLinker(TheAArch64Target,
+ createAArch64MCLinker);
+}
+
diff --git a/lib/Target/AArch64/AArch64PLT.cpp b/lib/Target/AArch64/AArch64PLT.cpp
new file mode 100644
index 0000000..c24327d
--- /dev/null
+++ b/lib/Target/AArch64/AArch64PLT.cpp
@@ -0,0 +1,171 @@
+//===- AArch64PLT.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "AArch64GOT.h"
+#include "AArch64PLT.h"
+#include "AArch64RelocationHelpers.h"
+
+#include <new>
+
+#include <llvm/Support/Casting.h>
+
+#include <mcld/LD/LDSection.h>
+#include <mcld/Support/MsgHandling.h>
+
+using namespace mcld;
+
+AArch64PLT0::AArch64PLT0(SectionData& pParent)
+ : PLT::Entry<sizeof(aarch64_plt0)>(pParent) {}
+
+AArch64PLT1::AArch64PLT1(SectionData& pParent)
+ : PLT::Entry<sizeof(aarch64_plt1)>(pParent) {}
+
+//===----------------------------------------------------------------------===//
+// AArch64PLT
+
+AArch64PLT::AArch64PLT(LDSection& pSection, AArch64GOT &pGOTPLT)
+ : PLT(pSection), m_GOT(pGOTPLT) {
+ new AArch64PLT0(*m_pSectionData);
+}
+
+AArch64PLT::~AArch64PLT()
+{
+}
+
+bool AArch64PLT::hasPLT1() const
+{
+ return (m_pSectionData->size() > 1);
+}
+
+void AArch64PLT::finalizeSectionSize()
+{
+ uint64_t size = (m_pSectionData->size() - 1) * sizeof(aarch64_plt1) +
+ sizeof(aarch64_plt0);
+ m_Section.setSize(size);
+
+ uint32_t offset = 0;
+ SectionData::iterator frag, fragEnd = m_pSectionData->end();
+ for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
+ frag->setOffset(offset);
+ offset += frag->size();
+ }
+}
+
+AArch64PLT1* AArch64PLT::create()
+{
+ AArch64PLT1* plt1_entry = new (std::nothrow) AArch64PLT1(*m_pSectionData);
+ if (!plt1_entry)
+ fatal(diag::fail_allocate_memory_plt);
+ return plt1_entry;
+}
+
+void AArch64PLT::applyPLT0()
+{
+ // malloc plt0
+ iterator first = m_pSectionData->getFragmentList().begin();
+ assert(first != m_pSectionData->getFragmentList().end() &&
+ "FragmentList is empty, applyPLT0 failed!");
+ AArch64PLT0* plt0 = &(llvm::cast<AArch64PLT0>(*first));
+ uint32_t* data = NULL;
+ data = static_cast<uint32_t*>(malloc(AArch64PLT0::EntrySize));
+ if (data == NULL)
+ fatal(diag::fail_allocate_memory_plt);
+ memcpy(data, aarch64_plt0, AArch64PLT0::EntrySize);
+
+ // apply plt0
+ uint64_t plt_base = m_Section.addr();
+ assert(plt_base && ".plt base address is NULL!");
+ uint64_t got_base = m_GOT.addr();
+ assert(got_base && ".got base address is NULL!");
+
+ // apply 2nd instruction
+ // get the address of got entry 2
+ uint64_t got_ent2_base = got_base + sizeof(AArch64GOTEntry::EntrySize) * 2;
+ // compute the immediate
+ AArch64Relocator::DWord imm = helper_get_page_address(got_ent2_base) -
+ helper_get_page_address(plt_base + (sizeof(AArch64PLT0::EntrySize) * 8));
+ data[1] = helper_reencode_adr_imm(data[1], imm >> 12);
+ // apply 3rd instruction
+ data[2] = helper_reencode_add_imm(data[2],
+ helper_get_page_offset(got_ent2_base) >> 3);
+ // apply 4th instruction
+ data[3] = helper_reencode_add_imm(data[3],
+ helper_get_page_offset(got_ent2_base));
+ plt0->setValue(reinterpret_cast<unsigned char*>(data));
+}
+
+void AArch64PLT::applyPLT1()
+{
+ uint64_t plt_base = m_Section.addr();
+ assert(plt_base && ".plt base address is NULL!");
+
+ uint64_t got_base = m_GOT.addr();
+ assert(got_base && ".got base address is NULL!");
+
+ AArch64PLT::iterator it = m_pSectionData->begin();
+ AArch64PLT::iterator ie = m_pSectionData->end();
+ assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
+
+ uint32_t GOTEntrySize = AArch64GOTEntry::EntrySize;
+ // first gotplt1 address
+ uint32_t GOTEntryAddress = got_base + GOTEntrySize * 3;
+ // first plt1 address
+ uint32_t PLTEntryAddress = plt_base + AArch64PLT0::EntrySize;
+
+ ++it; //skip PLT0
+ uint32_t PLT1EntrySize = AArch64PLT1::EntrySize;
+ AArch64PLT1* plt1 = NULL;
+
+ uint32_t* Out = NULL;
+ while (it != ie) {
+ plt1 = &(llvm::cast<AArch64PLT1>(*it));
+ Out = static_cast<uint32_t*>(malloc(AArch64PLT1::EntrySize));
+ memcpy(Out, aarch64_plt1, AArch64PLT1::EntrySize);
+ // apply 1st instruction
+ AArch64Relocator::DWord imm = helper_get_page_address(GOTEntryAddress) -
+ helper_get_page_address(PLTEntryAddress);
+ Out[0] = helper_reencode_adr_imm(Out[0], imm >> 12);
+ // apply 2nd instruction
+ Out[1] = helper_reencode_add_imm(
+ Out[1], helper_get_page_offset(GOTEntryAddress) >> 3);
+ // apply 3rd instruction
+ Out[2] = helper_reencode_add_imm(
+ Out[2], helper_get_page_offset(GOTEntryAddress));
+
+ plt1->setValue(reinterpret_cast<unsigned char*>(Out));
+ ++it;
+
+ GOTEntryAddress += GOTEntrySize;
+ PLTEntryAddress += PLT1EntrySize;
+ }
+
+ m_GOT.applyGOTPLT(plt_base);
+}
+
+uint64_t AArch64PLT::emit(MemoryRegion& pRegion)
+{
+ uint64_t result = 0x0;
+ iterator it = begin();
+
+ unsigned char* buffer = pRegion.begin();
+ memcpy(buffer, llvm::cast<AArch64PLT0>((*it)).getValue(),
+ AArch64PLT0::EntrySize);
+ result += AArch64PLT0::EntrySize;
+ ++it;
+
+ AArch64PLT1* plt1 = NULL;
+ AArch64PLT::iterator ie = end();
+ while (it != ie) {
+ plt1 = &(llvm::cast<AArch64PLT1>(*it));
+ memcpy(buffer + result, plt1->getValue(), AArch64PLT1::EntrySize);
+ result += AArch64PLT1::EntrySize;
+ ++it;
+ }
+ return result;
+}
+
diff --git a/lib/Target/AArch64/AArch64PLT.h b/lib/Target/AArch64/AArch64PLT.h
new file mode 100644
index 0000000..c63e2e0
--- /dev/null
+++ b/lib/Target/AArch64/AArch64PLT.h
@@ -0,0 +1,86 @@
+//===- AArch64PLT.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TARGET_AARCH64_AARCH64PLT_H
+#define TARGET_AARCH64_AARCH64PLT_H
+
+#include <mcld/Target/GOT.h>
+#include <mcld/Target/PLT.h>
+#include <mcld/Support/MemoryRegion.h>
+
+namespace {
+
+const uint8_t aarch64_plt0[] = {
+ 0xf0, 0x7b, 0xbf, 0xa9, /* stp x16, x30, [sp, #-16]! */
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, (GOT+16) */
+ 0x11, 0x0A, 0x40, 0xf9, /* ldr x17, [x16, #PLT_GOT+0x10] */
+ 0x10, 0x42, 0x00, 0x91, /* add x16, x16,#PLT_GOT+0x10 */
+ 0x20, 0x02, 0x1f, 0xd6, /* br x17 */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5 /* nop */
+};
+
+const uint8_t aarch64_plt1[] = {
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */
+ 0x11, 0x02, 0x40, 0xf9, /* ldr x17, [x16, PLTGOT + n * 8] */
+ 0x10, 0x02, 0x00, 0x91, /* add x16, x16, :lo12:PLTGOT + n * 8 */
+ 0x20, 0x02, 0x1f, 0xd6 /* br x17. */
+};
+
+} // anonymous namespace
+
+namespace mcld {
+
+class AArch64GOT;
+
+class AArch64PLT0 : public PLT::Entry<sizeof(aarch64_plt0)>
+{
+public:
+ AArch64PLT0(SectionData& pParent);
+};
+
+class AArch64PLT1 : public PLT::Entry<sizeof(aarch64_plt1)>
+{
+public:
+ AArch64PLT1(SectionData& pParent);
+};
+
+/** \class AArch64PLT
+ * \brief AArch64 Procedure Linkage Table
+ */
+class AArch64PLT : public PLT
+{
+public:
+ AArch64PLT(LDSection& pSection, AArch64GOT& pGOTPLT);
+ ~AArch64PLT();
+
+ // finalizeSectionSize - set LDSection size
+ void finalizeSectionSize();
+
+ // hasPLT1 - return if this plt section has any plt1 entry
+ bool hasPLT1() const;
+
+ AArch64PLT1* create();
+
+ AArch64PLT0* getPLT0() const;
+
+ void applyPLT0();
+
+ void applyPLT1();
+
+ uint64_t emit(MemoryRegion& pRegion);
+
+private:
+ AArch64GOT& m_GOT;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/AArch64/AArch64RelocationFunctions.h b/lib/Target/AArch64/AArch64RelocationFunctions.h
new file mode 100644
index 0000000..14c8c73
--- /dev/null
+++ b/lib/Target/AArch64/AArch64RelocationFunctions.h
@@ -0,0 +1,110 @@
+//===- AArch64RelocationFunction.h ----------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define DECL_AARCH64_APPLY_RELOC_FUNC(Name) \
+static AArch64Relocator::Result Name (Relocation& pEntry, AArch64Relocator& pParent);
+
+#define DECL_AARCH64_APPLY_RELOC_FUNCS \
+DECL_AARCH64_APPLY_RELOC_FUNC(none) \
+DECL_AARCH64_APPLY_RELOC_FUNC(abs) \
+DECL_AARCH64_APPLY_RELOC_FUNC(rel) \
+DECL_AARCH64_APPLY_RELOC_FUNC(call) \
+DECL_AARCH64_APPLY_RELOC_FUNC(condbr) \
+DECL_AARCH64_APPLY_RELOC_FUNC(adr_prel_pg_hi21) \
+DECL_AARCH64_APPLY_RELOC_FUNC(add_abs_lo12) \
+DECL_AARCH64_APPLY_RELOC_FUNC(adr_got_page) \
+DECL_AARCH64_APPLY_RELOC_FUNC(ld64_got_lo12) \
+DECL_AARCH64_APPLY_RELOC_FUNC(ldst_abs_lo12) \
+DECL_AARCH64_APPLY_RELOC_FUNC(unsupport)
+
+#define DECL_AARCH64_APPLY_RELOC_FUNC_PTRS(ValueType, MappedType) \
+ ValueType(0x0, MappedType(&none, "R_AARCH64_NULL")), \
+ ValueType(0x100, MappedType(&none, "R_AARCH64_NONE")), \
+ ValueType(0x101, MappedType(&abs, "R_AARCH64_ABS64", 64)), \
+ ValueType(0x102, MappedType(&abs, "R_AARCH64_ABS32", 32)), \
+ ValueType(0x103, MappedType(&abs, "R_AARCH64_ABS16", 16)), \
+ ValueType(0x104, MappedType(&rel, "R_AARCH64_PREL64", 64)), \
+ ValueType(0x105, MappedType(&rel, "R_AARCH64_PREL32", 32)), \
+ ValueType(0x106, MappedType(&rel, "R_AARCH64_PREL16", 16)), \
+ ValueType(0x107, MappedType(&unsupport, "R_AARCH64_MOVW_UABS_G0")), \
+ ValueType(0x108, MappedType(&unsupport, "R_AARCH64_MOVW_UABS_G0_NC")), \
+ ValueType(0x109, MappedType(&unsupport, "R_AARCH64_MOVW_UABS_G1")), \
+ ValueType(0x10a, MappedType(&unsupport, "R_AARCH64_MOVW_UABS_G1_NC")), \
+ ValueType(0x10b, MappedType(&unsupport, "R_AARCH64_MOVW_UABS_G2")), \
+ ValueType(0x10c, MappedType(&unsupport, "R_AARCH64_MOVW_UABS_G2_NC")), \
+ ValueType(0x10d, MappedType(&unsupport, "R_AARCH64_MOVW_UABS_G3")), \
+ ValueType(0x10e, MappedType(&unsupport, "R_AARCH64_MOVW_SABS_G0")), \
+ ValueType(0x10f, MappedType(&unsupport, "R_AARCH64_MOVW_SABS_G1")), \
+ ValueType(0x110, MappedType(&unsupport, "R_AARCH64_MOVW_SABS_G2")), \
+ ValueType(0x111, MappedType(&unsupport, "R_AARCH64_LD_PREL_LO19")), \
+ ValueType(0x112, MappedType(&unsupport, "R_AARCH64_ADR_PREL_LO21")), \
+ ValueType(0x113, MappedType(&adr_prel_pg_hi21, "R_AARCH64_ADR_PREL_PG_HI21", 32)), \
+ ValueType(0x114, MappedType(&adr_prel_pg_hi21, "R_AARCH64_ADR_PREL_PG_HI21_NC", 32)), \
+ ValueType(0x115, MappedType(&add_abs_lo12, "R_AARCH64_ADD_ABS_LO12_NC", 32)), \
+ ValueType(0x116, MappedType(&ldst_abs_lo12, "R_AARCH64_LDST8_ABS_LO12_NC", 32)), \
+ ValueType(0x117, MappedType(&unsupport, "R_AARCH64_TSTBR14")), \
+ ValueType(0x118, MappedType(&condbr, "R_AARCH64_CONDBR19", 32)), \
+ ValueType(0x11a, MappedType(&call, "R_AARCH64_JUMP26", 32)), \
+ ValueType(0x11b, MappedType(&call, "R_AARCH64_CALL26", 32)), \
+ ValueType(0x11c, MappedType(&ldst_abs_lo12, "R_AARCH64_LDST16_ABS_LO12_NC", 32)), \
+ ValueType(0x11d, MappedType(&ldst_abs_lo12, "R_AARCH64_LDST32_ABS_LO12_NC", 32)), \
+ ValueType(0x11e, MappedType(&ldst_abs_lo12, "R_AARCH64_LDST64_ABS_LO12_NC", 32)), \
+ ValueType(0x12b, MappedType(&ldst_abs_lo12, "R_AARCH64_LDST128_ABS_LO12_NC", 32)), \
+ ValueType(0x137, MappedType(&adr_got_page, "R_AARCH64_ADR_GOT_PAGE", 32)), \
+ ValueType(0x138, MappedType(&ld64_got_lo12, "R_AARCH64_LD64_GOT_LO12_NC", 32)), \
+ ValueType(0x20b, MappedType(&unsupport, "R_AARCH64_TLSLD_MOVW_DTPREL_G2")), \
+ ValueType(0x20c, MappedType(&unsupport, "R_AARCH64_TLSLD_MOVW_DTPREL_G1")), \
+ ValueType(0x20d, MappedType(&unsupport, "R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC")), \
+ ValueType(0x20e, MappedType(&unsupport, "R_AARCH64_TLSLD_MOVW_DTPREL_G0")), \
+ ValueType(0x20f, MappedType(&unsupport, "R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC")), \
+ ValueType(0x210, MappedType(&unsupport, "R_AARCH64_TLSLD_ADD_DTPREL_HI12")), \
+ ValueType(0x211, MappedType(&unsupport, "R_AARCH64_TLSLD_ADD_DTPREL_LO12")), \
+ ValueType(0x212, MappedType(&unsupport, "R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC")), \
+ ValueType(0x213, MappedType(&unsupport, "R_AARCH64_TLSLD_LDST8_DTPREL_LO12")), \
+ ValueType(0x214, MappedType(&unsupport, "R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC")), \
+ ValueType(0x215, MappedType(&unsupport, "R_AARCH64_TLSLD_LDST16_DTPREL_LO12")), \
+ ValueType(0x216, MappedType(&unsupport, "R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC")), \
+ ValueType(0x217, MappedType(&unsupport, "R_AARCH64_TLSLD_LDST32_DTPREL_LO12")), \
+ ValueType(0x218, MappedType(&unsupport, "R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC")), \
+ ValueType(0x219, MappedType(&unsupport, "R_AARCH64_TLSLD_LDST64_DTPREL_LO12")), \
+ ValueType(0x21a, MappedType(&unsupport, "R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC")), \
+ ValueType(0x21b, MappedType(&unsupport, "R_AARCH64_TLSIE_MOVW_GOTTPREL_G1")), \
+ ValueType(0x21c, MappedType(&unsupport, "R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC")), \
+ ValueType(0x21d, MappedType(&unsupport, "R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21")), \
+ ValueType(0x21e, MappedType(&unsupport, "R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC")), \
+ ValueType(0x21f, MappedType(&unsupport, "R_AARCH64_TLSIE_LD_GOTTPREL_PREL19")), \
+ ValueType(0x220, MappedType(&unsupport, "R_AARCH64_TLSLE_MOVW_TPREL_G2")), \
+ ValueType(0x221, MappedType(&unsupport, "R_AARCH64_TLSLE_MOVW_TPREL_G1")), \
+ ValueType(0x222, MappedType(&unsupport, "R_AARCH64_TLSLE_MOVW_TPREL_G1_NC")), \
+ ValueType(0x223, MappedType(&unsupport, "R_AARCH64_TLSLE_MOVW_TPREL_G0")), \
+ ValueType(0x224, MappedType(&unsupport, "R_AARCH64_TLSLE_MOVW_TPREL_G0_NC")), \
+ ValueType(0x225, MappedType(&unsupport, "R_AARCH64_TLSLE_ADD_TPREL_HI12")), \
+ ValueType(0x226, MappedType(&unsupport, "R_AARCH64_TLSLE_ADD_TPREL_LO12")), \
+ ValueType(0x227, MappedType(&unsupport, "R_AARCH64_TLSLE_ADD_TPREL_LO12_NC")), \
+ ValueType(0x228, MappedType(&unsupport, "R_AARCH64_TLSLE_LDST8_TPREL_LO12")), \
+ ValueType(0x229, MappedType(&unsupport, "R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC")), \
+ ValueType(0x22a, MappedType(&unsupport, "R_AARCH64_TLSLE_LDST16_TPREL_LO12")), \
+ ValueType(0x22b, MappedType(&unsupport, "R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC")), \
+ ValueType(0x22c, MappedType(&unsupport, "R_AARCH64_TLSLE_LDST32_TPREL_LO12")), \
+ ValueType(0x22d, MappedType(&unsupport, "R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC")), \
+ ValueType(0x22e, MappedType(&unsupport, "R_AARCH64_TLSLE_LDST64_TPREL_LO12")), \
+ ValueType(0x22f, MappedType(&unsupport, "R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC")), \
+ ValueType(0x232, MappedType(&unsupport, "R_AARCH64_TLSDESC_ADR_PAGE")), \
+ ValueType(0x233, MappedType(&unsupport, "R_AARCH64_TLSDESC_LD64_LO12_NC")), \
+ ValueType(0x234, MappedType(&unsupport, "R_AARCH64_TLSDESC_ADD_LO12_NC")), \
+ ValueType(0x239, MappedType(&unsupport, "R_AARCH64_TLSDESC_CALL")), \
+ ValueType( 1024, MappedType(&unsupport, "R_AARCH64_COPY")), \
+ ValueType( 1025, MappedType(&unsupport, "R_AARCH64_GLOB_DAT")), \
+ ValueType( 1026, MappedType(&unsupport, "R_AARCH64_JUMP_SLOT")), \
+ ValueType( 1027, MappedType(&unsupport, "R_AARCH64_RELATIVE")), \
+ ValueType( 1028, MappedType(&unsupport, "R_AARCH64_TLS_DTPREL64")), \
+ ValueType( 1029, MappedType(&unsupport, "R_AARCH64_TLS_DTPMOD64")), \
+ ValueType( 1030, MappedType(&unsupport, "R_AARCH64_TLS_TPREL64")), \
+ ValueType( 1031, MappedType(&unsupport, "R_AARCH64_TLSDESC")), \
+ ValueType( 1032, MappedType(&unsupport, "R_AARCH64_IRELATIVE"))
diff --git a/lib/Target/AArch64/AArch64RelocationHelpers.h b/lib/Target/AArch64/AArch64RelocationHelpers.h
new file mode 100644
index 0000000..beb6be8
--- /dev/null
+++ b/lib/Target/AArch64/AArch64RelocationHelpers.h
@@ -0,0 +1,212 @@
+//===- AArch64RelocationHelpers.h -----------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TARGET_AARCH64_AARCH64RELOCATIONHELPERS_H
+#define TARGET_AARCH64_AARCH64RELOCATIONHELPERS_H
+
+#include "AArch64Relocator.h"
+#include <llvm/Support/Host.h>
+
+namespace mcld {
+//===----------------------------------------------------------------------===//
+// Relocation helper functions
+//===----------------------------------------------------------------------===//
+// Return true if overflow
+static inline bool
+helper_check_signed_overflow(Relocator::DWord pValue, unsigned bits)
+{
+ if (bits >= sizeof(int64_t) * 8)
+ return false;
+ int64_t signed_val = static_cast<int64_t>(pValue);
+ int64_t max = (1 << (bits - 1)) - 1;
+ int64_t min = -(1 << (bits - 1));
+ if (signed_val > max || signed_val < min)
+ return true;
+ return false;
+}
+
+static inline Relocator::Address
+helper_get_page_address(Relocator::Address pValue)
+{
+ return (pValue & ~ (Relocator::Address) 0xFFF);
+}
+
+static inline Relocator::Address
+helper_get_page_offset(Relocator::Address pValue)
+{
+ return (pValue & (Relocator::Address) 0xFFF);
+}
+
+static inline uint32_t get_mask(uint32_t pValue)
+{
+ return ((1u << (pValue)) - 1);
+}
+
+static inline uint32_t
+helper_reencode_adr_imm(uint32_t pInst, uint32_t pImm)
+{
+ return (pInst & ~((get_mask(2) << 29) | (get_mask(19) << 5)))
+ | ((pImm & get_mask(2)) << 29) | ((pImm & (get_mask(19) << 2)) << 3);
+}
+
+// Reencode the imm field of add immediate.
+static inline uint32_t helper_reencode_add_imm(uint32_t pInst, uint32_t pImm)
+{
+ return (pInst & ~(get_mask(12) << 10)) | ((pImm & get_mask(12)) << 10);
+}
+
+// Encode the 26-bit offset of unconditional branch.
+static inline uint32_t
+helper_reencode_branch_offset_26(uint32_t pInst, uint32_t pOff)
+{
+ return (pInst & ~get_mask(26)) | (pOff & get_mask(26));
+}
+
+// Encode the 19-bit offset of conditional branch and compare & branch.
+static inline uint32_t
+helper_reencode_cond_branch_ofs_19(uint32_t pInst, uint32_t pOff)
+{
+ return (pInst & ~(get_mask(19) << 5)) | ((pOff & get_mask(19)) << 5);
+}
+
+// Reencode the imm field of ld/st pos immediate.
+static inline uint32_t
+helper_reencode_ldst_pos_imm (uint32_t pInst, uint32_t pImm)
+{
+ return (pInst & ~(get_mask(12) << 10)) | ((pImm & get_mask(12)) << 10);
+}
+
+static inline uint32_t helper_get_upper32(Relocator::DWord pData)
+{
+ if (llvm::sys::IsLittleEndianHost)
+ return pData >> 32;
+ return pData & 0xFFFFFFFF;
+}
+
+static inline void helper_put_upper32(uint32_t pData, Relocator::DWord& pDes)
+{
+ *(reinterpret_cast<uint32_t*>(&pDes)) = pData;
+}
+
+static inline Relocator::Address
+helper_get_PLT_address(ResolveInfo& pSym, AArch64Relocator& pParent)
+{
+ PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(pSym);
+ assert(NULL != plt_entry);
+ return pParent.getTarget().getPLT().addr() + plt_entry->getOffset();
+}
+
+static inline AArch64PLT1&
+helper_PLT_init(Relocation& pReloc, AArch64Relocator& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ AArch64GNULDBackend& ld_backend = pParent.getTarget();
+ assert(NULL == pParent.getSymPLTMap().lookUp(*rsym));
+
+ AArch64PLT1* plt_entry = ld_backend.getPLT().create();
+ pParent.getSymPLTMap().record(*rsym, *plt_entry);
+
+ // initialize plt and the corresponding gotplt and dyn rel entry.
+ assert(NULL == pParent.getSymGOTPLTMap().lookUp(*rsym) &&
+ "PLT entry not exist, but DynRel entry exist!");
+ AArch64GOTEntry* gotplt_entry = ld_backend.getGOTPLT().createGOTPLT();
+ pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
+
+ // init the corresponding rel entry in .rela.plt
+ Relocation& rel_entry = *ld_backend.getRelaPLT().create();
+ rel_entry.setType(R_AARCH64_JUMP_SLOT);
+ rel_entry.targetRef().assign(*gotplt_entry);
+ rel_entry.setSymInfo(rsym);
+ return *plt_entry;
+}
+
+/// helper_DynRel - Get an relocation entry in .rela.dyn
+static inline Relocation&
+helper_DynRela_init(ResolveInfo* pSym,
+ Fragment& pFrag,
+ uint64_t pOffset,
+ Relocator::Type pType,
+ AArch64Relocator& pParent)
+{
+ AArch64GNULDBackend& ld_backend = pParent.getTarget();
+ Relocation& rel_entry = *ld_backend.getRelaDyn().create();
+ rel_entry.setType(pType);
+ rel_entry.targetRef().assign(pFrag, pOffset);
+ if (pType == R_AARCH64_RELATIVE || NULL == pSym)
+ rel_entry.setSymInfo(NULL);
+ else
+ rel_entry.setSymInfo(pSym);
+
+ return rel_entry;
+}
+
+/// helper_use_relative_reloc - Check if symbol can use relocation
+/// R_AARCH64_RELATIVE
+static inline bool
+helper_use_relative_reloc(const ResolveInfo& pSym,
+ const AArch64Relocator& pParent)
+
+{
+ // if symbol is dynamic or undefine or preemptible
+ if (pSym.isDyn() ||
+ pSym.isUndef() ||
+ pParent.getTarget().isSymbolPreemptible(pSym))
+ return false;
+ return true;
+}
+
+static inline Relocator::Address
+helper_get_GOT_address(ResolveInfo& pSym, AArch64Relocator& pParent)
+{
+ AArch64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(pSym);
+ assert(NULL != got_entry);
+ return pParent.getTarget().getGOT().addr() + got_entry->getOffset();
+}
+
+static inline Relocator::Address
+helper_GOT_ORG(AArch64Relocator& pParent)
+{
+ return pParent.getTarget().getGOT().addr();
+}
+
+static inline AArch64GOTEntry&
+helper_GOT_init(Relocation& pReloc, bool pHasRel, AArch64Relocator& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ AArch64GNULDBackend& ld_backend = pParent.getTarget();
+ assert(NULL == pParent.getSymGOTMap().lookUp(*rsym));
+
+ AArch64GOTEntry* got_entry = ld_backend.getGOT().createGOT();
+ pParent.getSymGOTMap().record(*rsym, *got_entry);
+
+ // If we first get this GOT entry, we should initialize it.
+ if (!pHasRel) {
+ // No corresponding dynamic relocation, initialize to the symbol value.
+ got_entry->setValue(AArch64Relocator::SymVal);
+ }
+ else {
+ // Initialize got_entry content and the corresponding dynamic relocation.
+ if (helper_use_relative_reloc(*rsym, pParent)) {
+ got_entry->setValue(AArch64Relocator::SymVal);
+ Relocation& rel_entry = helper_DynRela_init(rsym, *got_entry, 0x0,
+ R_AARCH64_RELATIVE, pParent);
+ rel_entry.setAddend(AArch64Relocator::SymVal);
+ pParent.getRelRelMap().record(pReloc, rel_entry);
+ }
+ else {
+ helper_DynRela_init(rsym, *got_entry, 0x0, R_AARCH64_GLOB_DAT, pParent);
+ got_entry->setValue(0);
+ }
+ }
+ return *got_entry;
+}
+
+}
+#endif
diff --git a/lib/Target/AArch64/AArch64Relocator.cpp b/lib/Target/AArch64/AArch64Relocator.cpp
new file mode 100644
index 0000000..db99762
--- /dev/null
+++ b/lib/Target/AArch64/AArch64Relocator.cpp
@@ -0,0 +1,694 @@
+//===- AArch64Relocator.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <mcld/LinkerConfig.h>
+#include <mcld/IRBuilder.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/LD/LDSymbol.h>
+#include <mcld/LD/ELFFileFormat.h>
+#include <mcld/Object/ObjectBuilder.h>
+
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/DataTypes.h>
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/Host.h>
+
+#include "AArch64Relocator.h"
+#include "AArch64RelocationFunctions.h"
+#include "AArch64RelocationHelpers.h"
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// Relocation Functions and Tables
+//===----------------------------------------------------------------------===//
+DECL_AARCH64_APPLY_RELOC_FUNCS
+
+/// the prototype of applying function
+typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc,
+ AArch64Relocator& pParent);
+
+// the table entry of applying functions
+class ApplyFunctionEntry {
+public:
+ ApplyFunctionEntry() {}
+ ApplyFunctionEntry(ApplyFunctionType pFunc,
+ const char* pName,
+ size_t pSize = 0)
+ : func(pFunc), name(pName), size(pSize) { }
+ ApplyFunctionType func;
+ const char* name;
+ size_t size;
+};
+typedef std::map<Relocator::Type, ApplyFunctionEntry> ApplyFunctionMap;
+
+static const ApplyFunctionMap::value_type ApplyFunctionList[] = {
+ DECL_AARCH64_APPLY_RELOC_FUNC_PTRS(ApplyFunctionMap::value_type,
+ ApplyFunctionEntry)
+};
+
+// declare the table of applying functions
+static ApplyFunctionMap ApplyFunctions(ApplyFunctionList,
+ ApplyFunctionList + sizeof(ApplyFunctionList)/sizeof(ApplyFunctionList[0]));
+
+//===----------------------------------------------------------------------===//
+// AArch64Relocator
+//===----------------------------------------------------------------------===//
+AArch64Relocator::AArch64Relocator(AArch64GNULDBackend& pParent,
+ const LinkerConfig& pConfig)
+ : Relocator(pConfig),
+ m_Target(pParent) {
+}
+
+AArch64Relocator::~AArch64Relocator()
+{
+}
+
+Relocator::Result AArch64Relocator::applyRelocation(Relocation& pRelocation)
+{
+ Relocation::Type type = pRelocation.type();
+ // valid types are 0x0, 0x100-0x239
+ if ((type < 0x100 || type > 0x239) && (type != 0x0)) {
+ return Relocator::Unknown;
+ }
+ assert(ApplyFunctions.find(type) != ApplyFunctions.end());
+ return ApplyFunctions[type].func(pRelocation, *this);
+}
+
+const char* AArch64Relocator::getName(Relocator::Type pType) const
+{
+ assert(ApplyFunctions.find(pType) != ApplyFunctions.end());
+ return ApplyFunctions[pType].name;
+}
+
+Relocator::Size AArch64Relocator::getSize(Relocation::Type pType) const
+{
+ return ApplyFunctions[pType].size;
+}
+
+void AArch64Relocator::addCopyReloc(ResolveInfo& pSym)
+{
+ Relocation& rel_entry = *getTarget().getRelaDyn().create();
+ rel_entry.setType(R_AARCH64_COPY);
+ assert(pSym.outSymbol()->hasFragRef());
+ rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef());
+ rel_entry.setSymInfo(&pSym);
+}
+
+/// defineSymbolForCopyReloc
+/// For a symbol needing copy relocation, define a copy symbol in the BSS
+/// section and all other reference to this symbol should refer to this
+/// copy.
+/// This is executed at scan relocation stage.
+LDSymbol& AArch64Relocator::defineSymbolforCopyReloc(IRBuilder& pBuilder,
+ const ResolveInfo& pSym)
+{
+ // get or create corresponding BSS LDSection
+ LDSection* bss_sect_hdr = NULL;
+ ELFFileFormat* file_format = getTarget().getOutputFormat();
+ if (ResolveInfo::ThreadLocal == pSym.type())
+ bss_sect_hdr = &file_format->getTBSS();
+ else
+ bss_sect_hdr = &file_format->getBSS();
+
+ // get or create corresponding BSS SectionData
+ SectionData* bss_data = NULL;
+ if (bss_sect_hdr->hasSectionData())
+ bss_data = bss_sect_hdr->getSectionData();
+ else
+ bss_data = IRBuilder::CreateSectionData(*bss_sect_hdr);
+
+ // Determine the alignment by the symbol value
+ // FIXME: here we use the largest alignment
+ uint32_t addralign = config().targets().bitclass() / 8;
+
+ // allocate space in BSS for the copy symbol
+ Fragment* frag = new FillFragment(0x0, 1, pSym.size());
+ uint64_t size = ObjectBuilder::AppendFragment(*frag, *bss_data, addralign);
+ bss_sect_hdr->setSize(bss_sect_hdr->size() + size);
+
+ // change symbol binding to Global if it's a weak symbol
+ ResolveInfo::Binding binding = (ResolveInfo::Binding)pSym.binding();
+ if (binding == ResolveInfo::Weak)
+ binding = ResolveInfo::Global;
+
+ // Define the copy symbol in the bss section and resolve it
+ LDSymbol* cpy_sym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
+ pSym.name(),
+ (ResolveInfo::Type)pSym.type(),
+ ResolveInfo::Define,
+ binding,
+ pSym.size(), // size
+ 0x0, // value
+ FragmentRef::Create(*frag, 0x0),
+ (ResolveInfo::Visibility)pSym.other());
+
+ return *cpy_sym;
+}
+
+void
+AArch64Relocator::scanLocalReloc(Relocation& pReloc, const LDSection& pSection)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ switch(pReloc.type()) {
+ case llvm::ELF::R_AARCH64_ABS64:
+ // If buiding PIC object (shared library or PIC executable),
+ // a dynamic relocations with RELATIVE type to this location is needed.
+ // Reserve an entry in .rel.dyn
+ if (config().isCodeIndep()) {
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ getTarget().checkAndSetHasTextRel(*pSection.getLink());
+ // set up the dyn rel directly
+ Relocation& reloc = helper_DynRela_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ R_AARCH64_RELATIVE,
+ *this);
+ getRelRelMap().record(pReloc, reloc);
+ }
+ return;
+
+ case llvm::ELF::R_AARCH64_ABS32:
+ case llvm::ELF::R_AARCH64_ABS16:
+ // If buiding PIC object (shared library or PIC executable),
+ // a dynamic relocations with RELATIVE type to this location is needed.
+ // Reserve an entry in .rel.dyn
+ if (config().isCodeIndep()) {
+ // set up the dyn rel directly
+ Relocation& reloc = helper_DynRela_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(), pReloc.type(), *this);
+ getRelRelMap().record(pReloc, reloc);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ getTarget().checkAndSetHasTextRel(*pSection.getLink());
+ }
+ return;
+
+ case llvm::ELF::R_AARCH64_ADR_GOT_PAGE:
+ case llvm::ELF::R_AARCH64_LD64_GOT_LO12_NC: {
+ // Symbol needs GOT entry, reserve entry in .got
+ // return if we already create GOT for this symbol
+ if (rsym->reserved() & ReserveGOT)
+ return;
+ // If building PIC object, a dynamic relocation with
+ // type RELATIVE is needed to relocate this GOT entry.
+ if (config().isCodeIndep())
+ helper_GOT_init(pReloc, true, *this);
+ else
+ helper_GOT_init(pReloc, false, *this);
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
+ return;
+ }
+
+ default:
+ break;
+ }
+}
+
+void AArch64Relocator::scanGlobalReloc(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ const LDSection& pSection)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ switch(pReloc.type()) {
+ case llvm::ELF::R_AARCH64_ABS64:
+ case llvm::ELF::R_AARCH64_ABS32:
+ case llvm::ELF::R_AARCH64_ABS16:
+ // Absolute relocation type, symbol may needs PLT entry or
+ // dynamic relocation entry
+ if (getTarget().symbolNeedsPLT(*rsym)) {
+ // create plt for this symbol if it does not have one
+ if (!(rsym->reserved() & ReservePLT)){
+ // Symbol needs PLT entry, we need a PLT entry
+ // and the corresponding GOT and dynamic relocation entry
+ // in .got and .rel.plt.
+ helper_PLT_init(pReloc, *this);
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | ReservePLT);
+ }
+ }
+
+ if (getTarget().symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT),
+ true)) {
+ // symbol needs dynamic relocation entry, set up the dynrel entry
+ if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
+ addCopyReloc(*cpy_sym.resolveInfo());
+ }
+ else {
+ // set Rel bit and the dyn rel
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ getTarget().checkAndSetHasTextRel(*pSection.getLink());
+ if (llvm::ELF::R_AARCH64_ABS64 == pReloc.type() &&
+ helper_use_relative_reloc(*rsym, *this)) {
+ Relocation& reloc = helper_DynRela_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ R_AARCH64_RELATIVE,
+ *this);
+ getRelRelMap().record(pReloc, reloc);
+ }
+ else {
+ Relocation& reloc = helper_DynRela_init(rsym,
+ *pReloc.targetRef().frag(),
+ pReloc.targetRef().offset(),
+ pReloc.type(),
+ *this);
+ getRelRelMap().record(pReloc, reloc);
+ }
+ }
+ }
+ return;
+
+ case llvm::ELF::R_AARCH64_PREL64:
+ case llvm::ELF::R_AARCH64_PREL32:
+ case llvm::ELF::R_AARCH64_PREL16:
+ if (getTarget().symbolNeedsPLT(*rsym) &&
+ LinkerConfig::DynObj != config().codeGenType()) {
+ // create plt for this symbol if it does not have one
+ if (!(rsym->reserved() & ReservePLT)){
+ // Symbol needs PLT entry, we need a PLT entry
+ // and the corresponding GOT and dynamic relocation entry
+ // in .got and .rel.plt.
+ helper_PLT_init(pReloc, *this);
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | ReservePLT);
+ }
+ }
+
+ // Only PC relative relocation against dynamic symbol needs a
+ // dynamic relocation. Only dynamic copy relocation is allowed
+ // and PC relative relocation will be resolved to the local copy.
+ // All other dynamic relocations may lead to run-time relocation
+ // overflow.
+ if (getTarget().isDynamicSymbol(*rsym) &&
+ getTarget().symbolNeedsDynRel(*rsym,
+ (rsym->reserved() & ReservePLT),
+ false) &&
+ getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
+ addCopyReloc(*cpy_sym.resolveInfo());
+ }
+ return;
+
+ case llvm::ELF::R_AARCH64_CONDBR19:
+ case llvm::ELF::R_AARCH64_JUMP26:
+ case llvm::ELF::R_AARCH64_CALL26: {
+ // return if we already create plt for this symbol
+ if (rsym->reserved() & ReservePLT)
+ return;
+
+ // if the symbol's value can be decided at link time, then no need plt
+ if (getTarget().symbolFinalValueIsKnown(*rsym))
+ return;
+
+ // if symbol is defined in the ouput file and it's not
+ // preemptible, no need plt
+ if (rsym->isDefine() && !rsym->isDyn() &&
+ !getTarget().isSymbolPreemptible(*rsym)) {
+ return;
+ }
+
+ // Symbol needs PLT entry, we need to reserve a PLT entry
+ // and the corresponding GOT and dynamic relocation entry
+ // in .got and .rel.plt.
+ helper_PLT_init(pReloc, *this);
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | ReservePLT);
+ return;
+ }
+
+ case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21:
+ case R_AARCH64_ADR_PREL_PG_HI21_NC:
+ if (getTarget().symbolNeedsDynRel(*rsym,
+ (rsym->reserved() & ReservePLT),
+ false)) {
+ if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
+ addCopyReloc(*cpy_sym.resolveInfo());
+ }
+ }
+ if (getTarget().symbolNeedsPLT(*rsym)) {
+ // create plt for this symbol if it does not have one
+ if (!(rsym->reserved() & ReservePLT)){
+ // Symbol needs PLT entry, we need a PLT entry
+ // and the corresponding GOT and dynamic relocation entry
+ // in .got and .rel.plt.
+ helper_PLT_init(pReloc, *this);
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | ReservePLT);
+ }
+ }
+ return;
+
+ case llvm::ELF::R_AARCH64_ADR_GOT_PAGE:
+ case llvm::ELF::R_AARCH64_LD64_GOT_LO12_NC: {
+ // Symbol needs GOT entry, reserve entry in .got
+ // return if we already create GOT for this symbol
+ if (rsym->reserved() & ReserveGOT)
+ return;
+ // if the symbol cannot be fully resolved at link time, then we need a
+ // dynamic relocation
+ if (!getTarget().symbolFinalValueIsKnown(*rsym))
+ helper_GOT_init(pReloc, true, *this);
+ else
+ helper_GOT_init(pReloc, false, *this);
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
+ return;
+ }
+
+ default:
+ break;
+ }
+}
+
+void AArch64Relocator::scanRelocation(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection,
+ Input& pInput)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ assert(NULL != rsym &&
+ "ResolveInfo of relocation not set while scanRelocation");
+
+ assert(NULL != pSection.getLink());
+ if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC))
+ return;
+
+ // Scan relocation type to determine if an GOT/PLT/Dynamic Relocation
+ // entries should be created.
+ // FIXME: Below judgements concern nothing about TLS related relocation
+
+ // rsym is local
+ if (rsym->isLocal())
+ scanLocalReloc(pReloc, pSection);
+ // rsym is external
+ else
+ scanGlobalReloc(pReloc, pBuilder, pSection);
+
+ // check if we shoule issue undefined reference for the relocation target
+ // symbol
+ if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
+ issueUndefRef(pReloc, pSection, pInput);
+}
+
+//===----------------------------------------------------------------------===//
+// Each relocation function implementation
+//===----------------------------------------------------------------------===//
+
+// R_AARCH64_NONE
+Relocator::Result none(Relocation& pReloc, AArch64Relocator& pParent)
+{
+ return Relocator::OK;
+}
+
+Relocator::Result unsupport(Relocation& pReloc, AArch64Relocator& pParent)
+{
+ return Relocator::Unsupport;
+}
+
+// R_AARCH64_ABS64: S + A
+// R_AARCH64_ABS32: S + A
+// R_AARCH64_ABS16: S + A
+Relocator::Result abs(Relocation& pReloc, AArch64Relocator& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ Relocator::DWord A = pReloc.target() + pReloc.addend();
+ Relocator::DWord S = pReloc.symValue();
+ Relocation* dyn_rel = pParent.getRelRelMap().lookUp(pReloc);
+ bool has_dyn_rel = (NULL != dyn_rel);
+
+ LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
+ // If the flag of target section is not ALLOC, we will not scan this
+ // relocation but perform static relocation. (e.g., applying .debug section)
+ if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
+ pReloc.target() = S + A;
+ return Relocator::OK;
+ }
+ // A local symbol may need RELATIVE Type dynamic relocation
+ if (rsym->isLocal() && has_dyn_rel) {
+ dyn_rel->setAddend(S + A);
+ }
+
+ // An external symbol may need PLT and dynamic relocation
+ if (!rsym->isLocal()) {
+ if (rsym->reserved() & AArch64Relocator::ReservePLT) {
+ S = helper_get_PLT_address(*rsym, pParent);
+ }
+ // If we generate a dynamic relocation (except R_AARCH64_64_RELATIVE)
+ // for a place, we should not perform static relocation on it
+ // in order to keep the addend store in the place correct.
+ if (has_dyn_rel) {
+ if (llvm::ELF::R_AARCH64_ABS64 == pReloc.type() &&
+ R_AARCH64_RELATIVE == dyn_rel->type()) {
+ dyn_rel->setAddend(S + A);
+ }
+ else {
+ dyn_rel->setAddend(A);
+ return Relocator::OK;
+ }
+ }
+ }
+
+ // perform static relocation
+ pReloc.target() = S + A;
+ return Relocator::OK;
+}
+
+// R_AARCH64_PREL64: S + A - P
+// R_AARCH64_PREL32: S + A - P
+// R_AARCH64_PREL16: S + A - P
+Relocator::Result rel(Relocation& pReloc, AArch64Relocator& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ Relocator::Address S = pReloc.symValue();
+ Relocator::DWord A = pReloc.addend();
+ Relocator::DWord P = pReloc.place();
+
+ if (llvm::ELF::R_AARCH64_PREL64 != pReloc.type())
+ A += pReloc.target() & get_mask(pParent.getSize(pReloc.type()));
+ else
+ A += pReloc.target();
+
+ LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
+ // If the flag of target section is not ALLOC, we will not scan this
+ // relocation but perform static relocation. (e.g., applying .debug section)
+ if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
+ // if plt entry exists, the S value is the plt entry address
+ if (!rsym->isLocal()) {
+ if (rsym->reserved() & AArch64Relocator::ReservePLT) {
+ S = helper_get_PLT_address(*rsym, pParent);
+ }
+ }
+ }
+
+ Relocator::DWord X = S + A - P;
+ pReloc.target() = X;
+
+ if (llvm::ELF::R_AARCH64_PREL64 != pReloc.type() &&
+ helper_check_signed_overflow(X, pParent.getSize(pReloc.type())))
+ return Relocator::Overflow;
+ return Relocator::OK;
+}
+
+// R_AARCH64_ADD_ABS_LO12_NC: S + A
+Relocator::Result add_abs_lo12(Relocation& pReloc, AArch64Relocator& pParent)
+{
+ Relocator::Address value = 0x0;
+ Relocator::Address S = pReloc.symValue();
+ Relocator::DWord A = pReloc.addend();
+
+ value = helper_get_page_offset(S + A);
+ pReloc.target() = helper_reencode_add_imm(pReloc.target(), value);
+
+ return Relocator::OK;
+}
+
+// R_AARCH64_ADR_PREL_PG_HI21: ((PG(S + A) - PG(P)) >> 12)
+// R_AARCH64_ADR_PREL_PG_HI21_NC: ((PG(S + A) - PG(P)) >> 12)
+Relocator::Result
+adr_prel_pg_hi21(Relocation& pReloc, AArch64Relocator& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ Relocator::Address S = pReloc.symValue();
+ // if plt entry exists, the S value is the plt entry address
+ if (rsym->reserved() & AArch64Relocator::ReservePLT) {
+ S = helper_get_PLT_address(*rsym, pParent);
+ }
+ Relocator::DWord A = pReloc.addend();
+ Relocator::DWord P = pReloc.place() ;
+ Relocator::DWord X = helper_get_page_address(S + A) -
+ helper_get_page_address(P);
+
+ pReloc.target() = helper_reencode_adr_imm(pReloc.target(), (X >> 12));
+
+ return Relocator::OK;
+}
+
+// R_AARCH64_CALL26: S + A - P
+// R_AARCH64_JUMP26: S + A - P
+Relocator::Result call(Relocation& pReloc, AArch64Relocator& pParent)
+{
+ // If target is undefined weak symbol, we only need to jump to the
+ // next instruction unless it has PLT entry. Rewrite instruction
+ // to NOP.
+ if (pReloc.symInfo()->isWeak() &&
+ pReloc.symInfo()->isUndef() &&
+ !pReloc.symInfo()->isDyn() &&
+ !(pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)) {
+ // change target to NOP
+ pReloc.target() = 0xd503201f;
+ return Relocator::OK;
+ }
+
+ Relocator::Address S = pReloc.symValue();
+ Relocator::DWord A = pReloc.addend();
+ Relocator::Address P = pReloc.place();
+
+ // S depends on PLT exists or not
+ if (pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)
+ S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
+
+ Relocator::DWord X = S + A - P;
+ // TODO: check overflow..
+
+ pReloc.target() = helper_reencode_branch_offset_26(pReloc.target(), X >> 2);
+
+ return Relocator::OK;
+}
+
+// R_AARCH64_CONDBR19: S + A - P
+Relocator::Result condbr(Relocation& pReloc, AArch64Relocator& pParent)
+{
+ // If target is undefined weak symbol, we only need to jump to the
+ // next instruction unless it has PLT entry. Rewrite instruction
+ // to NOP.
+ if (pReloc.symInfo()->isWeak() &&
+ pReloc.symInfo()->isUndef() &&
+ !pReloc.symInfo()->isDyn() &&
+ !(pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)) {
+ // change target to NOP
+ pReloc.target() = 0xd503201f;
+ return Relocator::OK;
+ }
+
+ Relocator::Address S = pReloc.symValue();
+ Relocator::DWord A = pReloc.addend();
+ Relocator::Address P = pReloc.place();
+
+ // S depends on PLT exists or not
+ if (pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)
+ S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
+
+ Relocator::DWord X = S + A - P;
+ // TODO: check overflow..
+
+ pReloc.target() = helper_reencode_cond_branch_ofs_19(pReloc.target(), X >> 2);
+
+ return Relocator::OK;
+}
+
+// R_AARCH64_ADR_GOT_PAGE: Page(G(GDAT(S+A))) - Page(P)
+Relocator::Result adr_got_page(Relocation& pReloc, AArch64Relocator& pParent)
+{
+ if (!(pReloc.symInfo()->reserved() & AArch64Relocator::ReserveGOT)) {
+ return Relocator::BadReloc;
+ }
+
+ Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent);
+ Relocator::DWord A = pReloc.addend();
+ Relocator::Address P = pReloc.place();
+ Relocator::DWord X = helper_get_page_address(GOT_S + A) -
+ helper_get_page_address(P);
+
+ pReloc.target() = helper_reencode_adr_imm(pReloc.target(), (X >> 12));
+
+ // setup got entry value if needed
+ AArch64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
+ if (NULL != got_entry && AArch64Relocator::SymVal == got_entry->getValue())
+ got_entry->setValue(pReloc.symValue());
+ // setup relocation addend if needed
+ Relocation* dyn_rela = pParent.getRelRelMap().lookUp(pReloc);
+ if ((NULL != dyn_rela) && (AArch64Relocator::SymVal == dyn_rela->addend())) {
+ dyn_rela->setAddend(pReloc.symValue());
+ }
+ return Relocator::OK;
+}
+
+// R_AARCH64_LD64_GOT_LO12_NC: G(GDAT(S+A))
+Relocator::Result ld64_got_lo12(Relocation& pReloc, AArch64Relocator& pParent)
+{
+ if (!(pReloc.symInfo()->reserved() & AArch64Relocator::ReserveGOT)) {
+ return Relocator::BadReloc;
+ }
+
+ Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent);
+ Relocator::DWord A = pReloc.addend();
+ Relocator::DWord X = helper_get_page_offset(GOT_S + A);
+
+ pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 3));
+
+ // setup got entry value if needed
+ AArch64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
+ if (NULL != got_entry && AArch64Relocator::SymVal == got_entry->getValue())
+ got_entry->setValue(pReloc.symValue());
+
+ // setup relocation addend if needed
+ Relocation* dyn_rela = pParent.getRelRelMap().lookUp(pReloc);
+ if ((NULL != dyn_rela) && (AArch64Relocator::SymVal == dyn_rela->addend())) {
+ dyn_rela->setAddend(pReloc.symValue());
+ }
+
+ return Relocator::OK;
+}
+
+// R_AARCH64_LDST8_ABS_LO12_NC: S + A
+// R_AARCH64_LDST16_ABS_LO12_NC: S + A
+// R_AARCH64_LDST32_ABS_LO12_NC: S + A
+// R_AARCH64_LDST64_ABS_LO12_NC: S + A
+// R_AARCH64_LDST128_ABS_LO12_NC: S + A
+Relocator::Result ldst_abs_lo12(Relocation& pReloc, AArch64Relocator& pParent)
+{
+ Relocator::Address S = pReloc.symValue();
+ Relocator::DWord A = pReloc.addend();
+ Relocator::DWord X = helper_get_page_offset(S + A);
+
+ switch(pReloc.type()) {
+ case llvm::ELF::R_AARCH64_LDST8_ABS_LO12_NC:
+ pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), X);
+ break;
+ case llvm::ELF::R_AARCH64_LDST16_ABS_LO12_NC:
+ pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(),
+ (X >> 1));
+ break;
+ case llvm::ELF::R_AARCH64_LDST32_ABS_LO12_NC:
+ pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(),
+ (X >> 2));
+ break;
+ case llvm::ELF::R_AARCH64_LDST64_ABS_LO12_NC:
+ pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(),
+ (X >> 3));
+ break;
+ case llvm::ELF::R_AARCH64_LDST128_ABS_LO12_NC:
+ pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(),
+ (X >> 4));
+ break;
+ default:
+ break;
+ }
+ return Relocator::OK;
+}
+
diff --git a/lib/Target/AArch64/AArch64Relocator.h b/lib/Target/AArch64/AArch64Relocator.h
new file mode 100644
index 0000000..d49f85f
--- /dev/null
+++ b/lib/Target/AArch64/AArch64Relocator.h
@@ -0,0 +1,151 @@
+//===- AArch64Relocator.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TARGET_AARCH64_AARCH64RELOCATOR_H
+#define TARGET_AARCH64_AARCH64RELOCATOR_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/Relocator.h>
+#include <mcld/Target/GOT.h>
+#include <mcld/Target/KeyEntryMap.h>
+#include "AArch64LDBackend.h"
+
+namespace mcld {
+// FIXME: llvm::ELF doesn't define AArch64 dynamic relocation types
+enum {
+ // static relocations
+ R_AARCH64_ADR_PREL_PG_HI21_NC = 0x114,
+ // dyanmic rlocations
+ R_AARCH64_COPY = 1024,
+ R_AARCH64_GLOB_DAT = 1025,
+ R_AARCH64_JUMP_SLOT = 1026,
+ R_AARCH64_RELATIVE = 1027,
+ R_AARCH64_TLS_DTPREL64 = 1028,
+ R_AARCH64_TLS_DTPMOD64 = 1029,
+ R_AARCH64_TLS_TPREL64 = 1030,
+ R_AARCH64_TLSDESC = 1031,
+ R_AARCH64_IRELATIVE = 1032
+};
+
+/** \class AArch64Relocator
+ * \brief AArch64Relocator creates and destroys the AArch64 relocations.
+ *
+ */
+class AArch64Relocator : public Relocator
+{
+public:
+ typedef KeyEntryMap<ResolveInfo, AArch64GOTEntry> SymGOTMap;
+ typedef KeyEntryMap<ResolveInfo, AArch64PLT1> SymPLTMap;
+ typedef KeyEntryMap<Relocation, Relocation> RelRelMap;
+
+ /** \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 AArch64, there are three kinds of
+ * entries, GOT, PLT, and dynamic reloction.
+ *
+ * bit: 3 2 1 0
+ * | | PLT | GOT | Rel |
+ *
+ * value Name - Description
+ *
+ * 0000 None - no reserved entry
+ * 0001 ReserveRel - reserve an dynamic relocation entry
+ * 0010 ReserveGOT - reserve an GOT entry
+ * 0100 ReservePLT - reserve an PLT entry and the corresponding GOT,
+ *
+ */
+ enum ReservedEntryType {
+ None = 0,
+ ReserveRel = 1,
+ ReserveGOT = 2,
+ ReservePLT = 4,
+ };
+
+ /** \enum EntryValue
+ * \brief The value of the entries. The symbol value will be decided at after
+ * layout, so we mark the entry during scanRelocation and fill up the actual
+ * value when applying relocations.
+ */
+ enum EntryValue {
+ Default = 0,
+ SymVal = 1
+ };
+
+public:
+ AArch64Relocator(AArch64GNULDBackend& pParent, const LinkerConfig& pConfig);
+ ~AArch64Relocator();
+
+ Result applyRelocation(Relocation& pRelocation);
+
+ AArch64GNULDBackend& getTarget()
+ { return m_Target; }
+
+ const AArch64GNULDBackend& getTarget() const
+ { return m_Target; }
+
+ const char* getName(Relocation::Type pType) const;
+
+ Size getSize(Relocation::Type pType) const;
+
+ const SymGOTMap& getSymGOTMap() const { return m_SymGOTMap; }
+ SymGOTMap& getSymGOTMap() { return m_SymGOTMap; }
+
+ const SymPLTMap& getSymPLTMap() const { return m_SymPLTMap; }
+ SymPLTMap& getSymPLTMap() { return m_SymPLTMap; }
+
+ const SymGOTMap& getSymGOTPLTMap() const { return m_SymGOTPLTMap; }
+ SymGOTMap& getSymGOTPLTMap() { return m_SymGOTPLTMap; }
+
+ const RelRelMap& getRelRelMap() const { return m_RelRelMap; }
+ RelRelMap& getRelRelMap() { return m_RelRelMap; }
+
+ /// scanRelocation - determine the empty entries are needed or not and create
+ /// the empty entries if needed.
+ /// For AArch64, 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,
+ IRBuilder& pBuilder,
+ Module& pModule,
+ LDSection& pSection,
+ Input& pInput);
+
+private:
+ void scanLocalReloc(Relocation& pReloc, const LDSection& pSection);
+
+ void scanGlobalReloc(Relocation& pReloc,
+ IRBuilder& pBuilder,
+ const LDSection& pSection);
+
+ /// addCopyReloc - add a copy relocation into .rel.dyn for pSym
+ /// @param pSym - A resolved copy symbol that defined in BSS section
+ void addCopyReloc(ResolveInfo& pSym);
+
+ /// defineSymbolforCopyReloc - allocate a space in BSS section and
+ /// and force define the copy of pSym to BSS section
+ /// @return the output LDSymbol of the copy symbol
+ LDSymbol& defineSymbolforCopyReloc(IRBuilder& pLinker,
+ const ResolveInfo& pSym);
+
+private:
+ AArch64GNULDBackend& m_Target;
+ SymGOTMap m_SymGOTMap;
+ SymPLTMap m_SymPLTMap;
+ SymGOTMap m_SymGOTPLTMap;
+ RelRelMap m_RelRelMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/AArch64/AArch64TargetMachine.cpp b/lib/Target/AArch64/AArch64TargetMachine.cpp
new file mode 100644
index 0000000..c0515f4
--- /dev/null
+++ b/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -0,0 +1,30 @@
+//===- AArch64TargetMachine.cpp -------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "AArch64TargetMachine.h"
+#include "AArch64.h"
+
+#include <mcld/Support/TargetRegistry.h>
+
+using namespace mcld;
+
+AArch64BaseTargetMachine::AArch64BaseTargetMachine(llvm::TargetMachine& pPM,
+ const llvm::Target &pLLVMTarget,
+ const mcld::Target &pMCLDTarget,
+ const std::string& pTriple)
+ : MCLDTargetMachine(pPM, pLLVMTarget, pMCLDTarget, pTriple) {
+}
+
+//===----------------------------------------------------------------------===//
+// Initialize MCLDTargetMachine
+//===----------------------------------------------------------------------===//
+extern "C" void MCLDInitializeAArch64LDTarget() {
+ // Register createTargetMachine function pointer to mcld::Target
+ mcld::RegisterTargetMachine<mcld::AArch64BaseTargetMachine> X(mcld::TheAArch64Target);
+}
+
diff --git a/lib/Target/AArch64/AArch64TargetMachine.h b/lib/Target/AArch64/AArch64TargetMachine.h
new file mode 100644
index 0000000..aee0e8c
--- /dev/null
+++ b/lib/Target/AArch64/AArch64TargetMachine.h
@@ -0,0 +1,29 @@
+//===- AArch64TargetMachine.h ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TARGET_AARCH64_AARCH64TARGETMACHINE_H
+#define TARGET_AARCH64_AARCH64TARGETMACHINE_H
+
+#include "AArch64.h"
+#include <mcld/CodeGen/TargetMachine.h>
+
+namespace mcld {
+
+class AArch64BaseTargetMachine : public MCLDTargetMachine
+{
+public:
+ AArch64BaseTargetMachine(llvm::TargetMachine& pTM,
+ const llvm::Target& pLLVMTarget,
+ const mcld::Target& pMCLDTarget,
+ const std::string& pTriple);
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/AArch64/Android.mk b/lib/Target/AArch64/Android.mk
new file mode 100644
index 0000000..31383bf
--- /dev/null
+++ b/lib/Target/AArch64/Android.mk
@@ -0,0 +1,38 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_aarch64_target_SRC_FILES := \
+ AArch64Diagnostic.cpp \
+ AArch64ELFDynamic.cpp \
+ AArch64ELFMCLinker.cpp \
+ AArch64Emulation.cpp \
+ AArch64GOT.cpp \
+ AArch64LDBackend.cpp \
+ AArch64MCLinker.cpp \
+ AArch64PLT.cpp \
+ AArch64Relocator.cpp \
+ AArch64TargetMachine.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_aarch64_target_SRC_FILES)
+LOCAL_MODULE:= libmcldAArch64Target
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_aarch64_target_SRC_FILES)
+LOCAL_MODULE:= libmcldAArch64Target
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
+
diff --git a/lib/Target/AArch64/TargetInfo/AArch64TargetInfo.cpp b/lib/Target/AArch64/TargetInfo/AArch64TargetInfo.cpp
new file mode 100644
index 0000000..13472c9
--- /dev/null
+++ b/lib/Target/AArch64/TargetInfo/AArch64TargetInfo.cpp
@@ -0,0 +1,22 @@
+//===- AArch64TargetInfo.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/Support/Target.h>
+
+namespace mcld {
+
+mcld::Target TheAArch64Target;
+
+extern "C" void MCLDInitializeAArch64LDTargetInfo() {
+ // register into mcld::TargetRegistry
+ mcld::RegisterTarget<llvm::Triple::aarch64> X(TheAArch64Target, "aarch64");
+}
+
+} // namespace of mcld
+
diff --git a/lib/Target/AArch64/TargetInfo/Android.mk b/lib/Target/AArch64/TargetInfo/Android.mk
new file mode 100644
index 0000000..1b4026d
--- /dev/null
+++ b/lib/Target/AArch64/TargetInfo/Android.mk
@@ -0,0 +1,28 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_arm_info_SRC_FILES := \
+ AArch64TargetInfo.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_arm_info_SRC_FILES)
+LOCAL_MODULE:= libmcldAArch64Info
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_arm_info_SRC_FILES)
+LOCAL_MODULE:= libmcldAArch64Info
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)