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)
     37  : Stub(), m_Name("T2A_prototype"), m_pData(NULL), m_Size(0x0)
     38 {
     39   if (pIsOutputPIC) {
     40     m_pData = PIC_TEMPLATE;
     41     m_Size = sizeof(PIC_TEMPLATE);
     42     addFixup(12u, -4, 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
     52 THMToARMStub::THMToARMStub(const uint32_t* pData,
     53                            size_t pSize,
     54                            const_fixup_iterator pBegin,
     55                            const_fixup_iterator pEnd)
     56  : Stub(), m_Name("T2A_veneer"), m_pData(pData), m_Size(pSize)
     57 {
     58   for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it)
     59     addFixup(**it);
     60 }
     61 
     62 THMToARMStub::~THMToARMStub()
     63 {
     64 }
     65 
     66 bool THMToARMStub::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 ARM
     72   if ((pTargetSymValue & 0x1) == 0x0) {
     73     switch (pReloc.type()) {
     74       case llvm::ELF::R_ARM_THM_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() + 4u;
     78         int64_t branch_offset = static_cast<int64_t>(dest) - pSource;
     79         if ((branch_offset > ARMGNULDBackend::THM_MAX_FWD_BRANCH_OFFSET) ||
     80             (branch_offset < ARMGNULDBackend::THM_MAX_BWD_BRANCH_OFFSET))
     81           result = true;
     82         break;
     83       }
     84       case llvm::ELF::R_ARM_THM_JUMP24: {
     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 
     96 const std::string& THMToARMStub::name() const
     97 {
     98   return m_Name;
     99 }
    100 
    101 const uint8_t* THMToARMStub::getContent() const
    102 {
    103   return reinterpret_cast<const uint8_t*>(m_pData);
    104 }
    105 
    106 size_t THMToARMStub::size() const
    107 {
    108   return m_Size;
    109 }
    110 
    111 size_t THMToARMStub::alignment() const
    112 {
    113   return 4u;
    114 }
    115 
    116 // for T bit of this stub
    117 uint64_t THMToARMStub::initSymValue() const
    118 {
    119   return 0x1;
    120 }
    121 
    122 Stub* THMToARMStub::doClone()
    123 {
    124   return new THMToARMStub(m_pData, m_Size, fixup_begin(), fixup_end());
    125 }
    126 
    127