Home | History | Annotate | Download | only in AArch64
      1 //===- AArch64PLT.cpp -----------------------------------------------------===//
      2 //
      3 //                     The MCLinker Project
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 #include "AArch64GOT.h"
     10 #include "AArch64PLT.h"
     11 #include "AArch64RelocationHelpers.h"
     12 
     13 #include "mcld/LD/LDSection.h"
     14 #include "mcld/Support/MsgHandling.h"
     15 
     16 #include <llvm/Support/Casting.h>
     17 
     18 #include <new>
     19 
     20 namespace mcld {
     21 
     22 AArch64PLT0::AArch64PLT0(SectionData& pParent)
     23     : PLT::Entry<sizeof(aarch64_plt0)>(pParent) {
     24 }
     25 
     26 AArch64PLT1::AArch64PLT1(SectionData& pParent)
     27     : PLT::Entry<sizeof(aarch64_plt1)>(pParent) {
     28 }
     29 
     30 //===----------------------------------------------------------------------===//
     31 // AArch64PLT
     32 
     33 AArch64PLT::AArch64PLT(LDSection& pSection, AArch64GOT& pGOTPLT)
     34     : PLT(pSection), m_GOT(pGOTPLT) {
     35   new AArch64PLT0(*m_pSectionData);
     36 }
     37 
     38 AArch64PLT::~AArch64PLT() {
     39 }
     40 
     41 bool AArch64PLT::hasPLT1() const {
     42   return (m_pSectionData->size() > 1);
     43 }
     44 
     45 void AArch64PLT::finalizeSectionSize() {
     46   uint64_t size = (m_pSectionData->size() - 1) * sizeof(aarch64_plt1) +
     47                   sizeof(aarch64_plt0);
     48   m_Section.setSize(size);
     49 
     50   uint32_t offset = 0;
     51   SectionData::iterator frag, fragEnd = m_pSectionData->end();
     52   for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
     53     frag->setOffset(offset);
     54     offset += frag->size();
     55   }
     56 }
     57 
     58 AArch64PLT1* AArch64PLT::create() {
     59   AArch64PLT1* plt1_entry = new (std::nothrow) AArch64PLT1(*m_pSectionData);
     60   if (!plt1_entry)
     61     fatal(diag::fail_allocate_memory_plt);
     62   return plt1_entry;
     63 }
     64 
     65 void AArch64PLT::applyPLT0() {
     66   // malloc plt0
     67   iterator first = m_pSectionData->getFragmentList().begin();
     68   assert(first != m_pSectionData->getFragmentList().end() &&
     69          "FragmentList is empty, applyPLT0 failed!");
     70   AArch64PLT0* plt0 = &(llvm::cast<AArch64PLT0>(*first));
     71   uint32_t* data = NULL;
     72   data = static_cast<uint32_t*>(malloc(AArch64PLT0::EntrySize));
     73   if (data == NULL)
     74     fatal(diag::fail_allocate_memory_plt);
     75   memcpy(data, aarch64_plt0, AArch64PLT0::EntrySize);
     76 
     77   // apply plt0
     78   uint64_t plt_base = m_Section.addr();
     79   assert(plt_base && ".plt base address is NULL!");
     80   uint64_t got_base = m_GOT.addr();
     81   assert(got_base && ".got base address is NULL!");
     82 
     83   // apply 2nd instruction
     84   // get the address of got entry 2
     85   uint64_t got_ent2_base = got_base + sizeof(AArch64GOTEntry::EntrySize) * 2;
     86   // compute the immediate
     87   AArch64Relocator::DWord imm =
     88       helper_get_page_address(got_ent2_base) -
     89       helper_get_page_address(plt_base + (sizeof(AArch64PLT0::EntrySize) * 8));
     90   data[1] = helper_reencode_adr_imm(data[1], imm >> 12);
     91   // apply 3rd instruction
     92   data[2] = helper_reencode_add_imm(data[2],
     93                                     helper_get_page_offset(got_ent2_base) >> 3);
     94   // apply 4th instruction
     95   data[3] =
     96       helper_reencode_add_imm(data[3], helper_get_page_offset(got_ent2_base));
     97   plt0->setValue(reinterpret_cast<unsigned char*>(data));
     98 }
     99 
    100 void AArch64PLT::applyPLT1() {
    101   uint64_t plt_base = m_Section.addr();
    102   assert(plt_base && ".plt base address is NULL!");
    103 
    104   uint64_t got_base = m_GOT.addr();
    105   assert(got_base && ".got base address is NULL!");
    106 
    107   AArch64PLT::iterator it = m_pSectionData->begin();
    108   AArch64PLT::iterator ie = m_pSectionData->end();
    109   assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
    110 
    111   uint32_t GOTEntrySize = AArch64GOTEntry::EntrySize;
    112   // first gotplt1 address
    113   uint32_t GOTEntryAddress = got_base + GOTEntrySize * 3;
    114   // first plt1 address
    115   uint32_t PLTEntryAddress = plt_base + AArch64PLT0::EntrySize;
    116 
    117   ++it;  // skip PLT0
    118   uint32_t PLT1EntrySize = AArch64PLT1::EntrySize;
    119   AArch64PLT1* plt1 = NULL;
    120 
    121   uint32_t* Out = NULL;
    122   while (it != ie) {
    123     plt1 = &(llvm::cast<AArch64PLT1>(*it));
    124     Out = static_cast<uint32_t*>(malloc(AArch64PLT1::EntrySize));
    125     memcpy(Out, aarch64_plt1, AArch64PLT1::EntrySize);
    126     // apply 1st instruction
    127     AArch64Relocator::DWord imm = helper_get_page_address(GOTEntryAddress) -
    128                                   helper_get_page_address(PLTEntryAddress);
    129     Out[0] = helper_reencode_adr_imm(Out[0], imm >> 12);
    130     // apply 2nd instruction
    131     Out[1] = helper_reencode_add_imm(
    132         Out[1], helper_get_page_offset(GOTEntryAddress) >> 3);
    133     // apply 3rd instruction
    134     Out[2] = helper_reencode_add_imm(Out[2],
    135                                      helper_get_page_offset(GOTEntryAddress));
    136 
    137     plt1->setValue(reinterpret_cast<unsigned char*>(Out));
    138     ++it;
    139 
    140     GOTEntryAddress += GOTEntrySize;
    141     PLTEntryAddress += PLT1EntrySize;
    142   }
    143 
    144   m_GOT.applyGOTPLT(plt_base);
    145 }
    146 
    147 uint64_t AArch64PLT::emit(MemoryRegion& pRegion) {
    148   uint64_t result = 0x0;
    149   iterator it = begin();
    150 
    151   unsigned char* buffer = pRegion.begin();
    152   memcpy(buffer,
    153          llvm::cast<AArch64PLT0>((*it)).getValue(),
    154          AArch64PLT0::EntrySize);
    155   result += AArch64PLT0::EntrySize;
    156   ++it;
    157 
    158   AArch64PLT1* plt1 = NULL;
    159   AArch64PLT::iterator ie = end();
    160   while (it != ie) {
    161     plt1 = &(llvm::cast<AArch64PLT1>(*it));
    162     memcpy(buffer + result, plt1->getValue(), AArch64PLT1::EntrySize);
    163     result += AArch64PLT1::EntrySize;
    164     ++it;
    165   }
    166   return result;
    167 }
    168 
    169 }  // namespace mcld
    170