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