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