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