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 }  // namespace ELF
33 }  // namespace llvm
34 
35 namespace mcld {
36 
37 //===----------------------------------------------------------------------===//
38 // MipsRelocationInfo
39 //===----------------------------------------------------------------------===//
40 class MipsRelocationInfo {
41  public:
HasSubType(const Relocation & pParent,Relocation::Type pType)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 
MipsRelocationInfo(Relocation & pParent,bool pIsRel)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 
isNone() const69   bool isNone() const { return llvm::ELF::R_MIPS_NONE == type(); }
70 
isLast() const71   bool isLast() const { return llvm::ELF::R_MIPS_NONE == (m_Type >> 8); }
72 
next() const73   MipsRelocationInfo next() const {
74     return MipsRelocationInfo(*m_Parent, m_Type >> 8, result(), result(), 0);
75   }
76 
parent() const77   const Relocation& parent() const { return *m_Parent; }
78 
parent()79   Relocation& parent() { return *m_Parent; }
80 
type() const81   Relocation::Type type() const { return m_Type & 0xff; }
82 
A() const83   Relocation::DWord A() const { return m_Addend; }
84 
S() const85   Relocation::DWord S() const { return m_Symbol; }
86 
P() const87   Relocation::DWord P() const { return parent().place(); }
88 
result() const89   Relocation::DWord result() const { return m_Result; }
90 
result()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 
MipsRelocationInfo(Relocation & pParent,Relocation::Type pType,Relocation::DWord pResult,Relocation::DWord pAddend,Relocation::DWord pSymbol)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 
isFirst() const111   bool isFirst() const { return m_Type == parent().type(); }
112 };
113 
114 //===----------------------------------------------------------------------===//
115 // Relocation Functions and Tables
116 //===----------------------------------------------------------------------===//
117 DECL_MIPS_APPLY_RELOC_FUNCS
118 
119 /// the prototype of applying function
120 typedef Relocator::Result (*ApplyFunctionType)(MipsRelocationInfo&,
121                                                MipsRelocator& pParent);
122 
123 // the table entry of applying functions
124 struct 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
132 static const ApplyFunctionTriple ApplyFunctions[] = {
133     DECL_MIPS_APPLY_RELOC_FUNC_PTRS};
134 
135 //===----------------------------------------------------------------------===//
136 // MipsRelocator
137 //===----------------------------------------------------------------------===//
MipsRelocator(MipsGNULDBackend & pParent,const LinkerConfig & pConfig)138 MipsRelocator::MipsRelocator(MipsGNULDBackend& pParent,
139                              const LinkerConfig& pConfig)
140     : Relocator(pConfig),
141       m_Target(pParent),
142       m_pApplyingInput(NULL),
143       m_CurrentLo16Reloc(NULL) {
144 }
145 
applyRelocation(Relocation & pReloc)146 Relocator::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 
getName(Relocation::Type pType) const176 const char* MipsRelocator::getName(Relocation::Type pType) const {
177   return ApplyFunctions[pType & 0xff].name;
178 }
179 
getSize(Relocation::Type pType) const180 Relocator::Size MipsRelocator::getSize(Relocation::Type pType) const {
181   return ApplyFunctions[pType & 0xff].size;
182 }
183 
scanRelocation(Relocation & pReloc,IRBuilder & pBuilder,Module & pModule,LDSection & pSection,Input & pInput)184 void 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 
initializeScan(Input & pInput)223 bool MipsRelocator::initializeScan(Input& pInput) {
224   if (LinkerConfig::Object != config().codeGenType())
225     getTarget().getGOT().initializeScan(pInput);
226   return true;
227 }
228 
finalizeScan(Input & pInput)229 bool MipsRelocator::finalizeScan(Input& pInput) {
230   if (LinkerConfig::Object != config().codeGenType())
231     getTarget().getGOT().finalizeScan(pInput);
232   return true;
233 }
234 
initializeApply(Input & pInput)235 bool MipsRelocator::initializeApply(Input& pInput) {
236   m_pApplyingInput = &pInput;
237   return true;
238 }
239 
finalizeApply(Input & pInput)240 bool MipsRelocator::finalizeApply(Input& pInput) {
241   m_pApplyingInput = NULL;
242   return true;
243 }
244 
scanLocalReloc(MipsRelocationInfo & pReloc,IRBuilder & pBuilder,const LDSection & pSection)245 void 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 
scanGlobalReloc(MipsRelocationInfo & pReloc,IRBuilder & pBuilder,const LDSection & pSection)331 void 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 
isPostponed(const Relocation & pReloc) const431 bool 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 
addCopyReloc(ResolveInfo & pSym)442 void 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 
defineSymbolforCopyReloc(IRBuilder & pBuilder,const ResolveInfo & pSym)450 LDSymbol& 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 
postponeRelocation(Relocation & pReloc)514 void MipsRelocator::postponeRelocation(Relocation& pReloc) {
515   ResolveInfo* rsym = pReloc.symInfo();
516   m_PostponedRelocs[rsym].insert(&pReloc);
517 }
518 
applyPostponedRelocations(MipsRelocationInfo & pLo16Reloc)519 void 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 
isGpDisp(const Relocation & pReloc) const533 bool MipsRelocator::isGpDisp(const Relocation& pReloc) const {
534   return strcmp("_gp_disp", pReloc.symInfo()->name()) == 0;
535 }
536 
isRel() const537 bool MipsRelocator::isRel() const {
538   return config().targets().is32Bits();
539 }
540 
isLocalReloc(ResolveInfo & pSym) const541 bool MipsRelocator::isLocalReloc(ResolveInfo& pSym) const {
542   if (pSym.isUndef())
543     return false;
544 
545   return pSym.isLocal() || !getTarget().isDynamicSymbol(pSym) || !pSym.isDyn();
546 }
547 
getGPAddress()548 Relocator::Address MipsRelocator::getGPAddress() {
549   return getTarget().getGOT().getGPAddr(getApplyingInput());
550 }
551 
getGP0()552 Relocator::Address MipsRelocator::getGP0() {
553   return getTarget().getGP0(getApplyingInput());
554 }
555 
getLocalGOTEntry(MipsRelocationInfo & pReloc,Relocation::DWord entryValue)556 Fragment& 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 
getGlobalGOTEntry(MipsRelocationInfo & pReloc)584 Fragment& 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 
getGOTOffset(MipsRelocationInfo & pReloc)611 Relocator::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 
createDynRel(MipsRelocationInfo & pReloc)628 void 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 
calcAHL(const MipsRelocationInfo & pHiReloc)644 uint64_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 
isN64ABI() const655 bool MipsRelocator::isN64ABI() const {
656   return config().targets().is64Bits();
657 }
658 
getPLTAddress(ResolveInfo & rsym)659 uint64_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 
getDebugStringOffset(Relocation & pReloc) const685 uint32_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 
applyDebugStringOffset(Relocation & pReloc,uint32_t pOffset)696 void MipsRelocator::applyDebugStringOffset(Relocation& pReloc,
697                                            uint32_t pOffset) {
698   pReloc.target() = pOffset;
699 }
700 
701 
702 //===----------------------------------------------------------------------===//
703 // Mips32Relocator
704 //===----------------------------------------------------------------------===//
Mips32Relocator(Mips32GNULDBackend & pParent,const LinkerConfig & pConfig)705 Mips32Relocator::Mips32Relocator(Mips32GNULDBackend& pParent,
706                                  const LinkerConfig& pConfig)
707     : MipsRelocator(pParent, pConfig) {
708 }
709 
setupRelDynEntry(FragmentRef & pFragRef,ResolveInfo * pSym)710 void 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 //===----------------------------------------------------------------------===//
Mips64Relocator(Mips64GNULDBackend & pParent,const LinkerConfig & pConfig)721 Mips64Relocator::Mips64Relocator(Mips64GNULDBackend& pParent,
722                                  const LinkerConfig& pConfig)
723     : MipsRelocator(pParent, pConfig) {
724 }
725 
setupRelDynEntry(FragmentRef & pFragRef,ResolveInfo * pSym)726 void 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
none(MipsRelocationInfo & pReloc,MipsRelocator & pParent)743 static MipsRelocator::Result none(MipsRelocationInfo& pReloc,
744                                   MipsRelocator& pParent) {
745   return Relocator::OK;
746 }
747 
748 // R_MIPS_32: S + A
abs32(MipsRelocationInfo & pReloc,MipsRelocator & pParent)749 static 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
rel26(MipsRelocationInfo & pReloc,MipsRelocator & pParent)780 static 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
hi16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)803 static 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
lo16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)825 static 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
gprel16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)849 static 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
got16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)869 static 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
gothi16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)890 static 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
gotlo16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)902 static 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
sub(MipsRelocationInfo & pReloc,MipsRelocator & pParent)911 static 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
call16(MipsRelocationInfo & pReloc,MipsRelocator & pParent)922 static 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
gprel32(MipsRelocationInfo & pReloc,MipsRelocator & pParent)930 static 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
abs64(MipsRelocationInfo & pReloc,MipsRelocator & pParent)944 static 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
gotdisp(MipsRelocationInfo & pReloc,MipsRelocator & pParent)975 static 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:
gotoff(MipsRelocationInfo & pReloc,MipsRelocator & pParent)983 static 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:
jalr(MipsRelocationInfo & pReloc,MipsRelocator & pParent)990 static MipsRelocator::Result jalr(MipsRelocationInfo& pReloc,
991                                   MipsRelocator& pParent) {
992   return Relocator::OK;
993 }
994 
995 // R_MIPS_LA25_LUI
la25lui(MipsRelocationInfo & pReloc,MipsRelocator & pParent)996 static 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
la25j(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1006 static 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
la25add(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1016 static MipsRelocator::Result la25add(MipsRelocationInfo& pReloc,
1017                                      MipsRelocator& pParent) {
1018   pReloc.result() = pReloc.S();
1019 
1020   return Relocator::OK;
1021 }
1022 
1023 // R_MIPS_PC32:
pc32(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1024 static MipsRelocator::Result pc32(MipsRelocationInfo& pReloc,
1025                                   MipsRelocator& pParent) {
1026   return Relocator::OK;
1027 }
1028 
unsupported(MipsRelocationInfo & pReloc,MipsRelocator & pParent)1029 static MipsRelocator::Result unsupported(MipsRelocationInfo& pReloc,
1030                                          MipsRelocator& pParent) {
1031   return Relocator::Unsupported;
1032 }
1033 
1034 }  // namespace mcld
1035