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 #include <llvm/Support/raw_ostream.h>
     12 #include <llvm/Support/ErrorHandling.h>
     13 #include <mcld/Support/MemoryRegion.h>
     14 #include <new>
     15 
     16 namespace {
     17 
     18 const uint32_t arm_plt0[] = {
     19   0xe52de004, // str   lr, [sp, #-4]!
     20   0xe59fe004, // ldr   lr, [pc, #4]
     21   0xe08fe00e, // add   lr, pc, lr
     22   0xe5bef008, // ldr   pc, [lr, #8]!
     23   0x00000000, // &GOT[0] - .
     24 };
     25 
     26 const uint32_t arm_plt1[] = {
     27   0xe28fc600, // add   ip, pc, #0xNN00000
     28   0xe28cca00, // add   ip, ip, #0xNN000
     29   0xe5bcf000, // ldr   pc, [ip, #0xNNN]!
     30 };
     31 
     32 } // anonymous namespace
     33 
     34 using namespace mcld;
     35 
     36 ARMPLT0::ARMPLT0(llvm::MCSectionData* pParent)
     37   : PLTEntry(sizeof(arm_plt0), pParent) {}
     38 
     39 ARMPLT1::ARMPLT1(llvm::MCSectionData* pParent)
     40   : PLTEntry(sizeof(arm_plt1), pParent) {}
     41 
     42 //===----------------------------------------------------------------------===//
     43 // ARMPLT
     44 
     45 ARMPLT::ARMPLT(LDSection& pSection,
     46                llvm::MCSectionData& pSectionData,
     47                ARMGOT &pGOTPLT)
     48   : PLT(pSection, pSectionData), m_GOT(pGOTPLT), m_PLTEntryIterator() {
     49   ARMPLT0* plt0_entry = new ARMPLT0(&m_SectionData);
     50 
     51   m_Section.setSize(m_Section.size() + plt0_entry->getEntrySize());
     52 
     53   m_PLTEntryIterator = pSectionData.begin();
     54 }
     55 
     56 ARMPLT::~ARMPLT()
     57 {
     58 }
     59 
     60 void ARMPLT::reserveEntry(size_t pNum)
     61 {
     62   ARMPLT1* plt1_entry = 0;
     63 
     64   for (size_t i = 0; i < pNum; ++i) {
     65     plt1_entry = new (std::nothrow) ARMPLT1(&m_SectionData);
     66 
     67     if (!plt1_entry)
     68       llvm::report_fatal_error("Allocating new memory for ARMPLT1 failed!");
     69 
     70     m_Section.setSize(m_Section.size() + plt1_entry->getEntrySize());
     71 
     72     m_GOT.reserveGOTPLTEntry();
     73   }
     74 }
     75 
     76 PLTEntry* ARMPLT::getPLTEntry(const ResolveInfo& pSymbol, bool& pExist)
     77 {
     78    ARMPLT1 *&PLTEntry = m_PLTEntryMap[&pSymbol];
     79 
     80    pExist = 1;
     81 
     82    if (!PLTEntry) {
     83      GOTEntry *&GOTPLTEntry = m_GOT.lookupGOTPLTMap(pSymbol);
     84      assert(!GOTPLTEntry && "PLT entry and got.plt entry doesn't match!");
     85 
     86      pExist = 0;
     87 
     88      // This will skip PLT0.
     89      ++m_PLTEntryIterator;
     90      assert(m_PLTEntryIterator != m_SectionData.end() &&
     91             "The number of PLT Entries and ResolveInfo doesn't match");
     92 
     93      ARMGOT::iterator got_it = m_GOT.getNextGOTPLTEntry();
     94      ARMGOT::iterator got_ie = m_GOT.getGOTPLTEnd();
     95      assert(got_it != got_ie && "The number of GOTPLT and PLT doesn't match");
     96 
     97      PLTEntry = llvm::cast<ARMPLT1>(&(*m_PLTEntryIterator));
     98      GOTPLTEntry = llvm::cast<GOTEntry>(&(*got_it));
     99    }
    100 
    101    return PLTEntry;
    102 }
    103 
    104 GOTEntry* ARMPLT::getGOTPLTEntry(const ResolveInfo& pSymbol, bool& pExist)
    105 {
    106    GOTEntry *&GOTPLTEntry = m_GOT.lookupGOTPLTMap(pSymbol);
    107 
    108    pExist = 1;
    109 
    110    if (!GOTPLTEntry) {
    111      ARMPLT1 *&PLTEntry = m_PLTEntryMap[&pSymbol];
    112      assert(!PLTEntry && "PLT entry and got.plt entry doesn't match!");
    113 
    114      pExist = 0;
    115 
    116      // This will skip PLT0.
    117      ++m_PLTEntryIterator;
    118      assert(m_PLTEntryIterator != m_SectionData.end() &&
    119             "The number of PLT Entries and ResolveInfo doesn't match");
    120 
    121      ARMGOT::iterator got_it = m_GOT.getNextGOTPLTEntry();
    122      ARMGOT::iterator got_ie = m_GOT.getGOTPLTEnd();
    123      assert(got_it != got_ie && "The number of GOTPLT and PLT doesn't match");
    124 
    125      PLTEntry = llvm::cast<ARMPLT1>(&(*m_PLTEntryIterator));
    126      GOTPLTEntry = llvm::cast<GOTEntry>(&(*got_it));
    127    }
    128 
    129    return GOTPLTEntry;
    130 }
    131 
    132 ARMPLT0* ARMPLT::getPLT0() const {
    133 
    134   iterator first = m_SectionData.getFragmentList().begin();
    135   iterator end = m_SectionData.getFragmentList().end();
    136 
    137   assert(first!=end && "FragmentList is empty, getPLT0 failed!");
    138 
    139   ARMPLT0* plt0 = &(llvm::cast<ARMPLT0>(*first));
    140 
    141   return plt0;
    142 }
    143 
    144 void ARMPLT::applyPLT0() {
    145 
    146   uint64_t plt_base = m_Section.addr();
    147   assert(plt_base && ".plt base address is NULL!");
    148 
    149   uint64_t got_base = m_GOT.getSection().addr();
    150   assert(got_base && ".got base address is NULL!");
    151 
    152   uint32_t offset = 0;
    153 
    154   if (got_base > plt_base)
    155     offset = got_base - (plt_base + 16);
    156   else
    157     offset = (plt_base + 16) - got_base;
    158 
    159   iterator first = m_SectionData.getFragmentList().begin();
    160   iterator end = m_SectionData.getFragmentList().end();
    161 
    162   assert(first!=end && "FragmentList is empty, applyPLT0 failed!");
    163 
    164   ARMPLT0* plt0 = &(llvm::cast<ARMPLT0>(*first));
    165 
    166   uint32_t* data = 0;
    167   data = static_cast<uint32_t*>(malloc(plt0->getEntrySize()));
    168 
    169   if (!data)
    170     llvm::report_fatal_error("Allocating new memory for plt0 failed!");
    171 
    172   memcpy(data, arm_plt0, plt0->getEntrySize());
    173   data[4] = offset;
    174 
    175   plt0->setContent(reinterpret_cast<unsigned char*>(data));
    176 }
    177 
    178 void ARMPLT::applyPLT1() {
    179 
    180   uint64_t plt_base = m_Section.addr();
    181   assert(plt_base && ".plt base address is NULL!");
    182 
    183   uint64_t got_base = m_GOT.getSection().addr();
    184   assert(got_base && ".got base address is NULL!");
    185 
    186   ARMPLT::iterator it = m_SectionData.begin();
    187   ARMPLT::iterator ie = m_SectionData.end();
    188   assert(it!=ie && "FragmentList is empty, applyPLT1 failed!");
    189 
    190   uint32_t GOTEntrySize = m_GOT.getEntrySize();
    191   uint32_t GOTEntryAddress =
    192     got_base +  GOTEntrySize * 3;
    193 
    194   uint64_t PLTEntryAddress =
    195     plt_base + llvm::cast<ARMPLT0>((*it)).getEntrySize(); //Offset of PLT0
    196 
    197   ++it; //skip PLT0
    198   uint64_t PLT1EntrySize = llvm::cast<ARMPLT1>((*it)).getEntrySize();
    199   ARMPLT1* plt1 = NULL;
    200 
    201   uint32_t* Out = NULL;
    202   while (it != ie) {
    203     plt1 = &(llvm::cast<ARMPLT1>(*it));
    204     Out = static_cast<uint32_t*>(malloc(plt1->getEntrySize()));
    205 
    206     if (!Out)
    207       llvm::report_fatal_error("Allocating new memory for plt1 failed!");
    208 
    209     // Offset is the distance between the last PLT entry and the associated
    210     // GOT entry.
    211     int32_t Offset = (GOTEntryAddress - (PLTEntryAddress + 8));
    212 
    213     Out[0] = arm_plt1[0] | ((Offset >> 20) & 0xFF);
    214     Out[1] = arm_plt1[1] | ((Offset >> 12) & 0xFF);
    215     Out[2] = arm_plt1[2] | (Offset & 0xFFF);
    216 
    217     plt1->setContent(reinterpret_cast<unsigned char*>(Out));
    218     ++it;
    219 
    220     GOTEntryAddress += GOTEntrySize;
    221     PLTEntryAddress += PLT1EntrySize;
    222   }
    223 
    224   m_GOT.applyAllGOTPLT(plt_base);
    225 }
    226 
    227 uint64_t ARMPLT::emit(MemoryRegion& pRegion)
    228 {
    229   uint64_t result = 0x0;
    230   iterator it = begin();
    231   unsigned int plt0_size = llvm::cast<ARMPLT0>((*it)).getEntrySize();
    232 
    233   unsigned char* buffer = pRegion.getBuffer();
    234   memcpy(buffer, llvm::cast<ARMPLT0>((*it)).getContent(), plt0_size);
    235   result += plt0_size;
    236   ++it;
    237 
    238   ARMPLT1* plt1 = 0;
    239   ARMPLT::iterator ie = end();
    240   unsigned int entry_size = 0;
    241   while (it != ie) {
    242     plt1 = &(llvm::cast<ARMPLT1>(*it));
    243     entry_size = plt1->getEntrySize();
    244     memcpy(buffer + result, plt1->getContent(), entry_size);
    245     result += entry_size;
    246     ++it;
    247   }
    248   return result;
    249 }
    250