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