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
helper_check_signed_overflow(Relocator::DWord pValue,unsigned bits)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 
helper_get_page_address(Relocator::Address pValue)32 static inline Relocator::Address helper_get_page_address(
33     Relocator::Address pValue) {
34   return (pValue & ~(Relocator::Address)0xFFF);
35 }
36 
helper_get_page_offset(Relocator::Address pValue)37 static inline Relocator::Address helper_get_page_offset(
38     Relocator::Address pValue) {
39   return (pValue & (Relocator::Address)0xFFF);
40 }
41 
get_mask(uint32_t pValue)42 static inline uint32_t get_mask(uint32_t pValue) {
43   return ((1u << (pValue)) - 1);
44 }
45 
helper_reencode_adr_imm(uint32_t pInst,uint32_t pImm)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.
helper_reencode_add_imm(uint32_t pInst,uint32_t pImm)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.
helper_reencode_branch_offset_26(uint32_t pInst,uint32_t pOff)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.
helper_reencode_cond_branch_ofs_19(uint32_t pInst,uint32_t pOff)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.
helper_reencode_ldst_pos_imm(uint32_t pInst,uint32_t pImm)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 
helper_get_upper32(Relocator::DWord pData)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 
helper_put_upper32(uint32_t pData,Relocator::DWord & pDes)80 static inline void helper_put_upper32(uint32_t pData, Relocator::DWord& pDes) {
81   *(reinterpret_cast<uint32_t*>(&pDes)) = pData;
82 }
83 
helper_get_PLT_address(ResolveInfo & pSym,AArch64Relocator & pParent)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 
helper_PLT_init(Relocation & pReloc,AArch64Relocator & pParent)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
helper_DynRela_init(ResolveInfo * pSym,Fragment & pFrag,uint64_t pOffset,Relocator::Type pType,AArch64Relocator & pParent)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
helper_use_relative_reloc(const ResolveInfo & pSym,const AArch64Relocator & pParent)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 
helper_get_GOT_address(ResolveInfo & pSym,AArch64Relocator & pParent)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 
helper_GOT_ORG(AArch64Relocator & pParent)153 static inline Relocator::Address helper_GOT_ORG(AArch64Relocator& pParent) {
154   return pParent.getTarget().getGOT().addr();
155 }
156 
helper_GOT_init(Relocation & pReloc,bool pHasRel,AArch64Relocator & pParent)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