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