Home | History | Annotate | Download | only in ARM
      1 //===- THMToARMStub.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 "THMToARMStub.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 // THMToARMStub
     23 //===----------------------------------------------------------------------===//
     24 const uint32_t THMToARMStub::PIC_TEMPLATE[] = {
     25     0x46c04778,  // bx    pc ... nop
     26     0xe59fc000,  // ldr   ip, [pc, #0]
     27     0xe08cf00f,  // add   pc, ip, pc
     28     0x0          // dcd   R_ARM_REL32(X)
     29 };
     30 
     31 const uint32_t THMToARMStub::TEMPLATE[] = {
     32     0x46c04778,  // bx    pc ... nop
     33     0xe51ff004,  // ldr   pc, [pc, #-4]
     34     0x0          // dcd   R_ARM_ABS32(X)
     35 };
     36 
     37 THMToARMStub::THMToARMStub(bool pIsOutputPIC, bool pUsingThumb2)
     38     : m_pData(NULL),
     39       m_Name("T2A_prototype"),
     40       m_Size(0x0),
     41       m_bUsingThumb2(pUsingThumb2) {
     42   if (pIsOutputPIC) {
     43     m_pData = PIC_TEMPLATE;
     44     m_Size = sizeof(PIC_TEMPLATE);
     45     addFixup(12u, -4, llvm::ELF::R_ARM_REL32);
     46   } else {
     47     m_pData = TEMPLATE;
     48     m_Size = sizeof(TEMPLATE);
     49     addFixup(8u, 0x0, llvm::ELF::R_ARM_ABS32);
     50   }
     51 }
     52 
     53 /// for doClone
     54 THMToARMStub::THMToARMStub(const uint32_t* pData,
     55                            size_t pSize,
     56                            const_fixup_iterator pBegin,
     57                            const_fixup_iterator pEnd,
     58                            bool pUsingThumb2)
     59     : m_pData(pData),
     60       m_Name("T2A_veneer"),
     61       m_Size(pSize),
     62       m_bUsingThumb2(pUsingThumb2) {
     63   for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it)
     64     addFixup(**it);
     65 }
     66 
     67 THMToARMStub::~THMToARMStub() {
     68 }
     69 
     70 bool THMToARMStub::isMyDuty(const class Relocation& pReloc,
     71                             uint64_t pSource,
     72                             uint64_t pTargetSymValue) const {
     73   bool result = false;
     74   // Check if the branch target is ARM
     75   if ((pTargetSymValue & 0x1) == 0x0) {
     76     switch (pReloc.type()) {
     77       case llvm::ELF::R_ARM_THM_CALL: {
     78         // FIXME: Assuming blx is available (i.e., target is armv5 or above!)
     79         // then, we do not need a stub unless the branch target is too far.
     80         uint64_t dest = pTargetSymValue + pReloc.addend() + 4u;
     81         int64_t branch_offset = static_cast<int64_t>(dest) - pSource;
     82         if (m_bUsingThumb2) {
     83           if ((branch_offset > ARMGNULDBackend::THM2_MAX_FWD_BRANCH_OFFSET) ||
     84               (branch_offset < ARMGNULDBackend::THM2_MAX_BWD_BRANCH_OFFSET)) {
     85             result = true;
     86             break;
     87           }
     88         } else {
     89           if ((branch_offset > ARMGNULDBackend::THM_MAX_FWD_BRANCH_OFFSET) ||
     90               (branch_offset < ARMGNULDBackend::THM_MAX_BWD_BRANCH_OFFSET)) {
     91             result = true;
     92             break;
     93           }
     94         }
     95         break;
     96       }
     97       case llvm::ELF::R_ARM_THM_JUMP24: {
     98         // always need a stub to switch mode
     99         result = true;
    100         break;
    101       }
    102       default:
    103         break;
    104     }
    105   }
    106   return result;
    107 }
    108 
    109 const std::string& THMToARMStub::name() const {
    110   return m_Name;
    111 }
    112 
    113 const uint8_t* THMToARMStub::getContent() const {
    114   return reinterpret_cast<const uint8_t*>(m_pData);
    115 }
    116 
    117 size_t THMToARMStub::size() const {
    118   return m_Size;
    119 }
    120 
    121 size_t THMToARMStub::alignment() const {
    122   return 4u;
    123 }
    124 
    125 // for T bit of this stub
    126 uint64_t THMToARMStub::initSymValue() const {
    127   return 0x1;
    128 }
    129 
    130 Stub* THMToARMStub::doClone() {
    131   return new THMToARMStub(
    132       m_pData, m_Size, fixup_begin(), fixup_end(), m_bUsingThumb2);
    133 }
    134 
    135 }  // namespace mcld
    136