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