AArch64RelocationHelpers.h revision 551ae4ebd3e9d137ea668fb83ae4a55b8cfba451
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
15namespace mcld {
16//===----------------------------------------------------------------------===//
17// Relocation helper functions
18//===----------------------------------------------------------------------===//
19// Return true if overflow
20static inline bool
21helper_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
33static inline Relocator::Address
34helper_get_page_address(Relocator::Address pValue)
35{
36  return (pValue & ~ (Relocator::Address) 0xFFF);
37}
38
39static inline Relocator::Address
40helper_get_page_offset(Relocator::Address pValue)
41{
42  return (pValue & (Relocator::Address) 0xFFF);
43}
44
45static inline uint32_t get_mask(uint32_t pValue)
46{
47  return ((1u << (pValue)) - 1);
48}
49
50static inline uint32_t
51helper_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.
58static 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.
64static inline uint32_t
65helper_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.
71static inline uint32_t
72helper_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.
78static inline uint32_t
79helper_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
84static 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
91static inline void helper_put_upper32(uint32_t pData, Relocator::DWord& pDes)
92{
93  *(reinterpret_cast<uint32_t*>(&pDes)) = pData;
94}
95
96static inline Relocator::Address
97helper_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
104static inline AArch64PLT1&
105helper_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
130static inline Relocation&
131helper_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
151static inline bool
152helper_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
164static inline Relocator::Address
165helper_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
172static inline Relocator::Address
173helper_GOT_ORG(AArch64Relocator& pParent)
174{
175  return pParent.getTarget().getGOT().addr();
176}
177
178static inline AArch64GOTEntry&
179helper_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