X86PLT.cpp revision 67e37f1be98c926645219cfb47fab9e90d8c725c
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#include <llvm/Support/raw_ostream.h> 12#include <llvm/Support/ELF.h> 13#include <mcld/MC/MCLDOutput.h> 14#include <mcld/Support/MsgHandling.h> 15#include <new> 16 17namespace { 18 19const uint8_t x86_dyn_plt0[] = { 20 0xff, 0xb3, 0x04, 0, 0, 0, // pushl 0x4(%ebx) 21 0xff, 0xa3, 0x08, 0, 0, 0, // jmp *0x8(%ebx) 22 0x0f, 0x1f, 0x4, 0 // nopl 0(%eax) 23}; 24 25const uint8_t x86_dyn_plt1[] = { 26 0xff, 0xa3, 0, 0, 0, 0, // jmp *sym@GOT(%ebx) 27 0x68, 0, 0, 0, 0, // pushl $offset 28 0xe9, 0, 0, 0, 0 // jmp plt0 29}; 30 31const uint8_t x86_exec_plt0[] = { 32 0xff, 0x35, 0, 0, 0, 0, // pushl .got + 4 33 0xff, 0x25, 0, 0, 0, 0, // jmp *(.got + 8) 34 0x0f, 0x1f, 0x4, 0 // nopl 0(%eax) 35}; 36 37const uint8_t x86_exec_plt1[] = { 38 0xff, 0x25, 0, 0, 0, 0, // jmp *(sym in .got) 39 0x68, 0, 0, 0, 0, // pushl $offset 40 0xe9, 0, 0, 0, 0 // jmp plt0 41}; 42 43} 44 45namespace mcld { 46 47X86PLT0::X86PLT0(llvm::MCSectionData* pParent, unsigned int pSize) 48 : PLTEntry(pSize, pParent) { } 49 50X86PLT1::X86PLT1(llvm::MCSectionData* pParent, unsigned int pSize) 51 : PLTEntry(pSize, pParent) { } 52 53//===----------------------------------------------------------------------===// 54// X86PLT 55 56X86PLT::X86PLT(LDSection& pSection, 57 llvm::MCSectionData& pSectionData, 58 X86GOTPLT &pGOTPLT, 59 const Output& pOutput) 60 : PLT(pSection, pSectionData), 61 m_GOTPLT(pGOTPLT), 62 m_PLTEntryIterator(), 63 m_Output(pOutput) 64{ 65 assert (Output::DynObj == pOutput.type() || Output::Exec == pOutput.type()); 66 if (Output::DynObj == pOutput.type()) { 67 m_PLT0 = x86_dyn_plt0; 68 m_PLT1 = x86_dyn_plt1; 69 m_PLT0Size = sizeof (x86_dyn_plt0); 70 m_PLT1Size = sizeof (x86_dyn_plt1); 71 } 72 else { 73 m_PLT0 = x86_exec_plt0; 74 m_PLT1 = x86_exec_plt1; 75 m_PLT0Size = sizeof (x86_exec_plt0); 76 m_PLT1Size = sizeof (x86_exec_plt1); 77 } 78 X86PLT0* plt0_entry = new X86PLT0(&m_SectionData, m_PLT0Size); 79 80 m_Section.setSize(m_Section.size() + plt0_entry->getEntrySize()); 81 82 m_PLTEntryIterator = pSectionData.begin(); 83} 84 85X86PLT::~X86PLT() 86{ 87} 88 89void X86PLT::reserveEntry(size_t pNum) 90{ 91 X86PLT1* plt1_entry = 0; 92 93 for (size_t i = 0; i < pNum; ++i) { 94 plt1_entry = new (std::nothrow) X86PLT1(&m_SectionData, m_PLT1Size); 95 96 if (!plt1_entry) 97 fatal(diag::fail_allocate_memory) << "X86PLT1"; 98 99 m_Section.setSize(m_Section.size() + plt1_entry->getEntrySize()); 100 101 // reserve corresponding entry in .got.plt 102 m_GOTPLT.reserveEntry(pNum); 103 } 104} 105 106PLTEntry* X86PLT::getPLTEntry(const ResolveInfo& pSymbol, bool& pExist) 107{ 108 X86PLT1 *&PLTEntry = m_PLTEntryMap[&pSymbol]; 109 110 pExist = 1; 111 112 if (!PLTEntry) { 113 pExist = 0; 114 115 // This will skip PLT0. 116 ++m_PLTEntryIterator; 117 assert(m_PLTEntryIterator != m_SectionData.end() && 118 "The number of PLT Entries and ResolveInfo doesn't match"); 119 PLTEntry = llvm::cast<X86PLT1>(&(*m_PLTEntryIterator)); 120 } 121 return PLTEntry; 122} 123 124GOTEntry* X86PLT::getGOTPLTEntry(const ResolveInfo& pSymbol, bool& pExist) 125{ 126 return m_GOTPLT.getEntry(pSymbol, pExist); 127} 128 129X86PLT0* X86PLT::getPLT0() const { 130 131 iterator first = m_SectionData.getFragmentList().begin(); 132 133 assert(first != m_SectionData.getFragmentList().end() && 134 "FragmentList is empty, getPLT0 failed!"); 135 136 X86PLT0* plt0 = &(llvm::cast<X86PLT0>(*first)); 137 138 return plt0; 139} 140 141// FIXME: It only works on little endian machine. 142void X86PLT::applyPLT0() { 143 144 iterator first = m_SectionData.getFragmentList().begin(); 145 146 assert(first != m_SectionData.getFragmentList().end() && 147 "FragmentList is empty, applyPLT0 failed!"); 148 149 X86PLT0* plt0 = &(llvm::cast<X86PLT0>(*first)); 150 151 unsigned char* data = 0; 152 data = static_cast<unsigned char*>(malloc(plt0->getEntrySize())); 153 154 if (!data) 155 fatal(diag::fail_allocate_memory) << "plt0"; 156 157 memcpy(data, m_PLT0, plt0->getEntrySize()); 158 159 if (m_PLT0 == x86_exec_plt0) { 160 uint64_t got_base = m_GOTPLT.getSection().addr(); 161 assert(got_base && ".got base address is NULL!"); 162 uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2); 163 *offset = got_base + 4; 164 offset = reinterpret_cast<uint32_t*>(data + 8); 165 *offset = got_base + 8; 166 } 167 168 plt0->setContent(data); 169} 170 171// FIXME: It only works on little endian machine. 172void X86PLT::applyPLT1() { 173 174 uint64_t plt_base = m_Section.addr(); 175 assert(plt_base && ".plt base address is NULL!"); 176 177 uint64_t got_base = m_GOTPLT.getSection().addr(); 178 assert(got_base && ".got base address is NULL!"); 179 180 X86PLT::iterator it = m_SectionData.begin(); 181 X86PLT::iterator ie = m_SectionData.end(); 182 assert(it != ie && "FragmentList is empty, applyPLT1 failed!"); 183 184 uint64_t GOTEntrySize = m_GOTPLT.getEntrySize(); 185 186 // Skip GOT0 187 uint64_t GOTEntryOffset = GOTEntrySize * X86GOTPLT0Num; 188 189 //skip PLT0 190 uint64_t PLTEntryOffset = m_PLT0Size; 191 ++it; 192 193 X86PLT1* plt1 = 0; 194 195 uint64_t PLTRelOffset = 0; 196 197 while (it != ie) { 198 plt1 = &(llvm::cast<X86PLT1>(*it)); 199 unsigned char *data; 200 data = static_cast<unsigned char*>(malloc(plt1->getEntrySize())); 201 202 if (!data) 203 fatal(diag::fail_allocate_memory) << "plt1"; 204 205 memcpy(data, m_PLT1, plt1->getEntrySize()); 206 207 uint32_t* offset; 208 209 offset = reinterpret_cast<uint32_t*>(data + 2); 210 if (m_Output.type() == Output::DynObj) { 211 *offset = GOTEntryOffset; 212 } else { 213 // Exec 214 *offset = got_base + GOTEntryOffset; 215 } 216 GOTEntryOffset += GOTEntrySize; 217 218 offset = reinterpret_cast<uint32_t*>(data + 7); 219 *offset = PLTRelOffset; 220 PLTRelOffset += sizeof (llvm::ELF::Elf32_Rel); 221 222 offset = reinterpret_cast<uint32_t*>(data + 12); 223 *offset = -(PLTEntryOffset + 12 + 4); 224 PLTEntryOffset += m_PLT1Size; 225 226 plt1->setContent(data); 227 ++it; 228 } 229 230 // apply .got.plt 231 m_GOTPLT.applyAllGOTPLT(plt_base, m_PLT0Size, m_PLT1Size); 232} 233 234} // end namespace mcld 235 236