1 //===- ARMPLT.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 #include "ARMPLT.h" 11 12 #include <new> 13 14 #include <llvm/Support/Casting.h> 15 16 #include <mcld/LD/LDSection.h> 17 #include <mcld/Support/MemoryRegion.h> 18 #include <mcld/Support/MsgHandling.h> 19 20 using namespace mcld; 21 22 ARMPLT0::ARMPLT0(SectionData& pParent) 23 : PLT::Entry<sizeof(arm_plt0)>(pParent) {} 24 25 ARMPLT1::ARMPLT1(SectionData& pParent) 26 : PLT::Entry<sizeof(arm_plt1)>(pParent) {} 27 28 //===----------------------------------------------------------------------===// 29 // ARMPLT 30 31 ARMPLT::ARMPLT(LDSection& pSection, 32 ARMGOT &pGOTPLT) 33 : PLT(pSection), m_GOT(pGOTPLT), m_PLTEntryIterator() { 34 new ARMPLT0(*m_SectionData); 35 m_PLTEntryIterator = m_SectionData->begin(); 36 } 37 38 ARMPLT::~ARMPLT() 39 { 40 } 41 42 bool ARMPLT::hasPLT1() const 43 { 44 return (m_SectionData->size() > 1); 45 } 46 47 void ARMPLT::finalizeSectionSize() 48 { 49 uint64_t size = (m_SectionData->size() - 1) * sizeof(arm_plt1) + 50 sizeof(arm_plt0); 51 m_Section.setSize(size); 52 53 uint32_t offset = 0; 54 SectionData::iterator frag, fragEnd = m_SectionData->end(); 55 for (frag = m_SectionData->begin(); frag != fragEnd; ++frag) { 56 frag->setOffset(offset); 57 offset += frag->size(); 58 } 59 } 60 61 void ARMPLT::reserveEntry(size_t pNum) 62 { 63 ARMPLT1* plt1_entry = 0; 64 65 for (size_t i = 0; i < pNum; ++i) { 66 plt1_entry = new (std::nothrow) ARMPLT1(*m_SectionData); 67 68 if (!plt1_entry) 69 fatal(diag::fail_allocate_memory_plt); 70 71 m_GOT.reserveGOTPLT(); 72 } 73 } 74 75 ARMPLT1* ARMPLT::consume() 76 { 77 ++m_PLTEntryIterator; 78 assert(m_PLTEntryIterator != m_SectionData->end() && 79 "The number of PLT Entries and ResolveInfo doesn't match"); 80 81 return llvm::cast<ARMPLT1>(&(*m_PLTEntryIterator)); 82 } 83 84 ARMPLT0* ARMPLT::getPLT0() const { 85 86 iterator first = m_SectionData->getFragmentList().begin(); 87 88 assert(first != m_SectionData->getFragmentList().end() && 89 "FragmentList is empty, getPLT0 failed!"); 90 91 ARMPLT0* plt0 = &(llvm::cast<ARMPLT0>(*first)); 92 93 return plt0; 94 } 95 96 void ARMPLT::applyPLT0() { 97 98 uint64_t plt_base = m_Section.addr(); 99 assert(plt_base && ".plt base address is NULL!"); 100 101 uint64_t got_base = m_GOT.addr(); 102 assert(got_base && ".got base address is NULL!"); 103 104 uint32_t offset = 0; 105 106 if (got_base > plt_base) 107 offset = got_base - (plt_base + 16); 108 else 109 offset = (plt_base + 16) - got_base; 110 111 iterator first = m_SectionData->getFragmentList().begin(); 112 113 assert(first != m_SectionData->getFragmentList().end() && 114 "FragmentList is empty, applyPLT0 failed!"); 115 116 ARMPLT0* plt0 = &(llvm::cast<ARMPLT0>(*first)); 117 118 uint32_t* data = 0; 119 data = static_cast<uint32_t*>(malloc(ARMPLT0::EntrySize)); 120 121 if (!data) 122 fatal(diag::fail_allocate_memory_plt); 123 124 memcpy(data, arm_plt0, ARMPLT0::EntrySize); 125 data[4] = offset; 126 127 plt0->setValue(reinterpret_cast<unsigned char*>(data)); 128 } 129 130 void ARMPLT::applyPLT1() { 131 132 uint64_t plt_base = m_Section.addr(); 133 assert(plt_base && ".plt base address is NULL!"); 134 135 uint64_t got_base = m_GOT.addr(); 136 assert(got_base && ".got base address is NULL!"); 137 138 ARMPLT::iterator it = m_SectionData->begin(); 139 ARMPLT::iterator ie = m_SectionData->end(); 140 assert(it != ie && "FragmentList is empty, applyPLT1 failed!"); 141 142 uint32_t GOTEntrySize = ARMGOTEntry::EntrySize; 143 uint32_t GOTEntryAddress = 144 got_base + GOTEntrySize * 3; 145 146 uint64_t PLTEntryAddress = 147 plt_base + ARMPLT0::EntrySize; //Offset of PLT0 148 149 ++it; //skip PLT0 150 uint64_t PLT1EntrySize = ARMPLT1::EntrySize; 151 ARMPLT1* plt1 = NULL; 152 153 uint32_t* Out = NULL; 154 while (it != ie) { 155 plt1 = &(llvm::cast<ARMPLT1>(*it)); 156 Out = static_cast<uint32_t*>(malloc(ARMPLT1::EntrySize)); 157 158 if (!Out) 159 fatal(diag::fail_allocate_memory_plt); 160 161 // Offset is the distance between the last PLT entry and the associated 162 // GOT entry. 163 int32_t Offset = (GOTEntryAddress - (PLTEntryAddress + 8)); 164 165 Out[0] = arm_plt1[0] | ((Offset >> 20) & 0xFF); 166 Out[1] = arm_plt1[1] | ((Offset >> 12) & 0xFF); 167 Out[2] = arm_plt1[2] | (Offset & 0xFFF); 168 169 plt1->setValue(reinterpret_cast<unsigned char*>(Out)); 170 ++it; 171 172 GOTEntryAddress += GOTEntrySize; 173 PLTEntryAddress += PLT1EntrySize; 174 } 175 176 m_GOT.applyGOTPLT(plt_base); 177 } 178 179 uint64_t ARMPLT::emit(MemoryRegion& pRegion) 180 { 181 uint64_t result = 0x0; 182 iterator it = begin(); 183 184 unsigned char* buffer = pRegion.getBuffer(); 185 memcpy(buffer, llvm::cast<ARMPLT0>((*it)).getValue(), ARMPLT0::EntrySize); 186 result += ARMPLT0::EntrySize; 187 ++it; 188 189 ARMPLT1* plt1 = 0; 190 ARMPLT::iterator ie = end(); 191 while (it != ie) { 192 plt1 = &(llvm::cast<ARMPLT1>(*it)); 193 memcpy(buffer + result, plt1->getValue(), ARMPLT1::EntrySize); 194 result += ARMPLT1::EntrySize; 195 ++it; 196 } 197 return result; 198 } 199 200