Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 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> |
Stephen Hines | 37b74a3 | 2014-11-26 18:48:20 -0800 | [diff] [blame] | 11 | #include "mcld/Support/MsgHandling.h" |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 12 | #include "MipsGOTPLT.h" |
| 13 | #include "MipsPLT.h" |
| 14 | |
| 15 | namespace { |
| 16 | |
| 17 | const uint32_t PLT0[] = { |
Stephen Hines | 37b74a3 | 2014-11-26 18:48:20 -0800 | [diff] [blame] | 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 |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 26 | }; |
| 27 | |
| 28 | const uint32_t PLTA[] = { |
Stephen Hines | 37b74a3 | 2014-11-26 18:48:20 -0800 | [diff] [blame] | 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) |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 33 | }; |
| 34 | |
Stephen Hines | 37b74a3 | 2014-11-26 18:48:20 -0800 | [diff] [blame] | 35 | } // anonymous namespace |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 36 | |
| 37 | namespace mcld { |
| 38 | |
| 39 | //===----------------------------------------------------------------------===// |
| 40 | // MipsPLT0 Entry |
| 41 | //===----------------------------------------------------------------------===// |
Stephen Hines | 37b74a3 | 2014-11-26 18:48:20 -0800 | [diff] [blame] | 42 | class MipsPLT0 : public PLT::Entry<sizeof(PLT0)> { |
| 43 | public: |
| 44 | MipsPLT0(SectionData& pParent) : PLT::Entry<sizeof(PLT0)>(pParent) {} |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 45 | }; |
| 46 | |
| 47 | //===----------------------------------------------------------------------===// |
| 48 | // MipsPLTA Entry |
| 49 | //===----------------------------------------------------------------------===// |
Stephen Hines | 37b74a3 | 2014-11-26 18:48:20 -0800 | [diff] [blame] | 50 | class MipsPLTA : public PLT::Entry<sizeof(PLTA)> { |
| 51 | public: |
| 52 | MipsPLTA(SectionData& pParent) : PLT::Entry<sizeof(PLTA)>(pParent) {} |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 53 | }; |
| 54 | |
| 55 | //===----------------------------------------------------------------------===// |
| 56 | // MipsPLT |
| 57 | //===----------------------------------------------------------------------===// |
Stephen Hines | 37b74a3 | 2014-11-26 18:48:20 -0800 | [diff] [blame] | 58 | MipsPLT::MipsPLT(LDSection& pSection) : PLT(pSection) { |
Stephen Hines | 551ae4e | 2014-04-24 14:41:24 -0700 | [diff] [blame] | 59 | new MipsPLT0(*m_pSectionData); |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 60 | } |
| 61 | |
Stephen Hines | 37b74a3 | 2014-11-26 18:48:20 -0800 | [diff] [blame] | 62 | void MipsPLT::finalizeSectionSize() { |
| 63 | uint64_t size = sizeof(PLT0) + (m_pSectionData->size() - 1) * sizeof(PLTA); |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 64 | m_Section.setSize(size); |
| 65 | |
| 66 | uint32_t offset = 0; |
Stephen Hines | 551ae4e | 2014-04-24 14:41:24 -0700 | [diff] [blame] | 67 | SectionData::iterator frag, fragEnd = m_pSectionData->end(); |
| 68 | for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) { |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 69 | frag->setOffset(offset); |
| 70 | offset += frag->size(); |
| 71 | } |
| 72 | } |
| 73 | |
Stephen Hines | 37b74a3 | 2014-11-26 18:48:20 -0800 | [diff] [blame] | 74 | bool MipsPLT::hasPLT1() const { |
Stephen Hines | 551ae4e | 2014-04-24 14:41:24 -0700 | [diff] [blame] | 75 | return m_pSectionData->size() > 1; |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 76 | } |
| 77 | |
Stephen Hines | 37b74a3 | 2014-11-26 18:48:20 -0800 | [diff] [blame] | 78 | uint64_t MipsPLT::emit(MemoryRegion& pRegion) { |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 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 | |
Stephen Hines | cfcb224 | 2016-03-08 00:18:09 -0800 | [diff] [blame^] | 96 | PLTEntryBase* MipsPLT::create() { |
| 97 | return new MipsPLTA(*m_pSectionData); |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 98 | } |
| 99 | |
Stephen Hines | 37b74a3 | 2014-11-26 18:48:20 -0800 | [diff] [blame] | 100 | void MipsPLT::applyAllPLT(MipsGOTPLT& pGOTPLT) { |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 101 | assert(m_Section.addr() && ".plt base address is NULL!"); |
| 102 | |
| 103 | size_t count = 0; |
Stephen Hines | 37b74a3 | 2014-11-26 18:48:20 -0800 | [diff] [blame] | 104 | for (iterator it = m_pSectionData->begin(); it != m_pSectionData->end(); |
| 105 | ++it) { |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 106 | PLTEntryBase* plt = &(llvm::cast<PLTEntryBase>(*it)); |
| 107 | |
Stephen Hines | 551ae4e | 2014-04-24 14:41:24 -0700 | [diff] [blame] | 108 | if (it == m_pSectionData->begin()) { |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame] | 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 | |
Stephen Hines | 37b74a3 | 2014-11-26 18:48:20 -0800 | [diff] [blame] | 142 | } // namespace mcld |