AArch64Relocator.cpp revision a6c24dff8b7fa2551a3a885e77a2e814f5b764a2
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(llvm::ELF::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                                                llvm::ELF::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                                                    llvm::ELF::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_LO21:
326    case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21:
327    case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21_NC:
328      if (getTarget()
329              .symbolNeedsDynRel(
330                  *rsym, (rsym->reserved() & ReservePLT), false)) {
331        if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
332          LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
333          addCopyReloc(*cpy_sym.resolveInfo());
334        }
335      }
336      if (getTarget().symbolNeedsPLT(*rsym)) {
337        // create plt for this symbol if it does not have one
338        if (!(rsym->reserved() & ReservePLT)) {
339          // Symbol needs PLT entry, we need a PLT entry
340          // and the corresponding GOT and dynamic relocation entry
341          // in .got and .rel.plt.
342          helper_PLT_init(pReloc, *this);
343          // set PLT bit
344          rsym->setReserved(rsym->reserved() | ReservePLT);
345        }
346      }
347      return;
348
349    case llvm::ELF::R_AARCH64_ADR_GOT_PAGE:
350    case llvm::ELF::R_AARCH64_LD64_GOT_LO12_NC: {
351      // Symbol needs GOT entry, reserve entry in .got
352      // return if we already create GOT for this symbol
353      if (rsym->reserved() & ReserveGOT)
354        return;
355      // if the symbol cannot be fully resolved at link time, then we need a
356      // dynamic relocation
357      if (!getTarget().symbolFinalValueIsKnown(*rsym))
358        helper_GOT_init(pReloc, true, *this);
359      else
360        helper_GOT_init(pReloc, false, *this);
361      // set GOT bit
362      rsym->setReserved(rsym->reserved() | ReserveGOT);
363      return;
364    }
365
366    default:
367      break;
368  }
369}
370
371void AArch64Relocator::scanRelocation(Relocation& pReloc,
372                                      IRBuilder& pBuilder,
373                                      Module& pModule,
374                                      LDSection& pSection,
375                                      Input& pInput) {
376  ResolveInfo* rsym = pReloc.symInfo();
377  assert(rsym != NULL &&
378         "ResolveInfo of relocation not set while scanRelocation");
379
380  assert(pSection.getLink() != NULL);
381  if ((pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC) == 0)
382    return;
383
384  // Scan relocation type to determine if an GOT/PLT/Dynamic Relocation
385  // entries should be created.
386  // FIXME: Below judgements concern nothing about TLS related relocation
387
388  // rsym is local
389  if (rsym->isLocal())
390    scanLocalReloc(pReloc, pSection);
391  // rsym is external
392  else
393    scanGlobalReloc(pReloc, pBuilder, pSection);
394
395  // check if we shoule issue undefined reference for the relocation target
396  // symbol
397  if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
398    issueUndefRef(pReloc, pSection, pInput);
399}
400
401uint32_t AArch64Relocator::getDebugStringOffset(Relocation& pReloc) const {
402  if (pReloc.type() != llvm::ELF::R_AARCH64_ABS32)
403    error(diag::unsupport_reloc_for_debug_string)
404        << getName(pReloc.type()) << "mclinker@googlegroups.com";
405
406  if (pReloc.symInfo()->type() == ResolveInfo::Section)
407    return pReloc.target();
408  else
409    return pReloc.symInfo()->outSymbol()->fragRef()->offset() +
410               pReloc.target() + pReloc.addend();
411}
412
413void AArch64Relocator::applyDebugStringOffset(Relocation& pReloc,
414                                              uint32_t pOffset) {
415  pReloc.target() = pOffset;
416}
417
418//===----------------------------------------------------------------------===//
419// Each relocation function implementation
420//===----------------------------------------------------------------------===//
421
422// R_AARCH64_NONE
423Relocator::Result none(Relocation& pReloc, AArch64Relocator& pParent) {
424  return Relocator::OK;
425}
426
427Relocator::Result unsupported(Relocation& pReloc, AArch64Relocator& pParent) {
428  return Relocator::Unsupported;
429}
430
431// R_AARCH64_ABS64: S + A
432// R_AARCH64_ABS32: S + A
433// R_AARCH64_ABS16: S + A
434Relocator::Result abs(Relocation& pReloc, AArch64Relocator& pParent) {
435  ResolveInfo* rsym = pReloc.symInfo();
436  Relocator::DWord A = pReloc.target() + pReloc.addend();
437  Relocator::DWord S = pReloc.symValue();
438  Relocation* dyn_rel = pParent.getRelRelMap().lookUp(pReloc);
439  bool has_dyn_rel = (dyn_rel != NULL);
440
441  LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
442  // If the flag of target section is not ALLOC, we will not scan this
443  // relocation but perform static relocation. (e.g., applying .debug section)
444  if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
445    pReloc.target() = S + A;
446    return Relocator::OK;
447  }
448  // A local symbol may need RELATIVE Type dynamic relocation
449  if (rsym->isLocal() && has_dyn_rel) {
450    dyn_rel->setAddend(S + A);
451  }
452
453  // An external symbol may need PLT and dynamic relocation
454  if (!rsym->isLocal()) {
455    if (rsym->reserved() & AArch64Relocator::ReservePLT) {
456      S = helper_get_PLT_address(*rsym, pParent);
457    }
458    // If we generate a dynamic relocation (except R_AARCH64_64_RELATIVE)
459    // for a place, we should not perform static relocation on it
460    // in order to keep the addend store in the place correct.
461    if (has_dyn_rel) {
462      if (llvm::ELF::R_AARCH64_ABS64 == pReloc.type() &&
463          llvm::ELF::R_AARCH64_RELATIVE == dyn_rel->type()) {
464        dyn_rel->setAddend(S + A);
465      } else {
466        dyn_rel->setAddend(A);
467        return Relocator::OK;
468      }
469    }
470  }
471
472  // perform static relocation
473  pReloc.target() = S + A;
474  return Relocator::OK;
475}
476
477// R_AARCH64_PREL64: S + A - P
478// R_AARCH64_PREL32: S + A - P
479// R_AARCH64_PREL16: S + A - P
480Relocator::Result rel(Relocation& pReloc, AArch64Relocator& pParent) {
481  ResolveInfo* rsym = pReloc.symInfo();
482  Relocator::Address S = pReloc.symValue();
483  Relocator::DWord A = pReloc.addend();
484  Relocator::DWord P = pReloc.place();
485
486  if (llvm::ELF::R_AARCH64_PREL64 != pReloc.type())
487    A += pReloc.target() & get_mask(pParent.getSize(pReloc.type()));
488  else
489    A += pReloc.target();
490
491  LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
492  // If the flag of target section is not ALLOC, we will not scan this
493  // relocation but perform static relocation. (e.g., applying .debug section)
494  if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
495    // if plt entry exists, the S value is the plt entry address
496    if (!rsym->isLocal()) {
497      if (rsym->reserved() & AArch64Relocator::ReservePLT) {
498        S = helper_get_PLT_address(*rsym, pParent);
499      }
500    }
501  }
502
503  Relocator::DWord X = S + A - P;
504  pReloc.target() = X;
505
506  if (llvm::ELF::R_AARCH64_PREL64 != pReloc.type() &&
507      helper_check_signed_overflow(X, pParent.getSize(pReloc.type())))
508    return Relocator::Overflow;
509  return Relocator::OK;
510}
511
512// R_AARCH64_ADD_ABS_LO12_NC: S + A
513Relocator::Result add_abs_lo12(Relocation& pReloc, AArch64Relocator& pParent) {
514  Relocator::Address value = 0x0;
515  Relocator::Address S = pReloc.symValue();
516  Relocator::DWord A = pReloc.addend();
517
518  value = helper_get_page_offset(S + A);
519  pReloc.target() = helper_reencode_add_imm(pReloc.target(), value);
520
521  return Relocator::OK;
522}
523
524// R_AARCH64_ADR_PREL_LO21: S + A - P
525Relocator::Result adr_prel_lo21(Relocation& pReloc, AArch64Relocator& pParent) {
526  ResolveInfo* rsym = pReloc.symInfo();
527  Relocator::Address S = pReloc.symValue();
528  // if plt entry exists, the S value is the plt entry address
529  if (rsym->reserved() & AArch64Relocator::ReservePLT) {
530    S = helper_get_PLT_address(*rsym, pParent);
531  }
532  Relocator::DWord A = pReloc.addend();
533  Relocator::DWord P = pReloc.place();
534  Relocator::DWord X = S + A - P;
535
536  pReloc.target() = helper_reencode_adr_imm(pReloc.target(), X);
537
538  return Relocator::OK;
539}
540
541// R_AARCH64_ADR_PREL_PG_HI21: ((PG(S + A) - PG(P)) >> 12)
542// R_AARCH64_ADR_PREL_PG_HI21_NC: ((PG(S + A) - PG(P)) >> 12)
543Relocator::Result adr_prel_pg_hi21(Relocation& pReloc,
544                                   AArch64Relocator& pParent) {
545  ResolveInfo* rsym = pReloc.symInfo();
546  Relocator::Address S = pReloc.symValue();
547  // if plt entry exists, the S value is the plt entry address
548  if (rsym->reserved() & AArch64Relocator::ReservePLT) {
549    S = helper_get_PLT_address(*rsym, pParent);
550  }
551  Relocator::DWord A = pReloc.addend();
552  Relocator::DWord P = pReloc.place();
553  Relocator::DWord X =
554      helper_get_page_address(S + A) - helper_get_page_address(P);
555
556  pReloc.target() = helper_reencode_adr_imm(pReloc.target(), (X >> 12));
557
558  return Relocator::OK;
559}
560
561// R_AARCH64_CALL26: S + A - P
562// R_AARCH64_JUMP26: S + A - P
563Relocator::Result call(Relocation& pReloc, AArch64Relocator& pParent) {
564  // If target is undefined weak symbol, we only need to jump to the
565  // next instruction unless it has PLT entry. Rewrite instruction
566  // to NOP.
567  if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
568      !pReloc.symInfo()->isDyn() &&
569      !(pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)) {
570    // change target to NOP
571    pReloc.target() = 0xd503201f;
572    return Relocator::OK;
573  }
574
575  Relocator::Address S = pReloc.symValue();
576  Relocator::DWord A = pReloc.addend();
577  Relocator::Address P = pReloc.place();
578
579  // S depends on PLT exists or not
580  if (pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)
581    S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
582
583  Relocator::DWord X = S + A - P;
584  // TODO: check overflow..
585
586  pReloc.target() = helper_reencode_branch_offset_26(pReloc.target(), X >> 2);
587
588  return Relocator::OK;
589}
590
591// R_AARCH64_CONDBR19: S + A - P
592Relocator::Result condbr(Relocation& pReloc, AArch64Relocator& pParent) {
593  // If target is undefined weak symbol, we only need to jump to the
594  // next instruction unless it has PLT entry. Rewrite instruction
595  // to NOP.
596  if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
597      !pReloc.symInfo()->isDyn() &&
598      !(pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)) {
599    // change target to NOP
600    pReloc.target() = 0xd503201f;
601    return Relocator::OK;
602  }
603
604  Relocator::Address S = pReloc.symValue();
605  Relocator::DWord A = pReloc.addend();
606  Relocator::Address P = pReloc.place();
607
608  // S depends on PLT exists or not
609  if (pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)
610    S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
611
612  Relocator::DWord X = S + A - P;
613  // TODO: check overflow..
614
615  pReloc.target() = helper_reencode_cond_branch_ofs_19(pReloc.target(), X >> 2);
616
617  return Relocator::OK;
618}
619
620// R_AARCH64_ADR_GOT_PAGE: Page(G(GDAT(S+A))) - Page(P)
621Relocator::Result adr_got_page(Relocation& pReloc, AArch64Relocator& pParent) {
622  if (!(pReloc.symInfo()->reserved() & AArch64Relocator::ReserveGOT)) {
623    return Relocator::BadReloc;
624  }
625
626  Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent);
627  Relocator::DWord A = pReloc.addend();
628  Relocator::Address P = pReloc.place();
629  Relocator::DWord X =
630      helper_get_page_address(GOT_S + A) - helper_get_page_address(P);
631
632  pReloc.target() = helper_reencode_adr_imm(pReloc.target(), (X >> 12));
633
634  // setup got entry value if needed
635  AArch64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
636  if (got_entry != NULL && AArch64Relocator::SymVal == got_entry->getValue())
637    got_entry->setValue(pReloc.symValue());
638  // setup relocation addend if needed
639  Relocation* dyn_rela = pParent.getRelRelMap().lookUp(pReloc);
640  if ((dyn_rela != NULL) && (AArch64Relocator::SymVal == dyn_rela->addend())) {
641    dyn_rela->setAddend(pReloc.symValue());
642  }
643  return Relocator::OK;
644}
645
646// R_AARCH64_LD64_GOT_LO12_NC: G(GDAT(S+A))
647Relocator::Result ld64_got_lo12(Relocation& pReloc, AArch64Relocator& pParent) {
648  if (!(pReloc.symInfo()->reserved() & AArch64Relocator::ReserveGOT)) {
649    return Relocator::BadReloc;
650  }
651
652  Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent);
653  Relocator::DWord A = pReloc.addend();
654  Relocator::DWord X = helper_get_page_offset(GOT_S + A);
655
656  pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 3));
657
658  // setup got entry value if needed
659  AArch64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
660  if (got_entry != NULL && AArch64Relocator::SymVal == got_entry->getValue())
661    got_entry->setValue(pReloc.symValue());
662
663  // setup relocation addend if needed
664  Relocation* dyn_rela = pParent.getRelRelMap().lookUp(pReloc);
665  if ((dyn_rela != NULL) && (AArch64Relocator::SymVal == dyn_rela->addend())) {
666    dyn_rela->setAddend(pReloc.symValue());
667  }
668
669  return Relocator::OK;
670}
671
672// R_AARCH64_LDST8_ABS_LO12_NC: S + A
673// R_AARCH64_LDST16_ABS_LO12_NC: S + A
674// R_AARCH64_LDST32_ABS_LO12_NC: S + A
675// R_AARCH64_LDST64_ABS_LO12_NC: S + A
676// R_AARCH64_LDST128_ABS_LO12_NC: S + A
677Relocator::Result ldst_abs_lo12(Relocation& pReloc, AArch64Relocator& pParent) {
678  Relocator::Address S = pReloc.symValue();
679  Relocator::DWord A = pReloc.addend();
680  Relocator::DWord X = helper_get_page_offset(S + A);
681
682  switch (pReloc.type()) {
683    case llvm::ELF::R_AARCH64_LDST8_ABS_LO12_NC:
684      pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), X);
685      break;
686    case llvm::ELF::R_AARCH64_LDST16_ABS_LO12_NC:
687      pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 1));
688      break;
689    case llvm::ELF::R_AARCH64_LDST32_ABS_LO12_NC:
690      pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 2));
691      break;
692    case llvm::ELF::R_AARCH64_LDST64_ABS_LO12_NC:
693      pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 3));
694      break;
695    case llvm::ELF::R_AARCH64_LDST128_ABS_LO12_NC:
696      pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 4));
697      break;
698    default:
699      break;
700  }
701  return Relocator::OK;
702}
703
704}  // namespace mcld
705