HexagonRelocator.cpp revision 551ae4ebd3e9d137ea668fb83ae4a55b8cfba451
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                                      Relocator::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 Relocator::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 Relocator::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
128typedef 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
483Relocator::Result none(Relocation &pReloc, HexagonRelocator &pParent) {
484  return Relocator::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
490Relocator::Result applyAbs(Relocation &pReloc) {
491  Relocator::Address S = pReloc.symValue();
492  Relocator::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 Relocator::BadReloc;
552
553  result >>= shift;
554
555  if (effectiveBits) {
556    uint32_t range = 1 << effectiveBits;
557    if (result > (range - 1))
558      return Relocator::Overflow;
559  }
560
561  pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
562  return Relocator::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
569Relocator::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 Relocator::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 Relocator::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 Relocator::Overflow;
674  }
675
676  pReloc.target() |= (uint32_t) ApplyMask<int32_t>(bitMask, pResult);
677  return Relocator::OK;
678}
679
680Relocator::Result relocAbs(Relocation &pReloc, HexagonRelocator &pParent) {
681  ResolveInfo *rsym = pReloc.symInfo();
682  Relocator::Address S = pReloc.symValue();
683  Relocator::DWord A = pReloc.addend();
684
685  Relocation* rel_entry = pParent.getRelRelMap().lookUp(pReloc);
686  bool has_dyn_rel = (NULL != rel_entry);
687
688  // if the flag of target section is not ALLOC, we eprform only static
689  // relocation.
690  if (0 == (llvm::ELF::SHF_ALLOC &
691            pReloc.targetRef().frag()->getParent()->getSection().flag())) {
692    return applyAbs(pReloc);
693  }
694
695  // a local symbol with .rela type relocation
696  if (rsym->isLocal() && has_dyn_rel) {
697    rel_entry->setAddend(S + A);
698    return Relocator::OK;
699  }
700
701  if (!rsym->isLocal()) {
702    if (rsym->reserved() & HexagonRelocator::ReservePLT) {
703      S = helper_get_PLT_address(*rsym, pParent);
704    }
705
706    if (has_dyn_rel) {
707      if (llvm::ELF::R_HEX_32 == pReloc.type() &&
708          helper_use_relative_reloc(*rsym, pParent)) {
709        rel_entry->setAddend(S + A);
710      } else {
711        rel_entry->setAddend(A);
712        return Relocator::OK;
713      }
714    }
715  }
716
717  return applyAbs(pReloc);
718}
719
720Relocator::Result relocPCREL(Relocation &pReloc, HexagonRelocator &pParent) {
721  ResolveInfo *rsym = pReloc.symInfo();
722  int64_t result;
723
724  Relocator::Address S = pReloc.symValue();
725  Relocator::DWord A = pReloc.addend();
726  Relocator::DWord P = pReloc.place();
727
728  FragmentRef &target_fragref = pReloc.targetRef();
729  Fragment *target_frag = target_fragref.frag();
730  LDSection &target_sect = target_frag->getParent()->getSection();
731
732  result = (int64_t)(S + A - P);
733
734  // for relocs inside non ALLOC, just apply
735  if (0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
736    return applyRel(pReloc, result);
737  }
738
739  if (!rsym->isLocal()) {
740    if (rsym->reserved() & HexagonRelocator::ReservePLT) {
741      S = helper_get_PLT_address(*rsym, pParent);
742      result = (int64_t)(S + A - P);
743      applyRel(pReloc, result);
744      return Relocator::OK;
745    }
746  }
747
748  return applyRel(pReloc, result);
749}
750
751// R_HEX_GPREL16_0 and its class : Unsigned Verify
752Relocator::Result relocGPREL(Relocation &pReloc, HexagonRelocator &pParent) {
753  Relocator::Address S = pReloc.symValue();
754  Relocator::DWord A = pReloc.addend();
755  Relocator::DWord GP = pParent.getTarget().getGP();
756
757  uint32_t result = (uint32_t)(S + A - GP);
758  uint32_t shift = 0;
759  uint32_t alignment = 1;
760
761  switch (pReloc.type()) {
762  case llvm::ELF::R_HEX_GPREL16_0:
763    break;
764
765  case llvm::ELF::R_HEX_GPREL16_1:
766    shift = 1;
767    alignment = 2;
768    break;
769
770  case llvm::ELF::R_HEX_GPREL16_2:
771    shift = 2;
772    alignment = 4;
773    break;
774
775  case llvm::ELF::R_HEX_GPREL16_3:
776    shift = 3;
777    alignment = 8;
778    break;
779
780  default:
781    // show proper error
782    fatal(diag::unsupported_relocation) << (int)
783        pReloc.type() << "mclinker@googlegroups.com";
784  }
785
786  uint32_t range = 1 << 16;
787  uint32_t bitMask = FINDBITMASK(pReloc.target());
788
789  if ((shift != 0) && (result % alignment != 0))
790    return Relocator::BadReloc;
791
792  result >>= shift;
793
794  if (result < range - 1) {
795    pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
796    return Relocator::OK;
797  }
798  return Relocator::Overflow;
799}
800
801// R_HEX_PLT_B22_PCREL: PLT(S) + A - P
802Relocator::Result relocPLTB22PCREL(Relocation &pReloc,
803                                   HexagonRelocator &pParent) {
804  // PLT_S depends on if there is a PLT entry.
805  Relocator::Address PLT_S;
806  if ((pReloc.symInfo()->reserved() & HexagonRelocator::ReservePLT))
807    PLT_S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
808  else
809    PLT_S = pReloc.symValue();
810  Relocator::Address P = pReloc.place();
811  uint32_t bitMask = FINDBITMASK(pReloc.target());
812  uint32_t result = (PLT_S + pReloc.addend() - P) >> 2;
813  pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(bitMask, result);
814  return Relocator::OK;
815}
816
817//R_HEX_GOT_LO16 and its class : (G) Signed Truncate
818//Exception: R_HEX_GOT_16(_X): signed verify
819// Exception: R_HEX_GOT_11_X : unsigned truncate
820Relocator::Result relocGOT(Relocation &pReloc, HexagonRelocator &pParent) {
821  if (!(pReloc.symInfo()->reserved() & HexagonRelocator::ReserveGOT)) {
822    return Relocator::BadReloc;
823  }
824
825  // set got entry value if needed
826  HexagonGOTEntry *got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
827  assert(NULL != got_entry);
828  if (HexagonRelocator::SymVal == got_entry->getValue())
829    got_entry->setValue(pReloc.symValue());
830
831  Relocator::Address GOT_S =
832                             helper_get_GOT_address(*pReloc.symInfo(), pParent);
833  Relocator::Address GOT = pParent.getTarget().getGOTSymbolAddr();
834  int32_t result = (int32_t)(GOT_S - GOT);
835  uint32_t effectiveBits = 0;
836  uint32_t alignment = 1;
837  uint32_t bitMask = 0;
838  uint32_t result_u;
839  uint32_t shift = 0;
840
841  switch (pReloc.type()) {
842  case llvm::ELF::R_HEX_GOT_LO16:
843    bitMask = 0x00c03fff;
844    break;
845
846  case llvm::ELF::R_HEX_GOT_HI16:
847    bitMask = 0x00c03fff;
848    shift = 16;
849    alignment = 4;
850    break;
851
852  case llvm::ELF::R_HEX_GOT_32:
853    bitMask = 0xffffffff;
854    break;
855
856  case llvm::ELF::R_HEX_GOT_16:
857    bitMask = FINDBITMASK(pReloc.target());
858    effectiveBits = 16;
859    break;
860
861  case llvm::ELF::R_HEX_GOT_32_6_X:
862    bitMask = 0xfff3fff;
863    shift = 6;
864    break;
865
866  case llvm::ELF::R_HEX_GOT_16_X:
867    bitMask = FINDBITMASK(pReloc.target());
868    effectiveBits = 6;
869    break;
870
871  case llvm::ELF::R_HEX_GOT_11_X:
872    bitMask = FINDBITMASK(pReloc.target());
873    result_u = GOT_S - GOT;
874    pReloc.target() |= ApplyMask<uint32_t>(bitMask, result_u);
875    return Relocator::OK;
876
877  default:
878    // show proper error
879    fatal(diag::unsupported_relocation) << (int)
880        pReloc.type() << "mclinker@googlegroups.com";
881  }
882
883  if ((shift != 0) && (result % alignment != 0))
884    return Relocator::BadReloc;
885
886  result >>= shift;
887
888  if (effectiveBits) {
889    int32_t range = 1 << (effectiveBits - 1);
890    if ((result > range - 1) || (result < -range))
891      return Relocator::Overflow;
892  }
893  pReloc.target() |= ApplyMask<int32_t>(bitMask, result);
894  return Relocator::OK;
895}
896
897// R_HEX_GOTREL_LO16: and its class of relocs
898// (S + A - GOT) : Signed Truncate
899Relocator::Result relocGOTREL(Relocation &pReloc, HexagonRelocator &pParent) {
900  Relocator::Address S = pReloc.symValue();
901  Relocator::DWord A = pReloc.addend();
902  Relocator::Address GOT = pParent.getTarget().getGOTSymbolAddr();
903
904  uint32_t bitMask = 0;
905  uint32_t alignment = 1;
906  uint32_t shift = 0;
907
908  uint32_t result = (uint32_t)(S + A - GOT);
909
910  switch (pReloc.type()) {
911  case llvm::ELF::R_HEX_GOTREL_LO16:
912    bitMask = 0x00c03fff;
913    break;
914
915  case llvm::ELF::R_HEX_GOTREL_HI16:
916    bitMask = 0x00c03fff;
917    shift = 16;
918    alignment = 4;
919    break;
920
921  case llvm::ELF::R_HEX_GOTREL_32:
922    bitMask = 0xffffffff;
923    break;
924
925  case llvm::ELF::R_HEX_GOTREL_32_6_X:
926    bitMask = 0x0fff3fff;
927    shift = 6;
928    break;
929
930  case llvm::ELF::R_HEX_GOTREL_16_X:
931  case llvm::ELF::R_HEX_GOTREL_11_X:
932    bitMask = FINDBITMASK(pReloc.target());
933    break;
934
935  default:
936    // show proper error
937    fatal(diag::unsupported_relocation) << (int)
938        pReloc.type() << "mclinker@googlegroups.com";
939  }
940
941  if (result % alignment != 0)
942    return Relocator::BadReloc;
943
944  result >>= shift;
945
946  pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
947  return Relocator::OK;
948}
949
950Relocator::Result unsupport(Relocation &pReloc, HexagonRelocator &pParent) {
951  return Relocator::Unsupport;
952}
953