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_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