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 "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 // ARMToTHMStub
     23 //===----------------------------------------------------------------------===//
     24 const uint32_t ARMToTHMStub::PIC_TEMPLATE[] = {
     25     0xe59fc004,  // ldr   r12, [pc, #4]
     26     0xe08fc00c,  // add   ip, pc, ip
     27     0xe12fff1c,  // bx    ip
     28     0x0          // dcd   R_ARM_REL32(X)
     29 };
     30 
     31 const uint32_t ARMToTHMStub::TEMPLATE[] = {
     32     0xe59fc000,  // ldr   ip, [pc, #0]
     33     0xe12fff1c,  // bx    ip
     34     0x0          // dcd   R_ARM_ABS32(X)
     35 };
     36 
     37 ARMToTHMStub::ARMToTHMStub(bool pIsOutputPIC)
     38     : m_pData(NULL), m_Name("A2T_prototype"), m_Size(0x0) {
     39   if (pIsOutputPIC) {
     40     m_pData = PIC_TEMPLATE;
     41     m_Size = sizeof(PIC_TEMPLATE);
     42     addFixup(12u, 0x0, llvm::ELF::R_ARM_REL32);
     43   } else {
     44     m_pData = TEMPLATE;
     45     m_Size = sizeof(TEMPLATE);
     46     addFixup(8u, 0x0, llvm::ELF::R_ARM_ABS32);
     47   }
     48 }
     49 
     50 /// for doClone
     51 ARMToTHMStub::ARMToTHMStub(const uint32_t* pData,
     52                            size_t pSize,
     53                            const_fixup_iterator pBegin,
     54                            const_fixup_iterator pEnd)
     55     : m_pData(pData), m_Name("A2T_veneer"), m_Size(pSize) {
     56   for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it)
     57     addFixup(**it);
     58 }
     59 
     60 ARMToTHMStub::~ARMToTHMStub() {
     61 }
     62 
     63 bool ARMToTHMStub::isMyDuty(const class Relocation& pReloc,
     64                             uint64_t pSource,
     65                             uint64_t pTargetSymValue) const {
     66   bool result = false;
     67   // Check if the branch target is THUMB
     68   if ((pTargetSymValue & 0x1) != 0x0) {
     69     switch (pReloc.type()) {
     70       case llvm::ELF::R_ARM_CALL: {
     71         // FIXME: Assuming blx is available (i.e., target is armv5 or above!)
     72         // then, we do not need a stub unless the branch target is too far.
     73         uint64_t dest = pTargetSymValue + pReloc.addend() + 8u;
     74         int64_t branch_offset = static_cast<int64_t>(dest) - pSource;
     75         if ((branch_offset > ARMGNULDBackend::ARM_MAX_FWD_BRANCH_OFFSET) ||
     76             (branch_offset < ARMGNULDBackend::ARM_MAX_BWD_BRANCH_OFFSET)) {
     77           result = true;
     78           break;
     79         }
     80         break;
     81       }
     82       case llvm::ELF::R_ARM_PC24:
     83       case llvm::ELF::R_ARM_JUMP24:
     84       case llvm::ELF::R_ARM_PLT32: {
     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& ARMToTHMStub::name() const {
     97   return m_Name;
     98 }
     99 
    100 const uint8_t* ARMToTHMStub::getContent() const {
    101   return reinterpret_cast<const uint8_t*>(m_pData);
    102 }
    103 
    104 size_t ARMToTHMStub::size() const {
    105   return m_Size;
    106 }
    107 
    108 size_t ARMToTHMStub::alignment() const {
    109   return 4u;
    110 }
    111 
    112 Stub* ARMToTHMStub::doClone() {
    113   return new ARMToTHMStub(m_pData, m_Size, fixup_begin(), fixup_end());
    114 }
    115 
    116 }  // namespace mcld
    117