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