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