Home | History | Annotate | Download | only in Mips
      1 //===- MipsPLT.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 <llvm/Support/Casting.h>
     10 #include <llvm/Support/ELF.h>
     11 #include <mcld/Support/MsgHandling.h>
     12 #include "MipsGOTPLT.h"
     13 #include "MipsPLT.h"
     14 
     15 namespace {
     16 
     17 const uint32_t PLT0[] = {
     18   0x3c1c0000,         // lui $28, %hi(&GOTPLT[0])
     19   0x8f990000,         // lw $25, %lo(&GOTPLT[0])($28)
     20   0x279c0000,         // addiu $28, $28, %lo(&GOTPLT[0])
     21   0x031cc023,         // subu $24, $24, $28
     22   0x03e07821,         // move $15, $31
     23   0x0018c082,         // srl $24, $24, 2
     24   0x0320f809,         // jalr $25
     25   0x2718fffe          // subu $24, $24, 2
     26 };
     27 
     28 const uint32_t PLTA[] = {
     29   0x3c0f0000,         // lui $15, %hi(.got.plt entry)
     30   0x8df90000,         // l[wd] $25, %lo(.got.plt entry)($15)
     31   0x03200008,         // jr $25
     32   0x25f80000          // addiu $24, $15, %lo(.got.plt entry)
     33 };
     34 
     35 }
     36 
     37 namespace mcld {
     38 
     39 //===----------------------------------------------------------------------===//
     40 // MipsPLT0 Entry
     41 //===----------------------------------------------------------------------===//
     42 class MipsPLT0 : public PLT::Entry<sizeof(PLT0)>
     43 {
     44 public:
     45   MipsPLT0(SectionData& pParent)
     46     : PLT::Entry<sizeof(PLT0)>(pParent)
     47   {}
     48 };
     49 
     50 //===----------------------------------------------------------------------===//
     51 // MipsPLTA Entry
     52 //===----------------------------------------------------------------------===//
     53 class MipsPLTA : public PLT::Entry<sizeof(PLTA)>
     54 {
     55 public:
     56   MipsPLTA(SectionData& pParent)
     57     : PLT::Entry<sizeof(PLTA)>(pParent)
     58   {}
     59 };
     60 
     61 //===----------------------------------------------------------------------===//
     62 // MipsPLT
     63 //===----------------------------------------------------------------------===//
     64 MipsPLT::MipsPLT(LDSection& pSection)
     65   : PLT(pSection)
     66 {
     67   new MipsPLT0(*m_pSectionData);
     68   m_Last = m_pSectionData->begin();
     69 }
     70 
     71 void MipsPLT::finalizeSectionSize()
     72 {
     73   uint64_t size = sizeof(PLT0) +
     74                   (m_pSectionData->size() - 1) * sizeof(PLTA);
     75   m_Section.setSize(size);
     76 
     77   uint32_t offset = 0;
     78   SectionData::iterator frag, fragEnd = m_pSectionData->end();
     79   for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
     80     frag->setOffset(offset);
     81     offset += frag->size();
     82   }
     83 }
     84 
     85 bool MipsPLT::hasPLT1() const
     86 {
     87   return m_pSectionData->size() > 1;
     88 }
     89 
     90 uint64_t MipsPLT::emit(MemoryRegion& pRegion)
     91 {
     92   uint64_t result = 0x0;
     93   iterator it = begin();
     94 
     95   unsigned char* buffer = pRegion.begin();
     96   memcpy(buffer, llvm::cast<MipsPLT0>((*it)).getValue(), MipsPLT0::EntrySize);
     97   result += MipsPLT0::EntrySize;
     98   ++it;
     99 
    100   MipsPLTA* plta = 0;
    101   for (iterator ie = end(); it != ie; ++it) {
    102     plta = &(llvm::cast<MipsPLTA>(*it));
    103     memcpy(buffer + result, plta->getValue(), MipsPLTA::EntrySize);
    104     result += MipsPLTA::EntrySize;
    105   }
    106   return result;
    107 }
    108 
    109 void MipsPLT::reserveEntry(size_t pNum)
    110 {
    111   for (size_t i = 0; i < pNum; ++i) {
    112     Fragment* entry = new (std::nothrow) MipsPLTA(*m_pSectionData);
    113 
    114     if (NULL == entry)
    115       fatal(diag::fail_allocate_memory_plt);
    116   }
    117 }
    118 
    119 Fragment* MipsPLT::consume()
    120 {
    121   ++m_Last;
    122   assert(m_Last != m_pSectionData->end() &&
    123          "The number of PLT Entries and ResolveInfo doesn't match");
    124   return &(*m_Last);
    125 }
    126 
    127 void MipsPLT::applyAllPLT(MipsGOTPLT& pGOTPLT)
    128 {
    129   assert(m_Section.addr() && ".plt base address is NULL!");
    130 
    131   size_t count = 0;
    132   for (iterator it = m_pSectionData->begin(); it != m_pSectionData->end(); ++it) {
    133     PLTEntryBase* plt = &(llvm::cast<PLTEntryBase>(*it));
    134 
    135     if (it == m_pSectionData->begin()) {
    136       uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
    137 
    138       if (!data)
    139         fatal(diag::fail_allocate_memory_plt);
    140 
    141       memcpy(data, PLT0, plt->size());
    142 
    143       uint64_t gotAddr = pGOTPLT.addr();
    144 
    145       data[0] |= ((gotAddr + 0x8000) >> 16) & 0xffff;
    146       data[1] |= gotAddr & 0xffff;
    147       data[2] |= gotAddr & 0xffff;
    148 
    149       plt->setValue(reinterpret_cast<unsigned char*>(data));
    150     } else {
    151       uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
    152 
    153       if (!data)
    154         fatal(diag::fail_allocate_memory_plt);
    155 
    156       memcpy(data, PLTA, plt->size());
    157 
    158       uint64_t gotEntryAddr = pGOTPLT.getEntryAddr(count++);
    159 
    160       data[0] |= ((gotEntryAddr + 0x8000) >> 16) & 0xffff;
    161       data[1] |= gotEntryAddr & 0xffff;
    162       data[3] |= gotEntryAddr & 0xffff;
    163 
    164       plt->setValue(reinterpret_cast<unsigned char*>(data));
    165     }
    166   }
    167 }
    168 
    169 } //end mcld namespace
    170