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