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