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} 36 37namespace mcld { 38 39//===----------------------------------------------------------------------===// 40// MipsPLT0 Entry 41//===----------------------------------------------------------------------===// 42class MipsPLT0 : public PLT::Entry<sizeof(PLT0)> 43{ 44public: 45 MipsPLT0(SectionData& pParent) 46 : PLT::Entry<sizeof(PLT0)>(pParent) 47 {} 48}; 49 50//===----------------------------------------------------------------------===// 51// MipsPLTA Entry 52//===----------------------------------------------------------------------===// 53class MipsPLTA : public PLT::Entry<sizeof(PLTA)> 54{ 55public: 56 MipsPLTA(SectionData& pParent) 57 : PLT::Entry<sizeof(PLTA)>(pParent) 58 {} 59}; 60 61//===----------------------------------------------------------------------===// 62// MipsPLT 63//===----------------------------------------------------------------------===// 64MipsPLT::MipsPLT(LDSection& pSection) 65 : PLT(pSection) 66{ 67 new MipsPLT0(*m_pSectionData); 68 m_Last = m_pSectionData->begin(); 69} 70 71void 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 85bool MipsPLT::hasPLT1() const 86{ 87 return m_pSectionData->size() > 1; 88} 89 90uint64_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 109void 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 119Fragment* 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 127void 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