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