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