1cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines//===- AArch64LongBranchStub.cpp ------------------------------------------===// 2cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines// 3cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines// The MCLinker Project 4cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines// 5cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines// This file is distributed under the University of Illinois Open Source 6cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines// License. See LICENSE.TXT for details. 7cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines// 8cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines//===----------------------------------------------------------------------===// 9cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 10cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include "AArch64LongBranchStub.h" 11cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include "AArch64LDBackend.h" 12cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include "AArch64RelocationHelpers.h" 13cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 14cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include "mcld/Fragment/Relocation.h" 15cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include "mcld/LD/BranchIsland.h" 16cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include "mcld/LD/LDSymbol.h" 17cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include "mcld/LD/ResolveInfo.h" 18cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 19cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include <llvm/Support/ELF.h> 20cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 21cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include <cassert> 22cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 23cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesnamespace mcld { 24cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 25cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines//===----------------------------------------------------------------------===// 26cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines// AArch64LongBranchStub 27cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines//===----------------------------------------------------------------------===// 28cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesconst uint32_t AArch64LongBranchStub::PIC_TEMPLATE[] = { 29cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 0x58000090, // ldr ip0, 0x10 30cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 0x10000011, // adr ip1, #0 31cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 0x8b110210, // add ip0, ip0, ip1 32cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 0xd61f0200, // br ip0 33cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 0x00000000, // .xword <-- R_AARCH64_PREL64(X+12) 34cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 0x00000000, 35cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}; 36cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 37cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesconst uint32_t AArch64LongBranchStub::TEMPLATE[] = { 38cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 0x58000050, // ldr ip0, 0x8 39cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 0xd61f0200, // br ip0 40cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 0x00000000, // .xword <-- R_AARCH64_PREL64(X) 41cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 0x00000000, 42cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}; 43cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 44cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesconst uint32_t AArch64LongBranchStub::ADRP_TEMPLATE[] = { 45cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 0x90000010, // adrp ip0, X <-- R_AARCH64_ADR_PREL_PG_HI21(X) 46cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 0x91000210, // add ip0, ip0, :lo12:X <-- R_AARCH64_ADD_ABS_LO12_NC(X) 47cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 0xd61f0200, // br ip0 48cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}; 49cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 50cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen HinesAArch64LongBranchStub::AArch64LongBranchStub(bool pIsOutputPIC) 51cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines : m_pData(NULL), 52cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines m_Name("ljmp_prototype"), 53cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines m_Size(0x0) { 54cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines if (pIsOutputPIC) { 55cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines m_pData = PIC_TEMPLATE; 56cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines m_Size = sizeof(PIC_TEMPLATE); 57cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines addFixup(0x10, 12, llvm::ELF::R_AARCH64_PREL64); 58cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines } else { 59cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines m_pData = TEMPLATE; 60cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines m_Size = sizeof(TEMPLATE); 61cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines addFixup(0x8, 0, llvm::ELF::R_AARCH64_PREL64); 62cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines } 63cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines} 64cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 65cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines/// for doClone 66cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen HinesAArch64LongBranchStub::AArch64LongBranchStub(const uint32_t* pData, 67cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines size_t pSize, 68cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines const_fixup_iterator pBegin, 69cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines const_fixup_iterator pEnd) 70cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines : m_pData(pData), 71cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines m_Name("ljmp_veneer"), 72cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines m_Size(pSize) { 73cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it) { 74cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines addFixup(**it); 75cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines } 76cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines} 77cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 78cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen HinesAArch64LongBranchStub::~AArch64LongBranchStub() { 79cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines} 80cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 81cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesbool AArch64LongBranchStub::isMyDuty(const Relocation& pReloc, 82cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines uint64_t pSource, 83cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines uint64_t pTargetSymValue) const { 84cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines assert((pReloc.type() == llvm::ELF::R_AARCH64_CALL26) || 85cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines (pReloc.type() == llvm::ELF::R_AARCH64_JUMP26)); 86cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines int64_t dest = pTargetSymValue + pReloc.addend(); 87cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines int64_t branch_offset = dest - pSource; 88cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines if ((branch_offset > AArch64GNULDBackend::MAX_FWD_BRANCH_OFFSET) || 89cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines (branch_offset < AArch64GNULDBackend::MAX_BWD_BRANCH_OFFSET)) { 90cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines return true; 91cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines } 92cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines return false; 93cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines} 94cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 95cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesstatic bool isValidForADRP(uint64_t pSource, uint64_t pDest) { 96cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines int64_t imm = static_cast<int64_t>((helper_get_page_address(pDest) - 97cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines helper_get_page_address(pSource))) >> 12; 98cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines return ((imm <= AArch64GNULDBackend::MAX_ADRP_IMM) && 99cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines (imm >= AArch64GNULDBackend::MIN_ADRP_IMM)); 100cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines} 101cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 102cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesvoid AArch64LongBranchStub::applyFixup(Relocation& pSrcReloc, 103cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines IRBuilder& pBuilder, 104cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines BranchIsland& pIsland) { 105cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines // Try to relax the stub itself. 106cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines LDSymbol* symbol = pSrcReloc.symInfo()->outSymbol(); 107cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines uint64_t dest = symbol->fragRef()->frag()->getParent()->getSection().addr() + 108cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines symbol->fragRef()->getOutputOffset(); 109cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines uint64_t src = pIsland.getParent()->getSection().addr() + 110cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines pIsland.offset() + 111cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines pIsland.size(); 112cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines if (isValidForADRP(src, dest)) { 113cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines m_pData = ADRP_TEMPLATE; 114cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines m_Name = "adrp_veneer"; 115cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines m_Size = sizeof(ADRP_TEMPLATE); 116cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 117cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines getFixupList().clear(); 118cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines addFixup(0x0, 0, llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21); 119cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines addFixup(0x4, 0, llvm::ELF::R_AARCH64_ADD_ABS_LO12_NC); 120cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines } 121cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 122cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines Stub::applyFixup(pSrcReloc, pBuilder, pIsland); 123cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines} 124cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 125cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesconst std::string& AArch64LongBranchStub::name() const { 126cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines return m_Name; 127cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines} 128cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 129cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesconst uint8_t* AArch64LongBranchStub::getContent() const { 130cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines return reinterpret_cast<const uint8_t*>(m_pData); 131cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines} 132cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 133cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinessize_t AArch64LongBranchStub::size() const { 134cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines return m_Size; 135cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines} 136cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 137cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinessize_t AArch64LongBranchStub::alignment() const { 138cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines return 8; 139cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines} 140cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 141cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen HinesStub* AArch64LongBranchStub::doClone() { 142cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines return new AArch64LongBranchStub(m_pData, m_Size, fixup_begin(), fixup_end()); 143cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines} 144cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines 145cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines} // namespace mcld 146