diff options
author | Stephen Hines <srhines@google.com> | 2014-04-24 14:41:24 -0700 |
---|---|---|
committer | Stephen Hines <srhines@google.com> | 2014-04-24 15:22:31 -0700 |
commit | 551ae4ebd3e9d137ea668fb83ae4a55b8cfba451 (patch) | |
tree | c4ea60679a6fe2630e21bf6d46177b2c4fcab33b /lib/Target/AArch64 | |
parent | 334c6f83c1265eabd58ac7c8b860898038831eab (diff) | |
download | mclinker-551ae4ebd3e9d137ea668fb83ae4a55b8cfba451.tar.gz |
Update MCLinker for LLVM 3.5.
Change-Id: Ib07513d0eb2f8b7d3516a7dd8823f98820943cc9
Diffstat (limited to 'lib/Target/AArch64')
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) |