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 15 namespace { 16 17 const 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 28 const 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 37 namespace mcld { 38 39 //===----------------------------------------------------------------------===// 40 // MipsPLT0 Entry 41 //===----------------------------------------------------------------------===// 42 class MipsPLT0 : public PLT::Entry<sizeof(PLT0)> { 43 public: 44 MipsPLT0(SectionData& pParent) : PLT::Entry<sizeof(PLT0)>(pParent) {} 45 }; 46 47 //===----------------------------------------------------------------------===// 48 // MipsPLTA Entry 49 //===----------------------------------------------------------------------===// 50 class MipsPLTA : public PLT::Entry<sizeof(PLTA)> { 51 public: 52 MipsPLTA(SectionData& pParent) : PLT::Entry<sizeof(PLTA)>(pParent) {} 53 }; 54 55 //===----------------------------------------------------------------------===// 56 // MipsPLT 57 //===----------------------------------------------------------------------===// 58 MipsPLT::MipsPLT(LDSection& pSection) : PLT(pSection) { 59 new MipsPLT0(*m_pSectionData); 60 } 61 62 void MipsPLT::finalizeSectionSize() { 63 uint64_t size = sizeof(PLT0) + (m_pSectionData->size() - 1) * sizeof(PLTA); 64 m_Section.setSize(size); 65 66 uint32_t offset = 0; 67 SectionData::iterator frag, fragEnd = m_pSectionData->end(); 68 for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) { 69 frag->setOffset(offset); 70 offset += frag->size(); 71 } 72 } 73 74 bool MipsPLT::hasPLT1() const { 75 return m_pSectionData->size() > 1; 76 } 77 78 uint64_t MipsPLT::emit(MemoryRegion& pRegion) { 79 uint64_t result = 0x0; 80 iterator it = begin(); 81 82 unsigned char* buffer = pRegion.begin(); 83 memcpy(buffer, llvm::cast<MipsPLT0>((*it)).getValue(), MipsPLT0::EntrySize); 84 result += MipsPLT0::EntrySize; 85 ++it; 86 87 MipsPLTA* plta = 0; 88 for (iterator ie = end(); it != ie; ++it) { 89 plta = &(llvm::cast<MipsPLTA>(*it)); 90 memcpy(buffer + result, plta->getValue(), MipsPLTA::EntrySize); 91 result += MipsPLTA::EntrySize; 92 } 93 return result; 94 } 95 96 PLTEntryBase* MipsPLT::create() { 97 return new MipsPLTA(*m_pSectionData); 98 } 99 100 void MipsPLT::applyAllPLT(MipsGOTPLT& pGOTPLT) { 101 assert(m_Section.addr() && ".plt base address is NULL!"); 102 103 size_t count = 0; 104 for (iterator it = m_pSectionData->begin(); it != m_pSectionData->end(); 105 ++it) { 106 PLTEntryBase* plt = &(llvm::cast<PLTEntryBase>(*it)); 107 108 if (it == m_pSectionData->begin()) { 109 uint32_t* data = static_cast<uint32_t*>(malloc(plt->size())); 110 111 if (!data) 112 fatal(diag::fail_allocate_memory_plt); 113 114 memcpy(data, PLT0, plt->size()); 115 116 uint64_t gotAddr = pGOTPLT.addr(); 117 118 data[0] |= ((gotAddr + 0x8000) >> 16) & 0xffff; 119 data[1] |= gotAddr & 0xffff; 120 data[2] |= gotAddr & 0xffff; 121 122 plt->setValue(reinterpret_cast<unsigned char*>(data)); 123 } else { 124 uint32_t* data = static_cast<uint32_t*>(malloc(plt->size())); 125 126 if (!data) 127 fatal(diag::fail_allocate_memory_plt); 128 129 memcpy(data, PLTA, plt->size()); 130 131 uint64_t gotEntryAddr = pGOTPLT.getEntryAddr(count++); 132 133 data[0] |= ((gotEntryAddr + 0x8000) >> 16) & 0xffff; 134 data[1] |= gotEntryAddr & 0xffff; 135 data[3] |= gotEntryAddr & 0xffff; 136 137 plt->setValue(reinterpret_cast<unsigned char*>(data)); 138 } 139 } 140 } 141 142 } // namespace mcld 143