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