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