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