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