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