AArch64RelocationHelpers.h revision 37b74a387bb3993387029859c2d9d051c41c724e
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 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
32static inline Relocator::Address helper_get_page_address(
33    Relocator::Address pValue) {
34  return (pValue & ~(Relocator::Address)0xFFF);
35}
36
37static inline Relocator::Address helper_get_page_offset(
38    Relocator::Address pValue) {
39  return (pValue & (Relocator::Address)0xFFF);
40}
41
42static inline uint32_t get_mask(uint32_t pValue) {
43  return ((1u << (pValue)) - 1);
44}
45
46static 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.
52static 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.
57static 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.
63static 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.
69static 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
74static inline uint32_t helper_get_upper32(Relocator::DWord pData) {
75  if (llvm::sys::IsLittleEndianHost)
76    return pData >> 32;
77  return pData & 0xFFFFFFFF;
78}
79
80static inline void helper_put_upper32(uint32_t pData, Relocator::DWord& pDes) {
81  *(reinterpret_cast<uint32_t*>(&pDes)) = pData;
82}
83
84static 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
92static 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(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
117static 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 == 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
136static 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
145static 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
153static inline Relocator::Address helper_GOT_ORG(AArch64Relocator& pParent) {
154  return pParent.getTarget().getGOT().addr();
155}
156
157static 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, 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, R_AARCH64_GLOB_DAT, pParent);
182      got_entry->setValue(0);
183    }
184  }
185  return *got_entry;
186}
187
188}  // namespace mcld
189
190#endif  // TARGET_AARCH64_AARCH64RELOCATIONHELPERS_H_
191