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