Home | History | Annotate | Download | only in Mips
      1 //===- MipsRelocator.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/ELF.h>
     12 #include <mcld/Support/MsgHandling.h>
     13 #include <mcld/Target/OutputRelocSection.h>
     14 #include <mcld/LinkerConfig.h>
     15 #include <mcld/IRBuilder.h>
     16 
     17 #include "MipsRelocator.h"
     18 #include "MipsRelocationFunctions.h"
     19 
     20 using namespace mcld;
     21 
     22 //===----------------------------------------------------------------------===//
     23 // Relocation Functions and Tables
     24 //===----------------------------------------------------------------------===//
     25 DECL_MIPS_APPLY_RELOC_FUNCS
     26 
     27 /// the prototype of applying function
     28 typedef Relocator::Result (*ApplyFunctionType)(Relocation&, MipsRelocator&);
     29 
     30 // the table entry of applying functions
     31 struct ApplyFunctionTriple
     32 {
     33   ApplyFunctionType func;
     34   unsigned int type;
     35   const char* name;
     36   unsigned int size;
     37 };
     38 
     39 // declare the table of applying functions
     40 static const ApplyFunctionTriple ApplyFunctions[] = {
     41   DECL_MIPS_APPLY_RELOC_FUNC_PTRS
     42 };
     43 
     44 //===----------------------------------------------------------------------===//
     45 // MipsRelocator
     46 //===----------------------------------------------------------------------===//
     47 MipsRelocator::MipsRelocator(MipsGNULDBackend& pParent,
     48                              const LinkerConfig& pConfig)
     49   : Relocator(pConfig),
     50     m_Target(pParent),
     51     m_pApplyingInput(NULL),
     52     m_AHL(0)
     53 {
     54 }
     55 
     56 Relocator::Result
     57 MipsRelocator::applyRelocation(Relocation& pRelocation)
     58 {
     59   Relocation::Type type = pRelocation.type();
     60 
     61   if (type >= sizeof(ApplyFunctions) / sizeof(ApplyFunctions[0])) {
     62     return Unknown;
     63   }
     64 
     65   // apply the relocation
     66   return ApplyFunctions[type].func(pRelocation, *this);
     67 }
     68 
     69 const char* MipsRelocator::getName(Relocation::Type pType) const
     70 {
     71   return ApplyFunctions[pType].name;
     72 }
     73 
     74 Relocator::Size MipsRelocator::getSize(Relocation::Type pType) const
     75 {
     76   return ApplyFunctions[pType].size;
     77 }
     78 
     79 void MipsRelocator::scanRelocation(Relocation& pReloc,
     80                                    IRBuilder& pBuilder,
     81                                    Module& pModule,
     82                                    LDSection& pSection)
     83 {
     84   // rsym - The relocation target symbol
     85   ResolveInfo* rsym = pReloc.symInfo();
     86   assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
     87 
     88   // Skip relocation against _gp_disp
     89   if (NULL != getTarget().getGpDispSymbol()) {
     90     if (pReloc.symInfo() == getTarget().getGpDispSymbol()->resolveInfo())
     91       return;
     92   }
     93 
     94   pReloc.updateAddend();
     95 
     96   assert(NULL != pSection.getLink());
     97   if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC))
     98     return;
     99 
    100   // We test isLocal or if pInputSym is not a dynamic symbol
    101   // We assume -Bsymbolic to bind all symbols internaly via !rsym->isDyn()
    102   // Don't put undef symbols into local entries.
    103   if ((rsym->isLocal() || !getTarget().isDynamicSymbol(*rsym) ||
    104       !rsym->isDyn()) && !rsym->isUndef())
    105     scanLocalReloc(pReloc, pBuilder, pSection);
    106   else
    107     scanGlobalReloc(pReloc, pBuilder, pSection);
    108 
    109   // check if we shoule issue undefined reference for the relocation target
    110   // symbol
    111   if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
    112     fatal(diag::undefined_reference) << rsym->name();
    113 }
    114 
    115 bool MipsRelocator::initializeScan(Input& pInput)
    116 {
    117   getTarget().getGOT().initializeScan(pInput);
    118   return true;
    119 }
    120 
    121 bool MipsRelocator::finalizeScan(Input& pInput)
    122 {
    123   getTarget().getGOT().finalizeScan(pInput);
    124   return true;
    125 }
    126 
    127 bool MipsRelocator::initializeApply(Input& pInput)
    128 {
    129   m_pApplyingInput = &pInput;
    130   return true;
    131 }
    132 
    133 bool MipsRelocator::finalizeApply(Input& pInput)
    134 {
    135   m_pApplyingInput = NULL;
    136   return true;
    137 }
    138 
    139 void MipsRelocator::scanLocalReloc(Relocation& pReloc,
    140                                    IRBuilder& pBuilder,
    141                                    const LDSection& pSection)
    142 {
    143   ResolveInfo* rsym = pReloc.symInfo();
    144 
    145   switch (pReloc.type()){
    146     case llvm::ELF::R_MIPS_NONE:
    147     case llvm::ELF::R_MIPS_16:
    148       break;
    149     case llvm::ELF::R_MIPS_32:
    150       if (LinkerConfig::DynObj == config().codeGenType()) {
    151         // TODO: (simon) The gold linker does not create an entry in .rel.dyn
    152         // section if the symbol section flags contains SHF_EXECINSTR.
    153         // 1. Find the reason of this condition.
    154         // 2. Check this condition here.
    155         getTarget().getRelDyn().reserveEntry();
    156         rsym->setReserved(rsym->reserved() | ReserveRel);
    157         getTarget().checkAndSetHasTextRel(*pSection.getLink());
    158 
    159         // Remeber this rsym is a local GOT entry (as if it needs an entry).
    160         // Actually we don't allocate an GOT entry.
    161         getTarget().getGOT().setLocal(rsym);
    162       }
    163       break;
    164     case llvm::ELF::R_MIPS_REL32:
    165     case llvm::ELF::R_MIPS_26:
    166     case llvm::ELF::R_MIPS_HI16:
    167     case llvm::ELF::R_MIPS_LO16:
    168     case llvm::ELF::R_MIPS_PC16:
    169     case llvm::ELF::R_MIPS_SHIFT5:
    170     case llvm::ELF::R_MIPS_SHIFT6:
    171     case llvm::ELF::R_MIPS_64:
    172     case llvm::ELF::R_MIPS_GOT_PAGE:
    173     case llvm::ELF::R_MIPS_GOT_OFST:
    174     case llvm::ELF::R_MIPS_SUB:
    175     case llvm::ELF::R_MIPS_INSERT_A:
    176     case llvm::ELF::R_MIPS_INSERT_B:
    177     case llvm::ELF::R_MIPS_DELETE:
    178     case llvm::ELF::R_MIPS_HIGHER:
    179     case llvm::ELF::R_MIPS_HIGHEST:
    180     case llvm::ELF::R_MIPS_SCN_DISP:
    181     case llvm::ELF::R_MIPS_REL16:
    182     case llvm::ELF::R_MIPS_ADD_IMMEDIATE:
    183     case llvm::ELF::R_MIPS_PJUMP:
    184     case llvm::ELF::R_MIPS_RELGOT:
    185     case llvm::ELF::R_MIPS_JALR:
    186     case llvm::ELF::R_MIPS_GLOB_DAT:
    187     case llvm::ELF::R_MIPS_COPY:
    188     case llvm::ELF::R_MIPS_JUMP_SLOT:
    189       break;
    190     case llvm::ELF::R_MIPS_GOT16:
    191     case llvm::ELF::R_MIPS_CALL16:
    192     case llvm::ELF::R_MIPS_GOT_HI16:
    193     case llvm::ELF::R_MIPS_CALL_HI16:
    194     case llvm::ELF::R_MIPS_GOT_LO16:
    195     case llvm::ELF::R_MIPS_CALL_LO16:
    196       if (getTarget().getGOT().reserveLocalEntry(*rsym)) {
    197         if (getTarget().getGOT().hasMultipleGOT())
    198           getTarget().checkAndSetHasTextRel(*pSection.getLink());
    199         // Remeber this rsym is a local GOT entry
    200         getTarget().getGOT().setLocal(rsym);
    201       }
    202       break;
    203     case llvm::ELF::R_MIPS_GPREL32:
    204     case llvm::ELF::R_MIPS_GPREL16:
    205     case llvm::ELF::R_MIPS_LITERAL:
    206     case llvm::ELF::R_MIPS_GOT_DISP:
    207       break;
    208     case llvm::ELF::R_MIPS_TLS_DTPMOD32:
    209     case llvm::ELF::R_MIPS_TLS_DTPREL32:
    210     case llvm::ELF::R_MIPS_TLS_DTPMOD64:
    211     case llvm::ELF::R_MIPS_TLS_DTPREL64:
    212     case llvm::ELF::R_MIPS_TLS_GD:
    213     case llvm::ELF::R_MIPS_TLS_LDM:
    214     case llvm::ELF::R_MIPS_TLS_DTPREL_HI16:
    215     case llvm::ELF::R_MIPS_TLS_DTPREL_LO16:
    216     case llvm::ELF::R_MIPS_TLS_GOTTPREL:
    217     case llvm::ELF::R_MIPS_TLS_TPREL32:
    218     case llvm::ELF::R_MIPS_TLS_TPREL64:
    219     case llvm::ELF::R_MIPS_TLS_TPREL_HI16:
    220     case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
    221       break;
    222     default:
    223       fatal(diag::unknown_relocation) << (int)pReloc.type()
    224                                       << pReloc.symInfo()->name();
    225   }
    226 }
    227 
    228 void MipsRelocator::scanGlobalReloc(Relocation& pReloc,
    229                                     IRBuilder& pBuilder,
    230                                     const LDSection& pSection)
    231 {
    232   ResolveInfo* rsym = pReloc.symInfo();
    233 
    234   switch (pReloc.type()){
    235     case llvm::ELF::R_MIPS_NONE:
    236     case llvm::ELF::R_MIPS_INSERT_A:
    237     case llvm::ELF::R_MIPS_INSERT_B:
    238     case llvm::ELF::R_MIPS_DELETE:
    239     case llvm::ELF::R_MIPS_TLS_DTPMOD64:
    240     case llvm::ELF::R_MIPS_TLS_DTPREL64:
    241     case llvm::ELF::R_MIPS_REL16:
    242     case llvm::ELF::R_MIPS_ADD_IMMEDIATE:
    243     case llvm::ELF::R_MIPS_PJUMP:
    244     case llvm::ELF::R_MIPS_RELGOT:
    245     case llvm::ELF::R_MIPS_TLS_TPREL64:
    246       break;
    247     case llvm::ELF::R_MIPS_32:
    248     case llvm::ELF::R_MIPS_64:
    249     case llvm::ELF::R_MIPS_HI16:
    250     case llvm::ELF::R_MIPS_LO16:
    251       if (getTarget().symbolNeedsDynRel(*rsym, false, true)) {
    252         getTarget().getRelDyn().reserveEntry();
    253         rsym->setReserved(rsym->reserved() | ReserveRel);
    254         getTarget().checkAndSetHasTextRel(*pSection.getLink());
    255 
    256         // Remeber this rsym is a global GOT entry (as if it needs an entry).
    257         // Actually we don't allocate an GOT entry.
    258         getTarget().getGOT().setGlobal(rsym);
    259       }
    260       break;
    261     case llvm::ELF::R_MIPS_GOT16:
    262     case llvm::ELF::R_MIPS_CALL16:
    263     case llvm::ELF::R_MIPS_GOT_DISP:
    264     case llvm::ELF::R_MIPS_GOT_HI16:
    265     case llvm::ELF::R_MIPS_CALL_HI16:
    266     case llvm::ELF::R_MIPS_GOT_LO16:
    267     case llvm::ELF::R_MIPS_CALL_LO16:
    268     case llvm::ELF::R_MIPS_GOT_PAGE:
    269     case llvm::ELF::R_MIPS_GOT_OFST:
    270       if (getTarget().getGOT().reserveGlobalEntry(*rsym)) {
    271         if (getTarget().getGOT().hasMultipleGOT())
    272           getTarget().checkAndSetHasTextRel(*pSection.getLink());
    273         // Remeber this rsym is a global GOT entry
    274         getTarget().getGOT().setGlobal(rsym);
    275       }
    276       break;
    277     case llvm::ELF::R_MIPS_LITERAL:
    278     case llvm::ELF::R_MIPS_GPREL32:
    279       fatal(diag::invalid_global_relocation) << (int)pReloc.type()
    280                                              << pReloc.symInfo()->name();
    281       break;
    282     case llvm::ELF::R_MIPS_GPREL16:
    283       break;
    284     case llvm::ELF::R_MIPS_26:
    285     case llvm::ELF::R_MIPS_PC16:
    286       break;
    287     case llvm::ELF::R_MIPS_16:
    288     case llvm::ELF::R_MIPS_SHIFT5:
    289     case llvm::ELF::R_MIPS_SHIFT6:
    290     case llvm::ELF::R_MIPS_SUB:
    291     case llvm::ELF::R_MIPS_HIGHER:
    292     case llvm::ELF::R_MIPS_HIGHEST:
    293     case llvm::ELF::R_MIPS_SCN_DISP:
    294       break;
    295     case llvm::ELF::R_MIPS_TLS_DTPREL32:
    296     case llvm::ELF::R_MIPS_TLS_GD:
    297     case llvm::ELF::R_MIPS_TLS_LDM:
    298     case llvm::ELF::R_MIPS_TLS_DTPREL_HI16:
    299     case llvm::ELF::R_MIPS_TLS_DTPREL_LO16:
    300     case llvm::ELF::R_MIPS_TLS_GOTTPREL:
    301     case llvm::ELF::R_MIPS_TLS_TPREL32:
    302     case llvm::ELF::R_MIPS_TLS_TPREL_HI16:
    303     case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
    304       break;
    305     case llvm::ELF::R_MIPS_REL32:
    306       break;
    307     case llvm::ELF::R_MIPS_JALR:
    308       break;
    309     case llvm::ELF::R_MIPS_COPY:
    310     case llvm::ELF::R_MIPS_GLOB_DAT:
    311     case llvm::ELF::R_MIPS_JUMP_SLOT:
    312       fatal(diag::dynamic_relocation) << (int)pReloc.type();
    313       break;
    314     default:
    315       fatal(diag::unknown_relocation) << (int)pReloc.type()
    316                                       << pReloc.symInfo()->name();
    317   }
    318 }
    319 
    320 //===----------------------------------------------------------------------===//
    321 // Relocation helper function
    322 //===----------------------------------------------------------------------===//
    323 static const char * const GP_DISP_NAME = "_gp_disp";
    324 
    325 // Find next R_MIPS_LO16 relocation paired to pReloc.
    326 static
    327 Relocation* helper_FindLo16Reloc(Relocation& pReloc)
    328 {
    329   Relocation* reloc = static_cast<Relocation*>(pReloc.getNextNode());
    330   while (NULL != reloc)
    331   {
    332     if (llvm::ELF::R_MIPS_LO16 == reloc->type() &&
    333         reloc->symInfo() == pReloc.symInfo())
    334       return reloc;
    335 
    336     reloc = static_cast<Relocation*>(reloc->getNextNode());
    337   }
    338   return NULL;
    339 }
    340 
    341 // Check the symbol is _gp_disp.
    342 static
    343 bool helper_isGpDisp(const Relocation& pReloc)
    344 {
    345   const ResolveInfo* rsym = pReloc.symInfo();
    346   return 0 == strcmp(GP_DISP_NAME, rsym->name());
    347 }
    348 
    349 static
    350 Relocator::Address helper_GetGP(MipsRelocator& pParent)
    351 {
    352   return pParent.getTarget().getGOT().getGPAddr(pParent.getApplyingInput());
    353 }
    354 
    355 static
    356 void helper_SetupRelDynForGOTEntry(MipsGOTEntry& got_entry,
    357                                    Relocation& pReloc,
    358                                    ResolveInfo* rsym,
    359                                    MipsRelocator& pParent)
    360 {
    361   MipsGNULDBackend& ld_backend = pParent.getTarget();
    362 
    363   Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
    364   rel_entry.setType(llvm::ELF::R_MIPS_REL32);
    365   rel_entry.targetRef() = *FragmentRef::Create(got_entry, 0);
    366   rel_entry.setSymInfo(rsym);
    367 }
    368 
    369 static
    370 MipsGOTEntry& helper_GetGOTEntry(Relocation& pReloc, MipsRelocator& pParent)
    371 {
    372   // rsym - The relocation target symbol
    373   ResolveInfo* rsym = pReloc.symInfo();
    374   MipsGNULDBackend& ld_backend = pParent.getTarget();
    375   MipsGOT& got = ld_backend.getGOT();
    376   MipsGOTEntry* got_entry;
    377 
    378   if (got.isLocal(rsym) && ResolveInfo::Section == rsym->type()) {
    379     // Local section symbols consume local got entries.
    380     got_entry = got.consumeLocal();
    381     if (got.isPrimaryGOTConsumed())
    382       helper_SetupRelDynForGOTEntry(*got_entry, pReloc, NULL, pParent);
    383     return *got_entry;
    384   }
    385 
    386   got_entry = got.lookupEntry(rsym);
    387   if (NULL != got_entry) {
    388     // found a mapping, then return the mapped entry immediately
    389     return *got_entry;
    390   }
    391 
    392   // not found
    393   if (got.isLocal(rsym))
    394     got_entry = got.consumeLocal();
    395   else
    396     got_entry = got.consumeGlobal();
    397 
    398   got.recordEntry(rsym, got_entry);
    399 
    400   // If we first get this GOT entry, we should initialize it.
    401   if (!got.isLocal(rsym) || ResolveInfo::Section != rsym->type()) {
    402     if (!got.isPrimaryGOTConsumed())
    403       got_entry->setValue(pReloc.symValue());
    404   }
    405 
    406   if (got.isPrimaryGOTConsumed())
    407     helper_SetupRelDynForGOTEntry(*got_entry, pReloc,
    408                                   got.isLocal(rsym) ? NULL : rsym, pParent);
    409 
    410   return *got_entry;
    411 }
    412 
    413 static
    414 Relocator::Address helper_GetGOTOffset(Relocation& pReloc,
    415                                        MipsRelocator& pParent)
    416 {
    417   MipsGNULDBackend& ld_backend = pParent.getTarget();
    418   MipsGOT& got = ld_backend.getGOT();
    419   MipsGOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent);
    420   return got.getGPRelOffset(pParent.getApplyingInput(), got_entry);
    421 }
    422 
    423 static
    424 int32_t helper_CalcAHL(const Relocation& pHiReloc, const Relocation& pLoReloc)
    425 {
    426   assert((pHiReloc.type() == llvm::ELF::R_MIPS_HI16 ||
    427           pHiReloc.type() == llvm::ELF::R_MIPS_GOT16) &&
    428          pLoReloc.type() == llvm::ELF::R_MIPS_LO16 &&
    429          "Incorrect type of relocation for AHL calculation");
    430 
    431   // Note the addend is section symbol offset here
    432   assert (pHiReloc.addend() == pLoReloc.addend());
    433 
    434   int32_t AHI = pHiReloc.target();
    435   int32_t ALO = pLoReloc.target();
    436   int32_t AHL = ((AHI & 0xFFFF) << 16) + (int16_t)(ALO & 0xFFFF) +
    437                  pLoReloc.addend();
    438   return AHL;
    439 }
    440 
    441 static
    442 void helper_DynRel(Relocation& pReloc, MipsRelocator& pParent)
    443 {
    444   ResolveInfo* rsym = pReloc.symInfo();
    445   MipsGNULDBackend& ld_backend = pParent.getTarget();
    446   MipsGOT& got = ld_backend.getGOT();
    447 
    448   Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
    449 
    450   rel_entry.setType(llvm::ELF::R_MIPS_REL32);
    451   rel_entry.targetRef() = pReloc.targetRef();
    452 
    453   Relocator::DWord A = pReloc.target() + pReloc.addend();
    454   Relocator::DWord S = pReloc.symValue();
    455 
    456   if (got.isLocal(rsym)) {
    457     rel_entry.setSymInfo(NULL);
    458     pReloc.target() = A + S;
    459   }
    460   else {
    461     rel_entry.setSymInfo(rsym);
    462     // Don't add symbol value that will be resolved by the dynamic linker
    463     pReloc.target() = A;
    464   }
    465 }
    466 
    467 //=========================================//
    468 // Relocation functions implementation     //
    469 //=========================================//
    470 
    471 // R_MIPS_NONE and those unsupported/deprecated relocation type
    472 static
    473 MipsRelocator::Result none(Relocation& pReloc, MipsRelocator& pParent)
    474 {
    475   return MipsRelocator::OK;
    476 }
    477 
    478 // R_MIPS_32: S + A
    479 static
    480 MipsRelocator::Result abs32(Relocation& pReloc, MipsRelocator& pParent)
    481 {
    482   ResolveInfo* rsym = pReloc.symInfo();
    483 
    484   Relocator::DWord A = pReloc.target() + pReloc.addend();
    485   Relocator::DWord S = pReloc.symValue();
    486 
    487   LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
    488   // If the flag of target section is not ALLOC, we will not scan this relocation
    489   // but perform static relocation. (e.g., applying .debug section)
    490   if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
    491     pReloc.target() = S + A;
    492     return MipsRelocator::OK;
    493   }
    494 
    495   if (rsym->reserved() & MipsRelocator::ReserveRel) {
    496     helper_DynRel(pReloc, pParent);
    497 
    498     return MipsRelocator::OK;
    499   }
    500 
    501   pReloc.target() = (S + A);
    502 
    503   return MipsRelocator::OK;
    504 }
    505 
    506 // R_MIPS_HI16:
    507 //   local/external: ((AHL + S) - (short)(AHL + S)) >> 16
    508 //   _gp_disp      : ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16
    509 static
    510 MipsRelocator::Result hi16(Relocation& pReloc, MipsRelocator& pParent)
    511 {
    512   Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
    513   assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_HI16");
    514 
    515   int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc);
    516   int32_t res = 0;
    517 
    518   pParent.setAHL(AHL);
    519 
    520   if (helper_isGpDisp(pReloc)) {
    521     int32_t P = pReloc.place();
    522     int32_t GP = helper_GetGP(pParent);
    523     res = ((AHL + GP - P) - (int16_t)(AHL + GP - P)) >> 16;
    524   }
    525   else {
    526     int32_t S = pReloc.symValue();
    527     res = ((AHL + S) - (int16_t)(AHL + S)) >> 16;
    528   }
    529 
    530   pReloc.target() &= 0xFFFF0000;
    531   pReloc.target() |= (res & 0xFFFF);
    532 
    533   return MipsRelocator::OK;
    534 }
    535 
    536 // R_MIPS_LO16:
    537 //   local/external: AHL + S
    538 //   _gp_disp      : AHL + GP - P + 4
    539 static
    540 MipsRelocator::Result lo16(Relocation& pReloc, MipsRelocator& pParent)
    541 {
    542   int32_t res = 0;
    543 
    544   if (helper_isGpDisp(pReloc)) {
    545     int32_t P = pReloc.place();
    546     int32_t GP = helper_GetGP(pParent);
    547     int32_t AHL = pParent.getAHL();
    548     res = AHL + GP - P + 4;
    549   }
    550   else {
    551     int32_t S = pReloc.symValue();
    552     // The previous AHL may be for other hi/lo pairs.
    553     // We need to calcuate the lo part now.  It is easy.
    554     // Remember to add the section offset to ALO.
    555     int32_t ALO = (pReloc.target() & 0xFFFF) + pReloc.addend();
    556     res = ALO + S;
    557   }
    558 
    559   pReloc.target() &= 0xFFFF0000;
    560   pReloc.target() |= (res & 0xFFFF);
    561 
    562   return MipsRelocator::OK;
    563 }
    564 
    565 // R_MIPS_GOT16:
    566 //   local   : G (calculate AHL and put high 16 bit to GOT)
    567 //   external: G
    568 static
    569 MipsRelocator::Result got16(Relocation& pReloc, MipsRelocator& pParent)
    570 {
    571   MipsGNULDBackend& ld_backend = pParent.getTarget();
    572   MipsGOT& got = ld_backend.getGOT();
    573   ResolveInfo* rsym = pReloc.symInfo();
    574   Relocator::Address G = 0;
    575 
    576   if (rsym->isLocal()) {
    577     Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
    578     assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_GOT16");
    579 
    580     int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc);
    581     int32_t S = pReloc.symValue();
    582 
    583     pParent.setAHL(AHL);
    584 
    585     int32_t res = (AHL + S + 0x8000) & 0xFFFF0000;
    586     MipsGOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent);
    587 
    588     got_entry.setValue(res);
    589     G = got.getGPRelOffset(pParent.getApplyingInput(), got_entry);
    590   }
    591   else {
    592     G = helper_GetGOTOffset(pReloc, pParent);
    593   }
    594 
    595   pReloc.target() &= 0xFFFF0000;
    596   pReloc.target() |= (G & 0xFFFF);
    597 
    598   return MipsRelocator::OK;
    599 }
    600 
    601 // R_MIPS_GOTHI16:
    602 //   external: (G - (short)G) >> 16 + A
    603 static
    604 MipsRelocator::Result gothi16(Relocation& pReloc, MipsRelocator& pParent)
    605 {
    606   int32_t res = 0;
    607 
    608   Relocator::Address G = helper_GetGOTOffset(pReloc, pParent);
    609   int32_t A = pReloc.target() + pReloc.addend();
    610 
    611   res = (G - (int16_t)G) >> (16 + A);
    612 
    613   pReloc.target() &= 0xFFFF0000;
    614   pReloc.target() |= (res & 0xFFFF);
    615 
    616   return MipsRelocator::OK;
    617 }
    618 
    619 // R_MIPS_GOTLO16:
    620 //   external: G & 0xffff
    621 static
    622 MipsRelocator::Result gotlo16(Relocation& pReloc, MipsRelocator& pParent)
    623 {
    624   Relocator::Address G = helper_GetGOTOffset(pReloc, pParent);
    625 
    626   pReloc.target() &= 0xFFFF0000;
    627   pReloc.target() |= (G & 0xFFFF);
    628 
    629   return MipsRelocator::OK;
    630 }
    631 
    632 // R_MIPS_CALL16: G
    633 static
    634 MipsRelocator::Result call16(Relocation& pReloc, MipsRelocator& pParent)
    635 {
    636   Relocator::Address G = helper_GetGOTOffset(pReloc, pParent);
    637 
    638   pReloc.target() &= 0xFFFF0000;
    639   pReloc.target() |= (G & 0xFFFF);
    640 
    641   return MipsRelocator::OK;
    642 }
    643 
    644 // R_MIPS_GPREL32: A + S + GP0 - GP
    645 static
    646 MipsRelocator::Result gprel32(Relocation& pReloc, MipsRelocator& pParent)
    647 {
    648   // Remember to add the section offset to A.
    649   int32_t A = pReloc.target() + pReloc.addend();
    650   int32_t S = pReloc.symValue();
    651   int32_t GP = helper_GetGP(pParent);
    652 
    653   // llvm does not emits SHT_MIPS_REGINFO section.
    654   // Assume that GP0 is zero.
    655   pReloc.target() = (A + S - GP) & 0xFFFFFFFF;
    656 
    657   return MipsRelocator::OK;
    658 }
    659 
    660