122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//===- THMToARMStub.cpp ---------------------------------------------------===//
222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//
322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//                     The MCLinker Project
422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//
522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao// This file is distributed under the University of Illinois Open Source
622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao// License. See LICENSE.TXT for details.
722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//
822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//===----------------------------------------------------------------------===//
922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
1022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#include "THMToARMStub.h"
1122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#include "ARMLDBackend.h"
1222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
1337b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/Fragment/Relocation.h"
1437b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/LD/LDSymbol.h"
1537b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/LD/ResolveInfo.h"
1637b74a387bb3993387029859c2d9d051c41c724eStephen Hines
1722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#include <llvm/Support/ELF.h>
1822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
1937b74a387bb3993387029859c2d9d051c41c724eStephen Hinesnamespace mcld {
2022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
2122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//===----------------------------------------------------------------------===//
2222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao// THMToARMStub
2322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//===----------------------------------------------------------------------===//
2422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liaoconst uint32_t THMToARMStub::PIC_TEMPLATE[] = {
2537b74a387bb3993387029859c2d9d051c41c724eStephen Hines    0x46c04778,  // bx    pc ... nop
2637b74a387bb3993387029859c2d9d051c41c724eStephen Hines    0xe59fc000,  // ldr   ip, [pc, #0]
2737b74a387bb3993387029859c2d9d051c41c724eStephen Hines    0xe08cf00f,  // add   pc, ip, pc
2837b74a387bb3993387029859c2d9d051c41c724eStephen Hines    0x0          // dcd   R_ARM_REL32(X)
2922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao};
3022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
3122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liaoconst uint32_t THMToARMStub::TEMPLATE[] = {
3237b74a387bb3993387029859c2d9d051c41c724eStephen Hines    0x46c04778,  // bx    pc ... nop
3337b74a387bb3993387029859c2d9d051c41c724eStephen Hines    0xe51ff004,  // ldr   pc, [pc, #-4]
3437b74a387bb3993387029859c2d9d051c41c724eStephen Hines    0x0          // dcd   R_ARM_ABS32(X)
3522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao};
3622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
370dea6bc96bb52346737966839ac68644f7939f58Stephen HinesTHMToARMStub::THMToARMStub(bool pIsOutputPIC, bool pUsingThumb2)
3837b74a387bb3993387029859c2d9d051c41c724eStephen Hines    : m_pData(NULL),
3937b74a387bb3993387029859c2d9d051c41c724eStephen Hines      m_Name("T2A_prototype"),
4037b74a387bb3993387029859c2d9d051c41c724eStephen Hines      m_Size(0x0),
4137b74a387bb3993387029859c2d9d051c41c724eStephen Hines      m_bUsingThumb2(pUsingThumb2) {
4222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  if (pIsOutputPIC) {
4322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    m_pData = PIC_TEMPLATE;
4422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    m_Size = sizeof(PIC_TEMPLATE);
4522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    addFixup(12u, -4, llvm::ELF::R_ARM_REL32);
460dea6bc96bb52346737966839ac68644f7939f58Stephen Hines  } else {
4722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    m_pData = TEMPLATE;
4822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    m_Size = sizeof(TEMPLATE);
4922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    addFixup(8u, 0x0, llvm::ELF::R_ARM_ABS32);
5022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  }
5122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao}
5222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
5322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao/// for doClone
5422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei LiaoTHMToARMStub::THMToARMStub(const uint32_t* pData,
5522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao                           size_t pSize,
5622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao                           const_fixup_iterator pBegin,
570dea6bc96bb52346737966839ac68644f7939f58Stephen Hines                           const_fixup_iterator pEnd,
580dea6bc96bb52346737966839ac68644f7939f58Stephen Hines                           bool pUsingThumb2)
5937b74a387bb3993387029859c2d9d051c41c724eStephen Hines    : m_pData(pData),
6037b74a387bb3993387029859c2d9d051c41c724eStephen Hines      m_Name("T2A_veneer"),
6137b74a387bb3993387029859c2d9d051c41c724eStephen Hines      m_Size(pSize),
6237b74a387bb3993387029859c2d9d051c41c724eStephen Hines      m_bUsingThumb2(pUsingThumb2) {
6322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it)
6422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    addFixup(**it);
6522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao}
6622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
6737b74a387bb3993387029859c2d9d051c41c724eStephen HinesTHMToARMStub::~THMToARMStub() {
6822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao}
6922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
7022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liaobool THMToARMStub::isMyDuty(const class Relocation& pReloc,
7122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao                            uint64_t pSource,
7237b74a387bb3993387029859c2d9d051c41c724eStephen Hines                            uint64_t pTargetSymValue) const {
7322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  bool result = false;
7422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // Check if the branch target is ARM
7522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  if ((pTargetSymValue & 0x1) == 0x0) {
7622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    switch (pReloc.type()) {
7722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      case llvm::ELF::R_ARM_THM_CALL: {
7822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao        // FIXME: Assuming blx is available (i.e., target is armv5 or above!)
7922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao        // then, we do not need a stub unless the branch target is too far.
8022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao        uint64_t dest = pTargetSymValue + pReloc.addend() + 4u;
8122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao        int64_t branch_offset = static_cast<int64_t>(dest) - pSource;
820dea6bc96bb52346737966839ac68644f7939f58Stephen Hines        if (m_bUsingThumb2) {
830dea6bc96bb52346737966839ac68644f7939f58Stephen Hines          if ((branch_offset > ARMGNULDBackend::THM2_MAX_FWD_BRANCH_OFFSET) ||
840dea6bc96bb52346737966839ac68644f7939f58Stephen Hines              (branch_offset < ARMGNULDBackend::THM2_MAX_BWD_BRANCH_OFFSET)) {
850dea6bc96bb52346737966839ac68644f7939f58Stephen Hines            result = true;
860dea6bc96bb52346737966839ac68644f7939f58Stephen Hines            break;
870dea6bc96bb52346737966839ac68644f7939f58Stephen Hines          }
880dea6bc96bb52346737966839ac68644f7939f58Stephen Hines        } else {
890dea6bc96bb52346737966839ac68644f7939f58Stephen Hines          if ((branch_offset > ARMGNULDBackend::THM_MAX_FWD_BRANCH_OFFSET) ||
900dea6bc96bb52346737966839ac68644f7939f58Stephen Hines              (branch_offset < ARMGNULDBackend::THM_MAX_BWD_BRANCH_OFFSET)) {
910dea6bc96bb52346737966839ac68644f7939f58Stephen Hines            result = true;
920dea6bc96bb52346737966839ac68644f7939f58Stephen Hines            break;
930dea6bc96bb52346737966839ac68644f7939f58Stephen Hines          }
940dea6bc96bb52346737966839ac68644f7939f58Stephen Hines        }
9522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao        break;
9622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      }
9722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      case llvm::ELF::R_ARM_THM_JUMP24: {
9822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao        // always need a stub to switch mode
9922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao        result = true;
10022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao        break;
10122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      }
10222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      default:
10322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao        break;
10422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    }
10522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  }
10622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  return result;
10722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao}
10822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
10937b74a387bb3993387029859c2d9d051c41c724eStephen Hinesconst std::string& THMToARMStub::name() const {
11022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  return m_Name;
11122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao}
11222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
11337b74a387bb3993387029859c2d9d051c41c724eStephen Hinesconst uint8_t* THMToARMStub::getContent() const {
11422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  return reinterpret_cast<const uint8_t*>(m_pData);
11522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao}
11622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
11737b74a387bb3993387029859c2d9d051c41c724eStephen Hinessize_t THMToARMStub::size() const {
11822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  return m_Size;
11922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao}
12022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
12137b74a387bb3993387029859c2d9d051c41c724eStephen Hinessize_t THMToARMStub::alignment() const {
12222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  return 4u;
12322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao}
12422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
12522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao// for T bit of this stub
12637b74a387bb3993387029859c2d9d051c41c724eStephen Hinesuint64_t THMToARMStub::initSymValue() const {
12722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  return 0x1;
12822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao}
12922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
13037b74a387bb3993387029859c2d9d051c41c724eStephen HinesStub* THMToARMStub::doClone() {
13137b74a387bb3993387029859c2d9d051c41c724eStephen Hines  return new THMToARMStub(
13237b74a387bb3993387029859c2d9d051c41c724eStephen Hines      m_pData, m_Size, fixup_begin(), fixup_end(), m_bUsingThumb2);
13322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao}
13437b74a387bb3993387029859c2d9d051c41c724eStephen Hines
13537b74a387bb3993387029859c2d9d051c41c724eStephen Hines}  // namespace mcld
136