MipsGOT.cpp revision cfcb22478ca64c308df58f9abe6fa2dedb213c16
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 20namespace { 21const uint32_t Mips32ModulePtr = 1 << 31; 22const uint64_t Mips64ModulePtr = 1ull << 63; 23const size_t MipsGOT0Num = 2; 24const size_t MipsGOTGpOffset = 0x7FF0; 25const size_t MipsGOTSize = MipsGOTGpOffset + 0x7FFF; 26} 27 28namespace mcld { 29 30//===----------------------------------------------------------------------===// 31// MipsGOT::GOTMultipart 32//===----------------------------------------------------------------------===// 33MipsGOT::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 46bool MipsGOT::GOTMultipart::isConsumed() const { 47 return m_LocalNum == m_ConsumedLocal && m_GlobalNum == m_ConsumedGlobal && 48 m_TLSNum == m_ConsumedTLS; 49} 50 51void 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 57void 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 64void 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//===----------------------------------------------------------------------===// 74MipsGOT::LocalEntry::LocalEntry(const ResolveInfo* pInfo, 75 Relocation::DWord addend, 76 bool isGot16) 77 : m_pInfo(pInfo), m_Addend(addend), m_IsGot16(isGot16) { 78} 79 80bool 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//===----------------------------------------------------------------------===// 93MipsGOT::MipsGOT(LDSection& pSection) 94 : GOT(pSection), 95 m_pInput(NULL), 96 m_HasTLSLdmSymbol(false), 97 m_CurrentGOTPart(0), 98 m_GotTLSLdmEntry(nullptr) { 99} 100 101uint64_t MipsGOT::getGPDispAddress() const { 102 return addr() + MipsGOTGpOffset; 103} 104 105void MipsGOT::reserve(size_t pNum) { 106 for (size_t i = 0; i < pNum; ++i) 107 createEntry(0, m_SectionData); 108} 109 110bool MipsGOT::hasGOT1() const { 111 return !m_MultipartList.empty(); 112} 113 114bool MipsGOT::hasMultipleGOT() const { 115 return m_MultipartList.size() > 1; 116} 117 118void 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 149bool 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 159void 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 175void 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 195bool 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 204void 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 226void 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 236void MipsGOT::finalizeScan(const Input& pInput) { 237} 238 239bool 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 265bool 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 288bool 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 299bool 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 310bool 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 321bool MipsGOT::isPrimaryGOTConsumed() { 322 return m_CurrentGOTPart > 0; 323} 324 325Fragment* 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 337Fragment* 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 349Fragment* 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 361uint64_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 378uint64_t MipsGOT::getGPRelOffset(const Input& pInput, 379 const Fragment& pEntry) const { 380 return addr() + pEntry.getOffset() - getGPAddr(pInput); 381} 382 383void 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 391Fragment* 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 404void 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 425Fragment* 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 448void 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 458Fragment* 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 472size_t MipsGOT::getLocalNum() const { 473 assert(!m_MultipartList.empty() && "GOT is empty!"); 474 return m_MultipartList[0].m_LocalNum + MipsGOT0Num; 475} 476 477size_t MipsGOT::getGlobalNum() const { 478 return m_SymbolOrderMap.size(); 479} 480 481//===----------------------------------------------------------------------===// 482// Mips32GOT 483//===----------------------------------------------------------------------===// 484Mips32GOT::Mips32GOT(LDSection& pSection) : MipsGOT(pSection) { 485} 486 487void Mips32GOT::setEntryValue(Fragment* entry, uint64_t pValue) { 488 llvm::cast<Mips32GOTEntry>(entry)->setValue(pValue); 489} 490 491uint64_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 503Fragment* Mips32GOT::createEntry(uint64_t pValue, SectionData* pParent) { 504 return new Mips32GOTEntry(pValue, pParent); 505} 506 507size_t Mips32GOT::getEntrySize() const { 508 return Mips32GOTEntry::EntrySize; 509} 510 511void Mips32GOT::reserveHeader() { 512 createEntry(0, m_SectionData); 513 createEntry(Mips32ModulePtr, m_SectionData); 514} 515 516//===----------------------------------------------------------------------===// 517// Mips64GOT 518//===----------------------------------------------------------------------===// 519Mips64GOT::Mips64GOT(LDSection& pSection) : MipsGOT(pSection) { 520} 521 522void Mips64GOT::setEntryValue(Fragment* entry, uint64_t pValue) { 523 llvm::cast<Mips64GOTEntry>(entry)->setValue(pValue); 524} 525 526uint64_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 538Fragment* Mips64GOT::createEntry(uint64_t pValue, SectionData* pParent) { 539 return new Mips64GOTEntry(pValue, pParent); 540} 541 542size_t Mips64GOT::getEntrySize() const { 543 return Mips64GOTEntry::EntrySize; 544} 545 546void Mips64GOT::reserveHeader() { 547 createEntry(0, m_SectionData); 548 createEntry(Mips64ModulePtr, m_SectionData); 549} 550 551} // namespace mcld 552