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 }  // anonymous namespace
     36 
     37 namespace mcld {
     38 
     39 //===----------------------------------------------------------------------===//
     40 // MipsPLT0 Entry
     41 //===----------------------------------------------------------------------===//
     42 class MipsPLT0 : public PLT::Entry<sizeof(PLT0)> {
     43  public:
     44   MipsPLT0(SectionData& pParent) : PLT::Entry<sizeof(PLT0)>(pParent) {}
     45 };
     46 
     47 //===----------------------------------------------------------------------===//
     48 // MipsPLTA Entry
     49 //===----------------------------------------------------------------------===//
     50 class MipsPLTA : public PLT::Entry<sizeof(PLTA)> {
     51  public:
     52   MipsPLTA(SectionData& pParent) : PLT::Entry<sizeof(PLTA)>(pParent) {}
     53 };
     54 
     55 //===----------------------------------------------------------------------===//
     56 // MipsPLT
     57 //===----------------------------------------------------------------------===//
     58 MipsPLT::MipsPLT(LDSection& pSection) : PLT(pSection) {
     59   new MipsPLT0(*m_pSectionData);
     60   m_Last = m_pSectionData->begin();
     61 }
     62 
     63 void MipsPLT::finalizeSectionSize() {
     64   uint64_t size = sizeof(PLT0) + (m_pSectionData->size() - 1) * sizeof(PLTA);
     65   m_Section.setSize(size);
     66 
     67   uint32_t offset = 0;
     68   SectionData::iterator frag, fragEnd = m_pSectionData->end();
     69   for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
     70     frag->setOffset(offset);
     71     offset += frag->size();
     72   }
     73 }
     74 
     75 bool MipsPLT::hasPLT1() const {
     76   return m_pSectionData->size() > 1;
     77 }
     78 
     79 uint64_t MipsPLT::emit(MemoryRegion& pRegion) {
     80   uint64_t result = 0x0;
     81   iterator it = begin();
     82 
     83   unsigned char* buffer = pRegion.begin();
     84   memcpy(buffer, llvm::cast<MipsPLT0>((*it)).getValue(), MipsPLT0::EntrySize);
     85   result += MipsPLT0::EntrySize;
     86   ++it;
     87 
     88   MipsPLTA* plta = 0;
     89   for (iterator ie = end(); it != ie; ++it) {
     90     plta = &(llvm::cast<MipsPLTA>(*it));
     91     memcpy(buffer + result, plta->getValue(), MipsPLTA::EntrySize);
     92     result += MipsPLTA::EntrySize;
     93   }
     94   return result;
     95 }
     96 
     97 void MipsPLT::reserveEntry(size_t pNum) {
     98   for (size_t i = 0; i < pNum; ++i) {
     99     Fragment* entry = new (std::nothrow) MipsPLTA(*m_pSectionData);
    100 
    101     if (entry == NULL)
    102       fatal(diag::fail_allocate_memory_plt);
    103   }
    104 }
    105 
    106 Fragment* MipsPLT::consume() {
    107   ++m_Last;
    108   assert(m_Last != m_pSectionData->end() &&
    109          "The number of PLT Entries and ResolveInfo doesn't match");
    110   return &(*m_Last);
    111 }
    112 
    113 void MipsPLT::applyAllPLT(MipsGOTPLT& pGOTPLT) {
    114   assert(m_Section.addr() && ".plt base address is NULL!");
    115 
    116   size_t count = 0;
    117   for (iterator it = m_pSectionData->begin(); it != m_pSectionData->end();
    118        ++it) {
    119     PLTEntryBase* plt = &(llvm::cast<PLTEntryBase>(*it));
    120 
    121     if (it == m_pSectionData->begin()) {
    122       uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
    123 
    124       if (!data)
    125         fatal(diag::fail_allocate_memory_plt);
    126 
    127       memcpy(data, PLT0, plt->size());
    128 
    129       uint64_t gotAddr = pGOTPLT.addr();
    130 
    131       data[0] |= ((gotAddr + 0x8000) >> 16) & 0xffff;
    132       data[1] |= gotAddr & 0xffff;
    133       data[2] |= gotAddr & 0xffff;
    134 
    135       plt->setValue(reinterpret_cast<unsigned char*>(data));
    136     } else {
    137       uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
    138 
    139       if (!data)
    140         fatal(diag::fail_allocate_memory_plt);
    141 
    142       memcpy(data, PLTA, plt->size());
    143 
    144       uint64_t gotEntryAddr = pGOTPLT.getEntryAddr(count++);
    145 
    146       data[0] |= ((gotEntryAddr + 0x8000) >> 16) & 0xffff;
    147       data[1] |= gotEntryAddr & 0xffff;
    148       data[3] |= gotEntryAddr & 0xffff;
    149 
    150       plt->setValue(reinterpret_cast<unsigned char*>(data));
    151     }
    152   }
    153 }
    154 
    155 }  // namespace mcld
    156