Home | History | Annotate | Download | only in ARM
      1 //===- impl.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 
     11 #include <llvm/Support/Casting.h>
     12 
     13 #include <mcld/LD/LDSection.h>
     14 #include <mcld/LD/LDFileFormat.h>
     15 #include <mcld/Support/MemoryRegion.h>
     16 #include <mcld/Support/MsgHandling.h>
     17 
     18 namespace {
     19   const unsigned int ARMGOT0Num = 3;
     20 } // end of anonymous namespace
     21 
     22 using namespace mcld;
     23 
     24 //===----------------------------------------------------------------------===//
     25 // ARMGOT
     26 ARMGOT::ARMGOT(LDSection& pSection)
     27   : GOT(pSection), m_pLast(NULL)
     28 {
     29   // Create GOT0 entries.
     30   reserve(ARMGOT0Num);
     31 
     32   // Skip GOT0 entries.
     33   for (unsigned int i = 0; i < ARMGOT0Num; ++i) {
     34     consume();
     35   }
     36 }
     37 
     38 ARMGOT::~ARMGOT()
     39 {
     40 }
     41 
     42 bool ARMGOT::hasGOT1() const
     43 {
     44   return (m_SectionData->size() > ARMGOT0Num);
     45 }
     46 
     47 void ARMGOT::reserve(size_t pNum)
     48 {
     49   for (size_t i = 0; i < pNum; i++) {
     50     new ARMGOTEntry(0, m_SectionData);
     51   }
     52 }
     53 
     54 ARMGOTEntry* ARMGOT::consume()
     55 {
     56   if (NULL == m_pLast) {
     57     assert(!empty() && "Consume empty GOT entry!");
     58     m_pLast = llvm::cast<ARMGOTEntry>(&m_SectionData->front());
     59     return m_pLast;
     60   }
     61 
     62   m_pLast = llvm::cast<ARMGOTEntry>(m_pLast->getNextNode());
     63   return m_pLast;
     64 }
     65 
     66 void ARMGOT::reserveGOTPLT()
     67 {
     68   ARMGOTEntry* entry = new ARMGOTEntry(0, m_SectionData);
     69   if (NULL == m_GOTPLT.front) {
     70     // GOTPLT is empty
     71     if (NULL == m_GOT.front) {
     72       // GOT part is also empty. Since entry is the last entry, we can assign
     73       // it to GOTPLT directly.
     74       m_GOTPLT.front = entry;
     75     }
     76     else {
     77       // GOTn is not empty. Shift GOTn backward by one entry.
     78       m_GOTPLT.front = m_GOT.front;
     79       m_GOT.front = llvm::cast<ARMGOTEntry>(m_GOT.front->getNextNode());
     80     }
     81   }
     82   else {
     83     // GOTPLT is not empty
     84     if (NULL != m_GOT.front)
     85       m_GOT.front = llvm::cast<ARMGOTEntry>(m_GOT.front->getNextNode());
     86   }
     87 }
     88 
     89 void ARMGOT::reserveGOT()
     90 {
     91   ARMGOTEntry* entry = new ARMGOTEntry(0, m_SectionData);
     92   if (NULL == m_GOT.front) {
     93     // Entry must be the last entry. We can directly assign it to GOT part.
     94     m_GOT.front = entry;
     95   }
     96 }
     97 
     98 ARMGOTEntry* ARMGOT::consumeGOTPLT()
     99 {
    100   assert(NULL != m_GOTPLT.front && "Consuming empty GOTPLT section!");
    101 
    102   if (NULL == m_GOTPLT.last_used) {
    103     m_GOTPLT.last_used = m_GOTPLT.front;
    104   }
    105   else {
    106     m_GOTPLT.last_used = llvm::cast<ARMGOTEntry>(m_GOTPLT.last_used->getNextNode());
    107     assert(m_GOTPLT.last_used != m_GOT.front && "No GOT/PLT entry to consume!");
    108   }
    109   return m_GOTPLT.last_used;
    110 }
    111 
    112 ARMGOTEntry* ARMGOT::consumeGOT()
    113 {
    114   assert(NULL != m_GOT.front && "Consuming empty GOT section!");
    115 
    116   if (NULL == m_GOT.last_used) {
    117     m_GOT.last_used = m_GOT.front;
    118   }
    119   else {
    120     m_GOT.last_used = llvm::cast<ARMGOTEntry>(m_GOT.last_used->getNextNode());
    121     assert(m_GOT.last_used != NULL && "No GOTn entry to consume!");
    122   }
    123   return m_GOT.last_used;
    124 }
    125 
    126 void ARMGOT::applyGOT0(uint64_t pAddress)
    127 {
    128   llvm::cast<ARMGOTEntry>
    129     (*(m_SectionData->getFragmentList().begin())).setValue(pAddress);
    130 }
    131 
    132 void ARMGOT::applyGOTPLT(uint64_t pPLTBase)
    133 {
    134   if (NULL == m_GOTPLT.front)
    135     return;
    136 
    137   SectionData::iterator entry(m_GOTPLT.front);
    138   SectionData::iterator e_end;
    139   if (NULL == m_GOT.front)
    140     e_end = m_SectionData->end();
    141   else
    142     e_end = SectionData::iterator(m_GOT.front);
    143 
    144   while (entry != e_end) {
    145     llvm::cast<ARMGOTEntry>(entry)->setValue(pPLTBase);
    146     ++entry;
    147   }
    148 }
    149 
    150 uint64_t ARMGOT::emit(MemoryRegion& pRegion)
    151 {
    152   uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
    153 
    154   ARMGOTEntry* got = NULL;
    155   uint64_t result = 0x0;
    156   for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) {
    157       got = &(llvm::cast<ARMGOTEntry>((*it)));
    158       *buffer = static_cast<uint32_t>(got->getValue());
    159       result += ARMGOTEntry::EntrySize;
    160   }
    161   return result;
    162 }
    163 
    164