• 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 
10 #include <llvm/ADT/Twine.h>
11 #include <llvm/Support/ELF.h>
12 #include <mcld/Support/MsgHandling.h>
13 #include <mcld/Target/OutputRelocSection.h>
14 #include <mcld/LinkerConfig.h>
15 #include <mcld/IRBuilder.h>
16 
17 #include "MipsRelocator.h"
18 #include "MipsRelocationFunctions.h"
19 
20 using namespace mcld;
21 
22 //===----------------------------------------------------------------------===//
23 // Relocation Functions and Tables
24 //===----------------------------------------------------------------------===//
25 DECL_MIPS_APPLY_RELOC_FUNCS
26 
27 /// the prototype of applying function
28 typedef Relocator::Result (*ApplyFunctionType)(Relocation&, MipsRelocator&);
29 
30 // the table entry of applying functions
31 struct ApplyFunctionTriple
32 {
33   ApplyFunctionType func;
34   unsigned int type;
35   const char* name;
36   unsigned int size;
37 };
38 
39 // declare the table of applying functions
40 static const ApplyFunctionTriple ApplyFunctions[] = {
41   DECL_MIPS_APPLY_RELOC_FUNC_PTRS
42 };
43 
44 //===----------------------------------------------------------------------===//
45 // MipsRelocator
46 //===----------------------------------------------------------------------===//
MipsRelocator(MipsGNULDBackend & pParent,const LinkerConfig & pConfig)47 MipsRelocator::MipsRelocator(MipsGNULDBackend& pParent,
48                              const LinkerConfig& pConfig)
49   : Relocator(pConfig),
50     m_Target(pParent),
51     m_pApplyingInput(NULL),
52     m_AHL(0)
53 {
54 }
55 
56 Relocator::Result
applyRelocation(Relocation & pRelocation)57 MipsRelocator::applyRelocation(Relocation& pRelocation)
58 {
59   Relocation::Type type = pRelocation.type();
60 
61   if (type >= sizeof(ApplyFunctions) / sizeof(ApplyFunctions[0])) {
62     return Unknown;
63   }
64 
65   // apply the relocation
66   return ApplyFunctions[type].func(pRelocation, *this);
67 }
68 
getName(Relocation::Type pType) const69 const char* MipsRelocator::getName(Relocation::Type pType) const
70 {
71   return ApplyFunctions[pType].name;
72 }
73 
getSize(Relocation::Type pType) const74 Relocator::Size MipsRelocator::getSize(Relocation::Type pType) const
75 {
76   return ApplyFunctions[pType].size;
77 }
78 
scanRelocation(Relocation & pReloc,IRBuilder & pBuilder,Module & pModule,LDSection & pSection)79 void MipsRelocator::scanRelocation(Relocation& pReloc,
80                                    IRBuilder& pBuilder,
81                                    Module& pModule,
82                                    LDSection& pSection)
83 {
84   // rsym - The relocation target symbol
85   ResolveInfo* rsym = pReloc.symInfo();
86   assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
87 
88   // Skip relocation against _gp_disp
89   if (NULL != getTarget().getGpDispSymbol()) {
90     if (pReloc.symInfo() == getTarget().getGpDispSymbol()->resolveInfo())
91       return;
92   }
93 
94   pReloc.updateAddend();
95 
96   assert(NULL != pSection.getLink());
97   if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC))
98     return;
99 
100   // We test isLocal or if pInputSym is not a dynamic symbol
101   // We assume -Bsymbolic to bind all symbols internaly via !rsym->isDyn()
102   // Don't put undef symbols into local entries.
103   if ((rsym->isLocal() || !getTarget().isDynamicSymbol(*rsym) ||
104       !rsym->isDyn()) && !rsym->isUndef())
105     scanLocalReloc(pReloc, pBuilder, pSection);
106   else
107     scanGlobalReloc(pReloc, pBuilder, pSection);
108 
109   // check if we shoule issue undefined reference for the relocation target
110   // symbol
111   if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
112     fatal(diag::undefined_reference) << rsym->name();
113 }
114 
initializeScan(Input & pInput)115 bool MipsRelocator::initializeScan(Input& pInput)
116 {
117   getTarget().getGOT().initializeScan(pInput);
118   return true;
119 }
120 
finalizeScan(Input & pInput)121 bool MipsRelocator::finalizeScan(Input& pInput)
122 {
123   getTarget().getGOT().finalizeScan(pInput);
124   return true;
125 }
126 
initializeApply(Input & pInput)127 bool MipsRelocator::initializeApply(Input& pInput)
128 {
129   m_pApplyingInput = &pInput;
130   return true;
131 }
132 
finalizeApply(Input & pInput)133 bool MipsRelocator::finalizeApply(Input& pInput)
134 {
135   m_pApplyingInput = NULL;
136   return true;
137 }
138 
scanLocalReloc(Relocation & pReloc,IRBuilder & pBuilder,const LDSection & pSection)139 void MipsRelocator::scanLocalReloc(Relocation& pReloc,
140                                    IRBuilder& pBuilder,
141                                    const LDSection& pSection)
142 {
143   ResolveInfo* rsym = pReloc.symInfo();
144 
145   switch (pReloc.type()){
146     case llvm::ELF::R_MIPS_NONE:
147     case llvm::ELF::R_MIPS_16:
148       break;
149     case llvm::ELF::R_MIPS_32:
150       if (LinkerConfig::DynObj == config().codeGenType()) {
151         // TODO: (simon) The gold linker does not create an entry in .rel.dyn
152         // section if the symbol section flags contains SHF_EXECINSTR.
153         // 1. Find the reason of this condition.
154         // 2. Check this condition here.
155         getTarget().getRelDyn().reserveEntry();
156         rsym->setReserved(rsym->reserved() | ReserveRel);
157         getTarget().checkAndSetHasTextRel(*pSection.getLink());
158 
159         // Remeber this rsym is a local GOT entry (as if it needs an entry).
160         // Actually we don't allocate an GOT entry.
161         getTarget().getGOT().setLocal(rsym);
162       }
163       break;
164     case llvm::ELF::R_MIPS_REL32:
165     case llvm::ELF::R_MIPS_26:
166     case llvm::ELF::R_MIPS_HI16:
167     case llvm::ELF::R_MIPS_LO16:
168     case llvm::ELF::R_MIPS_PC16:
169     case llvm::ELF::R_MIPS_SHIFT5:
170     case llvm::ELF::R_MIPS_SHIFT6:
171     case llvm::ELF::R_MIPS_64:
172     case llvm::ELF::R_MIPS_GOT_PAGE:
173     case llvm::ELF::R_MIPS_GOT_OFST:
174     case llvm::ELF::R_MIPS_SUB:
175     case llvm::ELF::R_MIPS_INSERT_A:
176     case llvm::ELF::R_MIPS_INSERT_B:
177     case llvm::ELF::R_MIPS_DELETE:
178     case llvm::ELF::R_MIPS_HIGHER:
179     case llvm::ELF::R_MIPS_HIGHEST:
180     case llvm::ELF::R_MIPS_SCN_DISP:
181     case llvm::ELF::R_MIPS_REL16:
182     case llvm::ELF::R_MIPS_ADD_IMMEDIATE:
183     case llvm::ELF::R_MIPS_PJUMP:
184     case llvm::ELF::R_MIPS_RELGOT:
185     case llvm::ELF::R_MIPS_JALR:
186     case llvm::ELF::R_MIPS_GLOB_DAT:
187     case llvm::ELF::R_MIPS_COPY:
188     case llvm::ELF::R_MIPS_JUMP_SLOT:
189       break;
190     case llvm::ELF::R_MIPS_GOT16:
191     case llvm::ELF::R_MIPS_CALL16:
192     case llvm::ELF::R_MIPS_GOT_HI16:
193     case llvm::ELF::R_MIPS_CALL_HI16:
194     case llvm::ELF::R_MIPS_GOT_LO16:
195     case llvm::ELF::R_MIPS_CALL_LO16:
196       if (getTarget().getGOT().reserveLocalEntry(*rsym)) {
197         if (getTarget().getGOT().hasMultipleGOT())
198           getTarget().checkAndSetHasTextRel(*pSection.getLink());
199         // Remeber this rsym is a local GOT entry
200         getTarget().getGOT().setLocal(rsym);
201       }
202       break;
203     case llvm::ELF::R_MIPS_GPREL32:
204     case llvm::ELF::R_MIPS_GPREL16:
205     case llvm::ELF::R_MIPS_LITERAL:
206     case llvm::ELF::R_MIPS_GOT_DISP:
207       break;
208     case llvm::ELF::R_MIPS_TLS_DTPMOD32:
209     case llvm::ELF::R_MIPS_TLS_DTPREL32:
210     case llvm::ELF::R_MIPS_TLS_DTPMOD64:
211     case llvm::ELF::R_MIPS_TLS_DTPREL64:
212     case llvm::ELF::R_MIPS_TLS_GD:
213     case llvm::ELF::R_MIPS_TLS_LDM:
214     case llvm::ELF::R_MIPS_TLS_DTPREL_HI16:
215     case llvm::ELF::R_MIPS_TLS_DTPREL_LO16:
216     case llvm::ELF::R_MIPS_TLS_GOTTPREL:
217     case llvm::ELF::R_MIPS_TLS_TPREL32:
218     case llvm::ELF::R_MIPS_TLS_TPREL64:
219     case llvm::ELF::R_MIPS_TLS_TPREL_HI16:
220     case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
221       break;
222     default:
223       fatal(diag::unknown_relocation) << (int)pReloc.type()
224                                       << pReloc.symInfo()->name();
225   }
226 }
227 
scanGlobalReloc(Relocation & pReloc,IRBuilder & pBuilder,const LDSection & pSection)228 void MipsRelocator::scanGlobalReloc(Relocation& pReloc,
229                                     IRBuilder& pBuilder,
230                                     const LDSection& pSection)
231 {
232   ResolveInfo* rsym = pReloc.symInfo();
233 
234   switch (pReloc.type()){
235     case llvm::ELF::R_MIPS_NONE:
236     case llvm::ELF::R_MIPS_INSERT_A:
237     case llvm::ELF::R_MIPS_INSERT_B:
238     case llvm::ELF::R_MIPS_DELETE:
239     case llvm::ELF::R_MIPS_TLS_DTPMOD64:
240     case llvm::ELF::R_MIPS_TLS_DTPREL64:
241     case llvm::ELF::R_MIPS_REL16:
242     case llvm::ELF::R_MIPS_ADD_IMMEDIATE:
243     case llvm::ELF::R_MIPS_PJUMP:
244     case llvm::ELF::R_MIPS_RELGOT:
245     case llvm::ELF::R_MIPS_TLS_TPREL64:
246       break;
247     case llvm::ELF::R_MIPS_32:
248     case llvm::ELF::R_MIPS_64:
249     case llvm::ELF::R_MIPS_HI16:
250     case llvm::ELF::R_MIPS_LO16:
251       if (getTarget().symbolNeedsDynRel(*rsym, false, true)) {
252         getTarget().getRelDyn().reserveEntry();
253         rsym->setReserved(rsym->reserved() | ReserveRel);
254         getTarget().checkAndSetHasTextRel(*pSection.getLink());
255 
256         // Remeber this rsym is a global GOT entry (as if it needs an entry).
257         // Actually we don't allocate an GOT entry.
258         getTarget().getGOT().setGlobal(rsym);
259       }
260       break;
261     case llvm::ELF::R_MIPS_GOT16:
262     case llvm::ELF::R_MIPS_CALL16:
263     case llvm::ELF::R_MIPS_GOT_DISP:
264     case llvm::ELF::R_MIPS_GOT_HI16:
265     case llvm::ELF::R_MIPS_CALL_HI16:
266     case llvm::ELF::R_MIPS_GOT_LO16:
267     case llvm::ELF::R_MIPS_CALL_LO16:
268     case llvm::ELF::R_MIPS_GOT_PAGE:
269     case llvm::ELF::R_MIPS_GOT_OFST:
270       if (getTarget().getGOT().reserveGlobalEntry(*rsym)) {
271         if (getTarget().getGOT().hasMultipleGOT())
272           getTarget().checkAndSetHasTextRel(*pSection.getLink());
273         // Remeber this rsym is a global GOT entry
274         getTarget().getGOT().setGlobal(rsym);
275       }
276       break;
277     case llvm::ELF::R_MIPS_LITERAL:
278     case llvm::ELF::R_MIPS_GPREL32:
279       fatal(diag::invalid_global_relocation) << (int)pReloc.type()
280                                              << pReloc.symInfo()->name();
281       break;
282     case llvm::ELF::R_MIPS_GPREL16:
283       break;
284     case llvm::ELF::R_MIPS_26:
285     case llvm::ELF::R_MIPS_PC16:
286       break;
287     case llvm::ELF::R_MIPS_16:
288     case llvm::ELF::R_MIPS_SHIFT5:
289     case llvm::ELF::R_MIPS_SHIFT6:
290     case llvm::ELF::R_MIPS_SUB:
291     case llvm::ELF::R_MIPS_HIGHER:
292     case llvm::ELF::R_MIPS_HIGHEST:
293     case llvm::ELF::R_MIPS_SCN_DISP:
294       break;
295     case llvm::ELF::R_MIPS_TLS_DTPREL32:
296     case llvm::ELF::R_MIPS_TLS_GD:
297     case llvm::ELF::R_MIPS_TLS_LDM:
298     case llvm::ELF::R_MIPS_TLS_DTPREL_HI16:
299     case llvm::ELF::R_MIPS_TLS_DTPREL_LO16:
300     case llvm::ELF::R_MIPS_TLS_GOTTPREL:
301     case llvm::ELF::R_MIPS_TLS_TPREL32:
302     case llvm::ELF::R_MIPS_TLS_TPREL_HI16:
303     case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
304       break;
305     case llvm::ELF::R_MIPS_REL32:
306       break;
307     case llvm::ELF::R_MIPS_JALR:
308       break;
309     case llvm::ELF::R_MIPS_COPY:
310     case llvm::ELF::R_MIPS_GLOB_DAT:
311     case llvm::ELF::R_MIPS_JUMP_SLOT:
312       fatal(diag::dynamic_relocation) << (int)pReloc.type();
313       break;
314     default:
315       fatal(diag::unknown_relocation) << (int)pReloc.type()
316                                       << pReloc.symInfo()->name();
317   }
318 }
319 
320 //===----------------------------------------------------------------------===//
321 // Relocation helper function
322 //===----------------------------------------------------------------------===//
323 static const char * const GP_DISP_NAME = "_gp_disp";
324 
325 // Find next R_MIPS_LO16 relocation paired to pReloc.
326 static
helper_FindLo16Reloc(Relocation & pReloc)327 Relocation* helper_FindLo16Reloc(Relocation& pReloc)
328 {
329   Relocation* reloc = static_cast<Relocation*>(pReloc.getNextNode());
330   while (NULL != reloc)
331   {
332     if (llvm::ELF::R_MIPS_LO16 == reloc->type() &&
333         reloc->symInfo() == pReloc.symInfo())
334       return reloc;
335 
336     reloc = static_cast<Relocation*>(reloc->getNextNode());
337   }
338   return NULL;
339 }
340 
341 // Check the symbol is _gp_disp.
342 static
helper_isGpDisp(const Relocation & pReloc)343 bool helper_isGpDisp(const Relocation& pReloc)
344 {
345   const ResolveInfo* rsym = pReloc.symInfo();
346   return 0 == strcmp(GP_DISP_NAME, rsym->name());
347 }
348 
349 static
helper_GetGP(MipsRelocator & pParent)350 Relocator::Address helper_GetGP(MipsRelocator& pParent)
351 {
352   return pParent.getTarget().getGOT().getGPAddr(pParent.getApplyingInput());
353 }
354 
355 static
helper_SetupRelDynForGOTEntry(MipsGOTEntry & got_entry,Relocation & pReloc,ResolveInfo * rsym,MipsRelocator & pParent)356 void helper_SetupRelDynForGOTEntry(MipsGOTEntry& got_entry,
357                                    Relocation& pReloc,
358                                    ResolveInfo* rsym,
359                                    MipsRelocator& pParent)
360 {
361   MipsGNULDBackend& ld_backend = pParent.getTarget();
362 
363   Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
364   rel_entry.setType(llvm::ELF::R_MIPS_REL32);
365   rel_entry.targetRef() = *FragmentRef::Create(got_entry, 0);
366   rel_entry.setSymInfo(rsym);
367 }
368 
369 static
helper_GetGOTEntry(Relocation & pReloc,MipsRelocator & pParent)370 MipsGOTEntry& helper_GetGOTEntry(Relocation& pReloc, MipsRelocator& pParent)
371 {
372   // rsym - The relocation target symbol
373   ResolveInfo* rsym = pReloc.symInfo();
374   MipsGNULDBackend& ld_backend = pParent.getTarget();
375   MipsGOT& got = ld_backend.getGOT();
376   MipsGOTEntry* got_entry;
377 
378   if (got.isLocal(rsym) && ResolveInfo::Section == rsym->type()) {
379     // Local section symbols consume local got entries.
380     got_entry = got.consumeLocal();
381     if (got.isPrimaryGOTConsumed())
382       helper_SetupRelDynForGOTEntry(*got_entry, pReloc, NULL, pParent);
383     return *got_entry;
384   }
385 
386   got_entry = got.lookupEntry(rsym);
387   if (NULL != got_entry) {
388     // found a mapping, then return the mapped entry immediately
389     return *got_entry;
390   }
391 
392   // not found
393   if (got.isLocal(rsym))
394     got_entry = got.consumeLocal();
395   else
396     got_entry = got.consumeGlobal();
397 
398   got.recordEntry(rsym, got_entry);
399 
400   // If we first get this GOT entry, we should initialize it.
401   if (!got.isLocal(rsym) || ResolveInfo::Section != rsym->type()) {
402     if (!got.isPrimaryGOTConsumed())
403       got_entry->setValue(pReloc.symValue());
404   }
405 
406   if (got.isPrimaryGOTConsumed())
407     helper_SetupRelDynForGOTEntry(*got_entry, pReloc,
408                                   got.isLocal(rsym) ? NULL : rsym, pParent);
409 
410   return *got_entry;
411 }
412 
413 static
helper_GetGOTOffset(Relocation & pReloc,MipsRelocator & pParent)414 Relocator::Address helper_GetGOTOffset(Relocation& pReloc,
415                                        MipsRelocator& pParent)
416 {
417   MipsGNULDBackend& ld_backend = pParent.getTarget();
418   MipsGOT& got = ld_backend.getGOT();
419   MipsGOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent);
420   return got.getGPRelOffset(pParent.getApplyingInput(), got_entry);
421 }
422 
423 static
helper_CalcAHL(const Relocation & pHiReloc,const Relocation & pLoReloc)424 int32_t helper_CalcAHL(const Relocation& pHiReloc, const Relocation& pLoReloc)
425 {
426   assert((pHiReloc.type() == llvm::ELF::R_MIPS_HI16 ||
427           pHiReloc.type() == llvm::ELF::R_MIPS_GOT16) &&
428          pLoReloc.type() == llvm::ELF::R_MIPS_LO16 &&
429          "Incorrect type of relocation for AHL calculation");
430 
431   // Note the addend is section symbol offset here
432   assert (pHiReloc.addend() == pLoReloc.addend());
433 
434   int32_t AHI = pHiReloc.target();
435   int32_t ALO = pLoReloc.target();
436   int32_t AHL = ((AHI & 0xFFFF) << 16) + (int16_t)(ALO & 0xFFFF) +
437                  pLoReloc.addend();
438   return AHL;
439 }
440 
441 static
helper_DynRel(Relocation & pReloc,MipsRelocator & pParent)442 void helper_DynRel(Relocation& pReloc, MipsRelocator& pParent)
443 {
444   ResolveInfo* rsym = pReloc.symInfo();
445   MipsGNULDBackend& ld_backend = pParent.getTarget();
446   MipsGOT& got = ld_backend.getGOT();
447 
448   Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
449 
450   rel_entry.setType(llvm::ELF::R_MIPS_REL32);
451   rel_entry.targetRef() = pReloc.targetRef();
452 
453   Relocator::DWord A = pReloc.target() + pReloc.addend();
454   Relocator::DWord S = pReloc.symValue();
455 
456   if (got.isLocal(rsym)) {
457     rel_entry.setSymInfo(NULL);
458     pReloc.target() = A + S;
459   }
460   else {
461     rel_entry.setSymInfo(rsym);
462     // Don't add symbol value that will be resolved by the dynamic linker
463     pReloc.target() = A;
464   }
465 }
466 
467 //=========================================//
468 // Relocation functions implementation     //
469 //=========================================//
470 
471 // R_MIPS_NONE and those unsupported/deprecated relocation type
472 static
none(Relocation & pReloc,MipsRelocator & pParent)473 MipsRelocator::Result none(Relocation& pReloc, MipsRelocator& pParent)
474 {
475   return MipsRelocator::OK;
476 }
477 
478 // R_MIPS_32: S + A
479 static
abs32(Relocation & pReloc,MipsRelocator & pParent)480 MipsRelocator::Result abs32(Relocation& pReloc, MipsRelocator& pParent)
481 {
482   ResolveInfo* rsym = pReloc.symInfo();
483 
484   Relocator::DWord A = pReloc.target() + pReloc.addend();
485   Relocator::DWord S = pReloc.symValue();
486 
487   LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
488   // If the flag of target section is not ALLOC, we will not scan this relocation
489   // but perform static relocation. (e.g., applying .debug section)
490   if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
491     pReloc.target() = S + A;
492     return MipsRelocator::OK;
493   }
494 
495   if (rsym->reserved() & MipsRelocator::ReserveRel) {
496     helper_DynRel(pReloc, pParent);
497 
498     return MipsRelocator::OK;
499   }
500 
501   pReloc.target() = (S + A);
502 
503   return MipsRelocator::OK;
504 }
505 
506 // R_MIPS_HI16:
507 //   local/external: ((AHL + S) - (short)(AHL + S)) >> 16
508 //   _gp_disp      : ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16
509 static
hi16(Relocation & pReloc,MipsRelocator & pParent)510 MipsRelocator::Result hi16(Relocation& pReloc, MipsRelocator& pParent)
511 {
512   Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
513   assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_HI16");
514 
515   int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc);
516   int32_t res = 0;
517 
518   pParent.setAHL(AHL);
519 
520   if (helper_isGpDisp(pReloc)) {
521     int32_t P = pReloc.place();
522     int32_t GP = helper_GetGP(pParent);
523     res = ((AHL + GP - P) - (int16_t)(AHL + GP - P)) >> 16;
524   }
525   else {
526     int32_t S = pReloc.symValue();
527     res = ((AHL + S) - (int16_t)(AHL + S)) >> 16;
528   }
529 
530   pReloc.target() &= 0xFFFF0000;
531   pReloc.target() |= (res & 0xFFFF);
532 
533   return MipsRelocator::OK;
534 }
535 
536 // R_MIPS_LO16:
537 //   local/external: AHL + S
538 //   _gp_disp      : AHL + GP - P + 4
539 static
lo16(Relocation & pReloc,MipsRelocator & pParent)540 MipsRelocator::Result lo16(Relocation& pReloc, MipsRelocator& pParent)
541 {
542   int32_t res = 0;
543 
544   if (helper_isGpDisp(pReloc)) {
545     int32_t P = pReloc.place();
546     int32_t GP = helper_GetGP(pParent);
547     int32_t AHL = pParent.getAHL();
548     res = AHL + GP - P + 4;
549   }
550   else {
551     int32_t S = pReloc.symValue();
552     // The previous AHL may be for other hi/lo pairs.
553     // We need to calcuate the lo part now.  It is easy.
554     // Remember to add the section offset to ALO.
555     int32_t ALO = (pReloc.target() & 0xFFFF) + pReloc.addend();
556     res = ALO + S;
557   }
558 
559   pReloc.target() &= 0xFFFF0000;
560   pReloc.target() |= (res & 0xFFFF);
561 
562   return MipsRelocator::OK;
563 }
564 
565 // R_MIPS_GOT16:
566 //   local   : G (calculate AHL and put high 16 bit to GOT)
567 //   external: G
568 static
got16(Relocation & pReloc,MipsRelocator & pParent)569 MipsRelocator::Result got16(Relocation& pReloc, MipsRelocator& pParent)
570 {
571   MipsGNULDBackend& ld_backend = pParent.getTarget();
572   MipsGOT& got = ld_backend.getGOT();
573   ResolveInfo* rsym = pReloc.symInfo();
574   Relocator::Address G = 0;
575 
576   if (rsym->isLocal()) {
577     Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
578     assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_GOT16");
579 
580     int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc);
581     int32_t S = pReloc.symValue();
582 
583     pParent.setAHL(AHL);
584 
585     int32_t res = (AHL + S + 0x8000) & 0xFFFF0000;
586     MipsGOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent);
587 
588     got_entry.setValue(res);
589     G = got.getGPRelOffset(pParent.getApplyingInput(), got_entry);
590   }
591   else {
592     G = helper_GetGOTOffset(pReloc, pParent);
593   }
594 
595   pReloc.target() &= 0xFFFF0000;
596   pReloc.target() |= (G & 0xFFFF);
597 
598   return MipsRelocator::OK;
599 }
600 
601 // R_MIPS_GOTHI16:
602 //   external: (G - (short)G) >> 16 + A
603 static
gothi16(Relocation & pReloc,MipsRelocator & pParent)604 MipsRelocator::Result gothi16(Relocation& pReloc, MipsRelocator& pParent)
605 {
606   int32_t res = 0;
607 
608   Relocator::Address G = helper_GetGOTOffset(pReloc, pParent);
609   int32_t A = pReloc.target() + pReloc.addend();
610 
611   res = (G - (int16_t)G) >> (16 + A);
612 
613   pReloc.target() &= 0xFFFF0000;
614   pReloc.target() |= (res & 0xFFFF);
615 
616   return MipsRelocator::OK;
617 }
618 
619 // R_MIPS_GOTLO16:
620 //   external: G & 0xffff
621 static
gotlo16(Relocation & pReloc,MipsRelocator & pParent)622 MipsRelocator::Result gotlo16(Relocation& pReloc, MipsRelocator& pParent)
623 {
624   Relocator::Address G = helper_GetGOTOffset(pReloc, pParent);
625 
626   pReloc.target() &= 0xFFFF0000;
627   pReloc.target() |= (G & 0xFFFF);
628 
629   return MipsRelocator::OK;
630 }
631 
632 // R_MIPS_CALL16: G
633 static
call16(Relocation & pReloc,MipsRelocator & pParent)634 MipsRelocator::Result call16(Relocation& pReloc, MipsRelocator& pParent)
635 {
636   Relocator::Address G = helper_GetGOTOffset(pReloc, pParent);
637 
638   pReloc.target() &= 0xFFFF0000;
639   pReloc.target() |= (G & 0xFFFF);
640 
641   return MipsRelocator::OK;
642 }
643 
644 // R_MIPS_GPREL32: A + S + GP0 - GP
645 static
gprel32(Relocation & pReloc,MipsRelocator & pParent)646 MipsRelocator::Result gprel32(Relocation& pReloc, MipsRelocator& pParent)
647 {
648   // Remember to add the section offset to A.
649   int32_t A = pReloc.target() + pReloc.addend();
650   int32_t S = pReloc.symValue();
651   int32_t GP = helper_GetGP(pParent);
652 
653   // llvm does not emits SHT_MIPS_REGINFO section.
654   // Assume that GP0 is zero.
655   pReloc.target() = (A + S - GP) & 0xFFFFFFFF;
656 
657   return MipsRelocator::OK;
658 }
659 
660