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