• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
22 namespace mcld {
23 
24 //===----------------------------------------------------------------------===//
25 // MipsRelocationInfo
26 //===----------------------------------------------------------------------===//
27 class MipsRelocationInfo {
28  public:
HasSubType(const Relocation & pParent,Relocation::Type pType)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 
MipsRelocationInfo(Relocation & pParent,bool pIsRel)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 
isNone() const50   bool isNone() const { return llvm::ELF::R_MIPS_NONE == type(); }
isFirst() const51   bool isFirst() const { return type() == (parent().type() & 0xff); }
isLast() const52   bool isLast() const { return llvm::ELF::R_MIPS_NONE == (m_Type >> 8); }
53 
next() const54   MipsRelocationInfo next() const {
55     return MipsRelocationInfo(*m_Parent, m_Type >> 8, result(), result());
56   }
57 
parent() const58   const Relocation& parent() const { return *m_Parent; }
59 
parent()60   Relocation& parent() { return *m_Parent; }
61 
type() const62   Relocation::Type type() const { return m_Type & 0xff; }
63 
A() const64   Relocation::DWord A() const { return m_Addend; }
65 
S() const66   Relocation::DWord S() const { return m_Symbol; }
67 
P() const68   Relocation::DWord P() const { return parent().place(); }
69 
result() const70   Relocation::DWord result() const { return m_Result; }
71 
result()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 
MipsRelocationInfo(Relocation & pParent,Relocation::Type pType,Relocation::DWord pResult,Relocation::DWord pAddend)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 
helper_PLT_init(MipsRelocationInfo & pReloc,MipsRelocator & pParent)90 static 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 
helper_get_PLT_address(ResolveInfo & pSym,MipsRelocator & pParent)110 static 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 //===----------------------------------------------------------------------===//
120 DECL_MIPS_APPLY_RELOC_FUNCS
121 
122 /// the prototype of applying function
123 typedef Relocator::Result (*ApplyFunctionType)(MipsRelocationInfo&,
124                                                MipsRelocator& pParent);
125 
126 // the table entry of applying functions
127 struct 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
135 static const ApplyFunctionTriple ApplyFunctions[] = {
136     DECL_MIPS_APPLY_RELOC_FUNC_PTRS};
137 
138 //===----------------------------------------------------------------------===//
139 // MipsRelocator
140 //===----------------------------------------------------------------------===//
MipsRelocator(MipsGNULDBackend & pParent,const LinkerConfig & pConfig)141 MipsRelocator::MipsRelocator(MipsGNULDBackend& pParent,
142                              const LinkerConfig& pConfig)
143     : Relocator(pConfig),
144       m_Target(pParent),
145       m_pApplyingInput(NULL),
146       m_CurrentLo16Reloc(NULL) {
147 }
148 
applyRelocation(Relocation & pReloc)149 Relocator::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 
getName(Relocation::Type pType) const179 const char* MipsRelocator::getName(Relocation::Type pType) const {
180   return ApplyFunctions[pType & 0xff].name;
181 }
182 
scanRelocation(Relocation & pReloc,IRBuilder & pBuilder,Module & pModule,LDSection & pSection,Input & pInput)183 void 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 
initializeScan(Input & pInput)222 bool MipsRelocator::initializeScan(Input& pInput) {
223   if (LinkerConfig::Object != config().codeGenType())
224     getTarget().getGOT().initializeScan(pInput);
225   return true;
226 }
227 
finalizeScan(Input & pInput)228 bool MipsRelocator::finalizeScan(Input& pInput) {
229   if (LinkerConfig::Object != config().codeGenType())
230     getTarget().getGOT().finalizeScan(pInput);
231   return true;
232 }
233 
initializeApply(Input & pInput)234 bool MipsRelocator::initializeApply(Input& pInput) {
235   m_pApplyingInput = &pInput;
236   return true;
237 }
238 
finalizeApply(Input & pInput)239 bool MipsRelocator::finalizeApply(Input& pInput) {
240   m_pApplyingInput = NULL;
241   return true;
242 }
243 
scanLocalReloc(MipsRelocationInfo & pReloc,IRBuilder & pBuilder,const LDSection & pSection)244 void 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 
scanGlobalReloc(MipsRelocationInfo & pReloc,IRBuilder & pBuilder,const LDSection & pSection)345 void 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 
isPostponed(const Relocation & pReloc) const461 bool 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 
addCopyReloc(ResolveInfo & pSym)476 void 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 
defineSymbolforCopyReloc(IRBuilder & pBuilder,const ResolveInfo & pSym)484 LDSymbol& 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 
postponeRelocation(Relocation & pReloc)548 void MipsRelocator::postponeRelocation(Relocation& pReloc) {
549   ResolveInfo* rsym = pReloc.symInfo();
550   m_PostponedRelocs[rsym].insert(&pReloc);
551 }
552 
applyPostponedRelocations(MipsRelocationInfo & pLo16Reloc)553 void 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 
isGpDisp(const Relocation & pReloc) const567 bool MipsRelocator::isGpDisp(const Relocation& pReloc) const {
568   return strcmp("_gp_disp", pReloc.symInfo()->name()) == 0;
569 }
570 
isRel() const571 bool MipsRelocator::isRel() const {
572   return config().targets().is32Bits();
573 }
574 
isLocalReloc(ResolveInfo & pSym) const575 bool MipsRelocator::isLocalReloc(ResolveInfo& pSym) const {
576   if (pSym.isUndef())
577     return false;
578 
579   return pSym.isLocal() || !getTarget().isDynamicSymbol(pSym) || !pSym.isDyn();
580 }
581 
getGPAddress()582 Relocator::Address MipsRelocator::getGPAddress() {
583   return getTarget().getGOT().getGPAddr(getApplyingInput());
584 }
585 
getTPOffset()586 Relocator::Address MipsRelocator::getTPOffset() {
587   return getTarget().getTPOffset(getApplyingInput());
588 }
589 
getDTPOffset()590 Relocator::Address MipsRelocator::getDTPOffset() {
591   return getTarget().getDTPOffset(getApplyingInput());
592 }
593 
getGP0()594 Relocator::Address MipsRelocator::getGP0() {
595   return getTarget().getGP0(getApplyingInput());
596 }
597 
getLocalGOTEntry(MipsRelocationInfo & pReloc,Relocation::DWord entryValue)598 Fragment& 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 
getGlobalGOTEntry(MipsRelocationInfo & pReloc)626 Fragment& 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 
getTLSGOTEntry(MipsRelocationInfo & pReloc)653 Fragment& 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 
getGOTOffset(MipsRelocationInfo & pReloc)672 Relocator::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 
getTLSGOTOffset(MipsRelocationInfo & pReloc)689 Relocator::Address MipsRelocator::getTLSGOTOffset(MipsRelocationInfo& pReloc) {
690   MipsGOT& got = getTarget().getGOT();
691   return got.getGPRelOffset(getApplyingInput(), getTLSGOTEntry(pReloc));
692 }
693 
createDynRel(MipsRelocationInfo & pReloc)694 void 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 
calcAHL(const MipsRelocationInfo & pHiReloc)713 uint64_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 
isN64ABI() const727 bool MipsRelocator::isN64ABI() const {
728   return config().targets().is64Bits();
729 }
730 
getDebugStringOffset(Relocation & pReloc) const731 uint32_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 
applyDebugStringOffset(Relocation & pReloc,uint32_t pOffset)742 void MipsRelocator::applyDebugStringOffset(Relocation& pReloc,
743                                            uint32_t pOffset) {
744   pReloc.target() = pOffset;
745 }
746 
setupRelDynEntry(FragmentRef & pFragRef,ResolveInfo * pSym,Relocation::Type pType)747 void 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 //===----------------------------------------------------------------------===//
Mips32Relocator(Mips32GNULDBackend & pParent,const LinkerConfig & pConfig)758 Mips32Relocator::Mips32Relocator(Mips32GNULDBackend& pParent,
759                                  const LinkerConfig& pConfig)
760     : MipsRelocator(pParent, pConfig) {
761 }
762 
setupRel32DynEntry(FragmentRef & pFragRef,ResolveInfo * pSym)763 void Mips32Relocator::setupRel32DynEntry(FragmentRef& pFragRef,
764                                          ResolveInfo* pSym) {
765   setupRelDynEntry(pFragRef, pSym, llvm::ELF::R_MIPS_REL32);
766 }
767 
setupTLSDynEntry(Fragment & pFrag,ResolveInfo * pSym,Relocation::Type pType)768 void 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 
getSize(Relocation::Type pType) const787 Relocator::Size Mips32Relocator::getSize(Relocation::Type pType) const {
788   return ApplyFunctions[pType & 0xff].size;
789 }
790 
791 //===----------------------------------------------------------------------===//
792 // Mips64Relocator
793 //===----------------------------------------------------------------------===//
Mips64Relocator(Mips64GNULDBackend & pParent,const LinkerConfig & pConfig)794 Mips64Relocator::Mips64Relocator(Mips64GNULDBackend& pParent,
795                                  const LinkerConfig& pConfig)
796     : MipsRelocator(pParent, pConfig) {
797 }
798 
setupRel32DynEntry(FragmentRef & pFragRef,ResolveInfo * pSym)799 void 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 
setupTLSDynEntry(Fragment & pFrag,ResolveInfo * pSym,Relocation::Type pType)805 void 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 
getSize(Relocation::Type pType) const824 Relocator::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
none(MipsRelocationInfo & pReloc,MipsRelocator & pParent)837 static MipsRelocator::Result none(MipsRelocationInfo& pReloc,
838                                   MipsRelocator& pParent) {
839   return Relocator::OK;
840 }
841 
842 // R_MIPS_32: S + A
abs32(MipsRelocationInfo & pReloc,MipsRelocator & pParent)843 static 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
rel26(MipsRelocationInfo & pReloc,MipsRelocator & pParent)874 static 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
hi16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)897 static 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
lo16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)919 static 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
gprel16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)943 static 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
got16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)963 static 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
gothi16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)984 static 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
gotlo16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)996 static 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
sub(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1005 static 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
call16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1016 static 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
gprel32(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1024 static 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
abs64(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1038 static 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
gotdisp(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1069 static 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:
gotoff(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1077 static 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:
jalr(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1084 static MipsRelocator::Result jalr(MipsRelocationInfo& pReloc,
1085                                   MipsRelocator& pParent) {
1086   return Relocator::OK;
1087 }
1088 
1089 // R_MIPS_PC16
pc16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1090 static 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
pc32(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1100 static 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
pc18_s3(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1110 static 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
pc19_s2(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1120 static 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
pc21_s2(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1130 static 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
pc26_s2(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1140 static 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
pchi16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1150 static 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
pclo16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1160 static 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
tlshi16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1173 static 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
tlslo16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1194 static 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
tlsgot(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1213 static MipsRelocator::Result tlsgot(MipsRelocationInfo& pReloc,
1214                                     MipsRelocator& pParent) {
1215   pReloc.result() = pParent.getTLSGOTOffset(pReloc);
1216   return Relocator::OK;
1217 }
1218 
unsupported(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1219 static MipsRelocator::Result unsupported(MipsRelocationInfo& pReloc,
1220                                          MipsRelocator& pParent) {
1221   return Relocator::Unsupported;
1222 }
1223 
1224 }  // namespace mcld
1225