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