Home | History | Annotate | Download | only in AArch64
      1 //===- AArch64RelocationHelpers.h -----------------------------------------===//
      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 #ifndef TARGET_AARCH64_AARCH64RELOCATIONHELPERS_H
     10 #define TARGET_AARCH64_AARCH64RELOCATIONHELPERS_H
     11 
     12 #include "AArch64Relocator.h"
     13 #include <llvm/Support/Host.h>
     14 
     15 namespace mcld {
     16 //===----------------------------------------------------------------------===//
     17 // Relocation helper functions
     18 //===----------------------------------------------------------------------===//
     19 // Return true if overflow
     20 static inline bool
     21 helper_check_signed_overflow(Relocator::DWord pValue, unsigned bits)
     22 {
     23   if (bits >= sizeof(int64_t) * 8)
     24     return false;
     25   int64_t signed_val = static_cast<int64_t>(pValue);
     26   int64_t max = (1 << (bits - 1)) - 1;
     27   int64_t min = -(1 << (bits - 1));
     28   if (signed_val > max || signed_val < min)
     29     return true;
     30   return false;
     31 }
     32 
     33 static inline Relocator::Address
     34 helper_get_page_address(Relocator::Address pValue)
     35 {
     36   return (pValue & ~ (Relocator::Address) 0xFFF);
     37 }
     38 
     39 static inline Relocator::Address
     40 helper_get_page_offset(Relocator::Address pValue)
     41 {
     42   return (pValue & (Relocator::Address) 0xFFF);
     43 }
     44 
     45 static inline uint32_t get_mask(uint32_t pValue)
     46 {
     47   return ((1u << (pValue)) - 1);
     48 }
     49 
     50 static inline uint32_t
     51 helper_reencode_adr_imm(uint32_t pInst, uint32_t pImm)
     52 {
     53   return (pInst & ~((get_mask(2) << 29) | (get_mask(19) << 5)))
     54       | ((pImm & get_mask(2)) << 29) | ((pImm & (get_mask(19) << 2)) << 3);
     55 }
     56 
     57 // Reencode the imm field of add immediate.
     58 static inline uint32_t helper_reencode_add_imm(uint32_t pInst, uint32_t pImm)
     59 {
     60   return (pInst & ~(get_mask(12) << 10)) | ((pImm & get_mask(12)) << 10);
     61 }
     62 
     63 // Encode the 26-bit offset of unconditional branch.
     64 static inline uint32_t
     65 helper_reencode_branch_offset_26(uint32_t pInst, uint32_t pOff)
     66 {
     67   return (pInst & ~get_mask(26)) | (pOff & get_mask(26));
     68 }
     69 
     70 // Encode the 19-bit offset of conditional branch and compare & branch.
     71 static inline uint32_t
     72 helper_reencode_cond_branch_ofs_19(uint32_t pInst, uint32_t pOff)
     73 {
     74   return (pInst & ~(get_mask(19) << 5)) | ((pOff & get_mask(19)) << 5);
     75 }
     76 
     77 // Reencode the imm field of ld/st pos immediate.
     78 static inline uint32_t
     79 helper_reencode_ldst_pos_imm (uint32_t pInst, uint32_t pImm)
     80 {
     81   return (pInst & ~(get_mask(12) << 10)) | ((pImm & get_mask(12)) << 10);
     82 }
     83 
     84 static inline uint32_t helper_get_upper32(Relocator::DWord pData)
     85 {
     86   if (llvm::sys::IsLittleEndianHost)
     87     return pData >> 32;
     88   return pData & 0xFFFFFFFF;
     89 }
     90 
     91 static inline void helper_put_upper32(uint32_t pData, Relocator::DWord& pDes)
     92 {
     93   *(reinterpret_cast<uint32_t*>(&pDes)) = pData;
     94 }
     95 
     96 static inline Relocator::Address
     97 helper_get_PLT_address(ResolveInfo& pSym, AArch64Relocator& pParent)
     98 {
     99   PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(pSym);
    100   assert(NULL != plt_entry);
    101   return pParent.getTarget().getPLT().addr() + plt_entry->getOffset();
    102 }
    103 
    104 static inline AArch64PLT1&
    105 helper_PLT_init(Relocation& pReloc, AArch64Relocator& pParent)
    106 {
    107   // rsym - The relocation target symbol
    108   ResolveInfo* rsym = pReloc.symInfo();
    109   AArch64GNULDBackend& ld_backend = pParent.getTarget();
    110   assert(NULL == pParent.getSymPLTMap().lookUp(*rsym));
    111 
    112   AArch64PLT1* plt_entry = ld_backend.getPLT().create();
    113   pParent.getSymPLTMap().record(*rsym, *plt_entry);
    114 
    115   // initialize plt and the corresponding gotplt and dyn rel entry.
    116   assert(NULL == pParent.getSymGOTPLTMap().lookUp(*rsym) &&
    117          "PLT entry not exist, but DynRel entry exist!");
    118   AArch64GOTEntry* gotplt_entry = ld_backend.getGOTPLT().createGOTPLT();
    119   pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
    120 
    121   // init the corresponding rel entry in .rela.plt
    122   Relocation& rel_entry = *ld_backend.getRelaPLT().create();
    123   rel_entry.setType(R_AARCH64_JUMP_SLOT);
    124   rel_entry.targetRef().assign(*gotplt_entry);
    125   rel_entry.setSymInfo(rsym);
    126   return *plt_entry;
    127 }
    128 
    129 /// helper_DynRel - Get an relocation entry in .rela.dyn
    130 static inline Relocation&
    131 helper_DynRela_init(ResolveInfo* pSym,
    132                     Fragment& pFrag,
    133                     uint64_t pOffset,
    134                     Relocator::Type pType,
    135                     AArch64Relocator& pParent)
    136 {
    137   AArch64GNULDBackend& ld_backend = pParent.getTarget();
    138   Relocation& rel_entry = *ld_backend.getRelaDyn().create();
    139   rel_entry.setType(pType);
    140   rel_entry.targetRef().assign(pFrag, pOffset);
    141   if (pType == R_AARCH64_RELATIVE || NULL == pSym)
    142     rel_entry.setSymInfo(NULL);
    143   else
    144     rel_entry.setSymInfo(pSym);
    145 
    146   return rel_entry;
    147 }
    148 
    149 /// helper_use_relative_reloc - Check if symbol can use relocation
    150 /// R_AARCH64_RELATIVE
    151 static inline bool
    152 helper_use_relative_reloc(const ResolveInfo& pSym,
    153                           const AArch64Relocator& pParent)
    154 
    155 {
    156   // if symbol is dynamic or undefine or preemptible
    157   if (pSym.isDyn() ||
    158       pSym.isUndef() ||
    159       pParent.getTarget().isSymbolPreemptible(pSym))
    160     return false;
    161   return true;
    162 }
    163 
    164 static inline Relocator::Address
    165 helper_get_GOT_address(ResolveInfo& pSym, AArch64Relocator& pParent)
    166 {
    167   AArch64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(pSym);
    168   assert(NULL != got_entry);
    169   return pParent.getTarget().getGOT().addr() + got_entry->getOffset();
    170 }
    171 
    172 static inline Relocator::Address
    173 helper_GOT_ORG(AArch64Relocator& pParent)
    174 {
    175   return pParent.getTarget().getGOT().addr();
    176 }
    177 
    178 static inline AArch64GOTEntry&
    179 helper_GOT_init(Relocation& pReloc, bool pHasRel, AArch64Relocator& pParent)
    180 {
    181   // rsym - The relocation target symbol
    182   ResolveInfo* rsym = pReloc.symInfo();
    183   AArch64GNULDBackend& ld_backend = pParent.getTarget();
    184   assert(NULL == pParent.getSymGOTMap().lookUp(*rsym));
    185 
    186   AArch64GOTEntry* got_entry = ld_backend.getGOT().createGOT();
    187   pParent.getSymGOTMap().record(*rsym, *got_entry);
    188 
    189   // If we first get this GOT entry, we should initialize it.
    190   if (!pHasRel) {
    191     // No corresponding dynamic relocation, initialize to the symbol value.
    192     got_entry->setValue(AArch64Relocator::SymVal);
    193   }
    194   else {
    195     // Initialize got_entry content and the corresponding dynamic relocation.
    196     if (helper_use_relative_reloc(*rsym, pParent)) {
    197       got_entry->setValue(AArch64Relocator::SymVal);
    198       Relocation& rel_entry = helper_DynRela_init(rsym, *got_entry, 0x0,
    199                                                   R_AARCH64_RELATIVE, pParent);
    200       rel_entry.setAddend(AArch64Relocator::SymVal);
    201       pParent.getRelRelMap().record(pReloc, rel_entry);
    202     }
    203     else {
    204       helper_DynRela_init(rsym, *got_entry, 0x0, R_AARCH64_GLOB_DAT, pParent);
    205       got_entry->setValue(0);
    206     }
    207   }
    208   return *got_entry;
    209 }
    210 
    211 }
    212 #endif
    213