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