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 
26 namespace mcld {
27 
28 //===----------------------------------------------------------------------===//
29 // Relocation Functions and Tables
30 //===----------------------------------------------------------------------===//
31 DECL_AARCH64_APPLY_RELOC_FUNCS
32 
33 /// the prototype of applying function
34 typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc,
35                                                AArch64Relocator& pParent);
36 
37 // the table entry of applying functions
38 class ApplyFunctionEntry {
39  public:
ApplyFunctionEntry()40   ApplyFunctionEntry() {}
ApplyFunctionEntry(ApplyFunctionType pFunc,const char * pName,size_t pSize=0)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 };
49 typedef std::map<Relocator::Type, ApplyFunctionEntry> ApplyFunctionMap;
50 
51 static 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
56 static ApplyFunctionMap ApplyFunctions(ApplyFunctionList,
57                                        ApplyFunctionList +
58                                            sizeof(ApplyFunctionList) /
59                                                sizeof(ApplyFunctionList[0]));
60 
61 //===----------------------------------------------------------------------===//
62 // AArch64Relocator
63 //===----------------------------------------------------------------------===//
AArch64Relocator(AArch64GNULDBackend & pParent,const LinkerConfig & pConfig)64 AArch64Relocator::AArch64Relocator(AArch64GNULDBackend& pParent,
65                                    const LinkerConfig& pConfig)
66     : Relocator(pConfig), m_Target(pParent) {
67 }
68 
~AArch64Relocator()69 AArch64Relocator::~AArch64Relocator() {
70 }
71 
applyRelocation(Relocation & pRelocation)72 Relocator::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 
getName(Relocator::Type pType) const84 const char* AArch64Relocator::getName(Relocator::Type pType) const {
85   assert(ApplyFunctions.find(pType) != ApplyFunctions.end());
86   return ApplyFunctions[pType].name;
87 }
88 
getSize(Relocation::Type pType) const89 Relocator::Size AArch64Relocator::getSize(Relocation::Type pType) const {
90   return ApplyFunctions[pType].size;
91 }
92 
addCopyReloc(ResolveInfo & pSym)93 void 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.
defineSymbolforCopyReloc(IRBuilder & pBuilder,const ResolveInfo & pSym)106 LDSymbol& 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 
scanLocalReloc(Relocation & pReloc,const LDSection & pSection)151 void 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 
scanGlobalReloc(Relocation & pReloc,IRBuilder & pBuilder,const LDSection & pSection)215 void 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 
scanRelocation(Relocation & pReloc,IRBuilder & pBuilder,Module & pModule,LDSection & pSection,Input & pInput)374 void 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 
404 bool
mayHaveFunctionPointerAccess(const Relocation & pReloc) const405 AArch64Relocator::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 
getDebugStringOffset(Relocation & pReloc) const429 uint32_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 
applyDebugStringOffset(Relocation & pReloc,uint32_t pOffset)441 void 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
none(Relocation & pReloc,AArch64Relocator & pParent)451 Relocator::Result none(Relocation& pReloc, AArch64Relocator& pParent) {
452   return Relocator::OK;
453 }
454 
unsupported(Relocation & pReloc,AArch64Relocator & pParent)455 Relocator::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
abs(Relocation & pReloc,AArch64Relocator & pParent)462 Relocator::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
rel(Relocation & pReloc,AArch64Relocator & pParent)508 Relocator::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
add_abs_lo12(Relocation & pReloc,AArch64Relocator & pParent)541 Relocator::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
adr_prel_lo21(Relocation & pReloc,AArch64Relocator & pParent)553 Relocator::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)
adr_prel_pg_hi21(Relocation & pReloc,AArch64Relocator & pParent)571 Relocator::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
call(Relocation & pReloc,AArch64Relocator & pParent)591 Relocator::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
condbr(Relocation & pReloc,AArch64Relocator & pParent)620 Relocator::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)
adr_got_page(Relocation & pReloc,AArch64Relocator & pParent)649 Relocator::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))
ld64_got_lo12(Relocation & pReloc,AArch64Relocator & pParent)675 Relocator::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
ldst_abs_lo12(Relocation & pReloc,AArch64Relocator & pParent)705 Relocator::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