Home | History | Annotate | Download | only in ARM
      1 //===- ARMRelocator.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 <llvm/ADT/Twine.h>
     11 #include <llvm/Support/DataTypes.h>
     12 #include <llvm/Support/ELF.h>
     13 #include <llvm/Support/Host.h>
     14 #include <mcld/Support/MsgHandling.h>
     15 #include "ARMRelocator.h"
     16 #include "ARMRelocationFunctions.h"
     17 
     18 using namespace mcld;
     19 
     20 //===--------------------------------------------------------------------===//
     21 // Relocation Functions and Tables
     22 //===--------------------------------------------------------------------===//
     23 DECL_ARM_APPLY_RELOC_FUNCS
     24 
     25 /// the prototype of applying function
     26 typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc,
     27                                                ARMRelocator& pParent);
     28 
     29 // the table entry of applying functions
     30 struct ApplyFunctionTriple
     31 {
     32   ApplyFunctionType func;
     33   unsigned int type;
     34   const char* name;
     35 };
     36 
     37 // declare the table of applying functions
     38 static const ApplyFunctionTriple ApplyFunctions[] = {
     39   DECL_ARM_APPLY_RELOC_FUNC_PTRS
     40 };
     41 
     42 //===--------------------------------------------------------------------===//
     43 // ARMRelocator
     44 //===--------------------------------------------------------------------===//
     45 ARMRelocator::ARMRelocator(ARMGNULDBackend& pParent)
     46   : Relocator(),
     47     m_Target(pParent) {
     48 }
     49 
     50 ARMRelocator::~ARMRelocator()
     51 {
     52 }
     53 
     54 Relocator::Result
     55 ARMRelocator::applyRelocation(Relocation& pRelocation)
     56 {
     57   Relocation::Type type = pRelocation.type();
     58   if (type > 130) { // 131-255 doesn't noted in ARM spec
     59     return Relocator::Unknown;
     60   }
     61 
     62   return ApplyFunctions[type].func(pRelocation, *this);
     63 }
     64 
     65 const char* ARMRelocator::getName(Relocator::Type pType) const
     66 {
     67   return ApplyFunctions[pType].name;
     68 }
     69 
     70 Relocator::Size ARMRelocator::getSize(Relocation::Type pType) const
     71 {
     72   return 32;
     73 }
     74 
     75 //===--------------------------------------------------------------------===//
     76 // non-member functions
     77 //===--------------------------------------------------------------------===//
     78 static Relocator::DWord getThumbBit(const Relocation& pReloc)
     79 {
     80   // Set thumb bit if
     81   // - symbol has type of STT_FUNC, is defined and with bit 0 of its value set
     82   Relocator::DWord thumbBit =
     83        ((!pReloc.symInfo()->isUndef() || pReloc.symInfo()->isDyn()) &&
     84         (pReloc.symInfo()->type() == ResolveInfo::Function) &&
     85         ((pReloc.symValue() & 0x1) != 0))?
     86         1:0;
     87   return thumbBit;
     88 }
     89 
     90 
     91 
     92 
     93 //=========================================//
     94 // Relocation helper function              //
     95 //=========================================//
     96 
     97 // Using uint64_t to make sure those complicate operations won't cause
     98 // undefined behavior.
     99 static
    100 uint64_t helper_sign_extend(uint64_t pVal, uint64_t pOri_width)
    101 {
    102   assert(pOri_width <= 64);
    103   uint64_t sign_bit = 1 << (pOri_width - 1);
    104   return (pVal ^ sign_bit) - sign_bit;
    105   // Reverse sign bit, then subtract sign bit.
    106 }
    107 
    108 static
    109 uint64_t helper_bit_select(uint64_t pA, uint64_t pB, uint64_t pMask)
    110 {
    111   return (pA & ~pMask) | (pB & pMask) ;
    112 }
    113 
    114 // Check if symbol can use relocation R_ARM_RELATIVE
    115 static bool
    116 helper_use_relative_reloc(const ResolveInfo& pSym,
    117                           const ARMRelocator& pFactory)
    118 {
    119   // if symbol is dynamic or undefine or preemptible
    120   if (pSym.isDyn() ||
    121       pSym.isUndef() ||
    122       pFactory.getTarget().isSymbolPreemptible(pSym))
    123     return false;
    124   return true;
    125 }
    126 
    127 static
    128 ARMGOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
    129                                      ARMRelocator& pParent)
    130 {
    131   // rsym - The relocation target symbol
    132   ResolveInfo* rsym = pReloc.symInfo();
    133   ARMGNULDBackend& ld_backend = pParent.getTarget();
    134 
    135   ARMGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
    136   if (NULL == got_entry) {
    137     got_entry = ld_backend.getGOT().consumeGOT();
    138     pParent.getSymGOTMap().record(*rsym, *got_entry);
    139     // If we first get this GOT entry, we should initialize it.
    140     if (rsym->reserved() & ARMGNULDBackend::ReserveGOT) {
    141       // No corresponding dynamic relocation, initialize to the symbol value.
    142       got_entry->setValue(pReloc.symValue());
    143     }
    144     else if (rsym->reserved() & ARMGNULDBackend::GOTRel) {
    145 
    146       // Initialize corresponding dynamic relocation.
    147       Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
    148       if ( rsym->isLocal() ||
    149           helper_use_relative_reloc(*rsym, pParent)) {
    150         // Initialize got entry to target symbol address
    151         got_entry->setValue(pReloc.symValue());
    152         rel_entry.setType(llvm::ELF::R_ARM_RELATIVE);
    153         rel_entry.setSymInfo(0);
    154       }
    155       else {
    156         // Initialize got entry to 0 for corresponding dynamic relocation.
    157         got_entry->setValue(0);
    158         rel_entry.setType(llvm::ELF::R_ARM_GLOB_DAT);
    159         rel_entry.setSymInfo(rsym);
    160       }
    161       rel_entry.targetRef().assign(*got_entry);
    162     }
    163     else {
    164       fatal(diag::reserve_entry_number_mismatch_got);
    165     }
    166   }
    167   return *got_entry;
    168 }
    169 
    170 static
    171 ARMRelocator::Address helper_GOT_ORG(ARMRelocator& pParent)
    172 {
    173   return pParent.getTarget().getGOT().addr();
    174 }
    175 
    176 
    177 static
    178 ARMRelocator::Address helper_GOT(Relocation& pReloc, ARMRelocator& pParent)
    179 {
    180   ARMGOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent);
    181   return helper_GOT_ORG(pParent) + got_entry.getOffset();
    182 }
    183 
    184 
    185 static
    186 ARMPLT1& helper_get_PLT_and_init(Relocation& pReloc, ARMRelocator& pParent)
    187 {
    188   // rsym - The relocation target symbol
    189   ResolveInfo* rsym = pReloc.symInfo();
    190   ARMGNULDBackend& ld_backend = pParent.getTarget();
    191 
    192   ARMPLT1* plt_entry = pParent.getSymPLTMap().lookUp(*rsym);
    193   if (NULL != plt_entry)
    194     return *plt_entry;
    195 
    196   plt_entry = ld_backend.getPLT().consume();
    197   pParent.getSymPLTMap().record(*rsym, *plt_entry);
    198 
    199   // If we first get this PLT entry, we should initialize it.
    200   if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
    201     ARMGOTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym);
    202     assert(NULL == gotplt_entry && "PLT entry not exist, but DynRel entry exist!");
    203     gotplt_entry = ld_backend.getGOT().consumeGOTPLT();
    204     pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
    205 
    206     // Initialize corresponding dynamic relocation.
    207     Relocation& rel_entry = *ld_backend.getRelPLT().consumeEntry();
    208     rel_entry.setType(llvm::ELF::R_ARM_JUMP_SLOT);
    209     rel_entry.targetRef().assign(*gotplt_entry);
    210     rel_entry.setSymInfo(rsym);
    211   }
    212   else {
    213     fatal(diag::reserve_entry_number_mismatch_plt);
    214   }
    215 
    216   return *plt_entry;
    217 }
    218 
    219 static
    220 ARMRelocator::Address helper_PLT_ORG(ARMRelocator& pParent)
    221 {
    222   return pParent.getTarget().getPLT().addr();
    223 }
    224 
    225 
    226 static
    227 ARMRelocator::Address helper_PLT(Relocation& pReloc, ARMRelocator& pParent)
    228 {
    229   ARMPLT1& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
    230   return helper_PLT_ORG(pParent) + plt_entry.getOffset();
    231 }
    232 
    233 // Get an relocation entry in .rel.dyn and set its type to pType,
    234 // its FragmentRef to pReloc->targetFrag() and its ResolveInfo to
    235 // pReloc->symInfo()
    236 static
    237 void helper_DynRel(Relocation& pReloc,
    238                    ARMRelocator::Type pType,
    239                    ARMRelocator& pParent)
    240 {
    241   // rsym - The relocation target symbol
    242   ResolveInfo* rsym = pReloc.symInfo();
    243   ARMGNULDBackend& ld_backend = pParent.getTarget();
    244 
    245   Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
    246   rel_entry.setType(pType);
    247   rel_entry.targetRef() = pReloc.targetRef();
    248 
    249   if (pType == llvm::ELF::R_ARM_RELATIVE)
    250     rel_entry.setSymInfo(0);
    251   else
    252     rel_entry.setSymInfo(rsym);
    253 }
    254 
    255 static ARMRelocator::DWord
    256 helper_extract_movw_movt_addend(ARMRelocator::DWord pTarget)
    257 {
    258   // imm16: [19-16][11-0]
    259   return helper_sign_extend((((pTarget >> 4)) & 0xf000U) | (pTarget & 0xfffU),
    260                             16);
    261 }
    262 
    263 static ARMRelocator::DWord
    264 helper_insert_val_movw_movt_inst(ARMRelocator::DWord pTarget,
    265                                  ARMRelocator::DWord pImm)
    266 {
    267   // imm16: [19-16][11-0]
    268   pTarget &= 0xfff0f000U;
    269   pTarget |= pImm & 0x0fffU;
    270   pTarget |= (pImm & 0xf000U) << 4;
    271   return pTarget;
    272 }
    273 
    274 static ARMRelocator::DWord
    275 helper_extract_thumb_movw_movt_addend(ARMRelocator::DWord pValue)
    276 {
    277   // imm16: [19-16][26][14-12][7-0]
    278   return helper_sign_extend((((pValue >> 4) & 0xf000U) |
    279                              ((pValue >> 15) & 0x0800U) |
    280                              ((pValue >> 4) & 0x0700U) |
    281                              (pValue& 0x00ffU)),
    282                             16);
    283 }
    284 
    285 static ARMRelocator::DWord
    286 helper_insert_val_thumb_movw_movt_inst(ARMRelocator::DWord pValue,
    287                                        ARMRelocator::DWord pImm)
    288 {
    289   // imm16: [19-16][26][14-12][7-0]
    290   pValue &= 0xfbf08f00U;
    291   pValue |= (pImm & 0xf000U) << 4;
    292   pValue |= (pImm & 0x0800U) << 15;
    293   pValue |= (pImm & 0x0700U) << 4;
    294   pValue |= (pImm & 0x00ffU);
    295   return pValue;
    296 }
    297 
    298 static ARMRelocator::DWord
    299 helper_thumb32_branch_offset(ARMRelocator::DWord pUpper16,
    300                              ARMRelocator::DWord pLower16)
    301 {
    302   ARMRelocator::DWord s = (pUpper16 & (1U << 10)) >> 10,        // 26 bit
    303                            u  = pUpper16 & 0x3ffU,              // 25-16
    304                            l  = pLower16 & 0x7ffU,              // 10-0
    305                            j1 = (pLower16 & (1U << 13)) >> 13,  // 13
    306                            j2 = (pLower16 & (1U << 11)) >> 11;  // 11
    307   ARMRelocator::DWord i1 = j1 ^ s? 0: 1,
    308                               i2 = j2 ^ s? 0: 1;
    309 
    310   // [31-25][24][23][22][21-12][11-1][0]
    311   //      0   s  i1  i2      u     l  0
    312   return helper_sign_extend((s << 24) | (i1 << 23) | (i2 << 22) |
    313                             (u << 12) | (l << 1),
    314                             25);
    315 }
    316 
    317 static ARMRelocator::DWord
    318 helper_thumb32_branch_upper(ARMRelocator::DWord pUpper16,
    319                             ARMRelocator::DWord pOffset)
    320 {
    321   uint32_t sign = ((pOffset & 0x80000000U) >> 31);
    322   return (pUpper16 & ~0x7ffU) | ((pOffset >> 12) & 0x3ffU) | (sign << 10);
    323 }
    324 
    325 static ARMRelocator::DWord
    326 helper_thumb32_branch_lower(ARMRelocator::DWord pLower16,
    327                             ARMRelocator::DWord pOffset)
    328 {
    329   uint32_t sign = ((pOffset & 0x80000000U) >> 31);
    330   return ((pLower16 & ~0x2fffU) |
    331           ((((pOffset >> 23) & 1) ^ !sign) << 13) |
    332           ((((pOffset >> 22) & 1) ^ !sign) << 11) |
    333           ((pOffset >> 1) & 0x7ffU));
    334 }
    335 
    336 // Return true if overflow
    337 static bool
    338 helper_check_signed_overflow(ARMRelocator::DWord pValue,
    339                              unsigned bits)
    340 {
    341   int32_t signed_val = static_cast<int32_t>(pValue);
    342   int32_t max = (1 << (bits - 1)) - 1;
    343   int32_t min = -(1 << (bits - 1));
    344   if (signed_val > max || signed_val < min) {
    345     return true;
    346   } else {
    347     return false;
    348   }
    349 }
    350 
    351 
    352 //=========================================//
    353 // Each relocation function implementation //
    354 //=========================================//
    355 
    356 // R_ARM_NONE
    357 ARMRelocator::Result none(Relocation& pReloc, ARMRelocator& pParent)
    358 {
    359   return ARMRelocator::OK;
    360 }
    361 
    362 // R_ARM_ABS32: (S + A) | T
    363 ARMRelocator::Result abs32(Relocation& pReloc, ARMRelocator& pParent)
    364 {
    365   ResolveInfo* rsym = pReloc.symInfo();
    366   ARMRelocator::DWord T = getThumbBit(pReloc);
    367   ARMRelocator::DWord A = pReloc.target() + pReloc.addend();
    368   ARMRelocator::DWord S = pReloc.symValue();
    369 
    370   LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
    371 
    372   // If the flag of target section is not ALLOC, we will not scan this relocation
    373   // but perform static relocation. (e.g., applying .debug section)
    374   if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
    375     pReloc.target() = (S + A) | T;
    376     return ARMRelocator::OK;
    377   }
    378 
    379   // A local symbol may need REL Type dynamic relocation
    380   if (rsym->isLocal() && (rsym->reserved() & ARMGNULDBackend::ReserveRel)) {
    381     helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent);
    382     pReloc.target() = (S + A) | T ;
    383     return ARMRelocator::OK;
    384   }
    385 
    386   // An external symbol may need PLT and dynamic relocation
    387   if (!rsym->isLocal()) {
    388     if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
    389       S = helper_PLT(pReloc, pParent);
    390       T = 0 ; // PLT is not thumb
    391     }
    392     // If we generate a dynamic relocation (except R_ARM_RELATIVE)
    393     // for a place, we should not perform static relocation on it
    394     // in order to keep the addend store in the place correct.
    395     if (rsym->reserved() & ARMGNULDBackend::ReserveRel) {
    396       if (helper_use_relative_reloc(*rsym, pParent)) {
    397         helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent);
    398       }
    399       else {
    400         helper_DynRel(pReloc, pReloc.type(), pParent);
    401         return ARMRelocator::OK;
    402       }
    403     }
    404   }
    405 
    406 
    407   // perform static relocation
    408   pReloc.target() = (S + A) | T;
    409   return ARMRelocator::OK;
    410 }
    411 
    412 // R_ARM_REL32: ((S + A) | T) - P
    413 ARMRelocator::Result rel32(Relocation& pReloc, ARMRelocator& pParent)
    414 {
    415   // perform static relocation
    416   ARMRelocator::Address S = pReloc.symValue();
    417   ARMRelocator::DWord   T = getThumbBit(pReloc);
    418   ARMRelocator::DWord   A = pReloc.target() + pReloc.addend();
    419 
    420   // An external symbol may need PLT (this reloc is from stub)
    421   if (!pReloc.symInfo()->isLocal()) {
    422     if (pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) {
    423       S = helper_PLT(pReloc, pParent);
    424       T = 0;  // PLT is not thumb.
    425     }
    426   }
    427 
    428   // perform relocation
    429   pReloc.target() = ((S + A) | T) - pReloc.place();
    430 
    431   return ARMRelocator::OK;
    432 }
    433 
    434 // R_ARM_BASE_PREL: B(S) + A - P
    435 ARMRelocator::Result base_prel(Relocation& pReloc, ARMRelocator& pParent)
    436 {
    437   // perform static relocation
    438   ARMRelocator::DWord A = pReloc.target() + pReloc.addend();
    439   pReloc.target() = pReloc.symValue() + A - pReloc.place();
    440   return ARMRelocator::OK;
    441 }
    442 
    443 // R_ARM_GOTOFF32: ((S + A) | T) - GOT_ORG
    444 ARMRelocator::Result gotoff32(Relocation& pReloc, ARMRelocator& pParent)
    445 {
    446   ARMRelocator::DWord T = getThumbBit(pReloc);
    447   ARMRelocator::DWord A = pReloc.target() + pReloc.addend();
    448   ARMRelocator::Address GOT_ORG = helper_GOT_ORG(pParent);
    449   ARMRelocator::Address S = pReloc.symValue();
    450 
    451   pReloc.target() = ((S + A) | T) - GOT_ORG;
    452   return ARMRelocator::OK;
    453 }
    454 
    455 // R_ARM_GOT_BREL: GOT(S) + A - GOT_ORG
    456 ARMRelocator::Result got_brel(Relocation& pReloc, ARMRelocator& pParent)
    457 {
    458   if (!(pReloc.symInfo()->reserved() &
    459       (ARMGNULDBackend::ReserveGOT | ARMGNULDBackend::GOTRel))) {
    460     return ARMRelocator::BadReloc;
    461   }
    462   ARMRelocator::Address GOT_S   = helper_GOT(pReloc, pParent);
    463   ARMRelocator::DWord   A       = pReloc.target() + pReloc.addend();
    464   ARMRelocator::Address GOT_ORG = helper_GOT_ORG(pParent);
    465   // Apply relocation.
    466   pReloc.target() = GOT_S + A - GOT_ORG;
    467   return ARMRelocator::OK;
    468 }
    469 
    470 // R_ARM_GOT_PREL: GOT(S) + A - P
    471 ARMRelocator::Result got_prel(Relocation& pReloc, ARMRelocator& pParent)
    472 {
    473   if (!(pReloc.symInfo()->reserved() &
    474       (ARMGNULDBackend::ReserveGOT | ARMGNULDBackend::GOTRel))) {
    475     return ARMRelocator::BadReloc;
    476   }
    477   ARMRelocator::Address GOT_S   = helper_GOT(pReloc, pParent);
    478   ARMRelocator::DWord   A       = pReloc.target() + pReloc.addend();
    479   ARMRelocator::Address P = pReloc.place();
    480 
    481   // Apply relocation.
    482   pReloc.target() = GOT_S + A - P;
    483   return ARMRelocator::OK;
    484 }
    485 
    486 // R_ARM_PLT32: ((S + A) | T) - P
    487 // R_ARM_JUMP24: ((S + A) | T) - P
    488 // R_ARM_CALL: ((S + A) | T) - P
    489 ARMRelocator::Result call(Relocation& pReloc, ARMRelocator& pParent)
    490 {
    491   // If target is undefined weak symbol, we only need to jump to the
    492   // next instruction unless it has PLT entry. Rewrite instruction
    493   // to NOP.
    494   if (pReloc.symInfo()->isWeak() &&
    495       pReloc.symInfo()->isUndef() &&
    496       !pReloc.symInfo()->isDyn() &&
    497       !(pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT)) {
    498     // change target to NOP : mov r0, r0
    499     pReloc.target() = (pReloc.target() & 0xf0000000U) | 0x01a00000;
    500     return ARMRelocator::OK;
    501   }
    502 
    503   ARMRelocator::Address S; // S depends on PLT exists or not.
    504   ARMRelocator::DWord   T = getThumbBit(pReloc);
    505   ARMRelocator::DWord   A =
    506     helper_sign_extend((pReloc.target() & 0x00FFFFFFu) << 2, 26)
    507     + pReloc.addend();
    508   ARMRelocator::Address P = pReloc.place();
    509 
    510   S = pReloc.symValue();
    511   if (pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) {
    512     S = helper_PLT(pReloc, pParent);
    513     T = 0;  // PLT is not thumb.
    514   }
    515 
    516   // At this moment (after relaxation), if the jump target is thumb instruction,
    517   // switch mode is needed, rewrite the instruction to BLX
    518   // FIXME: check if we can use BLX instruction (check from .ARM.attribute
    519   // CPU ARCH TAG, which should be ARMv5 or above)
    520   if (T != 0) {
    521     // cannot rewrite to blx for R_ARM_JUMP24
    522     if (pReloc.type() == llvm::ELF::R_ARM_JUMP24)
    523       return ARMRelocator::BadReloc;
    524 
    525     pReloc.target() = (pReloc.target() & 0xffffff) |
    526                       0xfa000000 |
    527                       (((S + A - P) & 2) << 23);
    528   }
    529 
    530   ARMRelocator::DWord X = ((S + A) | T) - P;
    531   // Check X is 24bit sign int. If not, we should use stub or PLT before apply.
    532   if (helper_check_signed_overflow(X, 26))
    533     return ARMRelocator::Overflow;
    534   //                    Make sure the Imm is 0.          Result Mask.
    535   pReloc.target() = (pReloc.target() & 0xFF000000u) | ((X & 0x03FFFFFEu) >> 2);
    536   return ARMRelocator::OK;
    537 }
    538 
    539 // R_ARM_THM_CALL: ((S + A) | T) - P
    540 // R_ARM_THM_JUMP24: (((S + A) | T) - P)
    541 ARMRelocator::Result thm_call(Relocation& pReloc, ARMRelocator& pParent)
    542 {
    543   // If target is undefined weak symbol, we only need to jump to the
    544   // next instruction unless it has PLT entry. Rewrite instruction
    545   // to NOP.
    546   if (pReloc.symInfo()->isWeak() &&
    547       pReloc.symInfo()->isUndef() &&
    548       !pReloc.symInfo()->isDyn() &&
    549       !(pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT)) {
    550     pReloc.target() = (0xe000U << 16) | 0xbf00U;
    551     return ARMRelocator::OK;
    552   }
    553 
    554   // get lower and upper 16 bit instructions from relocation targetData
    555   uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
    556   uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
    557 
    558   ARMRelocator::DWord T = getThumbBit(pReloc);
    559   ARMRelocator::DWord A = helper_thumb32_branch_offset(upper_inst,
    560                                                                lower_inst);
    561   ARMRelocator::Address P = pReloc.place();
    562   ARMRelocator::Address S;
    563 
    564   // if symbol has plt
    565   if (pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) {
    566     S = helper_PLT(pReloc, pParent);
    567     T = 0;  // PLT is not thumb.
    568   }
    569   else {
    570     S = pReloc.symValue();
    571   }
    572 
    573   S = S + A;
    574 
    575   // At this moment (after relaxation), if the jump target is arm
    576   // instruction, switch mode is needed, rewrite the instruction to BLX
    577   // FIXME: check if we can use BLX instruction (check from .ARM.attribute
    578   // CPU ARCH TAG, which should be ARMv5 or above)
    579   if (T == 0) {
    580     // cannot rewrite to blx for R_ARM_THM_JUMP24
    581     if (pReloc.type() == llvm::ELF::R_ARM_THM_JUMP24)
    582       return ARMRelocator::BadReloc;
    583 
    584     // for BLX, select bit 1 from relocation base address to jump target
    585     // address
    586     S = helper_bit_select(S, P, 0x2);
    587     // rewrite instruction to BLX
    588     lower_inst &= ~0x1000U;
    589   }
    590   else {
    591     // otherwise, the instruction should be BL
    592     lower_inst |= 0x1000U;
    593   }
    594 
    595   ARMRelocator::DWord X = (S | T) - P;
    596 
    597   // FIXME: Check bit size is 24(thumb2) or 22?
    598   if (helper_check_signed_overflow(X, 25)) {
    599     return ARMRelocator::Overflow;
    600   }
    601 
    602   upper_inst = helper_thumb32_branch_upper(upper_inst, X);
    603   lower_inst = helper_thumb32_branch_lower(lower_inst, X);
    604 
    605   *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst;
    606   *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst;
    607 
    608   return ARMRelocator::OK;
    609 }
    610 
    611 // R_ARM_MOVW_ABS_NC: (S + A) | T
    612 ARMRelocator::Result movw_abs_nc(Relocation& pReloc, ARMRelocator& pParent)
    613 {
    614   ResolveInfo* rsym = pReloc.symInfo();
    615   ARMRelocator::Address S = pReloc.symValue();
    616   ARMRelocator::DWord T = getThumbBit(pReloc);
    617   ARMRelocator::DWord A =
    618       helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
    619   ARMRelocator::DWord X;
    620 
    621   LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
    622 
    623   // If the flag of target section is not ALLOC, we will not scan this
    624   // relocation but perform static relocation. (e.g., applying .debug section)
    625   if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
    626     // use plt
    627     if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
    628       S = helper_PLT(pReloc, pParent);
    629       T = 0 ; // PLT is not thumb
    630     }
    631   }
    632 
    633   // perform static relocation
    634   X = (S + A) | T;
    635   pReloc.target() = helper_insert_val_movw_movt_inst(
    636                                          pReloc.target() + pReloc.addend(), X);
    637   return ARMRelocator::OK;
    638 }
    639 
    640 // R_ARM_MOVW_PREL_NC: ((S + A) | T) - P
    641 ARMRelocator::Result movw_prel_nc(Relocation& pReloc, ARMRelocator& pParent)
    642 {
    643   ARMRelocator::Address S = pReloc.symValue();
    644   ARMRelocator::DWord T = getThumbBit(pReloc);
    645   ARMRelocator::DWord P = pReloc.place();
    646   ARMRelocator::DWord A =
    647       helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
    648   ARMRelocator::DWord X;
    649 
    650   X = ((S + A) | T) - P;
    651 
    652   if (helper_check_signed_overflow(X, 16)) {
    653     return ARMRelocator::Overflow;
    654   } else {
    655     pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
    656     return ARMRelocator::OK;
    657   }
    658 }
    659 
    660 // R_ARM_MOVT_ABS: S + A
    661 ARMRelocator::Result movt_abs(Relocation& pReloc, ARMRelocator& pParent)
    662 {
    663   ResolveInfo* rsym = pReloc.symInfo();
    664   ARMRelocator::Address S = pReloc.symValue();
    665   ARMRelocator::DWord A =
    666     helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
    667   ARMRelocator::DWord X;
    668 
    669   LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
    670 
    671   // If the flag of target section is not ALLOC, we will not scan this relocation
    672   // but perform static relocation. (e.g., applying .debug section)
    673   if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
    674     // use plt
    675     if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
    676       S = helper_PLT(pReloc, pParent);
    677     }
    678   }
    679 
    680   X = S + A;
    681   X >>= 16;
    682   // perform static relocation
    683   pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
    684   return ARMRelocator::OK;
    685 }
    686 
    687 // R_ARM_MOVT_PREL: S + A - P
    688 ARMRelocator::Result movt_prel(Relocation& pReloc, ARMRelocator& pParent)
    689 {
    690   ARMRelocator::Address S = pReloc.symValue();
    691   ARMRelocator::DWord P = pReloc.place();
    692   ARMRelocator::DWord A =
    693             helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
    694   ARMRelocator::DWord X;
    695 
    696   X = S + A - P;
    697   X >>= 16;
    698 
    699   pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
    700   return ARMRelocator::OK;
    701 }
    702 
    703 // R_ARM_THM_MOVW_ABS_NC: (S + A) | T
    704 ARMRelocator::Result thm_movw_abs_nc(Relocation& pReloc, ARMRelocator& pParent)
    705 {
    706   ResolveInfo* rsym = pReloc.symInfo();
    707   ARMRelocator::Address S = pReloc.symValue();
    708   ARMRelocator::DWord T = getThumbBit(pReloc);
    709 
    710   // get lower and upper 16 bit instructions from relocation targetData
    711   uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
    712   uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
    713   ARMRelocator::DWord val = ((upper_inst) << 16) | (lower_inst);
    714   ARMRelocator::DWord A =
    715       helper_extract_thumb_movw_movt_addend(val) + pReloc.addend();
    716   ARMRelocator::DWord X;
    717 
    718   LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
    719   // If the flag of target section is not ALLOC, we will not scan this relocation
    720   // but perform static relocation. (e.g., applying .debug section)
    721   if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
    722     // use plt
    723     if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
    724       S = helper_PLT(pReloc, pParent);
    725       T = 0; // PLT is not thumb
    726     }
    727   }
    728   X = (S + A) | T;
    729 
    730   val = helper_insert_val_thumb_movw_movt_inst(val, X);
    731   *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst;
    732   *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst;
    733 
    734   return ARMRelocator::OK;
    735 }
    736 
    737 // R_ARM_THM_MOVW_PREL_NC: ((S + A) | T) - P
    738 ARMRelocator::Result thm_movw_prel_nc(Relocation& pReloc, ARMRelocator& pParent)
    739 {
    740   ARMRelocator::Address S = pReloc.symValue();
    741   ARMRelocator::DWord T = getThumbBit(pReloc);
    742   ARMRelocator::DWord P = pReloc.place();
    743 
    744   // get lower and upper 16 bit instructions from relocation targetData
    745   uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
    746   uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
    747   ARMRelocator::DWord val = ((upper_inst) << 16) | (lower_inst);
    748   ARMRelocator::DWord A =
    749       helper_extract_thumb_movw_movt_addend(val) + pReloc.addend();
    750   ARMRelocator::DWord X;
    751 
    752   X = ((S + A) | T) - P;
    753 
    754   val = helper_insert_val_thumb_movw_movt_inst(val, X);
    755   *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst;
    756   *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst;
    757 
    758   return ARMRelocator::OK;
    759 }
    760 
    761 // R_ARM_THM_MOVW_BREL_NC: ((S + A) | T) - B(S)
    762 // R_ARM_THM_MOVW_BREL: ((S + A) | T) - B(S)
    763 ARMRelocator::Result thm_movw_brel(Relocation& pReloc, ARMRelocator& pParent)
    764 {
    765   ARMRelocator::Address S = pReloc.symValue();
    766   ARMRelocator::DWord T = getThumbBit(pReloc);
    767   ARMRelocator::DWord P = pReloc.place();
    768 
    769   // get lower and upper 16 bit instructions from relocation targetData
    770   uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
    771   uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
    772   ARMRelocator::DWord val = ((upper_inst) << 16) | (lower_inst);
    773   ARMRelocator::DWord A =
    774       helper_extract_thumb_movw_movt_addend(val) + pReloc.addend();
    775   ARMRelocator::DWord X;
    776 
    777   X = ((S + A) | T) - P;
    778 
    779   val = helper_insert_val_thumb_movw_movt_inst(val, X);
    780   *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst;
    781   *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst;
    782 
    783   return ARMRelocator::OK;
    784 }
    785 
    786 // R_ARM_THM_MOVT_ABS: S + A
    787 ARMRelocator::Result thm_movt_abs(Relocation& pReloc, ARMRelocator& pParent)
    788 {
    789   ResolveInfo* rsym = pReloc.symInfo();
    790   ARMRelocator::Address S = pReloc.symValue();
    791 
    792   // get lower and upper 16 bit instructions from relocation targetData
    793   uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
    794   uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
    795   ARMRelocator::DWord val = ((upper_inst) << 16) | (lower_inst);
    796   ARMRelocator::DWord A =
    797       helper_extract_thumb_movw_movt_addend(val) + pReloc.addend();
    798   ARMRelocator::DWord X;
    799 
    800   LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
    801   // If the flag of target section is not ALLOC, we will not scan this relocation
    802   // but perform static relocation. (e.g., applying .debug section)
    803   if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
    804     // use plt
    805     if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
    806       S = helper_PLT(pReloc, pParent);
    807     }
    808   }
    809 
    810   X = S + A;
    811   X >>= 16;
    812 
    813   // check 16-bit overflow
    814   if (helper_check_signed_overflow(X, 16)) {
    815     return ARMRelocator::Overflow;
    816   } else {
    817     val = helper_insert_val_thumb_movw_movt_inst(val, X);
    818     *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst;
    819     *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst;
    820     return ARMRelocator::OK;
    821   }
    822 }
    823 
    824 // R_ARM_THM_MOVT_PREL: S + A - P
    825 // R_ARM_THM_MOVT_BREL: S + A - B(S)
    826 ARMRelocator::Result thm_movt_prel(Relocation& pReloc, ARMRelocator& pParent)
    827 {
    828   ARMRelocator::Address S = pReloc.symValue();
    829   ARMRelocator::DWord P = pReloc.place();
    830 
    831   // get lower and upper 16 bit instructions from relocation targetData
    832   uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
    833   uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
    834   ARMRelocator::DWord val = ((upper_inst) << 16) | (lower_inst);
    835   ARMRelocator::DWord A =
    836       helper_extract_thumb_movw_movt_addend(val) + pReloc.addend();
    837   ARMRelocator::DWord X;
    838 
    839   X = S + A - P;
    840   X >>= 16;
    841 
    842   val = helper_insert_val_thumb_movw_movt_inst(val, X);
    843   *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst;
    844   *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst;
    845 
    846   return ARMRelocator::OK;
    847 }
    848 
    849 // R_ARM_PREL31: ((S + A) | T) - P
    850 ARMRelocator::Result prel31(Relocation& pReloc, ARMRelocator& pParent)
    851 {
    852   ARMRelocator::DWord target = pReloc.target();
    853   ARMRelocator::DWord T = getThumbBit(pReloc);
    854   ARMRelocator::DWord A = helper_sign_extend(target, 31) +
    855                                   pReloc.addend();
    856   ARMRelocator::DWord P = pReloc.place();
    857   ARMRelocator::Address S;
    858 
    859   S = pReloc.symValue();
    860   // if symbol has plt
    861   if ( pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) {
    862     S = helper_PLT(pReloc, pParent);
    863     T = 0;  // PLT is not thumb.
    864   }
    865 
    866   ARMRelocator::DWord X = ((S + A) | T) - P;
    867   pReloc.target() = helper_bit_select(target, X, 0x7fffffffU);
    868   if (helper_check_signed_overflow(X, 31))
    869     return ARMRelocator::Overflow;
    870   return ARMRelocator::OK;
    871 }
    872 
    873 // R_ARM_TLS_GD32: GOT(S) + A - P
    874 // R_ARM_TLS_IE32: GOT(S) + A - P
    875 // R_ARM_TLS_LE32: S + A - tp
    876 ARMRelocator::Result tls(Relocation& pReloc, ARMRelocator& pParent)
    877 {
    878   return ARMRelocator::Unsupport;
    879 }
    880 
    881 ARMRelocator::Result unsupport(Relocation& pReloc, ARMRelocator& pParent)
    882 {
    883   return ARMRelocator::Unsupport;
    884 }
    885