1 //===- ARMToTHMStub.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 "ARMToTHMStub.h"
11 #include "ARMLDBackend.h"
12 
13 #include <llvm/Support/ELF.h>
14 #include <mcld/LD/ResolveInfo.h>
15 #include <mcld/LD/LDSymbol.h>
16 #include <mcld/Fragment/Relocation.h>
17 
18 using namespace mcld;
19 
20 //===----------------------------------------------------------------------===//
21 // ARMToTHMStub
22 //===----------------------------------------------------------------------===//
23 const uint32_t ARMToTHMStub::PIC_TEMPLATE[] = {
24   0xe59fc004, // ldr   r12, [pc, #4]
25   0xe08fc00c, // add   ip, pc, ip
26   0xe12fff1c, // bx    ip
27   0x0         // dcd   R_ARM_REL32(X)
28 };
29 
30 const uint32_t ARMToTHMStub::TEMPLATE[] = {
31   0xe59fc000, // ldr   ip, [pc, #0]
32   0xe12fff1c, // bx    ip
33   0x0         // dcd   R_ARM_ABS32(X)
34 };
35 
ARMToTHMStub(bool pIsOutputPIC)36 ARMToTHMStub::ARMToTHMStub(bool pIsOutputPIC)
37  : m_pData(NULL), m_Name("A2T_prototype"), m_Size(0x0)
38 {
39   if (pIsOutputPIC) {
40     m_pData = PIC_TEMPLATE;
41     m_Size = sizeof(PIC_TEMPLATE);
42     addFixup(12u, 0x0, llvm::ELF::R_ARM_REL32);
43   }
44   else {
45     m_pData = TEMPLATE;
46     m_Size = sizeof(TEMPLATE);
47     addFixup(8u, 0x0, llvm::ELF::R_ARM_ABS32);
48   }
49 }
50 
51 /// for doClone
ARMToTHMStub(const uint32_t * pData,size_t pSize,const_fixup_iterator pBegin,const_fixup_iterator pEnd)52 ARMToTHMStub::ARMToTHMStub(const uint32_t* pData,
53                            size_t pSize,
54                            const_fixup_iterator pBegin,
55                            const_fixup_iterator pEnd)
56  : m_pData(pData), m_Name("A2T_veneer"), m_Size(pSize)
57 {
58   for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it)
59     addFixup(**it);
60 }
61 
~ARMToTHMStub()62 ARMToTHMStub::~ARMToTHMStub()
63 {
64 }
65 
isMyDuty(const class Relocation & pReloc,uint64_t pSource,uint64_t pTargetSymValue) const66 bool ARMToTHMStub::isMyDuty(const class Relocation& pReloc,
67                             uint64_t pSource,
68                             uint64_t pTargetSymValue) const
69 {
70   bool result = false;
71   // Check if the branch target is THUMB
72   if ((pTargetSymValue & 0x1) != 0x0) {
73     switch (pReloc.type()) {
74       case llvm::ELF::R_ARM_CALL: {
75         // FIXME: Assuming blx is available (i.e., target is armv5 or above!)
76         // then, we do not need a stub unless the branch target is too far.
77         uint64_t dest = pTargetSymValue + pReloc.addend() + 8u;
78         int64_t branch_offset = static_cast<int64_t>(dest) - pSource;
79         if ((branch_offset > ARMGNULDBackend::ARM_MAX_FWD_BRANCH_OFFSET) ||
80             (branch_offset < ARMGNULDBackend::ARM_MAX_BWD_BRANCH_OFFSET)) {
81           result = true;
82           break;
83         }
84         break;
85       }
86       case llvm::ELF::R_ARM_PC24:
87       case llvm::ELF::R_ARM_JUMP24:
88       case llvm::ELF::R_ARM_PLT32: {
89         // always need a stub to switch mode
90         result = true;
91         break;
92       }
93       default:
94         break;
95     }
96   }
97   return result;
98 }
99 
name() const100 const std::string& ARMToTHMStub::name() const
101 {
102   return m_Name;
103 }
104 
getContent() const105 const uint8_t* ARMToTHMStub::getContent() const
106 {
107   return reinterpret_cast<const uint8_t*>(m_pData);
108 }
109 
size() const110 size_t ARMToTHMStub::size() const
111 {
112   return m_Size;
113 }
114 
alignment() const115 size_t ARMToTHMStub::alignment() const
116 {
117   return 4u;
118 }
119 
doClone()120 Stub* ARMToTHMStub::doClone()
121 {
122   return new ARMToTHMStub(m_pData, m_Size, fixup_begin(), fixup_end());
123 }
124