MipsPLT.cpp revision 37b74a387bb3993387029859c2d9d051c41c724e
1//===- MipsPLT.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 <llvm/Support/Casting.h> 10#include <llvm/Support/ELF.h> 11#include "mcld/Support/MsgHandling.h" 12#include "MipsGOTPLT.h" 13#include "MipsPLT.h" 14 15namespace { 16 17const uint32_t PLT0[] = { 18 0x3c1c0000, // lui $28, %hi(&GOTPLT[0]) 19 0x8f990000, // lw $25, %lo(&GOTPLT[0])($28) 20 0x279c0000, // addiu $28, $28, %lo(&GOTPLT[0]) 21 0x031cc023, // subu $24, $24, $28 22 0x03e07821, // move $15, $31 23 0x0018c082, // srl $24, $24, 2 24 0x0320f809, // jalr $25 25 0x2718fffe // subu $24, $24, 2 26}; 27 28const uint32_t PLTA[] = { 29 0x3c0f0000, // lui $15, %hi(.got.plt entry) 30 0x8df90000, // l[wd] $25, %lo(.got.plt entry)($15) 31 0x03200008, // jr $25 32 0x25f80000 // addiu $24, $15, %lo(.got.plt entry) 33}; 34 35} // anonymous namespace 36 37namespace mcld { 38 39//===----------------------------------------------------------------------===// 40// MipsPLT0 Entry 41//===----------------------------------------------------------------------===// 42class MipsPLT0 : public PLT::Entry<sizeof(PLT0)> { 43 public: 44 MipsPLT0(SectionData& pParent) : PLT::Entry<sizeof(PLT0)>(pParent) {} 45}; 46 47//===----------------------------------------------------------------------===// 48// MipsPLTA Entry 49//===----------------------------------------------------------------------===// 50class MipsPLTA : public PLT::Entry<sizeof(PLTA)> { 51 public: 52 MipsPLTA(SectionData& pParent) : PLT::Entry<sizeof(PLTA)>(pParent) {} 53}; 54 55//===----------------------------------------------------------------------===// 56// MipsPLT 57//===----------------------------------------------------------------------===// 58MipsPLT::MipsPLT(LDSection& pSection) : PLT(pSection) { 59 new MipsPLT0(*m_pSectionData); 60 m_Last = m_pSectionData->begin(); 61} 62 63void MipsPLT::finalizeSectionSize() { 64 uint64_t size = sizeof(PLT0) + (m_pSectionData->size() - 1) * sizeof(PLTA); 65 m_Section.setSize(size); 66 67 uint32_t offset = 0; 68 SectionData::iterator frag, fragEnd = m_pSectionData->end(); 69 for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) { 70 frag->setOffset(offset); 71 offset += frag->size(); 72 } 73} 74 75bool MipsPLT::hasPLT1() const { 76 return m_pSectionData->size() > 1; 77} 78 79uint64_t MipsPLT::emit(MemoryRegion& pRegion) { 80 uint64_t result = 0x0; 81 iterator it = begin(); 82 83 unsigned char* buffer = pRegion.begin(); 84 memcpy(buffer, llvm::cast<MipsPLT0>((*it)).getValue(), MipsPLT0::EntrySize); 85 result += MipsPLT0::EntrySize; 86 ++it; 87 88 MipsPLTA* plta = 0; 89 for (iterator ie = end(); it != ie; ++it) { 90 plta = &(llvm::cast<MipsPLTA>(*it)); 91 memcpy(buffer + result, plta->getValue(), MipsPLTA::EntrySize); 92 result += MipsPLTA::EntrySize; 93 } 94 return result; 95} 96 97void MipsPLT::reserveEntry(size_t pNum) { 98 for (size_t i = 0; i < pNum; ++i) { 99 Fragment* entry = new (std::nothrow) MipsPLTA(*m_pSectionData); 100 101 if (entry == NULL) 102 fatal(diag::fail_allocate_memory_plt); 103 } 104} 105 106Fragment* MipsPLT::consume() { 107 ++m_Last; 108 assert(m_Last != m_pSectionData->end() && 109 "The number of PLT Entries and ResolveInfo doesn't match"); 110 return &(*m_Last); 111} 112 113void MipsPLT::applyAllPLT(MipsGOTPLT& pGOTPLT) { 114 assert(m_Section.addr() && ".plt base address is NULL!"); 115 116 size_t count = 0; 117 for (iterator it = m_pSectionData->begin(); it != m_pSectionData->end(); 118 ++it) { 119 PLTEntryBase* plt = &(llvm::cast<PLTEntryBase>(*it)); 120 121 if (it == m_pSectionData->begin()) { 122 uint32_t* data = static_cast<uint32_t*>(malloc(plt->size())); 123 124 if (!data) 125 fatal(diag::fail_allocate_memory_plt); 126 127 memcpy(data, PLT0, plt->size()); 128 129 uint64_t gotAddr = pGOTPLT.addr(); 130 131 data[0] |= ((gotAddr + 0x8000) >> 16) & 0xffff; 132 data[1] |= gotAddr & 0xffff; 133 data[2] |= gotAddr & 0xffff; 134 135 plt->setValue(reinterpret_cast<unsigned char*>(data)); 136 } else { 137 uint32_t* data = static_cast<uint32_t*>(malloc(plt->size())); 138 139 if (!data) 140 fatal(diag::fail_allocate_memory_plt); 141 142 memcpy(data, PLTA, plt->size()); 143 144 uint64_t gotEntryAddr = pGOTPLT.getEntryAddr(count++); 145 146 data[0] |= ((gotEntryAddr + 0x8000) >> 16) & 0xffff; 147 data[1] |= gotEntryAddr & 0xffff; 148 data[3] |= gotEntryAddr & 0xffff; 149 150 plt->setValue(reinterpret_cast<unsigned char*>(data)); 151 } 152 } 153} 154 155} // namespace mcld 156