MipsRelocator.cpp revision 41f2d34f9d4efad1928e890acc5c2924b5033909
1//===- MipsRelocator.cpp  -----------------------------------------===//
2//
3//                     The MCLinker Project
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include "MipsRelocator.h"
10#include "MipsRelocationFunctions.h"
11
12#include <mcld/IRBuilder.h>
13#include <mcld/LinkerConfig.h>
14#include <mcld/Object/ObjectBuilder.h>
15#include <mcld/Support/MsgHandling.h>
16#include <mcld/Target/OutputRelocSection.h>
17#include <mcld/LD/ELFFileFormat.h>
18
19#include <llvm/ADT/Twine.h>
20#include <llvm/Support/ELF.h>
21
22namespace llvm {
23namespace ELF {
24
25// FIXME: Consider upstream these relocation types to LLVM.
26enum {
27  R_MIPS_LA25_LUI = 200,
28  R_MIPS_LA25_J   = 201,
29  R_MIPS_LA25_ADD = 202,
30};
31
32} // end namespace ELF
33} // end namespace llvm
34
35using namespace mcld;
36
37//===----------------------------------------------------------------------===//
38// MipsRelocationInfo
39//===----------------------------------------------------------------------===//
40class mcld::MipsRelocationInfo
41{
42public:
43  static bool HasSubType(const Relocation& pParent, Relocation::Type pType)
44  {
45    if (llvm::ELF::R_MIPS_NONE == pType)
46      return true;
47
48    for (Relocation::Type type = pParent.type();
49         llvm::ELF::R_MIPS_NONE != (type & 0xff); type >>= 8) {
50      if ((type & 0xff) == pType)
51        return true;
52    }
53
54    return false;
55  }
56
57  MipsRelocationInfo(Relocation& pParent, bool pIsRel)
58    : m_Parent(&pParent),
59      m_Type(pParent.type()),
60      m_Addend(0),
61      m_Symbol(pParent.symValue()),
62      m_Result(pParent.target())
63  {
64    if (pIsRel && (type() < llvm::ELF::R_MIPS_LA25_LUI ||
65                   type() > llvm::ELF::R_MIPS_LA25_ADD))
66      m_Addend = pParent.target();
67    else
68      m_Addend = pParent.addend();
69  }
70
71  bool isNone() const
72  {
73    return llvm::ELF::R_MIPS_NONE == type();
74  }
75
76  bool isLast() const
77  {
78    return llvm::ELF::R_MIPS_NONE == (m_Type >> 8);
79  }
80
81  MipsRelocationInfo next() const
82  {
83    return MipsRelocationInfo(*m_Parent, m_Type >> 8, result(), result(), 0);
84  }
85
86  const Relocation& parent() const
87  {
88    return *m_Parent;
89  }
90
91  Relocation& parent()
92  {
93    return *m_Parent;
94  }
95
96  Relocation::Type type() const
97  {
98    return m_Type & 0xff;
99  }
100
101  Relocation::DWord A() const
102  {
103    return m_Addend;
104  }
105
106  Relocation::DWord S() const
107  {
108    return m_Symbol;
109  }
110
111  Relocation::DWord P() const
112  {
113    return parent().place();
114  }
115
116  Relocation::DWord result() const
117  {
118    return m_Result;
119  }
120
121  Relocation::DWord& result()
122  {
123    return m_Result;
124  }
125
126private:
127  Relocation* m_Parent;
128  Relocation::Type m_Type;
129  Relocation::DWord m_Addend;
130  Relocation::DWord m_Symbol;
131  Relocation::DWord m_Result;
132
133  MipsRelocationInfo(Relocation& pParent, Relocation::Type pType,
134                     Relocation::DWord pResult,
135                     Relocation::DWord pAddend, Relocation::DWord pSymbol)
136    : m_Parent(&pParent),
137      m_Type(pType),
138      m_Addend(pAddend),
139      m_Symbol(pSymbol),
140      m_Result(pResult)
141  {}
142
143  bool isFirst() const {
144    return m_Type == parent().type();
145  }
146};
147
148//===----------------------------------------------------------------------===//
149// Relocation Functions and Tables
150//===----------------------------------------------------------------------===//
151DECL_MIPS_APPLY_RELOC_FUNCS
152
153/// the prototype of applying function
154typedef Relocator::Result (*ApplyFunctionType)(MipsRelocationInfo&,
155                                               MipsRelocator& pParent);
156
157
158// the table entry of applying functions
159struct ApplyFunctionTriple
160{
161  ApplyFunctionType func;
162  unsigned int type;
163  const char* name;
164  unsigned int size;
165};
166
167// declare the table of applying functions
168static const ApplyFunctionTriple ApplyFunctions[] = {
169  DECL_MIPS_APPLY_RELOC_FUNC_PTRS
170};
171
172//===----------------------------------------------------------------------===//
173// MipsRelocator
174//===----------------------------------------------------------------------===//
175MipsRelocator::MipsRelocator(MipsGNULDBackend& pParent,
176                             const LinkerConfig& pConfig)
177  : Relocator(pConfig),
178    m_Target(pParent),
179    m_pApplyingInput(NULL),
180    m_CurrentLo16Reloc(NULL)
181{
182}
183
184Relocator::Result
185MipsRelocator::applyRelocation(Relocation& pReloc)
186{
187  // If m_CurrentLo16Reloc is not NULL we are processing
188  // postponed relocation. Otherwise check relocation type
189  // and postpone it for later handling.
190  if (NULL == m_CurrentLo16Reloc && isPostponed(pReloc)) {
191    postponeRelocation(pReloc);
192    return OK;
193  }
194
195  for (MipsRelocationInfo info(pReloc, isRel());
196       !info.isNone(); info = info.next()) {
197    if (info.type() >= sizeof(ApplyFunctions) / sizeof(ApplyFunctions[0]))
198      return Unknown;
199
200    const ApplyFunctionTriple & triple = ApplyFunctions[info.type()];
201
202    Result res = triple.func(info, *this);
203    if (OK != res)
204      return res;
205
206    if (info.isLast()) {
207      uint64_t mask = 0xFFFFFFFFFFFFFFFFULL >> (64 - triple.size);
208      pReloc.target() &= ~mask;
209      pReloc.target() |= info.result() & mask;
210    }
211  }
212
213  return OK;
214}
215
216const char* MipsRelocator::getName(Relocation::Type pType) const
217{
218  return ApplyFunctions[pType & 0xff].name;
219}
220
221Relocator::Size MipsRelocator::getSize(Relocation::Type pType) const
222{
223  return ApplyFunctions[pType & 0xff].size;
224}
225
226void MipsRelocator::scanRelocation(Relocation& pReloc,
227                                   IRBuilder& pBuilder,
228                                   Module& pModule,
229                                   LDSection& pSection,
230                                   Input& pInput)
231{
232  // rsym - The relocation target symbol
233  ResolveInfo* rsym = pReloc.symInfo();
234  assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
235
236  // Skip relocation against _gp_disp
237  if (NULL != getTarget().getGpDispSymbol() &&
238      rsym == getTarget().getGpDispSymbol()->resolveInfo())
239    return;
240
241  assert(NULL != pSection.getLink());
242  if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC))
243    return;
244
245  for (MipsRelocationInfo info(pReloc, isRel());
246       !info.isNone(); info = info.next()) {
247    // We test isLocal or if pInputSym is not a dynamic symbol
248    // We assume -Bsymbolic to bind all symbols internaly via !rsym->isDyn()
249    // Don't put undef symbols into local entries.
250    if (isLocalReloc(*rsym))
251      scanLocalReloc(info, pBuilder, pSection);
252    else
253      scanGlobalReloc(info, pBuilder, pSection);
254
255    if (getTarget().needsLA25Stub(info.type(), info.parent().symInfo()))
256      getTarget().addNonPICBranchSym(pReloc.symInfo());
257  }
258
259  // Check if we should issue undefined reference
260  // for the relocation target symbol.
261  if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
262    issueUndefRef(pReloc, pSection, pInput);
263}
264
265bool MipsRelocator::initializeScan(Input& pInput)
266{
267  if (LinkerConfig::Object != config().codeGenType())
268    getTarget().getGOT().initializeScan(pInput);
269  return true;
270}
271
272bool MipsRelocator::finalizeScan(Input& pInput)
273{
274  if (LinkerConfig::Object != config().codeGenType())
275    getTarget().getGOT().finalizeScan(pInput);
276  return true;
277}
278
279bool MipsRelocator::initializeApply(Input& pInput)
280{
281  m_pApplyingInput = &pInput;
282  return true;
283}
284
285bool MipsRelocator::finalizeApply(Input& pInput)
286{
287  m_pApplyingInput = NULL;
288  return true;
289}
290
291void MipsRelocator::scanLocalReloc(MipsRelocationInfo& pReloc,
292                                   IRBuilder& pBuilder,
293                                   const LDSection& pSection)
294{
295  ResolveInfo* rsym = pReloc.parent().symInfo();
296
297  switch (pReloc.type()){
298    case llvm::ELF::R_MIPS_NONE:
299    case llvm::ELF::R_MIPS_16:
300      break;
301    case llvm::ELF::R_MIPS_32:
302    case llvm::ELF::R_MIPS_64:
303      if (LinkerConfig::DynObj == config().codeGenType()) {
304        // TODO: (simon) The gold linker does not create an entry in .rel.dyn
305        // section if the symbol section flags contains SHF_EXECINSTR.
306        // 1. Find the reason of this condition.
307        // 2. Check this condition here.
308        getTarget().getRelDyn().reserveEntry();
309        rsym->setReserved(rsym->reserved() | ReserveRel);
310        getTarget().checkAndSetHasTextRel(*pSection.getLink());
311      }
312      break;
313    case llvm::ELF::R_MIPS_REL32:
314    case llvm::ELF::R_MIPS_26:
315    case llvm::ELF::R_MIPS_HI16:
316    case llvm::ELF::R_MIPS_LO16:
317    case llvm::ELF::R_MIPS_PC16:
318    case llvm::ELF::R_MIPS_SHIFT5:
319    case llvm::ELF::R_MIPS_SHIFT6:
320    case llvm::ELF::R_MIPS_SUB:
321    case llvm::ELF::R_MIPS_INSERT_A:
322    case llvm::ELF::R_MIPS_INSERT_B:
323    case llvm::ELF::R_MIPS_DELETE:
324    case llvm::ELF::R_MIPS_HIGHER:
325    case llvm::ELF::R_MIPS_HIGHEST:
326    case llvm::ELF::R_MIPS_SCN_DISP:
327    case llvm::ELF::R_MIPS_REL16:
328    case llvm::ELF::R_MIPS_ADD_IMMEDIATE:
329    case llvm::ELF::R_MIPS_PJUMP:
330    case llvm::ELF::R_MIPS_RELGOT:
331    case llvm::ELF::R_MIPS_JALR:
332    case llvm::ELF::R_MIPS_GLOB_DAT:
333    case llvm::ELF::R_MIPS_COPY:
334    case llvm::ELF::R_MIPS_JUMP_SLOT:
335      break;
336    case llvm::ELF::R_MIPS_GOT16:
337    case llvm::ELF::R_MIPS_CALL16:
338    case llvm::ELF::R_MIPS_GOT_HI16:
339    case llvm::ELF::R_MIPS_CALL_HI16:
340    case llvm::ELF::R_MIPS_GOT_LO16:
341    case llvm::ELF::R_MIPS_CALL_LO16:
342    case llvm::ELF::R_MIPS_GOT_DISP:
343    case llvm::ELF::R_MIPS_GOT_PAGE:
344    case llvm::ELF::R_MIPS_GOT_OFST:
345      if (getTarget().getGOT().reserveLocalEntry(*rsym,
346                                                 pReloc.type(), pReloc.A())) {
347        if (getTarget().getGOT().hasMultipleGOT())
348          getTarget().checkAndSetHasTextRel(*pSection.getLink());
349      }
350      break;
351    case llvm::ELF::R_MIPS_GPREL32:
352    case llvm::ELF::R_MIPS_GPREL16:
353    case llvm::ELF::R_MIPS_LITERAL:
354      break;
355    case llvm::ELF::R_MIPS_TLS_DTPMOD32:
356    case llvm::ELF::R_MIPS_TLS_DTPREL32:
357    case llvm::ELF::R_MIPS_TLS_DTPMOD64:
358    case llvm::ELF::R_MIPS_TLS_DTPREL64:
359    case llvm::ELF::R_MIPS_TLS_GD:
360    case llvm::ELF::R_MIPS_TLS_LDM:
361    case llvm::ELF::R_MIPS_TLS_DTPREL_HI16:
362    case llvm::ELF::R_MIPS_TLS_DTPREL_LO16:
363    case llvm::ELF::R_MIPS_TLS_GOTTPREL:
364    case llvm::ELF::R_MIPS_TLS_TPREL32:
365    case llvm::ELF::R_MIPS_TLS_TPREL64:
366    case llvm::ELF::R_MIPS_TLS_TPREL_HI16:
367    case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
368      break;
369    case llvm::ELF::R_MIPS_PC32:
370      break;
371    default:
372      fatal(diag::unknown_relocation) << (int)pReloc.type() << rsym->name();
373  }
374}
375
376void MipsRelocator::scanGlobalReloc(MipsRelocationInfo& pReloc,
377                                    IRBuilder& pBuilder,
378                                    const LDSection& pSection)
379{
380  ResolveInfo* rsym = pReloc.parent().symInfo();
381
382  switch (pReloc.type()){
383    case llvm::ELF::R_MIPS_NONE:
384    case llvm::ELF::R_MIPS_INSERT_A:
385    case llvm::ELF::R_MIPS_INSERT_B:
386    case llvm::ELF::R_MIPS_DELETE:
387    case llvm::ELF::R_MIPS_TLS_DTPMOD64:
388    case llvm::ELF::R_MIPS_TLS_DTPREL64:
389    case llvm::ELF::R_MIPS_REL16:
390    case llvm::ELF::R_MIPS_ADD_IMMEDIATE:
391    case llvm::ELF::R_MIPS_PJUMP:
392    case llvm::ELF::R_MIPS_RELGOT:
393    case llvm::ELF::R_MIPS_TLS_TPREL64:
394      break;
395    case llvm::ELF::R_MIPS_32:
396    case llvm::ELF::R_MIPS_64:
397    case llvm::ELF::R_MIPS_HI16:
398    case llvm::ELF::R_MIPS_LO16:
399      if (getTarget().symbolNeedsDynRel(*rsym, false, true)) {
400        getTarget().getRelDyn().reserveEntry();
401        if (getTarget().symbolNeedsCopyReloc(pReloc.parent(), *rsym)) {
402          LDSymbol& cpySym = defineSymbolforCopyReloc(pBuilder, *rsym);
403          addCopyReloc(*cpySym.resolveInfo());
404        }
405        else {
406          // set Rel bit
407          rsym->setReserved(rsym->reserved() | ReserveRel);
408          getTarget().checkAndSetHasTextRel(*pSection.getLink());
409        }
410      }
411      break;
412    case llvm::ELF::R_MIPS_GOT16:
413    case llvm::ELF::R_MIPS_CALL16:
414    case llvm::ELF::R_MIPS_GOT_DISP:
415    case llvm::ELF::R_MIPS_GOT_HI16:
416    case llvm::ELF::R_MIPS_CALL_HI16:
417    case llvm::ELF::R_MIPS_GOT_LO16:
418    case llvm::ELF::R_MIPS_CALL_LO16:
419    case llvm::ELF::R_MIPS_GOT_PAGE:
420    case llvm::ELF::R_MIPS_GOT_OFST:
421      if (getTarget().getGOT().reserveGlobalEntry(*rsym)) {
422        if (getTarget().getGOT().hasMultipleGOT())
423          getTarget().checkAndSetHasTextRel(*pSection.getLink());
424      }
425      break;
426    case llvm::ELF::R_MIPS_LITERAL:
427    case llvm::ELF::R_MIPS_GPREL32:
428      fatal(diag::invalid_global_relocation) << (int)pReloc.type()
429                                             << rsym->name();
430      break;
431    case llvm::ELF::R_MIPS_GPREL16:
432      break;
433    case llvm::ELF::R_MIPS_26:
434      // Create a PLT entry if the symbol requires it and does not have it.
435      if (getTarget().symbolNeedsPLT(*rsym) &&
436          !(rsym->reserved() & ReservePLT)) {
437        getTarget().getPLT().reserveEntry();
438        getTarget().getGOTPLT().reserve();
439        getTarget().getRelPLT().reserveEntry();
440        rsym->setReserved(rsym->reserved() | ReservePLT);
441      }
442      break;
443    case llvm::ELF::R_MIPS_PC16:
444      break;
445    case llvm::ELF::R_MIPS_16:
446    case llvm::ELF::R_MIPS_SHIFT5:
447    case llvm::ELF::R_MIPS_SHIFT6:
448    case llvm::ELF::R_MIPS_SUB:
449    case llvm::ELF::R_MIPS_HIGHER:
450    case llvm::ELF::R_MIPS_HIGHEST:
451    case llvm::ELF::R_MIPS_SCN_DISP:
452      break;
453    case llvm::ELF::R_MIPS_TLS_DTPREL32:
454    case llvm::ELF::R_MIPS_TLS_GD:
455    case llvm::ELF::R_MIPS_TLS_LDM:
456    case llvm::ELF::R_MIPS_TLS_DTPREL_HI16:
457    case llvm::ELF::R_MIPS_TLS_DTPREL_LO16:
458    case llvm::ELF::R_MIPS_TLS_GOTTPREL:
459    case llvm::ELF::R_MIPS_TLS_TPREL32:
460    case llvm::ELF::R_MIPS_TLS_TPREL_HI16:
461    case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
462      break;
463    case llvm::ELF::R_MIPS_REL32:
464    case llvm::ELF::R_MIPS_JALR:
465    case llvm::ELF::R_MIPS_PC32:
466      break;
467    case llvm::ELF::R_MIPS_COPY:
468    case llvm::ELF::R_MIPS_GLOB_DAT:
469    case llvm::ELF::R_MIPS_JUMP_SLOT:
470      fatal(diag::dynamic_relocation) << (int)pReloc.type();
471      break;
472    default:
473      fatal(diag::unknown_relocation) << (int)pReloc.type() << rsym->name();
474  }
475}
476
477bool MipsRelocator::isPostponed(const Relocation& pReloc) const
478{
479  if (MipsRelocationInfo::HasSubType(pReloc, llvm::ELF::R_MIPS_HI16))
480    return true;
481
482  if (MipsRelocationInfo::HasSubType(pReloc, llvm::ELF::R_MIPS_GOT16) &&
483      pReloc.symInfo()->isLocal())
484    return true;
485
486  return false;
487}
488
489void MipsRelocator::addCopyReloc(ResolveInfo& pSym)
490{
491  Relocation& relEntry = *getTarget().getRelDyn().consumeEntry();
492  relEntry.setType(llvm::ELF::R_MIPS_COPY);
493  assert(pSym.outSymbol()->hasFragRef());
494  relEntry.targetRef().assign(*pSym.outSymbol()->fragRef());
495  relEntry.setSymInfo(&pSym);
496}
497
498LDSymbol& MipsRelocator::defineSymbolforCopyReloc(IRBuilder& pBuilder,
499                                                  const ResolveInfo& pSym)
500{
501  // Get or create corresponding BSS LDSection
502  ELFFileFormat* fileFormat = getTarget().getOutputFormat();
503  LDSection* bssSectHdr =
504    ResolveInfo::ThreadLocal == pSym.type() ? &fileFormat->getTBSS()
505                                            : &fileFormat->getBSS();
506
507  // Get or create corresponding BSS SectionData
508  SectionData* bssData =
509    bssSectHdr->hasSectionData() ? bssSectHdr->getSectionData()
510                                 : IRBuilder::CreateSectionData(*bssSectHdr);
511
512  // Determine the alignment by the symbol value
513  // FIXME: here we use the largest alignment
514  uint32_t addrAlign = config().targets().bitclass() / 8;
515
516  // Allocate space in BSS for the copy symbol
517  Fragment* frag = new FillFragment(0x0, 1, pSym.size());
518  uint64_t size = ObjectBuilder::AppendFragment(*frag, *bssData, addrAlign);
519  bssSectHdr->setSize(bssSectHdr->size() + size);
520
521  // Change symbol binding to Global if it's a weak symbol
522  ResolveInfo::Binding binding = (ResolveInfo::Binding)pSym.binding();
523  if (binding == ResolveInfo::Weak)
524    binding = ResolveInfo::Global;
525
526  // Define the copy symbol in the bss section and resolve it
527  LDSymbol* cpySym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
528                      pSym.name(),
529                      (ResolveInfo::Type)pSym.type(),
530                      ResolveInfo::Define,
531                      binding,
532                      pSym.size(),  // size
533                      0x0,          // value
534                      FragmentRef::Create(*frag, 0x0),
535                      (ResolveInfo::Visibility)pSym.other());
536
537  // Output all other alias symbols if any
538  Module::AliasList* alias_list = pBuilder.getModule().getAliasList(pSym);
539  if (NULL == alias_list)
540    return *cpySym;
541
542  for (Module::alias_iterator it = alias_list->begin(), ie = alias_list->end();
543       it != ie; ++it) {
544    const ResolveInfo* alias = *it;
545    if (alias == &pSym || !alias->isDyn())
546      continue;
547
548    pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
549        alias->name(),
550        (ResolveInfo::Type)alias->type(),
551        ResolveInfo::Define,
552        binding,
553        alias->size(),  // size
554        0x0,            // value
555        FragmentRef::Create(*frag, 0x0),
556        (ResolveInfo::Visibility)alias->other());
557  }
558
559  return *cpySym;
560}
561
562void MipsRelocator::postponeRelocation(Relocation& pReloc)
563{
564  ResolveInfo* rsym = pReloc.symInfo();
565  m_PostponedRelocs[rsym].insert(&pReloc);
566}
567
568void MipsRelocator::applyPostponedRelocations(MipsRelocationInfo& pLo16Reloc)
569{
570  m_CurrentLo16Reloc = &pLo16Reloc;
571
572  ResolveInfo* rsym = pLo16Reloc.parent().symInfo();
573
574  RelocationSet & relocs = m_PostponedRelocs[rsym];
575  for (RelocationSet::iterator it = relocs.begin(); it != relocs.end(); ++it)
576    (*it)->apply(*this);
577
578  m_PostponedRelocs.erase(rsym);
579
580  m_CurrentLo16Reloc = NULL;
581}
582
583bool MipsRelocator::isGpDisp(const Relocation& pReloc) const
584{
585  return 0 == strcmp("_gp_disp", pReloc.symInfo()->name());
586}
587
588bool MipsRelocator::isRel() const
589{
590  return config().targets().is32Bits();
591}
592
593bool MipsRelocator::isLocalReloc(ResolveInfo& pSym) const
594{
595  if (pSym.isUndef())
596    return false;
597
598  return pSym.isLocal() ||
599         !getTarget().isDynamicSymbol(pSym) ||
600         !pSym.isDyn();
601}
602
603Relocator::Address MipsRelocator::getGPAddress()
604{
605  return getTarget().getGOT().getGPAddr(getApplyingInput());
606}
607
608Relocator::Address MipsRelocator::getGP0()
609{
610  return getTarget().getGP0(getApplyingInput());
611}
612
613Fragment& MipsRelocator::getLocalGOTEntry(MipsRelocationInfo& pReloc,
614                                          Relocation::DWord entryValue)
615{
616  // rsym - The relocation target symbol
617  ResolveInfo* rsym = pReloc.parent().symInfo();
618  MipsGOT& got = getTarget().getGOT();
619
620  assert(isLocalReloc(*rsym) &&
621         "Attempt to get a global GOT entry for the local relocation");
622
623  Fragment* got_entry = got.lookupLocalEntry(rsym, entryValue);
624
625  // Found a mapping, then return the mapped entry immediately.
626  if (NULL != got_entry)
627    return *got_entry;
628
629  // Not found.
630  got_entry = got.consumeLocal();
631
632  if (got.isPrimaryGOTConsumed())
633    setupRelDynEntry(*FragmentRef::Create(*got_entry, 0), NULL);
634  else
635    got.setEntryValue(got_entry, entryValue);
636
637  got.recordLocalEntry(rsym, entryValue, got_entry);
638
639  return *got_entry;
640}
641
642Fragment& MipsRelocator::getGlobalGOTEntry(MipsRelocationInfo& pReloc)
643{
644  // rsym - The relocation target symbol
645  ResolveInfo* rsym = pReloc.parent().symInfo();
646  MipsGOT& got = getTarget().getGOT();
647
648  assert(!isLocalReloc(*rsym) &&
649         "Attempt to get a local GOT entry for the global relocation");
650
651  Fragment* got_entry = got.lookupGlobalEntry(rsym);
652
653  // Found a mapping, then return the mapped entry immediately.
654  if (NULL != got_entry)
655    return *got_entry;
656
657  // Not found.
658  got_entry = got.consumeGlobal();
659
660  if (got.isPrimaryGOTConsumed())
661    setupRelDynEntry(*FragmentRef::Create(*got_entry, 0), rsym);
662  else
663    got.setEntryValue(got_entry, pReloc.parent().symValue());
664
665  got.recordGlobalEntry(rsym, got_entry);
666
667  return *got_entry;
668}
669
670Relocator::Address MipsRelocator::getGOTOffset(MipsRelocationInfo& pReloc)
671{
672  ResolveInfo* rsym = pReloc.parent().symInfo();
673  MipsGOT& got = getTarget().getGOT();
674
675  if (isLocalReloc(*rsym)) {
676    uint64_t value = pReloc.S();
677
678    if (ResolveInfo::Section == rsym->type())
679      value += pReloc.A();
680
681    return got.getGPRelOffset(getApplyingInput(),
682                              getLocalGOTEntry(pReloc, value));
683  }
684  else {
685    return got.getGPRelOffset(getApplyingInput(), getGlobalGOTEntry(pReloc));
686  }
687}
688
689void MipsRelocator::createDynRel(MipsRelocationInfo& pReloc)
690{
691  Relocator::DWord A = pReloc.A();
692  Relocator::DWord S = pReloc.S();
693
694  ResolveInfo* rsym = pReloc.parent().symInfo();
695
696  if (isLocalReloc(*rsym)) {
697    setupRelDynEntry(pReloc.parent().targetRef(), NULL);
698    pReloc.result() = A + S;
699  }
700  else {
701    setupRelDynEntry(pReloc.parent().targetRef(), rsym);
702    // Don't add symbol value that will be resolved by the dynamic linker.
703    pReloc.result() = A;
704  }
705}
706
707uint64_t MipsRelocator::calcAHL(const MipsRelocationInfo& pHiReloc)
708{
709  assert(NULL != m_CurrentLo16Reloc &&
710         "There is no saved R_MIPS_LO16 relocation");
711
712  uint64_t AHI = pHiReloc.A() & 0xFFFF;
713  uint64_t ALO = m_CurrentLo16Reloc->A() & 0xFFFF;
714  uint64_t AHL = (AHI << 16) + int16_t(ALO);
715
716  return AHL;
717}
718
719bool MipsRelocator::isN64ABI() const
720{
721  return config().targets().is64Bits();
722}
723
724uint64_t MipsRelocator::getPLTAddress(ResolveInfo& rsym)
725{
726  assert((rsym.reserved() & MipsRelocator::ReservePLT) &&
727         "Symbol does not require a PLT entry");
728
729  SymPLTMap::const_iterator it = m_SymPLTMap.find(&rsym);
730
731  Fragment* plt;
732
733  if (it != m_SymPLTMap.end()) {
734    plt = it->second.first;
735  }
736  else {
737    plt = getTarget().getPLT().consume();
738
739    Fragment* got = getTarget().getGOTPLT().consume();
740    Relocation* rel = getTarget().getRelPLT().consumeEntry();
741
742    rel->setType(llvm::ELF::R_MIPS_JUMP_SLOT);
743    rel->targetRef().assign(*got);
744    rel->setSymInfo(&rsym);
745
746    m_SymPLTMap[&rsym] = PLTDescriptor(plt, got);
747  }
748
749  return getTarget().getPLT().addr() + plt->getOffset();
750}
751
752//===----------------------------------------------------------------------===//
753// Mips32Relocator
754//===----------------------------------------------------------------------===//
755Mips32Relocator::Mips32Relocator(Mips32GNULDBackend& pParent,
756                                 const LinkerConfig& pConfig)
757  : MipsRelocator(pParent, pConfig)
758{}
759
760void Mips32Relocator::setupRelDynEntry(FragmentRef& pFragRef, ResolveInfo* pSym)
761{
762  Relocation& relEntry = *getTarget().getRelDyn().consumeEntry();
763  relEntry.setType(llvm::ELF::R_MIPS_REL32);
764  relEntry.targetRef() = pFragRef;
765  relEntry.setSymInfo(pSym);
766}
767
768//===----------------------------------------------------------------------===//
769// Mips64Relocator
770//===----------------------------------------------------------------------===//
771Mips64Relocator::Mips64Relocator(Mips64GNULDBackend& pParent,
772                                 const LinkerConfig& pConfig)
773  : MipsRelocator(pParent, pConfig)
774{}
775
776void Mips64Relocator::setupRelDynEntry(FragmentRef& pFragRef, ResolveInfo* pSym)
777{
778  Relocation::Type type = llvm::ELF::R_MIPS_REL32 |
779                          llvm::ELF::R_MIPS_64 << 8;
780  // FIXME (simon): Fix dynamic relocations.
781  type = llvm::ELF::R_MIPS_NONE;
782
783  Relocation& relEntry = *getTarget().getRelDyn().consumeEntry();
784  relEntry.setType(type);
785  relEntry.targetRef() = pFragRef;
786  relEntry.setSymInfo(pSym);
787}
788
789//=========================================//
790// Relocation functions implementation     //
791//=========================================//
792
793// R_MIPS_NONE and those unsupported/deprecated relocation type
794static
795MipsRelocator::Result none(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
796{
797  return Relocator::OK;
798}
799
800// R_MIPS_32: S + A
801static
802MipsRelocator::Result abs32(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
803{
804  ResolveInfo* rsym = pReloc.parent().symInfo();
805
806  Relocator::DWord A = pReloc.A();
807  Relocator::DWord S = pReloc.S();
808
809  LDSection& target_sect =
810    pReloc.parent().targetRef().frag()->getParent()->getSection();
811
812  // If the flag of target section is not ALLOC, we will not scan this relocation
813  // but perform static relocation. (e.g., applying .debug section)
814  if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
815    pReloc.result() = S + A;
816    return Relocator::OK;
817  }
818
819  if (rsym->reserved() & MipsRelocator::ReserveRel) {
820    pParent.createDynRel(pReloc);
821    return Relocator::OK;
822  }
823
824  pReloc.result() = S + A;
825
826  return Relocator::OK;
827}
828
829// R_MIPS_26:
830//   local   : ((A | ((P + 4) & 0x3F000000)) + S) >> 2
831//   external: (sign–extend(A) + S) >> 2
832static
833MipsRelocator::Result rel26(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
834{
835  ResolveInfo* rsym = pReloc.parent().symInfo();
836
837  int32_t A = ((pReloc.parent().target() & 0x03FFFFFF) << 2);
838  int32_t P = pReloc.P();
839  int32_t S = rsym->reserved() & MipsRelocator::ReservePLT
840                  ? pParent.getPLTAddress(*rsym)
841                  : pReloc.S();
842
843  if (rsym->isLocal())
844    pReloc.result() = A | ((P + 4) & 0x3F000000);
845  else
846    pReloc.result() = mcld::signExtend<28>(A);
847
848  pReloc.result() = (pReloc.result() + S) >> 2;
849
850  return Relocator::OK;
851}
852
853// R_MIPS_HI16:
854//   local/external: ((AHL + S) - (short)(AHL + S)) >> 16
855//   _gp_disp      : ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16
856static
857MipsRelocator::Result hi16(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
858{
859  uint64_t AHL = pParent.calcAHL(pReloc);
860
861  if (pParent.isGpDisp(pReloc.parent())) {
862    int32_t P = pReloc.P();
863    int32_t GP = pParent.getGPAddress();
864    pReloc.result() = ((AHL + GP - P) - (int16_t)(AHL + GP - P)) >> 16;
865  }
866  else {
867    int32_t S = pReloc.S();
868    if (pParent.isN64ABI())
869      pReloc.result() = (pReloc.A() + S + 0x8000ull) >> 16;
870    else
871      pReloc.result() = ((AHL + S) - (int16_t)(AHL + S)) >> 16;
872  }
873
874  return Relocator::OK;
875}
876
877// R_MIPS_LO16:
878//   local/external: AHL + S
879//   _gp_disp      : AHL + GP - P + 4
880static
881MipsRelocator::Result lo16(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
882{
883  // AHL is a combination of HI16 and LO16 addends. But R_MIPS_LO16
884  // uses low 16 bits of the AHL. That is why we do not need R_MIPS_HI16
885  // addend here.
886  int32_t AHL = (pReloc.A() & 0xFFFF);
887
888  if (pParent.isGpDisp(pReloc.parent())) {
889    int32_t P = pReloc.P();
890    int32_t GP = pParent.getGPAddress();
891    pReloc.result() = AHL + GP - P + 4;
892  }
893  else {
894    int32_t S = pReloc.S();
895    pReloc.result() = AHL + S;
896  }
897
898  pParent.applyPostponedRelocations(pReloc);
899
900  return Relocator::OK;
901}
902
903// R_MIPS_GPREL16:
904//   external: sign–extend(A) + S - GP
905//   local   : sign–extend(A) + S + GP0 – GP
906static
907MipsRelocator::Result gprel16(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
908{
909  // Remember to add the section offset to A.
910  uint64_t A = pReloc.A();
911  uint64_t S = pReloc.S();
912  uint64_t GP0 = pParent.getGP0();
913  uint64_t GP = pParent.getGPAddress();
914
915  ResolveInfo* rsym = pReloc.parent().symInfo();
916  if (rsym->isLocal())
917    pReloc.result() = A + S + GP0 - GP;
918  else
919    pReloc.result() = A + S - GP;
920
921  return Relocator::OK;
922}
923
924// R_MIPS_GOT16:
925//   local   : G (calculate AHL and put high 16 bit to GOT)
926//   external: G
927static
928MipsRelocator::Result got16(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
929{
930  if (pReloc.parent().symInfo()->isLocal()) {
931    int32_t AHL = pParent.calcAHL(pReloc);
932    int32_t S = pReloc.S();
933    int32_t res = (AHL + S + 0x8000) & 0xFFFF0000;
934
935    MipsGOT& got = pParent.getTarget().getGOT();
936
937    Fragment& got_entry = pParent.getLocalGOTEntry(pReloc, res);
938
939    pReloc.result() = got.getGPRelOffset(pParent.getApplyingInput(), got_entry);
940  }
941  else {
942    pReloc.result() = pParent.getGOTOffset(pReloc);
943  }
944
945  return Relocator::OK;
946}
947
948// R_MIPS_GOTHI16:
949//   external: (G - (short)G) >> 16 + A
950static
951MipsRelocator::Result gothi16(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
952{
953  Relocator::Address G = pParent.getGOTOffset(pReloc);
954  int32_t A = pReloc.A();
955
956  pReloc.result() = (G - (int16_t)G) >> (16 + A);
957
958  return Relocator::OK;
959}
960
961// R_MIPS_GOTLO16:
962//   external: G & 0xffff
963static
964MipsRelocator::Result gotlo16(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
965{
966  pReloc.result() = pParent.getGOTOffset(pReloc) & 0xffff;
967
968  return Relocator::OK;
969}
970
971// R_MIPS_SUB:
972//   external/local: S - A
973static
974MipsRelocator::Result sub(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
975{
976  uint64_t S = pReloc.S();
977  uint64_t A = pReloc.A();
978
979  pReloc.result() = S - A;
980
981  return Relocator::OK;
982}
983
984// R_MIPS_CALL16: G
985static
986MipsRelocator::Result call16(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
987{
988  pReloc.result() = pParent.getGOTOffset(pReloc);
989
990  return Relocator::OK;
991}
992
993// R_MIPS_GPREL32: A + S + GP0 - GP
994static
995MipsRelocator::Result gprel32(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
996{
997  // Remember to add the section offset to A.
998  uint64_t A = pReloc.A();
999  uint64_t S = pReloc.S();
1000  uint64_t GP0 = pParent.getGP0();
1001  uint64_t GP = pParent.getGPAddress();
1002
1003  pReloc.result() = A + S + GP0 - GP;
1004
1005  return Relocator::OK;
1006}
1007
1008// R_MIPS_64: S + A
1009static
1010MipsRelocator::Result abs64(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
1011{
1012  // FIXME (simon): Consider to merge with abs32() or use the same function
1013  // but with another mask size.
1014  ResolveInfo* rsym = pReloc.parent().symInfo();
1015
1016  Relocator::DWord A = pReloc.A();
1017  Relocator::DWord S = pReloc.S();
1018
1019  LDSection& target_sect =
1020    pReloc.parent().targetRef().frag()->getParent()->getSection();
1021
1022  // If the flag of target section is not ALLOC, we will not scan this relocation
1023  // but perform static relocation. (e.g., applying .debug section)
1024  if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
1025    pReloc.result() = S + A;
1026    return Relocator::OK;
1027  }
1028
1029  if (rsym->reserved() & MipsRelocator::ReserveRel) {
1030    pParent.createDynRel(pReloc);
1031    return Relocator::OK;
1032  }
1033
1034  pReloc.result() = S + A;
1035
1036  return Relocator::OK;
1037}
1038
1039// R_MIPS_GOT_DISP / R_MIPS_GOT_PAGE: G
1040static
1041MipsRelocator::Result gotdisp(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
1042{
1043  pReloc.result() = pParent.getGOTOffset(pReloc);
1044
1045  return Relocator::OK;
1046}
1047
1048// R_MIPS_GOT_OFST:
1049static
1050MipsRelocator::Result gotoff(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
1051{
1052  // FIXME (simon): Needs to be implemented.
1053  return Relocator::OK;
1054}
1055
1056// R_MIPS_JALR:
1057static
1058MipsRelocator::Result jalr(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
1059{
1060  return Relocator::OK;
1061}
1062
1063// R_MIPS_LA25_LUI
1064static
1065MipsRelocator::Result la25lui(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
1066{
1067  int32_t S = pReloc.S();
1068
1069  pReloc.result() = (S + 0x8000) >> 16;
1070
1071  return Relocator::OK;
1072}
1073
1074// R_MIPS_LA25_J
1075static
1076MipsRelocator::Result la25j(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
1077{
1078  int32_t S = pReloc.S();
1079
1080  pReloc.result() = S >> 2;
1081
1082  return Relocator::OK;
1083}
1084
1085// R_MIPS_LA25_ADD
1086static
1087MipsRelocator::Result la25add(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
1088{
1089  pReloc.result() = pReloc.S();
1090
1091  return Relocator::OK;
1092}
1093
1094// R_MIPS_PC32:
1095static
1096MipsRelocator::Result pc32(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
1097{
1098  return Relocator::OK;
1099}
1100
1101static
1102MipsRelocator::Result unsupport(MipsRelocationInfo& pReloc, MipsRelocator& pParent)
1103{
1104  return Relocator::Unsupport;
1105}
1106