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