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