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