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_PC24:
     87       case llvm::ELF::R_ARM_JUMP24:
     88       case llvm::ELF::R_ARM_PLT32: {
     89         // always need a stub to switch mode
     90         result = true;
     91         break;
     92       }
     93       default:
     94         break;
     95     }
     96   }
     97   return result;
     98 }
     99 
    100 const std::string& ARMToTHMStub::name() const
    101 {
    102   return m_Name;
    103 }
    104 
    105 const uint8_t* ARMToTHMStub::getContent() const
    106 {
    107   return reinterpret_cast<const uint8_t*>(m_pData);
    108 }
    109 
    110 size_t ARMToTHMStub::size() const
    111 {
    112   return m_Size;
    113 }
    114 
    115 size_t ARMToTHMStub::alignment() const
    116 {
    117   return 4u;
    118 }
    119 
    120 Stub* ARMToTHMStub::doClone()
    121 {
    122   return new ARMToTHMStub(m_pData, m_Size, fixup_begin(), fixup_end());
    123 }
    124 
    125