1 //===- impl.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 #include "ARMGOT.h" 10 11 #include <llvm/Support/Casting.h> 12 13 #include <mcld/LD/LDSection.h> 14 #include <mcld/LD/LDFileFormat.h> 15 #include <mcld/Support/MemoryRegion.h> 16 #include <mcld/Support/MsgHandling.h> 17 18 namespace { 19 const unsigned int ARMGOT0Num = 3; 20 } // end of anonymous namespace 21 22 using namespace mcld; 23 24 //===----------------------------------------------------------------------===// 25 // ARMGOT 26 ARMGOT::ARMGOT(LDSection& pSection) 27 : GOT(pSection), m_pLast(NULL) 28 { 29 // Create GOT0 entries. 30 reserve(ARMGOT0Num); 31 32 // Skip GOT0 entries. 33 for (unsigned int i = 0; i < ARMGOT0Num; ++i) { 34 consume(); 35 } 36 } 37 38 ARMGOT::~ARMGOT() 39 { 40 } 41 42 bool ARMGOT::hasGOT1() const 43 { 44 return (m_SectionData->size() > ARMGOT0Num); 45 } 46 47 void ARMGOT::reserve(size_t pNum) 48 { 49 for (size_t i = 0; i < pNum; i++) { 50 new ARMGOTEntry(0, m_SectionData); 51 } 52 } 53 54 ARMGOTEntry* ARMGOT::consume() 55 { 56 if (NULL == m_pLast) { 57 assert(!empty() && "Consume empty GOT entry!"); 58 m_pLast = llvm::cast<ARMGOTEntry>(&m_SectionData->front()); 59 return m_pLast; 60 } 61 62 m_pLast = llvm::cast<ARMGOTEntry>(m_pLast->getNextNode()); 63 return m_pLast; 64 } 65 66 void ARMGOT::reserveGOTPLT() 67 { 68 ARMGOTEntry* entry = new ARMGOTEntry(0, m_SectionData); 69 if (NULL == m_GOTPLT.front) { 70 // GOTPLT is empty 71 if (NULL == m_GOT.front) { 72 // GOT part is also empty. Since entry is the last entry, we can assign 73 // it to GOTPLT directly. 74 m_GOTPLT.front = entry; 75 } 76 else { 77 // GOTn is not empty. Shift GOTn backward by one entry. 78 m_GOTPLT.front = m_GOT.front; 79 m_GOT.front = llvm::cast<ARMGOTEntry>(m_GOT.front->getNextNode()); 80 } 81 } 82 else { 83 // GOTPLT is not empty 84 if (NULL != m_GOT.front) 85 m_GOT.front = llvm::cast<ARMGOTEntry>(m_GOT.front->getNextNode()); 86 } 87 } 88 89 void ARMGOT::reserveGOT() 90 { 91 ARMGOTEntry* entry = new ARMGOTEntry(0, m_SectionData); 92 if (NULL == m_GOT.front) { 93 // Entry must be the last entry. We can directly assign it to GOT part. 94 m_GOT.front = entry; 95 } 96 } 97 98 ARMGOTEntry* ARMGOT::consumeGOTPLT() 99 { 100 assert(NULL != m_GOTPLT.front && "Consuming empty GOTPLT section!"); 101 102 if (NULL == m_GOTPLT.last_used) { 103 m_GOTPLT.last_used = m_GOTPLT.front; 104 } 105 else { 106 m_GOTPLT.last_used = llvm::cast<ARMGOTEntry>(m_GOTPLT.last_used->getNextNode()); 107 assert(m_GOTPLT.last_used != m_GOT.front && "No GOT/PLT entry to consume!"); 108 } 109 return m_GOTPLT.last_used; 110 } 111 112 ARMGOTEntry* ARMGOT::consumeGOT() 113 { 114 assert(NULL != m_GOT.front && "Consuming empty GOT section!"); 115 116 if (NULL == m_GOT.last_used) { 117 m_GOT.last_used = m_GOT.front; 118 } 119 else { 120 m_GOT.last_used = llvm::cast<ARMGOTEntry>(m_GOT.last_used->getNextNode()); 121 assert(m_GOT.last_used != NULL && "No GOTn entry to consume!"); 122 } 123 return m_GOT.last_used; 124 } 125 126 void ARMGOT::applyGOT0(uint64_t pAddress) 127 { 128 llvm::cast<ARMGOTEntry> 129 (*(m_SectionData->getFragmentList().begin())).setValue(pAddress); 130 } 131 132 void ARMGOT::applyGOTPLT(uint64_t pPLTBase) 133 { 134 if (NULL == m_GOTPLT.front) 135 return; 136 137 SectionData::iterator entry(m_GOTPLT.front); 138 SectionData::iterator e_end; 139 if (NULL == m_GOT.front) 140 e_end = m_SectionData->end(); 141 else 142 e_end = SectionData::iterator(m_GOT.front); 143 144 while (entry != e_end) { 145 llvm::cast<ARMGOTEntry>(entry)->setValue(pPLTBase); 146 ++entry; 147 } 148 } 149 150 uint64_t ARMGOT::emit(MemoryRegion& pRegion) 151 { 152 uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer()); 153 154 ARMGOTEntry* got = NULL; 155 uint64_t result = 0x0; 156 for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) { 157 got = &(llvm::cast<ARMGOTEntry>((*it))); 158 *buffer = static_cast<uint32_t>(got->getValue()); 159 result += ARMGOTEntry::EntrySize; 160 } 161 return result; 162 } 163 164