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