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/MemoryRegion.h>
     15 #include <mcld/Support/MsgHandling.h>
     16 #include <mcld/Target/OutputRelocSection.h>
     17 
     18 #include "MipsGOT.h"
     19 #include "MipsRelocator.h"
     20 
     21 namespace {
     22   const size_t MipsGOT0Num = 1;
     23   const size_t MipsGOTGpOffset = 0x7FF0;
     24   const size_t MipsGOTSize = MipsGOTGpOffset + 0x7FFF;
     25 }
     26 
     27 using namespace mcld;
     28 
     29 //===----------------------------------------------------------------------===//
     30 // MipsGOTEntry
     31 //===----------------------------------------------------------------------===//
     32 MipsGOTEntry::MipsGOTEntry(uint64_t pContent, SectionData* pParent)
     33    : GOT::Entry<4>(pContent, pParent)
     34 {}
     35 
     36 //===----------------------------------------------------------------------===//
     37 // MipsGOT::GOTMultipart
     38 //===----------------------------------------------------------------------===//
     39 MipsGOT::GOTMultipart::GOTMultipart(size_t local, size_t global)
     40   : m_LocalNum(local),
     41     m_GlobalNum(global),
     42     m_ConsumedLocal(0),
     43     m_ConsumedGlobal(0),
     44     m_pLastLocal(NULL),
     45     m_pLastGlobal(NULL)
     46 {
     47 }
     48 
     49 bool MipsGOT::GOTMultipart::isConsumed() const
     50 {
     51   return m_LocalNum == m_ConsumedLocal &&
     52          m_GlobalNum == m_ConsumedGlobal;
     53 }
     54 
     55 void MipsGOT::GOTMultipart::consumeLocal()
     56 {
     57   assert(m_ConsumedLocal < m_LocalNum &&
     58          "Consumed too many local GOT entries");
     59   ++m_ConsumedLocal;
     60   m_pLastLocal = llvm::cast<MipsGOTEntry>(m_pLastLocal->getNextNode());
     61 }
     62 
     63 void MipsGOT::GOTMultipart::consumeGlobal()
     64 {
     65   assert(m_ConsumedGlobal < m_GlobalNum &&
     66          "Consumed too many global GOT entries");
     67   ++m_ConsumedGlobal;
     68   m_pLastGlobal = llvm::cast<MipsGOTEntry>(m_pLastGlobal->getNextNode());
     69 }
     70 
     71 //===----------------------------------------------------------------------===//
     72 // MipsGOT
     73 //===----------------------------------------------------------------------===//
     74 MipsGOT::MipsGOT(LDSection& pSection)
     75   : GOT(pSection),
     76     m_pInput(NULL),
     77     m_CurrentGOTPart(0)
     78 {
     79 }
     80 
     81 SizeTraits<32>::Address MipsGOT::getGPDispAddress() const
     82 {
     83   return addr() + MipsGOTGpOffset;
     84 }
     85 
     86 void MipsGOT::reserve(size_t pNum)
     87 {
     88   for (size_t i = 0; i < pNum; i++) {
     89     new MipsGOTEntry(0, m_SectionData);
     90   }
     91 }
     92 
     93 bool MipsGOT::hasGOT1() const
     94 {
     95   return !m_MultipartList.empty();
     96 }
     97 
     98 bool MipsGOT::hasMultipleGOT() const
     99 {
    100   return m_MultipartList.size() > 1;
    101 }
    102 
    103 void MipsGOT::finalizeScanning(OutputRelocSection& pRelDyn)
    104 {
    105   for (MultipartListType::iterator it = m_MultipartList.begin();
    106        it != m_MultipartList.end(); ++it) {
    107     reserve(MipsGOT0Num);
    108     it->m_pLastLocal = llvm::cast<MipsGOTEntry>(&m_SectionData->back());
    109     reserve(it->m_LocalNum);
    110     it->m_pLastGlobal = llvm::cast<MipsGOTEntry>(&m_SectionData->back());
    111     reserve(it->m_GlobalNum);
    112 
    113     if (it == m_MultipartList.begin())
    114       // Reserve entries in the second part of the primary GOT.
    115       // These entries correspond to the global symbols in all
    116       // non-primary GOTs.
    117       reserve(getGlobalNum() - it->m_GlobalNum);
    118     else {
    119       // Reserve reldyn entries for R_MIPS_REL32 relocations
    120       // for all global entries of secondary GOTs.
    121       // FIXME: (simon) Do not count local entries for non-pic.
    122       size_t count = it->m_GlobalNum + it->m_LocalNum;
    123       for (size_t i = 0; i < count; ++i)
    124         pRelDyn.reserveEntry();
    125     }
    126   }
    127 }
    128 
    129 bool MipsGOT::dynSymOrderCompare(const LDSymbol* pX, const LDSymbol* pY) const
    130 {
    131   SymbolOrderMapType::const_iterator itX = m_SymbolOrderMap.find(pX);
    132   SymbolOrderMapType::const_iterator itY = m_SymbolOrderMap.find(pY);
    133 
    134   if (itX != m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end())
    135     return itX->second < itY->second;
    136 
    137   return itX == m_SymbolOrderMap.end() && itY != m_SymbolOrderMap.end();
    138 }
    139 
    140 uint64_t MipsGOT::emit(MemoryRegion& pRegion)
    141 {
    142   uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
    143 
    144   uint64_t result = 0;
    145   for (iterator it = begin(), ie = end();
    146        it != ie; ++it, ++buffer) {
    147     MipsGOTEntry* got = &(llvm::cast<MipsGOTEntry>((*it)));
    148     *buffer = static_cast<uint32_t>(got->getValue());
    149     result += got->size();
    150   }
    151   return result;
    152 }
    153 
    154 void MipsGOT::initGOTList()
    155 {
    156   m_SymbolOrderMap.clear();
    157 
    158   m_MultipartList.clear();
    159   m_MultipartList.push_back(GOTMultipart());
    160 
    161   m_MultipartList.back().m_Inputs.insert(m_pInput);
    162 
    163   m_MergedGlobalSymbols.clear();
    164   m_InputGlobalSymbols.clear();
    165   m_MergedLocalSymbols.clear();
    166   m_InputLocalSymbols.clear();
    167 }
    168 
    169 void MipsGOT::changeInput()
    170 {
    171   m_MultipartList.back().m_Inputs.insert(m_pInput);
    172 
    173   for (SymbolSetType::iterator it = m_InputLocalSymbols.begin(),
    174                                end = m_InputLocalSymbols.end();
    175        it != end; ++it)
    176     m_MergedLocalSymbols.insert(*it);
    177 
    178   m_InputLocalSymbols.clear();
    179 
    180   for (SymbolUniqueMapType::iterator it = m_InputGlobalSymbols.begin(),
    181                                      end = m_InputGlobalSymbols.end();
    182        it != end; ++it)
    183     m_MergedGlobalSymbols.insert(it->first);
    184 
    185   m_InputGlobalSymbols.clear();
    186 }
    187 
    188 bool MipsGOT::isGOTFull() const
    189 {
    190   uint64_t gotCount = MipsGOT0Num +
    191                       m_MultipartList.back().m_LocalNum +
    192                       m_MultipartList.back().m_GlobalNum;
    193 
    194   gotCount += 1;
    195 
    196   return (gotCount * mcld::MipsGOTEntry::EntrySize) > MipsGOTSize;
    197 }
    198 
    199 void MipsGOT::split()
    200 {
    201   m_MergedLocalSymbols.clear();
    202   m_MergedGlobalSymbols.clear();
    203 
    204   size_t uniqueCount = 0;
    205   for (SymbolUniqueMapType::const_iterator it = m_InputGlobalSymbols.begin(),
    206                                            end = m_InputGlobalSymbols.end();
    207        it != end; ++it) {
    208     if (it->second)
    209       ++uniqueCount;
    210   }
    211 
    212   m_MultipartList.back().m_LocalNum -= m_InputLocalSymbols.size();
    213   m_MultipartList.back().m_GlobalNum -= uniqueCount;
    214   m_MultipartList.back().m_Inputs.erase(m_pInput);
    215 
    216   m_MultipartList.push_back(GOTMultipart(m_InputLocalSymbols.size(),
    217                                          m_InputGlobalSymbols.size()));
    218   m_MultipartList.back().m_Inputs.insert(m_pInput);
    219 }
    220 
    221 void MipsGOT::initializeScan(const Input& pInput)
    222 {
    223   if (m_pInput == NULL) {
    224     m_pInput = &pInput;
    225     initGOTList();
    226   }
    227   else {
    228     m_pInput = &pInput;
    229     changeInput();
    230   }
    231 }
    232 
    233 void MipsGOT::finalizeScan(const Input& pInput)
    234 {
    235 }
    236 
    237 bool MipsGOT::reserveLocalEntry(ResolveInfo& pInfo)
    238 {
    239   if (pInfo.type() != ResolveInfo::Section) {
    240     if (m_InputLocalSymbols.count(&pInfo))
    241       return false;
    242 
    243     if (m_MergedLocalSymbols.count(&pInfo)) {
    244       m_InputLocalSymbols.insert(&pInfo);
    245       return false;
    246     }
    247   }
    248 
    249   if (isGOTFull())
    250     split();
    251 
    252   if (pInfo.type() != ResolveInfo::Section)
    253     m_InputLocalSymbols.insert(&pInfo);
    254 
    255   ++m_MultipartList.back().m_LocalNum;
    256   return true;
    257 }
    258 
    259 bool MipsGOT::reserveGlobalEntry(ResolveInfo& pInfo)
    260 {
    261   if (m_InputGlobalSymbols.count(&pInfo))
    262     return false;
    263 
    264   if (m_MergedGlobalSymbols.count(&pInfo)) {
    265     m_InputGlobalSymbols[&pInfo] = false;
    266     return false;
    267   }
    268 
    269   if (isGOTFull())
    270     split();
    271 
    272   m_InputGlobalSymbols[&pInfo] = true;
    273   ++m_MultipartList.back().m_GlobalNum;
    274 
    275   if (!(pInfo.reserved() & MipsRelocator::ReserveGot)) {
    276     m_SymbolOrderMap[pInfo.outSymbol()] = m_SymbolOrderMap.size();
    277     pInfo.setReserved(pInfo.reserved() | MipsRelocator::ReserveGot);
    278   }
    279 
    280   return true;
    281 }
    282 
    283 bool MipsGOT::isPrimaryGOTConsumed()
    284 {
    285   return m_CurrentGOTPart > 0;
    286 }
    287 
    288 MipsGOTEntry* MipsGOT::consumeLocal()
    289 {
    290   assert(m_CurrentGOTPart < m_MultipartList.size() && "GOT number is out of range!");
    291 
    292   if (m_MultipartList[m_CurrentGOTPart].isConsumed())
    293     ++m_CurrentGOTPart;
    294 
    295   m_MultipartList[m_CurrentGOTPart].consumeLocal();
    296 
    297   return m_MultipartList[m_CurrentGOTPart].m_pLastLocal;
    298 }
    299 
    300 MipsGOTEntry* MipsGOT::consumeGlobal()
    301 {
    302   assert(m_CurrentGOTPart < m_MultipartList.size() && "GOT number is out of range!");
    303 
    304   if (m_MultipartList[m_CurrentGOTPart].isConsumed())
    305     ++m_CurrentGOTPart;
    306 
    307   m_MultipartList[m_CurrentGOTPart].consumeGlobal();
    308 
    309   return m_MultipartList[m_CurrentGOTPart].m_pLastGlobal;
    310 }
    311 
    312 SizeTraits<32>::Address MipsGOT::getGPAddr(const Input& pInput) const
    313 {
    314   uint64_t gotSize = 0;
    315   for (MultipartListType::const_iterator it = m_MultipartList.begin();
    316                                          it != m_MultipartList.end(); ++it) {
    317     if (it->m_Inputs.count(&pInput))
    318       break;
    319 
    320     gotSize += (MipsGOT0Num + it->m_LocalNum + it->m_GlobalNum);
    321     if (it == m_MultipartList.begin())
    322       gotSize += getGlobalNum() - it->m_GlobalNum;
    323   }
    324 
    325   return addr() + gotSize * MipsGOTEntry::EntrySize + MipsGOTGpOffset;
    326 }
    327 
    328 SizeTraits<32>::Offset MipsGOT::getGPRelOffset(const Input& pInput,
    329                                                const MipsGOTEntry& pEntry) const
    330 {
    331   SizeTraits<32>::Address gpAddr = getGPAddr(pInput);
    332   return addr() + pEntry.getOffset() - gpAddr;
    333 }
    334 
    335 void MipsGOT::recordEntry(const ResolveInfo* pInfo, MipsGOTEntry* pEntry)
    336 {
    337   GotEntryKey key;
    338   key.m_GOTPage = m_CurrentGOTPart;
    339   key.m_pInfo = pInfo;
    340   m_GotEntriesMap[key] = pEntry;
    341 }
    342 
    343 MipsGOTEntry* MipsGOT::lookupEntry(const ResolveInfo* pInfo)
    344 {
    345   GotEntryKey key;
    346   key.m_GOTPage= m_CurrentGOTPart;
    347   key.m_pInfo = pInfo;
    348   GotEntryMapType::iterator it = m_GotEntriesMap.find(key);
    349 
    350   if (it == m_GotEntriesMap.end())
    351     return NULL;
    352 
    353   return it->second;
    354 }
    355 
    356 size_t MipsGOT::getLocalNum() const
    357 {
    358   assert(!m_MultipartList.empty() && "GOT is empty!");
    359   return m_MultipartList[0].m_LocalNum + MipsGOT0Num;
    360 }
    361 
    362 size_t MipsGOT::getGlobalNum() const
    363 {
    364   return m_SymbolOrderMap.size();
    365 }
    366