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