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