1 //===- THMToTHMStub.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 10 #include "THMToTHMStub.h" 11 #include "ARMLDBackend.h" 12 13 #include "mcld/Fragment/Relocation.h" 14 #include "mcld/LD/LDSymbol.h" 15 #include "mcld/LD/ResolveInfo.h" 16 17 #include <llvm/Support/ELF.h> 18 19 namespace mcld { 20 21 //===----------------------------------------------------------------------===// 22 // THMToTHMStub 23 //===----------------------------------------------------------------------===// 24 const uint32_t THMToTHMStub::PIC_TEMPLATE[] = { 25 0x46c04778, // bx pc ... nop 26 0xe59fc004, // ldr r12, [pc, #4] 27 0xe08fc00c, // add ip, pc, ip 28 0xe12fff1c, // bx ip 29 0x0 // dcd R_ARM_REL32(X) 30 }; 31 32 const uint32_t THMToTHMStub::TEMPLATE[] = { 33 0x46c04778, // bx pc ... nop 34 0xe59fc000, // ldr ip, [pc, #0] 35 0xe12fff1c, // bx ip 36 0x0 // dcd R_ARM_ABS32(X) 37 }; 38 39 THMToTHMStub::THMToTHMStub(bool pIsOutputPIC, bool pUsingThumb2) 40 : m_pData(NULL), 41 m_Name("T2T_prototype"), 42 m_Size(0x0), 43 m_bUsingThumb2(pUsingThumb2) { 44 if (pIsOutputPIC) { 45 m_pData = PIC_TEMPLATE; 46 m_Size = sizeof(PIC_TEMPLATE); 47 addFixup(16u, 0x0, llvm::ELF::R_ARM_REL32); 48 } else { 49 m_pData = TEMPLATE; 50 m_Size = sizeof(TEMPLATE); 51 addFixup(12u, 0x0, llvm::ELF::R_ARM_ABS32); 52 } 53 } 54 55 /// for doClone 56 THMToTHMStub::THMToTHMStub(const uint32_t* pData, 57 size_t pSize, 58 const_fixup_iterator pBegin, 59 const_fixup_iterator pEnd, 60 bool pUsingThumb2) 61 : m_pData(pData), 62 m_Name("T2T_veneer"), 63 m_Size(pSize), 64 m_bUsingThumb2(pUsingThumb2) { 65 for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it) 66 addFixup(**it); 67 } 68 69 THMToTHMStub::~THMToTHMStub() { 70 } 71 72 bool THMToTHMStub::isMyDuty(const class Relocation& pReloc, 73 uint64_t pSource, 74 uint64_t pTargetSymValue) const { 75 bool result = false; 76 // Check if the branch target is THUMB 77 if ((pTargetSymValue & 0x1) != 0x0) { 78 switch (pReloc.type()) { 79 case llvm::ELF::R_ARM_THM_CALL: 80 case llvm::ELF::R_ARM_THM_JUMP24: { 81 // Check if the branch target is too far 82 uint64_t dest = pTargetSymValue + pReloc.addend() + 4u; 83 int64_t branch_offset = static_cast<int64_t>(dest) - pSource; 84 if (m_bUsingThumb2) { 85 if ((branch_offset > ARMGNULDBackend::THM2_MAX_FWD_BRANCH_OFFSET) || 86 (branch_offset < ARMGNULDBackend::THM2_MAX_BWD_BRANCH_OFFSET)) { 87 result = true; 88 break; 89 } 90 } else { 91 if ((branch_offset > ARMGNULDBackend::THM_MAX_FWD_BRANCH_OFFSET) || 92 (branch_offset < ARMGNULDBackend::THM_MAX_BWD_BRANCH_OFFSET)) { 93 result = true; 94 break; 95 } 96 } 97 break; 98 } 99 default: 100 break; 101 } 102 } 103 return result; 104 } 105 106 const std::string& THMToTHMStub::name() const { 107 return m_Name; 108 } 109 110 const uint8_t* THMToTHMStub::getContent() const { 111 return reinterpret_cast<const uint8_t*>(m_pData); 112 } 113 114 size_t THMToTHMStub::size() const { 115 return m_Size; 116 } 117 118 size_t THMToTHMStub::alignment() const { 119 return 4u; 120 } 121 122 uint64_t THMToTHMStub::initSymValue() const { 123 return 0x1; 124 } 125 126 Stub* THMToTHMStub::doClone() { 127 return new THMToTHMStub( 128 m_pData, m_Size, fixup_begin(), fixup_end(), m_bUsingThumb2); 129 } 130 131 } // namespace mcld 132