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