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