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