Home | History | Annotate | Download | only in Hexagon
      1 //===- HexagonRelocator.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 #include "HexagonRelocator.h"
     10 #include "HexagonRelocationFunctions.h"
     11 #include "HexagonEncodings.h"
     12 
     13 #include "mcld/LD/ELFFileFormat.h"
     14 #include "mcld/LD/LDSymbol.h"
     15 #include "mcld/Support/MsgHandling.h"
     16 
     17 #include <llvm/ADT/Twine.h>
     18 #include <llvm/Support/DataTypes.h>
     19 #include <llvm/Support/ELF.h>
     20 
     21 namespace mcld {
     22 
     23 //===--------------------------------------------------------------------===//
     24 // Relocation Helper Functions
     25 //===--------------------------------------------------------------------===//
     26 /// helper_DynRel - Get an relocation entry in .rela.dyn
     27 static Relocation& helper_DynRel_init(ResolveInfo* pSym,
     28                                       Fragment& pFrag,
     29                                       uint64_t pOffset,
     30                                       Relocator::Type pType,
     31                                       HexagonRelocator& pParent) {
     32   HexagonLDBackend& ld_backend = pParent.getTarget();
     33   Relocation& rela_entry = *ld_backend.getRelaDyn().create();
     34   rela_entry.setType(pType);
     35   rela_entry.targetRef().assign(pFrag, pOffset);
     36   if (pType == llvm::ELF::R_HEX_RELATIVE || pSym == NULL)
     37     rela_entry.setSymInfo(0);
     38   else
     39     rela_entry.setSymInfo(pSym);
     40 
     41   return rela_entry;
     42 }
     43 
     44 /// helper_use_relative_reloc - Check if symbol can use relocation
     45 /// R_HEX_RELATIVE
     46 static bool helper_use_relative_reloc(const ResolveInfo& pSym,
     47                                       const HexagonRelocator& pFactory) {
     48   // if symbol is dynamic or undefine or preemptible
     49   if (pSym.isDyn() || pSym.isUndef() ||
     50       pFactory.getTarget().isSymbolPreemptible(pSym))
     51     return false;
     52   return true;
     53 }
     54 
     55 static HexagonGOTEntry& helper_GOT_init(Relocation& pReloc,
     56                                         bool pHasRel,
     57                                         HexagonRelocator& pParent) {
     58   // rsym - The relocation target symbol
     59   ResolveInfo* rsym = pReloc.symInfo();
     60   HexagonLDBackend& ld_backend = pParent.getTarget();
     61   assert(pParent.getSymGOTMap().lookUp(*rsym) == NULL);
     62 
     63   HexagonGOTEntry* got_entry = ld_backend.getGOT().create();
     64   pParent.getSymGOTMap().record(*rsym, *got_entry);
     65 
     66   if (!pHasRel) {
     67     // No corresponding dynamic relocation, initialize to the symbol value.
     68     got_entry->setValue(HexagonRelocator::SymVal);
     69   } else {
     70     // Initialize got_entry content and the corresponding dynamic relocation.
     71     if (helper_use_relative_reloc(*rsym, pParent)) {
     72       helper_DynRel_init(
     73           rsym, *got_entry, 0x0, llvm::ELF::R_HEX_RELATIVE, pParent);
     74       got_entry->setValue(HexagonRelocator::SymVal);
     75     } else {
     76       helper_DynRel_init(
     77           rsym, *got_entry, 0x0, llvm::ELF::R_HEX_GLOB_DAT, pParent);
     78       got_entry->setValue(0);
     79     }
     80   }
     81   return *got_entry;
     82 }
     83 
     84 static Relocator::Address helper_get_GOT_address(ResolveInfo& pSym,
     85                                                  HexagonRelocator& pParent) {
     86   HexagonGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(pSym);
     87   assert(got_entry != NULL);
     88   return pParent.getTarget().getGOT().addr() + got_entry->getOffset();
     89 }
     90 
     91 static PLTEntryBase& helper_PLT_init(Relocation& pReloc,
     92                                      HexagonRelocator& pParent) {
     93   // rsym - The relocation target symbol
     94   ResolveInfo* rsym = pReloc.symInfo();
     95   HexagonLDBackend& ld_backend = pParent.getTarget();
     96   assert(pParent.getSymPLTMap().lookUp(*rsym) == NULL);
     97 
     98   PLTEntryBase* plt_entry = ld_backend.getPLT().create();
     99   pParent.getSymPLTMap().record(*rsym, *plt_entry);
    100 
    101   assert(pParent.getSymGOTPLTMap().lookUp(*rsym) == NULL &&
    102          "PLT entry not exist, but DynRel entry exist!");
    103   HexagonGOTEntry* gotplt_entry = ld_backend.getGOTPLT().create();
    104   pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
    105   // init the corresponding rel entry in .rela.plt
    106   Relocation& rela_entry = *ld_backend.getRelaPLT().create();
    107   rela_entry.setType(llvm::ELF::R_HEX_JMP_SLOT);
    108   rela_entry.targetRef().assign(*gotplt_entry);
    109   rela_entry.setSymInfo(rsym);
    110 
    111   return *plt_entry;
    112 }
    113 
    114 static Relocator::Address helper_get_PLT_address(ResolveInfo& pSym,
    115                                                  HexagonRelocator& pParent) {
    116   PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(pSym);
    117   assert(plt_entry != NULL);
    118   return pParent.getTarget().getPLT().addr() + plt_entry->getOffset();
    119 }
    120 
    121 //===--------------------------------------------------------------------===//
    122 // Relocation Functions and Tables
    123 //===--------------------------------------------------------------------===//
    124 DECL_HEXAGON_APPLY_RELOC_FUNCS
    125 
    126 /// the prototype of applying function
    127 typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc,
    128                                                HexagonRelocator& pParent);
    129 
    130 // the table entry of applying functions
    131 struct ApplyFunctionTriple {
    132   ApplyFunctionType func;
    133   unsigned int type;
    134   const char* name;
    135 };
    136 
    137 // declare the table of applying functions
    138 static const ApplyFunctionTriple ApplyFunctions[] = {
    139     DECL_HEXAGON_APPLY_RELOC_FUNC_PTRS};
    140 
    141 static uint32_t findBitMask(uint32_t insn,
    142                             Instruction* encodings,
    143                             int32_t numInsns) {
    144   for (int32_t i = 0; i < numInsns; ++i) {
    145     if (((insn & 0xc000) == 0) && !(encodings[i].isDuplex))
    146       continue;
    147 
    148     if (((insn & 0xc000) != 0) && (encodings[i].isDuplex))
    149       continue;
    150 
    151     if (((encodings[i].insnMask) & insn) == encodings[i].insnCmpMask)
    152       return encodings[i].insnBitMask;
    153   }
    154   assert(0);
    155   // Should not be here, but add a return for -Werror=return-type
    156   // error: control reaches end of non-void function
    157   return -1;
    158 }
    159 
    160 #define FINDBITMASK(INSN)     \
    161   findBitMask((uint32_t)INSN, \
    162               insn_encodings, \
    163               sizeof(insn_encodings) / sizeof(Instruction))
    164 
    165 //===--------------------------------------------------------------------===//
    166 // HexagonRelocator
    167 //===--------------------------------------------------------------------===//
    168 HexagonRelocator::HexagonRelocator(HexagonLDBackend& pParent,
    169                                    const LinkerConfig& pConfig)
    170     : Relocator(pConfig), m_Target(pParent) {
    171 }
    172 
    173 HexagonRelocator::~HexagonRelocator() {
    174 }
    175 
    176 Relocator::Result HexagonRelocator::applyRelocation(Relocation& pRelocation) {
    177   Relocation::Type type = pRelocation.type();
    178 
    179   if (type > 85) {  // 86-255 relocs do not exists for Hexagon
    180     return Relocator::Unknown;
    181   }
    182 
    183   // apply the relocation
    184   return ApplyFunctions[type].func(pRelocation, *this);
    185 }
    186 
    187 const char* HexagonRelocator::getName(Relocation::Type pType) const {
    188   return ApplyFunctions[pType].name;
    189 }
    190 
    191 Relocator::Size HexagonRelocator::getSize(Relocation::Type pType) const {
    192   return 32;
    193 }
    194 
    195 void HexagonRelocator::scanRelocation(Relocation& pReloc,
    196                                       IRBuilder& pLinker,
    197                                       Module& pModule,
    198                                       LDSection& pSection,
    199                                       Input& pInput) {
    200   if (LinkerConfig::Object == config().codeGenType())
    201     return;
    202 
    203   // rsym - The relocation target symbol
    204   ResolveInfo* rsym = pReloc.symInfo();
    205   assert(rsym != NULL &&
    206          "ResolveInfo of relocation not set while scanRelocation");
    207 
    208   if (config().isCodeStatic())
    209     return;
    210 
    211   assert(pSection.getLink() != NULL);
    212   if ((pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC) == 0)
    213     return;
    214 
    215   if (rsym->isLocal())  // rsym is local
    216     scanLocalReloc(pReloc, pLinker, pModule, pSection);
    217   else  // rsym is external
    218     scanGlobalReloc(pReloc, pLinker, pModule, pSection);
    219 
    220   // check if we should issue undefined reference for the relocation target
    221   // symbol
    222   if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
    223     issueUndefRef(pReloc, pSection, pInput);
    224 }
    225 
    226 void HexagonRelocator::addCopyReloc(ResolveInfo& pSym,
    227                                     HexagonLDBackend& pTarget) {
    228   Relocation& rel_entry = *pTarget.getRelaDyn().create();
    229   rel_entry.setType(pTarget.getCopyRelType());
    230   assert(pSym.outSymbol()->hasFragRef());
    231   rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef());
    232   rel_entry.setSymInfo(&pSym);
    233 }
    234 
    235 void HexagonRelocator::scanLocalReloc(Relocation& pReloc,
    236                                       IRBuilder& pBuilder,
    237                                       Module& pModule,
    238                                       LDSection& pSection) {
    239   // rsym - The relocation target symbol
    240   ResolveInfo* rsym = pReloc.symInfo();
    241 
    242   switch (pReloc.type()) {
    243     case llvm::ELF::R_HEX_LO16:
    244     case llvm::ELF::R_HEX_HI16:
    245     case llvm::ELF::R_HEX_16:
    246     case llvm::ELF::R_HEX_8:
    247     case llvm::ELF::R_HEX_32_6_X:
    248     case llvm::ELF::R_HEX_16_X:
    249     case llvm::ELF::R_HEX_12_X:
    250     case llvm::ELF::R_HEX_11_X:
    251     case llvm::ELF::R_HEX_10_X:
    252     case llvm::ELF::R_HEX_9_X:
    253     case llvm::ELF::R_HEX_8_X:
    254     case llvm::ELF::R_HEX_7_X:
    255     case llvm::ELF::R_HEX_6_X:
    256       assert(!(rsym->reserved() & ReserveRel) &&
    257              "Cannot apply this relocation for read only section");
    258       return;
    259 
    260     case llvm::ELF::R_HEX_32:
    261       // If buiding PIC object (shared library or PIC executable),
    262       // a dynamic relocations with RELATIVE type to this location is needed.
    263       // Reserve an entry in .rel.dyn
    264       if (config().isCodeIndep()) {
    265         Relocation& reloc = helper_DynRel_init(rsym,
    266                                                *pReloc.targetRef().frag(),
    267                                                pReloc.targetRef().offset(),
    268                                                llvm::ELF::R_HEX_RELATIVE,
    269                                                *this);
    270         // we need to set up the relocation addend at apply relocation, record
    271         // the
    272         // relocation
    273         getRelRelMap().record(pReloc, reloc);
    274 
    275         // set Rel bit
    276         rsym->setReserved(rsym->reserved() | ReserveRel);
    277         getTarget().checkAndSetHasTextRel(*pSection.getLink());
    278       }
    279       return;
    280 
    281     default:
    282       return;
    283   }
    284 }
    285 
    286 void HexagonRelocator::scanGlobalReloc(Relocation& pReloc,
    287                                        IRBuilder& pBuilder,
    288                                        Module& pModule,
    289                                        LDSection& pSection) {
    290   // rsym - The relocation target symbol
    291   ResolveInfo* rsym = pReloc.symInfo();
    292   HexagonLDBackend& ld_backend = getTarget();
    293 
    294   switch (pReloc.type()) {
    295     case llvm::ELF::R_HEX_LO16:
    296     case llvm::ELF::R_HEX_HI16:
    297     case llvm::ELF::R_HEX_16:
    298     case llvm::ELF::R_HEX_8:
    299     case llvm::ELF::R_HEX_32_6_X:
    300     case llvm::ELF::R_HEX_16_X:
    301     case llvm::ELF::R_HEX_12_X:
    302     case llvm::ELF::R_HEX_11_X:
    303     case llvm::ELF::R_HEX_10_X:
    304     case llvm::ELF::R_HEX_9_X:
    305     case llvm::ELF::R_HEX_8_X:
    306     case llvm::ELF::R_HEX_7_X:
    307     case llvm::ELF::R_HEX_6_X:
    308       assert(!(rsym->reserved() & ReserveRel) &&
    309              "Cannot apply this relocation for read only section");
    310       return;
    311 
    312     case llvm::ELF::R_HEX_32:
    313       if (ld_backend.symbolNeedsPLT(*rsym)) {
    314         // create PLT for this symbol if it does not have.
    315         if (!(rsym->reserved() & ReservePLT)) {
    316           helper_PLT_init(pReloc, *this);
    317           rsym->setReserved(rsym->reserved() | ReservePLT);
    318         }
    319       }
    320 
    321       if (ld_backend.symbolNeedsDynRel(
    322               *rsym, (rsym->reserved() & ReservePLT), true)) {
    323         if (ld_backend.symbolNeedsCopyReloc(pReloc, *rsym)) {
    324           LDSymbol& cpy_sym =
    325               defineSymbolforCopyReloc(pBuilder, *rsym, ld_backend);
    326           addCopyReloc(*cpy_sym.resolveInfo(), ld_backend);
    327         } else {
    328           Relocation& reloc = helper_DynRel_init(rsym,
    329                                                  *pReloc.targetRef().frag(),
    330                                                  pReloc.targetRef().offset(),
    331                                                  llvm::ELF::R_HEX_RELATIVE,
    332                                                  *this);
    333           // we need to set up the relocation addend at apply relocation, record
    334           // the
    335           // relocation
    336           getRelRelMap().record(pReloc, reloc);
    337           rsym->setReserved(rsym->reserved() | ReserveRel);
    338           ld_backend.checkAndSetHasTextRel(*pSection.getLink());
    339         }
    340       }
    341       return;
    342 
    343     case llvm::ELF::R_HEX_GOTREL_LO16:
    344     case llvm::ELF::R_HEX_GOTREL_HI16:
    345     case llvm::ELF::R_HEX_GOTREL_32:
    346     case llvm::ELF::R_HEX_GOTREL_32_6_X:
    347     case llvm::ELF::R_HEX_GOTREL_16_X:
    348     case llvm::ELF::R_HEX_GOTREL_11_X:
    349       // This assumes that GOT exists
    350       return;
    351 
    352     case llvm::ELF::R_HEX_GOT_LO16:
    353     case llvm::ELF::R_HEX_GOT_HI16:
    354     case llvm::ELF::R_HEX_GOT_32:
    355     case llvm::ELF::R_HEX_GOT_16:
    356     case llvm::ELF::R_HEX_GOT_32_6_X:
    357     case llvm::ELF::R_HEX_GOT_16_X:
    358     case llvm::ELF::R_HEX_GOT_11_X:
    359       // Symbol needs GOT entry, reserve entry in .got
    360       // return if we already create GOT for this symbol
    361       if (rsym->reserved() & ReserveGOT)
    362         return;
    363       // If the GOT is used in statically linked binaries,
    364       // the GOT entry is enough and no relocation is needed.
    365       if (config().isCodeStatic())
    366         helper_GOT_init(pReloc, false, *this);
    367       else
    368         helper_GOT_init(pReloc, true, *this);
    369       // set GOT bit
    370       rsym->setReserved(rsym->reserved() | ReserveGOT);
    371       return;
    372 
    373     case llvm::ELF::R_HEX_B22_PCREL:
    374     case llvm::ELF::R_HEX_B15_PCREL:
    375     case llvm::ELF::R_HEX_B7_PCREL:
    376     case llvm::ELF::R_HEX_B13_PCREL:
    377     case llvm::ELF::R_HEX_B9_PCREL:
    378     case llvm::ELF::R_HEX_B32_PCREL_X:
    379     case llvm::ELF::R_HEX_B22_PCREL_X:
    380     case llvm::ELF::R_HEX_B15_PCREL_X:
    381     case llvm::ELF::R_HEX_B13_PCREL_X:
    382     case llvm::ELF::R_HEX_B9_PCREL_X:
    383     case llvm::ELF::R_HEX_B7_PCREL_X:
    384     case llvm::ELF::R_HEX_32_PCREL:
    385     case llvm::ELF::R_HEX_6_PCREL_X:
    386     case llvm::ELF::R_HEX_PLT_B22_PCREL:
    387       if (rsym->reserved() & ReservePLT)
    388         return;
    389       if (ld_backend.symbolNeedsPLT(*rsym) ||
    390           pReloc.type() == llvm::ELF::R_HEX_PLT_B22_PCREL) {
    391         helper_PLT_init(pReloc, *this);
    392         rsym->setReserved(rsym->reserved() | ReservePLT);
    393       }
    394       return;
    395 
    396     default:
    397       break;
    398   }  // end of switch
    399 }
    400 
    401 /// defineSymbolforCopyReloc
    402 /// For a symbol needing copy relocation, define a copy symbol in the BSS
    403 /// section and all other reference to this symbol should refer to this
    404 /// copy.
    405 /// @note This is executed at `scan relocation' stage.
    406 LDSymbol& HexagonRelocator::defineSymbolforCopyReloc(
    407     IRBuilder& pBuilder,
    408     const ResolveInfo& pSym,
    409     HexagonLDBackend& pTarget) {
    410   // get or create corresponding BSS LDSection
    411   LDSection* bss_sect_hdr = NULL;
    412   ELFFileFormat* file_format = pTarget.getOutputFormat();
    413   if (ResolveInfo::ThreadLocal == pSym.type())
    414     bss_sect_hdr = &file_format->getTBSS();
    415   else
    416     bss_sect_hdr = &file_format->getBSS();
    417 
    418   // get or create corresponding BSS SectionData
    419   assert(bss_sect_hdr != NULL);
    420   SectionData* bss_section = NULL;
    421   if (bss_sect_hdr->hasSectionData())
    422     bss_section = bss_sect_hdr->getSectionData();
    423   else
    424     bss_section = IRBuilder::CreateSectionData(*bss_sect_hdr);
    425 
    426   // Determine the alignment by the symbol value
    427   // FIXME: here we use the largest alignment
    428   uint32_t addralign = config().targets().bitclass() / 8;
    429 
    430   // allocate space in BSS for the copy symbol
    431   Fragment* frag = new FillFragment(0x0, 1, pSym.size());
    432   uint64_t size = ObjectBuilder::AppendFragment(*frag, *bss_section, addralign);
    433   bss_sect_hdr->setSize(bss_sect_hdr->size() + size);
    434 
    435   // change symbol binding to Global if it's a weak symbol
    436   ResolveInfo::Binding binding = (ResolveInfo::Binding)pSym.binding();
    437   if (binding == ResolveInfo::Weak)
    438     binding = ResolveInfo::Global;
    439 
    440   // Define the copy symbol in the bss section and resolve it
    441   LDSymbol* cpy_sym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
    442       pSym.name(),
    443       (ResolveInfo::Type)pSym.type(),
    444       ResolveInfo::Define,
    445       binding,
    446       pSym.size(),  // size
    447       0x0,          // value
    448       FragmentRef::Create(*frag, 0x0),
    449       (ResolveInfo::Visibility)pSym.other());
    450 
    451   // output all other alias symbols if any
    452   Module& pModule = pBuilder.getModule();
    453   Module::AliasList* alias_list = pModule.getAliasList(pSym);
    454   if (alias_list != NULL) {
    455     Module::alias_iterator it, it_e = alias_list->end();
    456     for (it = alias_list->begin(); it != it_e; ++it) {
    457       const ResolveInfo* alias = *it;
    458       if (alias != &pSym && alias->isDyn()) {
    459         pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
    460             alias->name(),
    461             (ResolveInfo::Type)alias->type(),
    462             ResolveInfo::Define,
    463             binding,
    464             alias->size(),  // size
    465             0x0,            // value
    466             FragmentRef::Create(*frag, 0x0),
    467             (ResolveInfo::Visibility)alias->other());
    468       }
    469     }
    470   }
    471 
    472   return *cpy_sym;
    473 }
    474 
    475 void HexagonRelocator::partialScanRelocation(Relocation& pReloc,
    476                                              Module& pModule) {
    477   pReloc.updateAddend();
    478   // if we meet a section symbol
    479   if (pReloc.symInfo()->type() == ResolveInfo::Section) {
    480     LDSymbol* input_sym = pReloc.symInfo()->outSymbol();
    481 
    482     // 1. update the relocation target offset
    483     assert(input_sym->hasFragRef());
    484     // 2. get the output LDSection which the symbol defined in
    485     const LDSection& out_sect =
    486         input_sym->fragRef()->frag()->getParent()->getSection();
    487     ResolveInfo* sym_info =
    488         pModule.getSectionSymbolSet().get(out_sect)->resolveInfo();
    489     // set relocation target symbol to the output section symbol's resolveInfo
    490     pReloc.setSymInfo(sym_info);
    491   }
    492 }
    493 
    494 //=========================================//
    495 // Each relocation function implementation //
    496 //=========================================//
    497 
    498 // R_HEX_NONE
    499 Relocator::Result none(Relocation& pReloc, HexagonRelocator& pParent) {
    500   return Relocator::OK;
    501 }
    502 
    503 // R_HEX_32 and its class of relocations use only addend and symbol value
    504 // S + A : result is unsigned truncate.
    505 // Exception: R_HEX_32_6_X : unsigned verify
    506 Relocator::Result applyAbs(Relocation& pReloc) {
    507   Relocator::Address S = pReloc.symValue();
    508   Relocator::DWord A = pReloc.addend();
    509   uint32_t result = (uint32_t)(S + A);
    510   uint32_t bitMask = 0;
    511   uint32_t effectiveBits = 0;
    512   uint32_t alignment = 1;
    513   uint32_t shift = 0;
    514 
    515   switch (pReloc.type()) {
    516     case llvm::ELF::R_HEX_LO16:
    517       bitMask = 0x00c03fff;
    518       break;
    519 
    520     case llvm::ELF::R_HEX_HI16:
    521       shift = 16;
    522       bitMask = 0x00c03fff;
    523       break;
    524 
    525     case llvm::ELF::R_HEX_32:
    526       bitMask = 0xffffffff;
    527       break;
    528 
    529     case llvm::ELF::R_HEX_16:
    530       bitMask = 0x0000ffff;
    531       alignment = 2;
    532       break;
    533 
    534     case llvm::ELF::R_HEX_8:
    535       bitMask = 0x000000ff;
    536       alignment = 1;
    537       break;
    538 
    539     case llvm::ELF::R_HEX_12_X:
    540       bitMask = 0x000007e0;
    541       break;
    542 
    543     case llvm::ELF::R_HEX_32_6_X:
    544       bitMask = 0xfff3fff;
    545       shift = 6;
    546       effectiveBits = 26;
    547       break;
    548 
    549     case llvm::ELF::R_HEX_16_X:
    550     case llvm::ELF::R_HEX_11_X:
    551     case llvm::ELF::R_HEX_10_X:
    552     case llvm::ELF::R_HEX_9_X:
    553     case llvm::ELF::R_HEX_8_X:
    554     case llvm::ELF::R_HEX_7_X:
    555     case llvm::ELF::R_HEX_6_X:
    556       bitMask = FINDBITMASK(pReloc.target());
    557       break;
    558 
    559     default:
    560       // show proper error
    561       fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type())
    562                                           << "mclinker (at) googlegroups.com";
    563   }
    564 
    565   if ((shift != 0) && (result % alignment != 0))
    566     return Relocator::BadReloc;
    567 
    568   result >>= shift;
    569 
    570   if (effectiveBits) {
    571     uint32_t range = 1 << effectiveBits;
    572     if (result > (range - 1))
    573       return Relocator::Overflow;
    574   }
    575 
    576   pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
    577   return Relocator::OK;
    578 }
    579 
    580 // R_HEX_B22_PCREL and its class of relocations, use
    581 // S + A - P : result is signed verify.
    582 // Exception: R_HEX_B32_PCREL_X : signed truncate
    583 // Another Exception: R_HEX_6_PCREL_X is unsigned truncate
    584 Relocator::Result applyRel(Relocation& pReloc, int64_t pResult) {
    585   uint32_t bitMask = 0;
    586   uint32_t effectiveBits = 0;
    587   uint32_t alignment = 1;
    588   uint32_t result;
    589   uint32_t shift = 0;
    590 
    591   switch (pReloc.type()) {
    592     case llvm::ELF::R_HEX_B22_PCREL:
    593       bitMask = 0x01ff3ffe;
    594       effectiveBits = 22;
    595       alignment = 4;
    596       shift = 2;
    597       break;
    598 
    599     case llvm::ELF::R_HEX_B15_PCREL:
    600       bitMask = 0x00df20fe;
    601       effectiveBits = 15;
    602       alignment = 4;
    603       shift = 2;
    604       break;
    605 
    606     case llvm::ELF::R_HEX_B7_PCREL:
    607       bitMask = 0x00001f18;
    608       effectiveBits = 7;
    609       alignment = 4;
    610       shift = 2;
    611       break;
    612 
    613     case llvm::ELF::R_HEX_B13_PCREL:
    614       bitMask = 0x00202ffe;
    615       effectiveBits = 13;
    616       alignment = 4;
    617       shift = 2;
    618       break;
    619 
    620     case llvm::ELF::R_HEX_B9_PCREL:
    621       bitMask = 0x003000fe;
    622       effectiveBits = 9;
    623       alignment = 4;
    624       shift = 2;
    625       break;
    626 
    627     case llvm::ELF::R_HEX_B32_PCREL_X:
    628       bitMask = 0xfff3fff;
    629       shift = 6;
    630       break;
    631 
    632     case llvm::ELF::R_HEX_B22_PCREL_X:
    633       bitMask = 0x01ff3ffe;
    634       effectiveBits = 22;
    635       pResult &= 0x3f;
    636       break;
    637 
    638     case llvm::ELF::R_HEX_B15_PCREL_X:
    639       bitMask = 0x00df20fe;
    640       effectiveBits = 15;
    641       pResult &= 0x3f;
    642       break;
    643 
    644     case llvm::ELF::R_HEX_B13_PCREL_X:
    645       bitMask = 0x00202ffe;
    646       effectiveBits = 13;
    647       pResult &= 0x3f;
    648       break;
    649 
    650     case llvm::ELF::R_HEX_B9_PCREL_X:
    651       bitMask = 0x003000fe;
    652       effectiveBits = 9;
    653       pResult &= 0x3f;
    654       break;
    655 
    656     case llvm::ELF::R_HEX_B7_PCREL_X:
    657       bitMask = 0x00001f18;
    658       effectiveBits = 7;
    659       pResult &= 0x3f;
    660       break;
    661 
    662     case llvm::ELF::R_HEX_32_PCREL:
    663       bitMask = 0xffffffff;
    664       effectiveBits = 32;
    665       break;
    666 
    667     case llvm::ELF::R_HEX_6_PCREL_X:
    668       // This is unique since it has a unsigned operand and its truncated
    669       bitMask = FINDBITMASK(pReloc.target());
    670       result = pReloc.addend() + pReloc.symValue() - pReloc.place();
    671       pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
    672       return Relocator::OK;
    673 
    674     default:
    675       // show proper error
    676       fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type())
    677                                           << "mclinker (at) googlegroups.com";
    678   }
    679 
    680   if ((shift != 0) && (pResult % alignment != 0))
    681     return Relocator::BadReloc;
    682 
    683   pResult >>= shift;
    684 
    685   if (effectiveBits) {
    686     int64_t range = 1LL << (effectiveBits - 1);
    687     if ((pResult > (range - 1)) || (pResult < -range))
    688       return Relocator::Overflow;
    689   }
    690 
    691   pReloc.target() |= (uint32_t)ApplyMask<int32_t>(bitMask, pResult);
    692   return Relocator::OK;
    693 }
    694 
    695 Relocator::Result relocAbs(Relocation& pReloc, HexagonRelocator& pParent) {
    696   ResolveInfo* rsym = pReloc.symInfo();
    697   Relocator::Address S = pReloc.symValue();
    698   Relocator::DWord A = pReloc.addend();
    699 
    700   Relocation* rel_entry = pParent.getRelRelMap().lookUp(pReloc);
    701   bool has_dyn_rel = (rel_entry != NULL);
    702 
    703   // if the flag of target section is not ALLOC, we eprform only static
    704   // relocation.
    705   if (0 == (llvm::ELF::SHF_ALLOC &
    706             pReloc.targetRef().frag()->getParent()->getSection().flag())) {
    707     return applyAbs(pReloc);
    708   }
    709 
    710   // a local symbol with .rela type relocation
    711   if (rsym->isLocal() && has_dyn_rel) {
    712     rel_entry->setAddend(S + A);
    713     return Relocator::OK;
    714   }
    715 
    716   if (!rsym->isLocal()) {
    717     if (rsym->reserved() & HexagonRelocator::ReservePLT) {
    718       S = helper_get_PLT_address(*rsym, pParent);
    719     }
    720 
    721     if (has_dyn_rel) {
    722       if (llvm::ELF::R_HEX_32 == pReloc.type() &&
    723           helper_use_relative_reloc(*rsym, pParent)) {
    724         rel_entry->setAddend(S + A);
    725       } else {
    726         rel_entry->setAddend(A);
    727         return Relocator::OK;
    728       }
    729     }
    730   }
    731 
    732   return applyAbs(pReloc);
    733 }
    734 
    735 Relocator::Result relocPCREL(Relocation& pReloc, HexagonRelocator& pParent) {
    736   ResolveInfo* rsym = pReloc.symInfo();
    737   int64_t result;
    738 
    739   Relocator::Address S = pReloc.symValue();
    740   Relocator::DWord A = pReloc.addend();
    741   Relocator::DWord P = pReloc.place();
    742 
    743   FragmentRef& target_fragref = pReloc.targetRef();
    744   Fragment* target_frag = target_fragref.frag();
    745   LDSection& target_sect = target_frag->getParent()->getSection();
    746 
    747   result = (int64_t)(S + A - P);
    748 
    749   // for relocs inside non ALLOC, just apply
    750   if ((llvm::ELF::SHF_ALLOC & target_sect.flag()) == 0) {
    751     return applyRel(pReloc, result);
    752   }
    753 
    754   if (!rsym->isLocal()) {
    755     if (rsym->reserved() & HexagonRelocator::ReservePLT) {
    756       S = helper_get_PLT_address(*rsym, pParent);
    757       result = (int64_t)(S + A - P);
    758       applyRel(pReloc, result);
    759       return Relocator::OK;
    760     }
    761   }
    762 
    763   return applyRel(pReloc, result);
    764 }
    765 
    766 // R_HEX_GPREL16_0 and its class : Unsigned Verify
    767 Relocator::Result relocGPREL(Relocation& pReloc, HexagonRelocator& pParent) {
    768   Relocator::Address S = pReloc.symValue();
    769   Relocator::DWord A = pReloc.addend();
    770   Relocator::DWord GP = pParent.getTarget().getGP();
    771 
    772   uint32_t result = (uint32_t)(S + A - GP);
    773   uint32_t shift = 0;
    774   uint32_t alignment = 1;
    775 
    776   switch (pReloc.type()) {
    777     case llvm::ELF::R_HEX_GPREL16_0:
    778       break;
    779 
    780     case llvm::ELF::R_HEX_GPREL16_1:
    781       shift = 1;
    782       alignment = 2;
    783       break;
    784 
    785     case llvm::ELF::R_HEX_GPREL16_2:
    786       shift = 2;
    787       alignment = 4;
    788       break;
    789 
    790     case llvm::ELF::R_HEX_GPREL16_3:
    791       shift = 3;
    792       alignment = 8;
    793       break;
    794 
    795     default:
    796       // show proper error
    797       fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type())
    798                                           << "mclinker (at) googlegroups.com";
    799   }
    800 
    801   uint32_t range = 1 << 16;
    802   uint32_t bitMask = FINDBITMASK(pReloc.target());
    803 
    804   if ((shift != 0) && (result % alignment != 0))
    805     return Relocator::BadReloc;
    806 
    807   result >>= shift;
    808 
    809   if (result < range - 1) {
    810     pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
    811     return Relocator::OK;
    812   }
    813   return Relocator::Overflow;
    814 }
    815 
    816 // R_HEX_PLT_B22_PCREL: PLT(S) + A - P
    817 Relocator::Result relocPLTB22PCREL(Relocation& pReloc,
    818                                    HexagonRelocator& pParent) {
    819   // PLT_S depends on if there is a PLT entry.
    820   Relocator::Address PLT_S;
    821   if ((pReloc.symInfo()->reserved() & HexagonRelocator::ReservePLT))
    822     PLT_S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
    823   else
    824     PLT_S = pReloc.symValue();
    825   Relocator::Address P = pReloc.place();
    826   uint32_t bitMask = FINDBITMASK(pReloc.target());
    827   uint32_t result = (PLT_S + pReloc.addend() - P) >> 2;
    828   pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(bitMask, result);
    829   return Relocator::OK;
    830 }
    831 
    832 // R_HEX_GOT_LO16 and its class : (G) Signed Truncate
    833 // Exception: R_HEX_GOT_16(_X): signed verify
    834 // Exception: R_HEX_GOT_11_X : unsigned truncate
    835 Relocator::Result relocGOT(Relocation& pReloc, HexagonRelocator& pParent) {
    836   if (!(pReloc.symInfo()->reserved() & HexagonRelocator::ReserveGOT)) {
    837     return Relocator::BadReloc;
    838   }
    839 
    840   // set got entry value if needed
    841   HexagonGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
    842   assert(got_entry != NULL);
    843   if (HexagonRelocator::SymVal == got_entry->getValue())
    844     got_entry->setValue(pReloc.symValue());
    845 
    846   Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent);
    847   Relocator::Address GOT = pParent.getTarget().getGOTSymbolAddr();
    848   int32_t result = (int32_t)(GOT_S - GOT);
    849   uint32_t effectiveBits = 0;
    850   uint32_t alignment = 1;
    851   uint32_t bitMask = 0;
    852   uint32_t result_u;
    853   uint32_t shift = 0;
    854 
    855   switch (pReloc.type()) {
    856     case llvm::ELF::R_HEX_GOT_LO16:
    857       bitMask = 0x00c03fff;
    858       break;
    859 
    860     case llvm::ELF::R_HEX_GOT_HI16:
    861       bitMask = 0x00c03fff;
    862       shift = 16;
    863       alignment = 4;
    864       break;
    865 
    866     case llvm::ELF::R_HEX_GOT_32:
    867       bitMask = 0xffffffff;
    868       break;
    869 
    870     case llvm::ELF::R_HEX_GOT_16:
    871       bitMask = FINDBITMASK(pReloc.target());
    872       effectiveBits = 16;
    873       break;
    874 
    875     case llvm::ELF::R_HEX_GOT_32_6_X:
    876       bitMask = 0xfff3fff;
    877       shift = 6;
    878       break;
    879 
    880     case llvm::ELF::R_HEX_GOT_16_X:
    881       bitMask = FINDBITMASK(pReloc.target());
    882       effectiveBits = 6;
    883       break;
    884 
    885     case llvm::ELF::R_HEX_GOT_11_X:
    886       bitMask = FINDBITMASK(pReloc.target());
    887       result_u = GOT_S - GOT;
    888       pReloc.target() |= ApplyMask<uint32_t>(bitMask, result_u);
    889       return Relocator::OK;
    890 
    891     default:
    892       // show proper error
    893       fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type())
    894                                           << "mclinker (at) googlegroups.com";
    895   }
    896 
    897   if ((shift != 0) && (result % alignment != 0))
    898     return Relocator::BadReloc;
    899 
    900   result >>= shift;
    901 
    902   if (effectiveBits) {
    903     int32_t range = 1 << (effectiveBits - 1);
    904     if ((result > range - 1) || (result < -range))
    905       return Relocator::Overflow;
    906   }
    907   pReloc.target() |= ApplyMask<int32_t>(bitMask, result);
    908   return Relocator::OK;
    909 }
    910 
    911 // R_HEX_GOTREL_LO16: and its class of relocs
    912 // (S + A - GOT) : Signed Truncate
    913 Relocator::Result relocGOTREL(Relocation& pReloc, HexagonRelocator& pParent) {
    914   Relocator::Address S = pReloc.symValue();
    915   Relocator::DWord A = pReloc.addend();
    916   Relocator::Address GOT = pParent.getTarget().getGOTSymbolAddr();
    917 
    918   uint32_t bitMask = 0;
    919   uint32_t alignment = 1;
    920   uint32_t shift = 0;
    921 
    922   uint32_t result = (uint32_t)(S + A - GOT);
    923 
    924   switch (pReloc.type()) {
    925     case llvm::ELF::R_HEX_GOTREL_LO16:
    926       bitMask = 0x00c03fff;
    927       break;
    928 
    929     case llvm::ELF::R_HEX_GOTREL_HI16:
    930       bitMask = 0x00c03fff;
    931       shift = 16;
    932       alignment = 4;
    933       break;
    934 
    935     case llvm::ELF::R_HEX_GOTREL_32:
    936       bitMask = 0xffffffff;
    937       break;
    938 
    939     case llvm::ELF::R_HEX_GOTREL_32_6_X:
    940       bitMask = 0x0fff3fff;
    941       shift = 6;
    942       break;
    943 
    944     case llvm::ELF::R_HEX_GOTREL_16_X:
    945     case llvm::ELF::R_HEX_GOTREL_11_X:
    946       bitMask = FINDBITMASK(pReloc.target());
    947       break;
    948 
    949     default:
    950       // show proper error
    951       fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type())
    952                                           << "mclinker (at) googlegroups.com";
    953   }
    954 
    955   if (result % alignment != 0)
    956     return Relocator::BadReloc;
    957 
    958   result >>= shift;
    959 
    960   pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
    961   return Relocator::OK;
    962 }
    963 
    964 Relocator::Result unsupported(Relocation& pReloc, HexagonRelocator& pParent) {
    965   return Relocator::Unsupported;
    966 }
    967 
    968 }  // namespace mcld
    969