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