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 "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:
     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 // 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 //===----------------------------------------------------------------------===//
     64 AArch64Relocator::AArch64Relocator(AArch64GNULDBackend& pParent,
     65                                    const LinkerConfig& pConfig)
     66     : Relocator(pConfig), m_Target(pParent) {
     67 }
     68 
     69 AArch64Relocator::~AArch64Relocator() {
     70 }
     71 
     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 
     84 const char* AArch64Relocator::getName(Relocator::Type pType) const {
     85   assert(ApplyFunctions.find(pType) != ApplyFunctions.end());
     86   return ApplyFunctions[pType].name;
     87 }
     88 
     89 Relocator::Size AArch64Relocator::getSize(Relocation::Type pType) const {
     90   return ApplyFunctions[pType].size;
     91 }
     92 
     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.
    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 
    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 
    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 
    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
    405 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 
    429 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 (at) 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 
    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
    451 Relocator::Result none(Relocation& pReloc, AArch64Relocator& pParent) {
    452   return Relocator::OK;
    453 }
    454 
    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
    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
    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
    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
    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)
    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
    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
    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)
    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))
    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
    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