Home | History | Annotate | Download | only in X86
      1 //===- X86PLT.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 "X86GOTPLT.h"
     10 #include "X86PLT.h"
     11 
     12 #include <llvm/Support/ELF.h>
     13 #include <llvm/Support/Casting.h>
     14 
     15 #include <mcld/LD/LDSection.h>
     16 #include <mcld/LinkerConfig.h>
     17 #include <mcld/Support/MsgHandling.h>
     18 
     19 using namespace mcld;
     20 
     21 //===----------------------------------------------------------------------===//
     22 // PLT entry data
     23 //===----------------------------------------------------------------------===//
     24 X86_32DynPLT0::X86_32DynPLT0(SectionData& pParent)
     25   : PLT::Entry<sizeof(x86_32_dyn_plt0)>(pParent)
     26 {
     27 }
     28 
     29 X86_32DynPLT1::X86_32DynPLT1(SectionData& pParent)
     30   : PLT::Entry<sizeof(x86_32_dyn_plt1)>(pParent)
     31 {
     32 }
     33 
     34 X86_32ExecPLT0::X86_32ExecPLT0(SectionData& pParent)
     35   : PLT::Entry<sizeof(x86_32_exec_plt0)>(pParent)
     36 {
     37 }
     38 
     39 X86_32ExecPLT1::X86_32ExecPLT1(SectionData& pParent)
     40   : PLT::Entry<sizeof(x86_32_exec_plt1)>(pParent)
     41 {
     42 }
     43 
     44 X86_64PLT0::X86_64PLT0(SectionData& pParent)
     45   : PLT::Entry<sizeof(x86_64_plt0)>(pParent)
     46 {
     47 }
     48 
     49 X86_64PLT1::X86_64PLT1(SectionData& pParent)
     50   : PLT::Entry<sizeof(x86_64_plt1)>(pParent)
     51 {
     52 }
     53 
     54 //===----------------------------------------------------------------------===//
     55 // X86PLT
     56 //===----------------------------------------------------------------------===//
     57 X86PLT::X86PLT(LDSection& pSection, const LinkerConfig& pConfig, int got_size)
     58   : PLT(pSection),
     59     m_Config(pConfig)
     60 {
     61   assert(LinkerConfig::DynObj == m_Config.codeGenType() ||
     62          LinkerConfig::Exec   == m_Config.codeGenType() ||
     63          LinkerConfig::Binary == m_Config.codeGenType());
     64 
     65   if (got_size == 32) {
     66     if (LinkerConfig::DynObj == m_Config.codeGenType()) {
     67       m_PLT0 = x86_32_dyn_plt0;
     68       m_PLT1 = x86_32_dyn_plt1;
     69       m_PLT0Size = sizeof (x86_32_dyn_plt0);
     70       m_PLT1Size = sizeof (x86_32_dyn_plt1);
     71       // create PLT0
     72       new X86_32DynPLT0(*m_pSectionData);
     73     }
     74     else {
     75       m_PLT0 = x86_32_exec_plt0;
     76       m_PLT1 = x86_32_exec_plt1;
     77       m_PLT0Size = sizeof (x86_32_exec_plt0);
     78       m_PLT1Size = sizeof (x86_32_exec_plt1);
     79       // create PLT0
     80       new X86_32ExecPLT0(*m_pSectionData);
     81     }
     82   }
     83   else {
     84     assert(got_size == 64);
     85     m_PLT0 = x86_64_plt0;
     86     m_PLT1 = x86_64_plt1;
     87     m_PLT0Size = sizeof (x86_64_plt0);
     88     m_PLT1Size = sizeof (x86_64_plt1);
     89     // create PLT0
     90     new X86_64PLT0(*m_pSectionData);
     91   }
     92 }
     93 
     94 X86PLT::~X86PLT()
     95 {
     96 }
     97 
     98 void X86PLT::finalizeSectionSize()
     99 {
    100   uint64_t size = 0;
    101   // plt0 size
    102   size = getPLT0()->size();
    103 
    104   // get first plt1 entry
    105   X86PLT::iterator it = begin();
    106   ++it;
    107   if (end() != it) {
    108     // plt1 size
    109     PLTEntryBase* plt1 = &(llvm::cast<PLTEntryBase>(*it));
    110     size += (m_pSectionData->size() - 1) * plt1->size();
    111   }
    112   m_Section.setSize(size);
    113 
    114   uint32_t offset = 0;
    115   SectionData::iterator frag, fragEnd = m_pSectionData->end();
    116   for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
    117     frag->setOffset(offset);
    118     offset += frag->size();
    119   }
    120 }
    121 
    122 bool X86PLT::hasPLT1() const
    123 {
    124   return (m_pSectionData->size() > 1);
    125 }
    126 
    127 PLTEntryBase* X86PLT::create()
    128 {
    129   if (LinkerConfig::DynObj == m_Config.codeGenType())
    130     return new X86_32DynPLT1(*m_pSectionData);
    131   else
    132     return new X86_32ExecPLT1(*m_pSectionData);
    133 }
    134 
    135 PLTEntryBase* X86PLT::getPLT0() const
    136 {
    137   iterator first = m_pSectionData->getFragmentList().begin();
    138 
    139   assert(first != m_pSectionData->getFragmentList().end() &&
    140          "FragmentList is empty, getPLT0 failed!");
    141 
    142   PLTEntryBase* plt0 = &(llvm::cast<PLTEntryBase>(*first));
    143 
    144   return plt0;
    145 }
    146 
    147 //===----------------------------------------------------------------------===//
    148 // X86_32PLT
    149 //===----------------------------------------------------------------------===//
    150 X86_32PLT::X86_32PLT(LDSection& pSection,
    151                      X86_32GOTPLT& pGOTPLT,
    152                      const LinkerConfig& pConfig)
    153   : X86PLT(pSection, pConfig, 32),
    154     m_GOTPLT(pGOTPLT) {
    155 }
    156 
    157 // FIXME: It only works on little endian machine.
    158 void X86_32PLT::applyPLT0()
    159 {
    160   PLTEntryBase* plt0 = getPLT0();
    161 
    162   unsigned char* data = 0;
    163   data = static_cast<unsigned char*>(malloc(plt0->size()));
    164 
    165   if (!data)
    166     fatal(diag::fail_allocate_memory_plt);
    167 
    168   memcpy(data, m_PLT0, plt0->size());
    169 
    170   if (m_PLT0 == x86_32_exec_plt0) {
    171     uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2);
    172     *offset = m_GOTPLT.addr() + 4;
    173     offset = reinterpret_cast<uint32_t*>(data + 8);
    174     *offset = m_GOTPLT.addr() + 8;
    175   }
    176 
    177   plt0->setValue(data);
    178 }
    179 
    180 // FIXME: It only works on little endian machine.
    181 void X86_32PLT::applyPLT1()
    182 {
    183   assert(m_Section.addr() && ".plt base address is NULL!");
    184 
    185   X86PLT::iterator it = m_pSectionData->begin();
    186   X86PLT::iterator ie = m_pSectionData->end();
    187   assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
    188 
    189   uint64_t GOTEntrySize = X86_32GOTEntry::EntrySize;
    190 
    191   // Skip GOT0
    192   uint64_t GOTEntryOffset = GOTEntrySize * X86GOTPLT0Num;
    193   if (LinkerConfig::Exec == m_Config.codeGenType())
    194     GOTEntryOffset += m_GOTPLT.addr();
    195 
    196   //skip PLT0
    197   uint64_t PLTEntryOffset = m_PLT0Size;
    198   ++it;
    199 
    200   PLTEntryBase* plt1 = 0;
    201 
    202   uint64_t PLTRelOffset = 0;
    203 
    204   while (it != ie) {
    205     plt1 = &(llvm::cast<PLTEntryBase>(*it));
    206     unsigned char *data;
    207     data = static_cast<unsigned char*>(malloc(plt1->size()));
    208 
    209     if (!data)
    210       fatal(diag::fail_allocate_memory_plt);
    211 
    212     memcpy(data, m_PLT1, plt1->size());
    213 
    214     uint32_t* offset;
    215 
    216     offset = reinterpret_cast<uint32_t*>(data + 2);
    217     *offset = GOTEntryOffset;
    218     GOTEntryOffset += GOTEntrySize;
    219 
    220     offset = reinterpret_cast<uint32_t*>(data + 7);
    221     *offset = PLTRelOffset;
    222     PLTRelOffset += sizeof (llvm::ELF::Elf32_Rel);
    223 
    224     offset = reinterpret_cast<uint32_t*>(data + 12);
    225     *offset = -(PLTEntryOffset + 12 + 4);
    226     PLTEntryOffset += m_PLT1Size;
    227 
    228     plt1->setValue(data);
    229     ++it;
    230   }
    231 }
    232 
    233 //===----------------------------------------------------------------------===//
    234 // X86_64PLT
    235 //===----------------------------------------------------------------------===//
    236 X86_64PLT::X86_64PLT(LDSection& pSection,
    237                      X86_64GOTPLT& pGOTPLT,
    238                      const LinkerConfig& pConfig)
    239   : X86PLT(pSection, pConfig, 64),
    240     m_GOTPLT(pGOTPLT) {
    241 }
    242 
    243 // FIXME: It only works on little endian machine.
    244 void X86_64PLT::applyPLT0()
    245 {
    246   PLTEntryBase* plt0 = getPLT0();
    247 
    248   unsigned char* data = 0;
    249   data = static_cast<unsigned char*>(malloc(plt0->size()));
    250 
    251   if (!data)
    252     fatal(diag::fail_allocate_memory_plt);
    253 
    254   memcpy(data, m_PLT0, plt0->size());
    255 
    256   // pushq GOT + 8(%rip)
    257   uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2);
    258   *offset = m_GOTPLT.addr() - addr() + 8 - 6;
    259   // jmq *GOT + 16(%rip)
    260   offset = reinterpret_cast<uint32_t*>(data + 8);
    261   *offset = m_GOTPLT.addr() - addr() + 16 - 12;
    262 
    263   plt0->setValue(data);
    264 }
    265 
    266 // FIXME: It only works on little endian machine.
    267 void X86_64PLT::applyPLT1()
    268 {
    269   assert(m_Section.addr() && ".plt base address is NULL!");
    270 
    271   X86PLT::iterator it = m_pSectionData->begin();
    272   X86PLT::iterator ie = m_pSectionData->end();
    273   assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
    274 
    275   uint64_t GOTEntrySize = X86_64GOTEntry::EntrySize;
    276 
    277   // compute sym@GOTPCREL of the PLT1 entry.
    278   uint64_t SymGOTPCREL = m_GOTPLT.addr();
    279 
    280   // Skip GOT0
    281   SymGOTPCREL += GOTEntrySize * X86GOTPLT0Num;
    282 
    283   // skip PLT0
    284   uint64_t PLTEntryOffset = m_PLT0Size;
    285   ++it;
    286 
    287   // PC-relative to entry in PLT section.
    288   SymGOTPCREL -= addr() + PLTEntryOffset + 6;
    289 
    290   PLTEntryBase* plt1 = 0;
    291 
    292   uint64_t PLTRelIndex = 0;
    293 
    294   while (it != ie) {
    295     plt1 = &(llvm::cast<PLTEntryBase>(*it));
    296     unsigned char *data;
    297     data = static_cast<unsigned char*>(malloc(plt1->size()));
    298 
    299     if (!data)
    300       fatal(diag::fail_allocate_memory_plt);
    301 
    302     memcpy(data, m_PLT1, plt1->size());
    303 
    304     uint32_t* offset;
    305 
    306     // jmpq *sym@GOTPCREL(%rip)
    307     offset = reinterpret_cast<uint32_t*>(data + 2);
    308     *offset = SymGOTPCREL;
    309     SymGOTPCREL += GOTEntrySize - m_PLT1Size;
    310 
    311     // pushq $index
    312     offset = reinterpret_cast<uint32_t*>(data + 7);
    313     *offset = PLTRelIndex;
    314     PLTRelIndex++;
    315 
    316     // jmpq plt0
    317     offset = reinterpret_cast<uint32_t*>(data + 12);
    318     *offset = -(PLTEntryOffset + 12 + 4);
    319     PLTEntryOffset += m_PLT1Size;
    320 
    321     plt1->setValue(data);
    322     ++it;
    323   }
    324 }
    325 
    326