• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,unsigned bits)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
helper_get_page_address(Relocator::Address pValue)34 helper_get_page_address(Relocator::Address pValue)
35 {
36   return (pValue & ~ (Relocator::Address) 0xFFF);
37 }
38 
39 static inline Relocator::Address
helper_get_page_offset(Relocator::Address pValue)40 helper_get_page_offset(Relocator::Address pValue)
41 {
42   return (pValue & (Relocator::Address) 0xFFF);
43 }
44 
get_mask(uint32_t pValue)45 static inline uint32_t get_mask(uint32_t pValue)
46 {
47   return ((1u << (pValue)) - 1);
48 }
49 
50 static inline uint32_t
helper_reencode_adr_imm(uint32_t pInst,uint32_t pImm)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.
helper_reencode_add_imm(uint32_t pInst,uint32_t pImm)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
helper_reencode_branch_offset_26(uint32_t pInst,uint32_t pOff)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
helper_reencode_cond_branch_ofs_19(uint32_t pInst,uint32_t pOff)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
helper_reencode_ldst_pos_imm(uint32_t pInst,uint32_t pImm)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 
helper_get_upper32(Relocator::DWord pData)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 
helper_put_upper32(uint32_t pData,Relocator::DWord & pDes)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
helper_get_PLT_address(ResolveInfo & pSym,AArch64Relocator & pParent)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&
helper_PLT_init(Relocation & pReloc,AArch64Relocator & pParent)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&
helper_DynRela_init(ResolveInfo * pSym,Fragment & pFrag,uint64_t pOffset,Relocator::Type pType,AArch64Relocator & pParent)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
helper_use_relative_reloc(const ResolveInfo & pSym,const AArch64Relocator & pParent)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
helper_get_GOT_address(ResolveInfo & pSym,AArch64Relocator & pParent)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
helper_GOT_ORG(AArch64Relocator & pParent)173 helper_GOT_ORG(AArch64Relocator& pParent)
174 {
175   return pParent.getTarget().getGOT().addr();
176 }
177 
178 static inline AArch64GOTEntry&
helper_GOT_init(Relocation & pReloc,bool pHasRel,AArch64Relocator & pParent)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