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