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