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 
THMToTHMStub(bool pIsOutputPIC,bool pUsingThumb2)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
THMToTHMStub(const uint32_t * pData,size_t pSize,const_fixup_iterator pBegin,const_fixup_iterator pEnd,bool pUsingThumb2)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 
~THMToTHMStub()69 THMToTHMStub::~THMToTHMStub() {
70 }
71 
isMyDuty(const class Relocation & pReloc,uint64_t pSource,uint64_t pTargetSymValue) const72 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 
name() const106 const std::string& THMToTHMStub::name() const {
107   return m_Name;
108 }
109 
getContent() const110 const uint8_t* THMToTHMStub::getContent() const {
111   return reinterpret_cast<const uint8_t*>(m_pData);
112 }
113 
size() const114 size_t THMToTHMStub::size() const {
115   return m_Size;
116 }
117 
alignment() const118 size_t THMToTHMStub::alignment() const {
119   return 4u;
120 }
121 
initSymValue() const122 uint64_t THMToTHMStub::initSymValue() const {
123   return 0x1;
124 }
125 
doClone()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