Home | History | Annotate | Download | only in ARM
      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 
     36 ARMToTHMStub::ARMToTHMStub(bool pIsOutputPIC)
     37  : Stub(), m_Name("A2T_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, 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
     52 ARMToTHMStub::ARMToTHMStub(const uint32_t* pData,
     53                            size_t pSize,
     54                            const_fixup_iterator pBegin,
     55                            const_fixup_iterator pEnd)
     56  : Stub(), m_Name("A2T_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 ARMToTHMStub::~ARMToTHMStub()
     63 {
     64 }
     65 
     66 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_JUMP24:
     87       case llvm::ELF::R_ARM_PLT32: {
     88         // always need a stub to switch mode
     89         result = true;
     90         break;
     91       }
     92       default:
     93         break;
     94     }
     95   }
     96   return result;
     97 }
     98 
     99 const std::string& ARMToTHMStub::name() const
    100 {
    101   return m_Name;
    102 }
    103 
    104 const uint8_t* ARMToTHMStub::getContent() const
    105 {
    106   return reinterpret_cast<const uint8_t*>(m_pData);
    107 }
    108 
    109 size_t ARMToTHMStub::size() const
    110 {
    111   return m_Size;
    112 }
    113 
    114 size_t ARMToTHMStub::alignment() const
    115 {
    116   return 4u;
    117 }
    118 
    119 Stub* ARMToTHMStub::doClone()
    120 {
    121   return new ARMToTHMStub(m_pData, m_Size, fixup_begin(), fixup_end());
    122 }
    123 
    124