1 //===- MipsGOT.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 10 #include "mcld/LD/ResolveInfo.h" 11 #include "mcld/Support/MsgHandling.h" 12 #include "mcld/Target/OutputRelocSection.h" 13 14 #include "MipsGOT.h" 15 #include "MipsRelocator.h" 16 17 #include <llvm/Support/Casting.h> 18 #include <llvm/Support/ELF.h> 19 20 namespace { 21 const uint32_t Mips32ModulePtr = 1 << 31; 22 const uint64_t Mips64ModulePtr = 1ull << 63; 23 const size_t MipsGOT0Num = 2; 24 const size_t MipsGOTGpOffset = 0x7FF0; 25 const size_t MipsGOTSize = MipsGOTGpOffset + 0x7FFF; 26 } 27 28 namespace mcld { 29 30 //===----------------------------------------------------------------------===// 31 // MipsGOT::GOTMultipart 32 //===----------------------------------------------------------------------===// 33 MipsGOT::GOTMultipart::GOTMultipart(size_t local, size_t global) 34 : m_LocalNum(local), 35 m_GlobalNum(global), 36 m_TLSNum(0), 37 m_TLSDynNum(0), 38 m_ConsumedLocal(0), 39 m_ConsumedGlobal(0), 40 m_ConsumedTLS(0), 41 m_pLastLocal(NULL), 42 m_pLastGlobal(NULL), 43 m_pLastTLS(NULL) { 44 } 45 46 bool MipsGOT::GOTMultipart::isConsumed() const { 47 return m_LocalNum == m_ConsumedLocal && m_GlobalNum == m_ConsumedGlobal && 48 m_TLSNum == m_ConsumedTLS; 49 } 50 51 void MipsGOT::GOTMultipart::consumeLocal() { 52 assert(m_ConsumedLocal < m_LocalNum && "Consumed too many local GOT entries"); 53 ++m_ConsumedLocal; 54 m_pLastLocal = m_pLastLocal->getNextNode(); 55 } 56 57 void MipsGOT::GOTMultipart::consumeGlobal() { 58 assert(m_ConsumedGlobal < m_GlobalNum && 59 "Consumed too many global GOT entries"); 60 ++m_ConsumedGlobal; 61 m_pLastGlobal = m_pLastGlobal->getNextNode(); 62 } 63 64 void MipsGOT::GOTMultipart::consumeTLS(Relocation::Type pType) { 65 assert(m_ConsumedTLS < m_TLSNum && 66 "Consumed too many TLS GOT entries"); 67 m_ConsumedTLS += pType == llvm::ELF::R_MIPS_TLS_GOTTPREL ? 1 : 2; 68 m_pLastTLS = m_pLastTLS->getNextNode(); 69 } 70 71 //===----------------------------------------------------------------------===// 72 // MipsGOT::LocalEntry 73 //===----------------------------------------------------------------------===// 74 MipsGOT::LocalEntry::LocalEntry(const ResolveInfo* pInfo, 75 Relocation::DWord addend, 76 bool isGot16) 77 : m_pInfo(pInfo), m_Addend(addend), m_IsGot16(isGot16) { 78 } 79 80 bool MipsGOT::LocalEntry::operator<(const LocalEntry& O) const { 81 if (m_pInfo != O.m_pInfo) 82 return m_pInfo < O.m_pInfo; 83 84 if (m_Addend != O.m_Addend) 85 return m_Addend < O.m_Addend; 86 87 return m_IsGot16 < O.m_IsGot16; 88 } 89 90 //===----------------------------------------------------------------------===// 91 // MipsGOT 92 //===----------------------------------------------------------------------===// 93 MipsGOT::MipsGOT(LDSection& pSection) 94 : GOT(pSection), 95 m_pInput(NULL), 96 m_HasTLSLdmSymbol(false), 97 m_CurrentGOTPart(0), 98 m_GotTLSLdmEntry(nullptr) { 99 } 100 101 uint64_t MipsGOT::getGPDispAddress() const { 102 return addr() + MipsGOTGpOffset; 103 } 104 105 void MipsGOT::reserve(size_t pNum) { 106 for (size_t i = 0; i < pNum; ++i) 107 createEntry(0, m_SectionData); 108 } 109 110 bool MipsGOT::hasGOT1() const { 111 return !m_MultipartList.empty(); 112 } 113 114 bool MipsGOT::hasMultipleGOT() const { 115 return m_MultipartList.size() > 1; 116 } 117 118 void MipsGOT::finalizeScanning(OutputRelocSection& pRelDyn) { 119 for (MultipartListType::iterator it = m_MultipartList.begin(); 120 it != m_MultipartList.end(); 121 ++it) { 122 reserveHeader(); 123 it->m_pLastLocal = &m_SectionData->back(); 124 reserve(it->m_LocalNum); 125 it->m_pLastGlobal = &m_SectionData->back(); 126 reserve(it->m_GlobalNum); 127 it->m_pLastTLS = &m_SectionData->back(); 128 reserve(it->m_TLSNum); 129 130 if (it == m_MultipartList.begin()) { 131 // Reserve entries in the second part of the primary GOT. 132 // These entries correspond to the global symbols in all 133 // non-primary GOTs. 134 reserve(getGlobalNum() - it->m_GlobalNum); 135 } else { 136 // Reserve reldyn entries for R_MIPS_REL32 relocations 137 // for all global entries of secondary GOTs. 138 // FIXME: (simon) Do not count local entries for non-pic. 139 size_t count = it->m_GlobalNum + it->m_LocalNum; 140 for (size_t i = 0; i < count; ++i) 141 pRelDyn.reserveEntry(); 142 } 143 144 for (size_t i = 0; i < it->m_TLSDynNum; ++i) 145 pRelDyn.reserveEntry(); 146 } 147 } 148 149 bool MipsGOT::dynSymOrderCompare(const LDSymbol* pX, const LDSymbol* pY) const { 150 SymbolOrderMapType::const_iterator itX = m_SymbolOrderMap.find(pX); 151 SymbolOrderMapType::const_iterator itY = m_SymbolOrderMap.find(pY); 152 153 if (itX != m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end()) 154 return itX->second < itY->second; 155 156 return itX == m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end(); 157 } 158 159 void MipsGOT::initGOTList() { 160 m_SymbolOrderMap.clear(); 161 162 m_MultipartList.clear(); 163 m_MultipartList.push_back(GOTMultipart()); 164 165 m_MultipartList.back().m_Inputs.insert(m_pInput); 166 167 m_MergedGlobalSymbols.clear(); 168 m_InputGlobalSymbols.clear(); 169 m_MergedLocalSymbols.clear(); 170 m_InputLocalSymbols.clear(); 171 m_InputTLSGdSymbols.clear(); 172 m_HasTLSLdmSymbol = false; 173 } 174 175 void MipsGOT::changeInput() { 176 m_MultipartList.back().m_Inputs.insert(m_pInput); 177 178 for (LocalSymbolSetType::iterator it = m_InputLocalSymbols.begin(), 179 end = m_InputLocalSymbols.end(); 180 it != end; 181 ++it) 182 m_MergedLocalSymbols.insert(*it); 183 184 m_InputLocalSymbols.clear(); 185 186 for (SymbolUniqueMapType::iterator it = m_InputGlobalSymbols.begin(), 187 end = m_InputGlobalSymbols.end(); 188 it != end; 189 ++it) 190 m_MergedGlobalSymbols.insert(it->first); 191 192 m_InputGlobalSymbols.clear(); 193 } 194 195 bool MipsGOT::isGOTFull() const { 196 uint64_t gotCount = MipsGOT0Num + m_MultipartList.back().m_LocalNum + 197 m_MultipartList.back().m_GlobalNum; 198 199 gotCount += 1; 200 201 return gotCount * getEntrySize() > MipsGOTSize; 202 } 203 204 void MipsGOT::split() { 205 m_MergedLocalSymbols.clear(); 206 m_MergedGlobalSymbols.clear(); 207 208 size_t uniqueCount = 0; 209 for (SymbolUniqueMapType::const_iterator it = m_InputGlobalSymbols.begin(), 210 end = m_InputGlobalSymbols.end(); 211 it != end; 212 ++it) { 213 if (it->second) 214 ++uniqueCount; 215 } 216 217 m_MultipartList.back().m_LocalNum -= m_InputLocalSymbols.size(); 218 m_MultipartList.back().m_GlobalNum -= uniqueCount; 219 m_MultipartList.back().m_Inputs.erase(m_pInput); 220 221 m_MultipartList.push_back( 222 GOTMultipart(m_InputLocalSymbols.size(), m_InputGlobalSymbols.size())); 223 m_MultipartList.back().m_Inputs.insert(m_pInput); 224 } 225 226 void MipsGOT::initializeScan(const Input& pInput) { 227 if (m_pInput == NULL) { 228 m_pInput = &pInput; 229 initGOTList(); 230 } else { 231 m_pInput = &pInput; 232 changeInput(); 233 } 234 } 235 236 void MipsGOT::finalizeScan(const Input& pInput) { 237 } 238 239 bool MipsGOT::reserveLocalEntry(ResolveInfo& pInfo, 240 int reloc, 241 Relocation::DWord pAddend) { 242 LocalEntry entry(&pInfo, pAddend, reloc == llvm::ELF::R_MIPS_GOT16); 243 244 if (m_InputLocalSymbols.count(entry)) 245 // Do nothing, if we have seen this symbol 246 // in the current input already. 247 return false; 248 249 if (m_MergedLocalSymbols.count(entry)) { 250 // We have seen this symbol in previous inputs. 251 // Remember that it exists in the current input too. 252 m_InputLocalSymbols.insert(entry); 253 return false; 254 } 255 256 if (isGOTFull()) 257 split(); 258 259 m_InputLocalSymbols.insert(entry); 260 261 ++m_MultipartList.back().m_LocalNum; 262 return true; 263 } 264 265 bool MipsGOT::reserveGlobalEntry(ResolveInfo& pInfo) { 266 if (m_InputGlobalSymbols.count(&pInfo)) 267 return false; 268 269 if (m_MergedGlobalSymbols.count(&pInfo)) { 270 m_InputGlobalSymbols[&pInfo] = false; 271 return false; 272 } 273 274 if (isGOTFull()) 275 split(); 276 277 m_InputGlobalSymbols[&pInfo] = true; 278 ++m_MultipartList.back().m_GlobalNum; 279 280 if (!(pInfo.reserved() & MipsRelocator::ReserveGot)) { 281 m_SymbolOrderMap[pInfo.outSymbol()] = m_SymbolOrderMap.size(); 282 pInfo.setReserved(pInfo.reserved() | MipsRelocator::ReserveGot); 283 } 284 285 return true; 286 } 287 288 bool MipsGOT::reserveTLSGdEntry(ResolveInfo& pInfo) { 289 if (m_InputTLSGdSymbols.count(&pInfo)) 290 return false; 291 292 m_InputTLSGdSymbols.insert(&pInfo); 293 m_MultipartList.back().m_TLSNum += 2; 294 m_MultipartList.back().m_TLSDynNum += 2; 295 296 return true; 297 } 298 299 bool MipsGOT::reserveTLSLdmEntry() { 300 if (m_HasTLSLdmSymbol) 301 return false; 302 303 m_HasTLSLdmSymbol = true; 304 m_MultipartList.back().m_TLSNum += 2; 305 m_MultipartList.back().m_TLSDynNum += 1; 306 307 return true; 308 } 309 310 bool MipsGOT::reserveTLSGotEntry(ResolveInfo& pInfo) { 311 if (m_InputTLSGotSymbols.count(&pInfo)) 312 return false; 313 314 m_InputTLSGotSymbols.insert(&pInfo); 315 m_MultipartList.back().m_TLSNum += 1; 316 m_MultipartList.back().m_TLSDynNum += 1; 317 318 return true; 319 } 320 321 bool MipsGOT::isPrimaryGOTConsumed() { 322 return m_CurrentGOTPart > 0; 323 } 324 325 Fragment* MipsGOT::consumeLocal() { 326 assert(m_CurrentGOTPart < m_MultipartList.size() && 327 "GOT number is out of range!"); 328 329 if (m_MultipartList[m_CurrentGOTPart].isConsumed()) 330 ++m_CurrentGOTPart; 331 332 m_MultipartList[m_CurrentGOTPart].consumeLocal(); 333 334 return m_MultipartList[m_CurrentGOTPart].m_pLastLocal; 335 } 336 337 Fragment* MipsGOT::consumeGlobal() { 338 assert(m_CurrentGOTPart < m_MultipartList.size() && 339 "GOT number is out of range!"); 340 341 if (m_MultipartList[m_CurrentGOTPart].isConsumed()) 342 ++m_CurrentGOTPart; 343 344 m_MultipartList[m_CurrentGOTPart].consumeGlobal(); 345 346 return m_MultipartList[m_CurrentGOTPart].m_pLastGlobal; 347 } 348 349 Fragment* MipsGOT::consumeTLS(Relocation::Type pType) { 350 assert(m_CurrentGOTPart < m_MultipartList.size() && 351 "GOT number is out of range!"); 352 353 if (m_MultipartList[m_CurrentGOTPart].isConsumed()) 354 ++m_CurrentGOTPart; 355 356 m_MultipartList[m_CurrentGOTPart].consumeTLS(pType); 357 358 return m_MultipartList[m_CurrentGOTPart].m_pLastTLS; 359 } 360 361 uint64_t MipsGOT::getGPAddr(const Input& pInput) const { 362 uint64_t gotSize = 0; 363 for (MultipartListType::const_iterator it = m_MultipartList.begin(), 364 ie = m_MultipartList.end(); 365 it != ie; 366 ++it) { 367 if (it->m_Inputs.count(&pInput)) 368 break; 369 370 gotSize += (MipsGOT0Num + it->m_LocalNum + it->m_GlobalNum); 371 if (it == m_MultipartList.begin()) 372 gotSize += getGlobalNum() - it->m_GlobalNum; 373 } 374 375 return addr() + gotSize * getEntrySize() + MipsGOTGpOffset; 376 } 377 378 uint64_t MipsGOT::getGPRelOffset(const Input& pInput, 379 const Fragment& pEntry) const { 380 return addr() + pEntry.getOffset() - getGPAddr(pInput); 381 } 382 383 void MipsGOT::recordGlobalEntry(const ResolveInfo* pInfo, Fragment* pEntry) { 384 GotEntryKey key; 385 key.m_GOTPage = m_CurrentGOTPart; 386 key.m_pInfo = pInfo; 387 key.m_Addend = 0; 388 m_GotGlobalEntriesMap[key] = pEntry; 389 } 390 391 Fragment* MipsGOT::lookupGlobalEntry(const ResolveInfo* pInfo) { 392 GotEntryKey key; 393 key.m_GOTPage = m_CurrentGOTPart; 394 key.m_pInfo = pInfo; 395 key.m_Addend = 0; 396 GotEntryMapType::iterator it = m_GotGlobalEntriesMap.find(key); 397 398 if (it == m_GotGlobalEntriesMap.end()) 399 return NULL; 400 401 return it->second; 402 } 403 404 void MipsGOT::recordTLSEntry(const ResolveInfo* pInfo, Fragment* pEntry, 405 Relocation::Type pType) { 406 if (pType == llvm::ELF::R_MIPS_TLS_LDM) { 407 m_GotTLSLdmEntry = pEntry; 408 } else if (pType == llvm::ELF::R_MIPS_TLS_GD) { 409 GotEntryKey key; 410 key.m_GOTPage = m_CurrentGOTPart; 411 key.m_pInfo = pInfo; 412 key.m_Addend = 0; 413 m_GotTLSGdEntriesMap[key] = pEntry; 414 } else if (pType == llvm::ELF::R_MIPS_TLS_GOTTPREL) { 415 GotEntryKey key; 416 key.m_GOTPage = m_CurrentGOTPart; 417 key.m_pInfo = pInfo; 418 key.m_Addend = 0; 419 m_GotTLSGotEntriesMap[key] = pEntry; 420 } else { 421 llvm_unreachable("Unexpected relocation"); 422 } 423 } 424 425 Fragment* MipsGOT::lookupTLSEntry(const ResolveInfo* pInfo, 426 Relocation::Type pType) { 427 if (pType == llvm::ELF::R_MIPS_TLS_LDM) 428 return m_GotTLSLdmEntry; 429 if (pType == llvm::ELF::R_MIPS_TLS_GD) { 430 GotEntryKey key; 431 key.m_GOTPage = m_CurrentGOTPart; 432 key.m_pInfo = pInfo; 433 key.m_Addend = 0; 434 GotEntryMapType::iterator it = m_GotTLSGdEntriesMap.find(key); 435 return it == m_GotTLSGdEntriesMap.end() ? nullptr : it->second; 436 } 437 if (pType == llvm::ELF::R_MIPS_TLS_GOTTPREL) { 438 GotEntryKey key; 439 key.m_GOTPage = m_CurrentGOTPart; 440 key.m_pInfo = pInfo; 441 key.m_Addend = 0; 442 GotEntryMapType::iterator it = m_GotTLSGotEntriesMap.find(key); 443 return it == m_GotTLSGotEntriesMap.end() ? nullptr : it->second; 444 } 445 llvm_unreachable("Unexpected relocation"); 446 } 447 448 void MipsGOT::recordLocalEntry(const ResolveInfo* pInfo, 449 Relocation::DWord pAddend, 450 Fragment* pEntry) { 451 GotEntryKey key; 452 key.m_GOTPage = m_CurrentGOTPart; 453 key.m_pInfo = pInfo; 454 key.m_Addend = pAddend; 455 m_GotLocalEntriesMap[key] = pEntry; 456 } 457 458 Fragment* MipsGOT::lookupLocalEntry(const ResolveInfo* pInfo, 459 Relocation::DWord pAddend) { 460 GotEntryKey key; 461 key.m_GOTPage = m_CurrentGOTPart; 462 key.m_pInfo = pInfo; 463 key.m_Addend = pAddend; 464 GotEntryMapType::iterator it = m_GotLocalEntriesMap.find(key); 465 466 if (it == m_GotLocalEntriesMap.end()) 467 return NULL; 468 469 return it->second; 470 } 471 472 size_t MipsGOT::getLocalNum() const { 473 assert(!m_MultipartList.empty() && "GOT is empty!"); 474 return m_MultipartList[0].m_LocalNum + MipsGOT0Num; 475 } 476 477 size_t MipsGOT::getGlobalNum() const { 478 return m_SymbolOrderMap.size(); 479 } 480 481 //===----------------------------------------------------------------------===// 482 // Mips32GOT 483 //===----------------------------------------------------------------------===// 484 Mips32GOT::Mips32GOT(LDSection& pSection) : MipsGOT(pSection) { 485 } 486 487 void Mips32GOT::setEntryValue(Fragment* entry, uint64_t pValue) { 488 llvm::cast<Mips32GOTEntry>(entry)->setValue(pValue); 489 } 490 491 uint64_t Mips32GOT::emit(MemoryRegion& pRegion) { 492 uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.begin()); 493 494 uint64_t result = 0; 495 for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) { 496 Mips32GOTEntry* got = &(llvm::cast<Mips32GOTEntry>((*it))); 497 *buffer = static_cast<uint32_t>(got->getValue()); 498 result += got->size(); 499 } 500 return result; 501 } 502 503 Fragment* Mips32GOT::createEntry(uint64_t pValue, SectionData* pParent) { 504 return new Mips32GOTEntry(pValue, pParent); 505 } 506 507 size_t Mips32GOT::getEntrySize() const { 508 return Mips32GOTEntry::EntrySize; 509 } 510 511 void Mips32GOT::reserveHeader() { 512 createEntry(0, m_SectionData); 513 createEntry(Mips32ModulePtr, m_SectionData); 514 } 515 516 //===----------------------------------------------------------------------===// 517 // Mips64GOT 518 //===----------------------------------------------------------------------===// 519 Mips64GOT::Mips64GOT(LDSection& pSection) : MipsGOT(pSection) { 520 } 521 522 void Mips64GOT::setEntryValue(Fragment* entry, uint64_t pValue) { 523 llvm::cast<Mips64GOTEntry>(entry)->setValue(pValue); 524 } 525 526 uint64_t Mips64GOT::emit(MemoryRegion& pRegion) { 527 uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.begin()); 528 529 uint64_t result = 0; 530 for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) { 531 Mips64GOTEntry* got = &(llvm::cast<Mips64GOTEntry>((*it))); 532 *buffer = static_cast<uint64_t>(got->getValue()); 533 result += got->size(); 534 } 535 return result; 536 } 537 538 Fragment* Mips64GOT::createEntry(uint64_t pValue, SectionData* pParent) { 539 return new Mips64GOTEntry(pValue, pParent); 540 } 541 542 size_t Mips64GOT::getEntrySize() const { 543 return Mips64GOTEntry::EntrySize; 544 } 545 546 void Mips64GOT::reserveHeader() { 547 createEntry(0, m_SectionData); 548 createEntry(Mips64ModulePtr, m_SectionData); 549 } 550 551 } // namespace mcld 552