Home | History | Annotate | Download | only in Mips
      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