AArch64Relocator.cpp revision 37b74a387bb3993387029859c2d9d051c41c724e
1//===- AArch64Relocator.cpp  ----------------------------------------------===//
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
10#include "mcld/LinkerConfig.h"
11#include "mcld/IRBuilder.h"
12#include "mcld/Support/MsgHandling.h"
13#include "mcld/LD/LDSymbol.h"
14#include "mcld/LD/ELFFileFormat.h"
15#include "mcld/Object/ObjectBuilder.h"
16
17#include "AArch64Relocator.h"
18#include "AArch64RelocationFunctions.h"
19#include "AArch64RelocationHelpers.h"
20
21#include <llvm/ADT/Twine.h>
22#include <llvm/Support/DataTypes.h>
23#include <llvm/Support/ELF.h>
24#include <llvm/Support/Host.h>
25
26namespace mcld {
27
28//===----------------------------------------------------------------------===//
29// Relocation Functions and Tables
30//===----------------------------------------------------------------------===//
31DECL_AARCH64_APPLY_RELOC_FUNCS
32
33/// the prototype of applying function
34typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc,
35                                               AArch64Relocator& pParent);
36
37// the table entry of applying functions
38class ApplyFunctionEntry {
39 public:
40  ApplyFunctionEntry() {}
41  ApplyFunctionEntry(ApplyFunctionType pFunc,
42                     const char* pName,
43                     size_t pSize = 0)
44      : func(pFunc), name(pName), size(pSize) {}
45  ApplyFunctionType func;
46  const char* name;
47  size_t size;
48};
49typedef std::map<Relocator::Type, ApplyFunctionEntry> ApplyFunctionMap;
50
51static const ApplyFunctionMap::value_type ApplyFunctionList[] = {
52    DECL_AARCH64_APPLY_RELOC_FUNC_PTRS(ApplyFunctionMap::value_type,
53                                       ApplyFunctionEntry)};
54
55// declare the table of applying functions
56static ApplyFunctionMap ApplyFunctions(ApplyFunctionList,
57                                       ApplyFunctionList +
58                                           sizeof(ApplyFunctionList) /
59                                               sizeof(ApplyFunctionList[0]));
60
61//===----------------------------------------------------------------------===//
62// AArch64Relocator
63//===----------------------------------------------------------------------===//
64AArch64Relocator::AArch64Relocator(AArch64GNULDBackend& pParent,
65                                   const LinkerConfig& pConfig)
66    : Relocator(pConfig), m_Target(pParent) {
67}
68
69AArch64Relocator::~AArch64Relocator() {
70}
71
72Relocator::Result AArch64Relocator::applyRelocation(Relocation& pRelocation) {
73  Relocation::Type type = pRelocation.type();
74  // valid types are 0x0, 0x100-0x239
75  if ((type < 0x100 || type > 0x239) && (type != 0x0)) {
76    return Relocator::Unknown;
77  }
78  assert(ApplyFunctions.find(type) != ApplyFunctions.end());
79  return ApplyFunctions[type].func(pRelocation, *this);
80}
81
82const char* AArch64Relocator::getName(Relocator::Type pType) const {
83  assert(ApplyFunctions.find(pType) != ApplyFunctions.end());
84  return ApplyFunctions[pType].name;
85}
86
87Relocator::Size AArch64Relocator::getSize(Relocation::Type pType) const {
88  return ApplyFunctions[pType].size;
89}
90
91void AArch64Relocator::addCopyReloc(ResolveInfo& pSym) {
92  Relocation& rel_entry = *getTarget().getRelaDyn().create();
93  rel_entry.setType(R_AARCH64_COPY);
94  assert(pSym.outSymbol()->hasFragRef());
95  rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef());
96  rel_entry.setSymInfo(&pSym);
97}
98
99/// defineSymbolForCopyReloc
100/// For a symbol needing copy relocation, define a copy symbol in the BSS
101/// section and all other reference to this symbol should refer to this
102/// copy.
103/// This is executed at scan relocation stage.
104LDSymbol& AArch64Relocator::defineSymbolforCopyReloc(IRBuilder& pBuilder,
105                                                     const ResolveInfo& pSym) {
106  // get or create corresponding BSS LDSection
107  LDSection* bss_sect_hdr = NULL;
108  ELFFileFormat* file_format = getTarget().getOutputFormat();
109  if (ResolveInfo::ThreadLocal == pSym.type())
110    bss_sect_hdr = &file_format->getTBSS();
111  else
112    bss_sect_hdr = &file_format->getBSS();
113
114  // get or create corresponding BSS SectionData
115  SectionData* bss_data = NULL;
116  if (bss_sect_hdr->hasSectionData())
117    bss_data = bss_sect_hdr->getSectionData();
118  else
119    bss_data = IRBuilder::CreateSectionData(*bss_sect_hdr);
120
121  // Determine the alignment by the symbol value
122  // FIXME: here we use the largest alignment
123  uint32_t addralign = config().targets().bitclass() / 8;
124
125  // allocate space in BSS for the copy symbol
126  Fragment* frag = new FillFragment(0x0, 1, pSym.size());
127  uint64_t size = ObjectBuilder::AppendFragment(*frag, *bss_data, addralign);
128  bss_sect_hdr->setSize(bss_sect_hdr->size() + size);
129
130  // change symbol binding to Global if it's a weak symbol
131  ResolveInfo::Binding binding = (ResolveInfo::Binding)pSym.binding();
132  if (binding == ResolveInfo::Weak)
133    binding = ResolveInfo::Global;
134
135  // Define the copy symbol in the bss section and resolve it
136  LDSymbol* cpy_sym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
137      pSym.name(),
138      (ResolveInfo::Type)pSym.type(),
139      ResolveInfo::Define,
140      binding,
141      pSym.size(),  // size
142      0x0,          // value
143      FragmentRef::Create(*frag, 0x0),
144      (ResolveInfo::Visibility)pSym.other());
145
146  return *cpy_sym;
147}
148
149void AArch64Relocator::scanLocalReloc(Relocation& pReloc,
150                                      const LDSection& pSection) {
151  // rsym - The relocation target symbol
152  ResolveInfo* rsym = pReloc.symInfo();
153  switch (pReloc.type()) {
154    case llvm::ELF::R_AARCH64_ABS64:
155      // If buiding PIC object (shared library or PIC executable),
156      // a dynamic relocations with RELATIVE type to this location is needed.
157      // Reserve an entry in .rel.dyn
158      if (config().isCodeIndep()) {
159        // set Rel bit
160        rsym->setReserved(rsym->reserved() | ReserveRel);
161        getTarget().checkAndSetHasTextRel(*pSection.getLink());
162        // set up the dyn rel directly
163        Relocation& reloc = helper_DynRela_init(rsym,
164                                                *pReloc.targetRef().frag(),
165                                                pReloc.targetRef().offset(),
166                                                R_AARCH64_RELATIVE,
167                                                *this);
168        getRelRelMap().record(pReloc, reloc);
169      }
170      return;
171
172    case llvm::ELF::R_AARCH64_ABS32:
173    case llvm::ELF::R_AARCH64_ABS16:
174      // If buiding PIC object (shared library or PIC executable),
175      // a dynamic relocations with RELATIVE type to this location is needed.
176      // Reserve an entry in .rel.dyn
177      if (config().isCodeIndep()) {
178        // set up the dyn rel directly
179        Relocation& reloc = helper_DynRela_init(rsym,
180                                                *pReloc.targetRef().frag(),
181                                                pReloc.targetRef().offset(),
182                                                pReloc.type(),
183                                                *this);
184        getRelRelMap().record(pReloc, reloc);
185        // set Rel bit
186        rsym->setReserved(rsym->reserved() | ReserveRel);
187        getTarget().checkAndSetHasTextRel(*pSection.getLink());
188      }
189      return;
190
191    case llvm::ELF::R_AARCH64_ADR_GOT_PAGE:
192    case llvm::ELF::R_AARCH64_LD64_GOT_LO12_NC: {
193      // Symbol needs GOT entry, reserve entry in .got
194      // return if we already create GOT for this symbol
195      if (rsym->reserved() & ReserveGOT)
196        return;
197      // If building PIC object, a dynamic relocation with
198      // type RELATIVE is needed to relocate this GOT entry.
199      if (config().isCodeIndep())
200        helper_GOT_init(pReloc, true, *this);
201      else
202        helper_GOT_init(pReloc, false, *this);
203      // set GOT bit
204      rsym->setReserved(rsym->reserved() | ReserveGOT);
205      return;
206    }
207
208    default:
209      break;
210  }
211}
212
213void AArch64Relocator::scanGlobalReloc(Relocation& pReloc,
214                                       IRBuilder& pBuilder,
215                                       const LDSection& pSection) {
216  // rsym - The relocation target symbol
217  ResolveInfo* rsym = pReloc.symInfo();
218  switch (pReloc.type()) {
219    case llvm::ELF::R_AARCH64_ABS64:
220    case llvm::ELF::R_AARCH64_ABS32:
221    case llvm::ELF::R_AARCH64_ABS16:
222      // Absolute relocation type, symbol may needs PLT entry or
223      // dynamic relocation entry
224      if (getTarget().symbolNeedsPLT(*rsym)) {
225        // create plt for this symbol if it does not have one
226        if (!(rsym->reserved() & ReservePLT)) {
227          // Symbol needs PLT entry, we need a PLT entry
228          // and the corresponding GOT and dynamic relocation entry
229          // in .got and .rel.plt.
230          helper_PLT_init(pReloc, *this);
231          // set PLT bit
232          rsym->setReserved(rsym->reserved() | ReservePLT);
233        }
234      }
235
236      if (getTarget()
237              .symbolNeedsDynRel(
238                  *rsym, (rsym->reserved() & ReservePLT), true)) {
239        // symbol needs dynamic relocation entry, set up the dynrel entry
240        if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
241          LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
242          addCopyReloc(*cpy_sym.resolveInfo());
243        } else {
244          // set Rel bit and the dyn rel
245          rsym->setReserved(rsym->reserved() | ReserveRel);
246          getTarget().checkAndSetHasTextRel(*pSection.getLink());
247          if (llvm::ELF::R_AARCH64_ABS64 == pReloc.type() &&
248              helper_use_relative_reloc(*rsym, *this)) {
249            Relocation& reloc = helper_DynRela_init(rsym,
250                                                    *pReloc.targetRef().frag(),
251                                                    pReloc.targetRef().offset(),
252                                                    R_AARCH64_RELATIVE,
253                                                    *this);
254            getRelRelMap().record(pReloc, reloc);
255          } else {
256            Relocation& reloc = helper_DynRela_init(rsym,
257                                                    *pReloc.targetRef().frag(),
258                                                    pReloc.targetRef().offset(),
259                                                    pReloc.type(),
260                                                    *this);
261            getRelRelMap().record(pReloc, reloc);
262          }
263        }
264      }
265      return;
266
267    case llvm::ELF::R_AARCH64_PREL64:
268    case llvm::ELF::R_AARCH64_PREL32:
269    case llvm::ELF::R_AARCH64_PREL16:
270      if (getTarget().symbolNeedsPLT(*rsym) &&
271          LinkerConfig::DynObj != config().codeGenType()) {
272        // create plt for this symbol if it does not have one
273        if (!(rsym->reserved() & ReservePLT)) {
274          // Symbol needs PLT entry, we need a PLT entry
275          // and the corresponding GOT and dynamic relocation entry
276          // in .got and .rel.plt.
277          helper_PLT_init(pReloc, *this);
278          // set PLT bit
279          rsym->setReserved(rsym->reserved() | ReservePLT);
280        }
281      }
282
283      // Only PC relative relocation against dynamic symbol needs a
284      // dynamic relocation.  Only dynamic copy relocation is allowed
285      // and PC relative relocation will be resolved to the local copy.
286      // All other dynamic relocations may lead to run-time relocation
287      // overflow.
288      if (getTarget().isDynamicSymbol(*rsym) &&
289          getTarget()
290              .symbolNeedsDynRel(
291                  *rsym, (rsym->reserved() & ReservePLT), false) &&
292          getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
293        LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
294        addCopyReloc(*cpy_sym.resolveInfo());
295      }
296      return;
297
298    case llvm::ELF::R_AARCH64_CONDBR19:
299    case llvm::ELF::R_AARCH64_JUMP26:
300    case llvm::ELF::R_AARCH64_CALL26: {
301      // return if we already create plt for this symbol
302      if (rsym->reserved() & ReservePLT)
303        return;
304
305      // if the symbol's value can be decided at link time, then no need plt
306      if (getTarget().symbolFinalValueIsKnown(*rsym))
307        return;
308
309      // if symbol is defined in the ouput file and it's not
310      // preemptible, no need plt
311      if (rsym->isDefine() && !rsym->isDyn() &&
312          !getTarget().isSymbolPreemptible(*rsym)) {
313        return;
314      }
315
316      // Symbol needs PLT entry, we need to reserve a PLT entry
317      // and the corresponding GOT and dynamic relocation entry
318      // in .got and .rel.plt.
319      helper_PLT_init(pReloc, *this);
320      // set PLT bit
321      rsym->setReserved(rsym->reserved() | ReservePLT);
322      return;
323    }
324
325    case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21:
326    case R_AARCH64_ADR_PREL_PG_HI21_NC:
327      if (getTarget()
328              .symbolNeedsDynRel(
329                  *rsym, (rsym->reserved() & ReservePLT), false)) {
330        if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
331          LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
332          addCopyReloc(*cpy_sym.resolveInfo());
333        }
334      }
335      if (getTarget().symbolNeedsPLT(*rsym)) {
336        // create plt for this symbol if it does not have one
337        if (!(rsym->reserved() & ReservePLT)) {
338          // Symbol needs PLT entry, we need a PLT entry
339          // and the corresponding GOT and dynamic relocation entry
340          // in .got and .rel.plt.
341          helper_PLT_init(pReloc, *this);
342          // set PLT bit
343          rsym->setReserved(rsym->reserved() | ReservePLT);
344        }
345      }
346      return;
347
348    case llvm::ELF::R_AARCH64_ADR_GOT_PAGE:
349    case llvm::ELF::R_AARCH64_LD64_GOT_LO12_NC: {
350      // Symbol needs GOT entry, reserve entry in .got
351      // return if we already create GOT for this symbol
352      if (rsym->reserved() & ReserveGOT)
353        return;
354      // if the symbol cannot be fully resolved at link time, then we need a
355      // dynamic relocation
356      if (!getTarget().symbolFinalValueIsKnown(*rsym))
357        helper_GOT_init(pReloc, true, *this);
358      else
359        helper_GOT_init(pReloc, false, *this);
360      // set GOT bit
361      rsym->setReserved(rsym->reserved() | ReserveGOT);
362      return;
363    }
364
365    default:
366      break;
367  }
368}
369
370void AArch64Relocator::scanRelocation(Relocation& pReloc,
371                                      IRBuilder& pBuilder,
372                                      Module& pModule,
373                                      LDSection& pSection,
374                                      Input& pInput) {
375  ResolveInfo* rsym = pReloc.symInfo();
376  assert(rsym != NULL &&
377         "ResolveInfo of relocation not set while scanRelocation");
378
379  assert(pSection.getLink() != NULL);
380  if ((pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC) == 0)
381    return;
382
383  // Scan relocation type to determine if an GOT/PLT/Dynamic Relocation
384  // entries should be created.
385  // FIXME: Below judgements concern nothing about TLS related relocation
386
387  // rsym is local
388  if (rsym->isLocal())
389    scanLocalReloc(pReloc, pSection);
390  // rsym is external
391  else
392    scanGlobalReloc(pReloc, pBuilder, pSection);
393
394  // check if we shoule issue undefined reference for the relocation target
395  // symbol
396  if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
397    issueUndefRef(pReloc, pSection, pInput);
398}
399
400uint32_t AArch64Relocator::getDebugStringOffset(Relocation& pReloc) const {
401  if (pReloc.type() != llvm::ELF::R_AARCH64_ABS32)
402    error(diag::unsupport_reloc_for_debug_string)
403        << getName(pReloc.type()) << "mclinker@googlegroups.com";
404
405  if (pReloc.symInfo()->type() == ResolveInfo::Section)
406    return pReloc.target();
407  else
408    return pReloc.symInfo()->outSymbol()->fragRef()->offset() +
409               pReloc.target() + pReloc.addend();
410}
411
412void AArch64Relocator::applyDebugStringOffset(Relocation& pReloc,
413                                              uint32_t pOffset) {
414  pReloc.target() = pOffset;
415}
416
417//===----------------------------------------------------------------------===//
418// Each relocation function implementation
419//===----------------------------------------------------------------------===//
420
421// R_AARCH64_NONE
422Relocator::Result none(Relocation& pReloc, AArch64Relocator& pParent) {
423  return Relocator::OK;
424}
425
426Relocator::Result unsupported(Relocation& pReloc, AArch64Relocator& pParent) {
427  return Relocator::Unsupported;
428}
429
430// R_AARCH64_ABS64: S + A
431// R_AARCH64_ABS32: S + A
432// R_AARCH64_ABS16: S + A
433Relocator::Result abs(Relocation& pReloc, AArch64Relocator& pParent) {
434  ResolveInfo* rsym = pReloc.symInfo();
435  Relocator::DWord A = pReloc.target() + pReloc.addend();
436  Relocator::DWord S = pReloc.symValue();
437  Relocation* dyn_rel = pParent.getRelRelMap().lookUp(pReloc);
438  bool has_dyn_rel = (dyn_rel != NULL);
439
440  LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
441  // If the flag of target section is not ALLOC, we will not scan this
442  // relocation but perform static relocation. (e.g., applying .debug section)
443  if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
444    pReloc.target() = S + A;
445    return Relocator::OK;
446  }
447  // A local symbol may need RELATIVE Type dynamic relocation
448  if (rsym->isLocal() && has_dyn_rel) {
449    dyn_rel->setAddend(S + A);
450  }
451
452  // An external symbol may need PLT and dynamic relocation
453  if (!rsym->isLocal()) {
454    if (rsym->reserved() & AArch64Relocator::ReservePLT) {
455      S = helper_get_PLT_address(*rsym, pParent);
456    }
457    // If we generate a dynamic relocation (except R_AARCH64_64_RELATIVE)
458    // for a place, we should not perform static relocation on it
459    // in order to keep the addend store in the place correct.
460    if (has_dyn_rel) {
461      if (llvm::ELF::R_AARCH64_ABS64 == pReloc.type() &&
462          R_AARCH64_RELATIVE == dyn_rel->type()) {
463        dyn_rel->setAddend(S + A);
464      } else {
465        dyn_rel->setAddend(A);
466        return Relocator::OK;
467      }
468    }
469  }
470
471  // perform static relocation
472  pReloc.target() = S + A;
473  return Relocator::OK;
474}
475
476// R_AARCH64_PREL64: S + A - P
477// R_AARCH64_PREL32: S + A - P
478// R_AARCH64_PREL16: S + A - P
479Relocator::Result rel(Relocation& pReloc, AArch64Relocator& pParent) {
480  ResolveInfo* rsym = pReloc.symInfo();
481  Relocator::Address S = pReloc.symValue();
482  Relocator::DWord A = pReloc.addend();
483  Relocator::DWord P = pReloc.place();
484
485  if (llvm::ELF::R_AARCH64_PREL64 != pReloc.type())
486    A += pReloc.target() & get_mask(pParent.getSize(pReloc.type()));
487  else
488    A += pReloc.target();
489
490  LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
491  // If the flag of target section is not ALLOC, we will not scan this
492  // relocation but perform static relocation. (e.g., applying .debug section)
493  if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
494    // if plt entry exists, the S value is the plt entry address
495    if (!rsym->isLocal()) {
496      if (rsym->reserved() & AArch64Relocator::ReservePLT) {
497        S = helper_get_PLT_address(*rsym, pParent);
498      }
499    }
500  }
501
502  Relocator::DWord X = S + A - P;
503  pReloc.target() = X;
504
505  if (llvm::ELF::R_AARCH64_PREL64 != pReloc.type() &&
506      helper_check_signed_overflow(X, pParent.getSize(pReloc.type())))
507    return Relocator::Overflow;
508  return Relocator::OK;
509}
510
511// R_AARCH64_ADD_ABS_LO12_NC: S + A
512Relocator::Result add_abs_lo12(Relocation& pReloc, AArch64Relocator& pParent) {
513  Relocator::Address value = 0x0;
514  Relocator::Address S = pReloc.symValue();
515  Relocator::DWord A = pReloc.addend();
516
517  value = helper_get_page_offset(S + A);
518  pReloc.target() = helper_reencode_add_imm(pReloc.target(), value);
519
520  return Relocator::OK;
521}
522
523// R_AARCH64_ADR_PREL_PG_HI21: ((PG(S + A) - PG(P)) >> 12)
524// R_AARCH64_ADR_PREL_PG_HI21_NC: ((PG(S + A) - PG(P)) >> 12)
525Relocator::Result adr_prel_pg_hi21(Relocation& pReloc,
526                                   AArch64Relocator& pParent) {
527  ResolveInfo* rsym = pReloc.symInfo();
528  Relocator::Address S = pReloc.symValue();
529  // if plt entry exists, the S value is the plt entry address
530  if (rsym->reserved() & AArch64Relocator::ReservePLT) {
531    S = helper_get_PLT_address(*rsym, pParent);
532  }
533  Relocator::DWord A = pReloc.addend();
534  Relocator::DWord P = pReloc.place();
535  Relocator::DWord X =
536      helper_get_page_address(S + A) - helper_get_page_address(P);
537
538  pReloc.target() = helper_reencode_adr_imm(pReloc.target(), (X >> 12));
539
540  return Relocator::OK;
541}
542
543// R_AARCH64_CALL26: S + A - P
544// R_AARCH64_JUMP26: S + A - P
545Relocator::Result call(Relocation& pReloc, AArch64Relocator& pParent) {
546  // If target is undefined weak symbol, we only need to jump to the
547  // next instruction unless it has PLT entry. Rewrite instruction
548  // to NOP.
549  if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
550      !pReloc.symInfo()->isDyn() &&
551      !(pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)) {
552    // change target to NOP
553    pReloc.target() = 0xd503201f;
554    return Relocator::OK;
555  }
556
557  Relocator::Address S = pReloc.symValue();
558  Relocator::DWord A = pReloc.addend();
559  Relocator::Address P = pReloc.place();
560
561  // S depends on PLT exists or not
562  if (pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)
563    S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
564
565  Relocator::DWord X = S + A - P;
566  // TODO: check overflow..
567
568  pReloc.target() = helper_reencode_branch_offset_26(pReloc.target(), X >> 2);
569
570  return Relocator::OK;
571}
572
573// R_AARCH64_CONDBR19: S + A - P
574Relocator::Result condbr(Relocation& pReloc, AArch64Relocator& pParent) {
575  // If target is undefined weak symbol, we only need to jump to the
576  // next instruction unless it has PLT entry. Rewrite instruction
577  // to NOP.
578  if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
579      !pReloc.symInfo()->isDyn() &&
580      !(pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)) {
581    // change target to NOP
582    pReloc.target() = 0xd503201f;
583    return Relocator::OK;
584  }
585
586  Relocator::Address S = pReloc.symValue();
587  Relocator::DWord A = pReloc.addend();
588  Relocator::Address P = pReloc.place();
589
590  // S depends on PLT exists or not
591  if (pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)
592    S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
593
594  Relocator::DWord X = S + A - P;
595  // TODO: check overflow..
596
597  pReloc.target() = helper_reencode_cond_branch_ofs_19(pReloc.target(), X >> 2);
598
599  return Relocator::OK;
600}
601
602// R_AARCH64_ADR_GOT_PAGE: Page(G(GDAT(S+A))) - Page(P)
603Relocator::Result adr_got_page(Relocation& pReloc, AArch64Relocator& pParent) {
604  if (!(pReloc.symInfo()->reserved() & AArch64Relocator::ReserveGOT)) {
605    return Relocator::BadReloc;
606  }
607
608  Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent);
609  Relocator::DWord A = pReloc.addend();
610  Relocator::Address P = pReloc.place();
611  Relocator::DWord X =
612      helper_get_page_address(GOT_S + A) - helper_get_page_address(P);
613
614  pReloc.target() = helper_reencode_adr_imm(pReloc.target(), (X >> 12));
615
616  // setup got entry value if needed
617  AArch64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
618  if (got_entry != NULL && AArch64Relocator::SymVal == got_entry->getValue())
619    got_entry->setValue(pReloc.symValue());
620  // setup relocation addend if needed
621  Relocation* dyn_rela = pParent.getRelRelMap().lookUp(pReloc);
622  if ((dyn_rela != NULL) && (AArch64Relocator::SymVal == dyn_rela->addend())) {
623    dyn_rela->setAddend(pReloc.symValue());
624  }
625  return Relocator::OK;
626}
627
628// R_AARCH64_LD64_GOT_LO12_NC: G(GDAT(S+A))
629Relocator::Result ld64_got_lo12(Relocation& pReloc, AArch64Relocator& pParent) {
630  if (!(pReloc.symInfo()->reserved() & AArch64Relocator::ReserveGOT)) {
631    return Relocator::BadReloc;
632  }
633
634  Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent);
635  Relocator::DWord A = pReloc.addend();
636  Relocator::DWord X = helper_get_page_offset(GOT_S + A);
637
638  pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 3));
639
640  // setup got entry value if needed
641  AArch64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
642  if (got_entry != NULL && AArch64Relocator::SymVal == got_entry->getValue())
643    got_entry->setValue(pReloc.symValue());
644
645  // setup relocation addend if needed
646  Relocation* dyn_rela = pParent.getRelRelMap().lookUp(pReloc);
647  if ((dyn_rela != NULL) && (AArch64Relocator::SymVal == dyn_rela->addend())) {
648    dyn_rela->setAddend(pReloc.symValue());
649  }
650
651  return Relocator::OK;
652}
653
654// R_AARCH64_LDST8_ABS_LO12_NC: S + A
655// R_AARCH64_LDST16_ABS_LO12_NC: S + A
656// R_AARCH64_LDST32_ABS_LO12_NC: S + A
657// R_AARCH64_LDST64_ABS_LO12_NC: S + A
658// R_AARCH64_LDST128_ABS_LO12_NC: S + A
659Relocator::Result ldst_abs_lo12(Relocation& pReloc, AArch64Relocator& pParent) {
660  Relocator::Address S = pReloc.symValue();
661  Relocator::DWord A = pReloc.addend();
662  Relocator::DWord X = helper_get_page_offset(S + A);
663
664  switch (pReloc.type()) {
665    case llvm::ELF::R_AARCH64_LDST8_ABS_LO12_NC:
666      pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), X);
667      break;
668    case llvm::ELF::R_AARCH64_LDST16_ABS_LO12_NC:
669      pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 1));
670      break;
671    case llvm::ELF::R_AARCH64_LDST32_ABS_LO12_NC:
672      pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 2));
673      break;
674    case llvm::ELF::R_AARCH64_LDST64_ABS_LO12_NC:
675      pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 3));
676      break;
677    case llvm::ELF::R_AARCH64_LDST128_ABS_LO12_NC:
678      pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 4));
679      break;
680    default:
681      break;
682  }
683  return Relocator::OK;
684}
685
686}  // namespace mcld
687