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_ConsumedLocal(0), 37 m_ConsumedGlobal(0), 38 m_pLastLocal(NULL), 39 m_pLastGlobal(NULL) { 40 } 41 42 bool MipsGOT::GOTMultipart::isConsumed() const { 43 return m_LocalNum == m_ConsumedLocal && m_GlobalNum == m_ConsumedGlobal; 44 } 45 46 void MipsGOT::GOTMultipart::consumeLocal() { 47 assert(m_ConsumedLocal < m_LocalNum && "Consumed too many local GOT entries"); 48 ++m_ConsumedLocal; 49 m_pLastLocal = m_pLastLocal->getNextNode(); 50 } 51 52 void MipsGOT::GOTMultipart::consumeGlobal() { 53 assert(m_ConsumedGlobal < m_GlobalNum && 54 "Consumed too many global GOT entries"); 55 ++m_ConsumedGlobal; 56 m_pLastGlobal = m_pLastGlobal->getNextNode(); 57 } 58 59 //===----------------------------------------------------------------------===// 60 // MipsGOT::LocalEntry 61 //===----------------------------------------------------------------------===// 62 MipsGOT::LocalEntry::LocalEntry(const ResolveInfo* pInfo, 63 Relocation::DWord addend, 64 bool isGot16) 65 : m_pInfo(pInfo), m_Addend(addend), m_IsGot16(isGot16) { 66 } 67 68 bool MipsGOT::LocalEntry::operator<(const LocalEntry& O) const { 69 if (m_pInfo != O.m_pInfo) 70 return m_pInfo < O.m_pInfo; 71 72 if (m_Addend != O.m_Addend) 73 return m_Addend < O.m_Addend; 74 75 return m_IsGot16 < O.m_IsGot16; 76 } 77 78 //===----------------------------------------------------------------------===// 79 // MipsGOT 80 //===----------------------------------------------------------------------===// 81 MipsGOT::MipsGOT(LDSection& pSection) 82 : GOT(pSection), m_pInput(NULL), m_CurrentGOTPart(0) { 83 } 84 85 uint64_t MipsGOT::getGPDispAddress() const { 86 return addr() + MipsGOTGpOffset; 87 } 88 89 void MipsGOT::reserve(size_t pNum) { 90 for (size_t i = 0; i < pNum; ++i) 91 createEntry(0, m_SectionData); 92 } 93 94 bool MipsGOT::hasGOT1() const { 95 return !m_MultipartList.empty(); 96 } 97 98 bool MipsGOT::hasMultipleGOT() const { 99 return m_MultipartList.size() > 1; 100 } 101 102 void MipsGOT::finalizeScanning(OutputRelocSection& pRelDyn) { 103 for (MultipartListType::iterator it = m_MultipartList.begin(); 104 it != m_MultipartList.end(); 105 ++it) { 106 reserveHeader(); 107 it->m_pLastLocal = &m_SectionData->back(); 108 reserve(it->m_LocalNum); 109 it->m_pLastGlobal = &m_SectionData->back(); 110 reserve(it->m_GlobalNum); 111 112 if (it == m_MultipartList.begin()) { 113 // Reserve entries in the second part of the primary GOT. 114 // These entries correspond to the global symbols in all 115 // non-primary GOTs. 116 reserve(getGlobalNum() - it->m_GlobalNum); 117 } else { 118 // Reserve reldyn entries for R_MIPS_REL32 relocations 119 // for all global entries of secondary GOTs. 120 // FIXME: (simon) Do not count local entries for non-pic. 121 size_t count = it->m_GlobalNum + it->m_LocalNum; 122 for (size_t i = 0; i < count; ++i) 123 pRelDyn.reserveEntry(); 124 } 125 } 126 } 127 128 bool MipsGOT::dynSymOrderCompare(const LDSymbol* pX, const LDSymbol* pY) const { 129 SymbolOrderMapType::const_iterator itX = m_SymbolOrderMap.find(pX); 130 SymbolOrderMapType::const_iterator itY = m_SymbolOrderMap.find(pY); 131 132 if (itX != m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end()) 133 return itX->second < itY->second; 134 135 return itX == m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end(); 136 } 137 138 void MipsGOT::initGOTList() { 139 m_SymbolOrderMap.clear(); 140 141 m_MultipartList.clear(); 142 m_MultipartList.push_back(GOTMultipart()); 143 144 m_MultipartList.back().m_Inputs.insert(m_pInput); 145 146 m_MergedGlobalSymbols.clear(); 147 m_InputGlobalSymbols.clear(); 148 m_MergedLocalSymbols.clear(); 149 m_InputLocalSymbols.clear(); 150 } 151 152 void MipsGOT::changeInput() { 153 m_MultipartList.back().m_Inputs.insert(m_pInput); 154 155 for (LocalSymbolSetType::iterator it = m_InputLocalSymbols.begin(), 156 end = m_InputLocalSymbols.end(); 157 it != end; 158 ++it) 159 m_MergedLocalSymbols.insert(*it); 160 161 m_InputLocalSymbols.clear(); 162 163 for (SymbolUniqueMapType::iterator it = m_InputGlobalSymbols.begin(), 164 end = m_InputGlobalSymbols.end(); 165 it != end; 166 ++it) 167 m_MergedGlobalSymbols.insert(it->first); 168 169 m_InputGlobalSymbols.clear(); 170 } 171 172 bool MipsGOT::isGOTFull() const { 173 uint64_t gotCount = MipsGOT0Num + m_MultipartList.back().m_LocalNum + 174 m_MultipartList.back().m_GlobalNum; 175 176 gotCount += 1; 177 178 return gotCount * getEntrySize() > MipsGOTSize; 179 } 180 181 void MipsGOT::split() { 182 m_MergedLocalSymbols.clear(); 183 m_MergedGlobalSymbols.clear(); 184 185 size_t uniqueCount = 0; 186 for (SymbolUniqueMapType::const_iterator it = m_InputGlobalSymbols.begin(), 187 end = m_InputGlobalSymbols.end(); 188 it != end; 189 ++it) { 190 if (it->second) 191 ++uniqueCount; 192 } 193 194 m_MultipartList.back().m_LocalNum -= m_InputLocalSymbols.size(); 195 m_MultipartList.back().m_GlobalNum -= uniqueCount; 196 m_MultipartList.back().m_Inputs.erase(m_pInput); 197 198 m_MultipartList.push_back( 199 GOTMultipart(m_InputLocalSymbols.size(), m_InputGlobalSymbols.size())); 200 m_MultipartList.back().m_Inputs.insert(m_pInput); 201 } 202 203 void MipsGOT::initializeScan(const Input& pInput) { 204 if (m_pInput == NULL) { 205 m_pInput = &pInput; 206 initGOTList(); 207 } else { 208 m_pInput = &pInput; 209 changeInput(); 210 } 211 } 212 213 void MipsGOT::finalizeScan(const Input& pInput) { 214 } 215 216 bool MipsGOT::reserveLocalEntry(ResolveInfo& pInfo, 217 int reloc, 218 Relocation::DWord pAddend) { 219 LocalEntry entry(&pInfo, pAddend, reloc == llvm::ELF::R_MIPS_GOT16); 220 221 if (m_InputLocalSymbols.count(entry)) 222 // Do nothing, if we have seen this symbol 223 // in the current input already. 224 return false; 225 226 if (m_MergedLocalSymbols.count(entry)) { 227 // We have seen this symbol in previous inputs. 228 // Remember that it exists in the current input too. 229 m_InputLocalSymbols.insert(entry); 230 return false; 231 } 232 233 if (isGOTFull()) 234 split(); 235 236 m_InputLocalSymbols.insert(entry); 237 238 ++m_MultipartList.back().m_LocalNum; 239 return true; 240 } 241 242 bool MipsGOT::reserveGlobalEntry(ResolveInfo& pInfo) { 243 if (m_InputGlobalSymbols.count(&pInfo)) 244 return false; 245 246 if (m_MergedGlobalSymbols.count(&pInfo)) { 247 m_InputGlobalSymbols[&pInfo] = false; 248 return false; 249 } 250 251 if (isGOTFull()) 252 split(); 253 254 m_InputGlobalSymbols[&pInfo] = true; 255 ++m_MultipartList.back().m_GlobalNum; 256 257 if (!(pInfo.reserved() & MipsRelocator::ReserveGot)) { 258 m_SymbolOrderMap[pInfo.outSymbol()] = m_SymbolOrderMap.size(); 259 pInfo.setReserved(pInfo.reserved() | MipsRelocator::ReserveGot); 260 } 261 262 return true; 263 } 264 265 bool MipsGOT::isPrimaryGOTConsumed() { 266 return m_CurrentGOTPart > 0; 267 } 268 269 Fragment* MipsGOT::consumeLocal() { 270 assert(m_CurrentGOTPart < m_MultipartList.size() && 271 "GOT number is out of range!"); 272 273 if (m_MultipartList[m_CurrentGOTPart].isConsumed()) 274 ++m_CurrentGOTPart; 275 276 m_MultipartList[m_CurrentGOTPart].consumeLocal(); 277 278 return m_MultipartList[m_CurrentGOTPart].m_pLastLocal; 279 } 280 281 Fragment* MipsGOT::consumeGlobal() { 282 assert(m_CurrentGOTPart < m_MultipartList.size() && 283 "GOT number is out of range!"); 284 285 if (m_MultipartList[m_CurrentGOTPart].isConsumed()) 286 ++m_CurrentGOTPart; 287 288 m_MultipartList[m_CurrentGOTPart].consumeGlobal(); 289 290 return m_MultipartList[m_CurrentGOTPart].m_pLastGlobal; 291 } 292 293 uint64_t MipsGOT::getGPAddr(const Input& pInput) const { 294 uint64_t gotSize = 0; 295 for (MultipartListType::const_iterator it = m_MultipartList.begin(), 296 ie = m_MultipartList.end(); 297 it != ie; 298 ++it) { 299 if (it->m_Inputs.count(&pInput)) 300 break; 301 302 gotSize += (MipsGOT0Num + it->m_LocalNum + it->m_GlobalNum); 303 if (it == m_MultipartList.begin()) 304 gotSize += getGlobalNum() - it->m_GlobalNum; 305 } 306 307 return addr() + gotSize * getEntrySize() + MipsGOTGpOffset; 308 } 309 310 uint64_t MipsGOT::getGPRelOffset(const Input& pInput, 311 const Fragment& pEntry) const { 312 return addr() + pEntry.getOffset() - getGPAddr(pInput); 313 } 314 315 void MipsGOT::recordGlobalEntry(const ResolveInfo* pInfo, Fragment* pEntry) { 316 GotEntryKey key; 317 key.m_GOTPage = m_CurrentGOTPart; 318 key.m_pInfo = pInfo; 319 key.m_Addend = 0; 320 m_GotGlobalEntriesMap[key] = pEntry; 321 } 322 323 Fragment* MipsGOT::lookupGlobalEntry(const ResolveInfo* pInfo) { 324 GotEntryKey key; 325 key.m_GOTPage = m_CurrentGOTPart; 326 key.m_pInfo = pInfo; 327 key.m_Addend = 0; 328 GotEntryMapType::iterator it = m_GotGlobalEntriesMap.find(key); 329 330 if (it == m_GotGlobalEntriesMap.end()) 331 return NULL; 332 333 return it->second; 334 } 335 336 void MipsGOT::recordLocalEntry(const ResolveInfo* pInfo, 337 Relocation::DWord pAddend, 338 Fragment* pEntry) { 339 GotEntryKey key; 340 key.m_GOTPage = m_CurrentGOTPart; 341 key.m_pInfo = pInfo; 342 key.m_Addend = pAddend; 343 m_GotLocalEntriesMap[key] = pEntry; 344 } 345 346 Fragment* MipsGOT::lookupLocalEntry(const ResolveInfo* pInfo, 347 Relocation::DWord pAddend) { 348 GotEntryKey key; 349 key.m_GOTPage = m_CurrentGOTPart; 350 key.m_pInfo = pInfo; 351 key.m_Addend = pAddend; 352 GotEntryMapType::iterator it = m_GotLocalEntriesMap.find(key); 353 354 if (it == m_GotLocalEntriesMap.end()) 355 return NULL; 356 357 return it->second; 358 } 359 360 size_t MipsGOT::getLocalNum() const { 361 assert(!m_MultipartList.empty() && "GOT is empty!"); 362 return m_MultipartList[0].m_LocalNum + MipsGOT0Num; 363 } 364 365 size_t MipsGOT::getGlobalNum() const { 366 return m_SymbolOrderMap.size(); 367 } 368 369 //===----------------------------------------------------------------------===// 370 // Mips32GOT 371 //===----------------------------------------------------------------------===// 372 Mips32GOT::Mips32GOT(LDSection& pSection) : MipsGOT(pSection) { 373 } 374 375 void Mips32GOT::setEntryValue(Fragment* entry, uint64_t pValue) { 376 llvm::cast<Mips32GOTEntry>(entry)->setValue(pValue); 377 } 378 379 uint64_t Mips32GOT::emit(MemoryRegion& pRegion) { 380 uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.begin()); 381 382 uint64_t result = 0; 383 for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) { 384 Mips32GOTEntry* got = &(llvm::cast<Mips32GOTEntry>((*it))); 385 *buffer = static_cast<uint32_t>(got->getValue()); 386 result += got->size(); 387 } 388 return result; 389 } 390 391 Fragment* Mips32GOT::createEntry(uint64_t pValue, SectionData* pParent) { 392 return new Mips32GOTEntry(pValue, pParent); 393 } 394 395 size_t Mips32GOT::getEntrySize() const { 396 return Mips32GOTEntry::EntrySize; 397 } 398 399 void Mips32GOT::reserveHeader() { 400 createEntry(0, m_SectionData); 401 createEntry(Mips32ModulePtr, m_SectionData); 402 } 403 404 //===----------------------------------------------------------------------===// 405 // Mips64GOT 406 //===----------------------------------------------------------------------===// 407 Mips64GOT::Mips64GOT(LDSection& pSection) : MipsGOT(pSection) { 408 } 409 410 void Mips64GOT::setEntryValue(Fragment* entry, uint64_t pValue) { 411 llvm::cast<Mips64GOTEntry>(entry)->setValue(pValue); 412 } 413 414 uint64_t Mips64GOT::emit(MemoryRegion& pRegion) { 415 uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.begin()); 416 417 uint64_t result = 0; 418 for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) { 419 Mips64GOTEntry* got = &(llvm::cast<Mips64GOTEntry>((*it))); 420 *buffer = static_cast<uint64_t>(got->getValue()); 421 result += got->size(); 422 } 423 return result; 424 } 425 426 Fragment* Mips64GOT::createEntry(uint64_t pValue, SectionData* pParent) { 427 return new Mips64GOTEntry(pValue, pParent); 428 } 429 430 size_t Mips64GOT::getEntrySize() const { 431 return Mips64GOTEntry::EntrySize; 432 } 433 434 void Mips64GOT::reserveHeader() { 435 createEntry(0, m_SectionData); 436 createEntry(Mips64ModulePtr, m_SectionData); 437 } 438 439 } // namespace mcld 440