MipsRelocator.cpp revision f7ac0f19a1c8d0ad14bcf6456ce368b830fea886
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
20using namespace mcld;
21
22//===----------------------------------------------------------------------===//
23// Relocation Functions and Tables
24//===----------------------------------------------------------------------===//
25DECL_MIPS_APPLY_RELOC_FUNCS
26
27/// the prototype of applying function
28typedef Relocator::Result (*ApplyFunctionType)(Relocation&, MipsRelocator&);
29
30// the table entry of applying functions
31struct 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
40static const ApplyFunctionTriple ApplyFunctions[] = {
41  DECL_MIPS_APPLY_RELOC_FUNC_PTRS
42};
43
44//===----------------------------------------------------------------------===//
45// MipsRelocator
46//===----------------------------------------------------------------------===//
47MipsRelocator::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
56Relocator::Result
57MipsRelocator::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
69const char* MipsRelocator::getName(Relocation::Type pType) const
70{
71  return ApplyFunctions[pType].name;
72}
73
74Relocator::Size MipsRelocator::getSize(Relocation::Type pType) const
75{
76  return ApplyFunctions[pType].size;
77}
78
79void 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
115bool MipsRelocator::initializeScan(Input& pInput)
116{
117  getTarget().getGOT().initializeScan(pInput);
118  return true;
119}
120
121bool MipsRelocator::finalizeScan(Input& pInput)
122{
123  getTarget().getGOT().finalizeScan(pInput);
124  return true;
125}
126
127bool MipsRelocator::initializeApply(Input& pInput)
128{
129  m_pApplyingInput = &pInput;
130  return true;
131}
132
133bool MipsRelocator::finalizeApply(Input& pInput)
134{
135  m_pApplyingInput = NULL;
136  return true;
137}
138
139void 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
228void 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//===----------------------------------------------------------------------===//
323static const char * const GP_DISP_NAME = "_gp_disp";
324
325// Find next R_MIPS_LO16 relocation paired to pReloc.
326static
327Relocation* 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.
342static
343bool helper_isGpDisp(const Relocation& pReloc)
344{
345  const ResolveInfo* rsym = pReloc.symInfo();
346  return 0 == strcmp(GP_DISP_NAME, rsym->name());
347}
348
349static
350Relocator::Address helper_GetGP(MipsRelocator& pParent)
351{
352  return pParent.getTarget().getGOT().getGPAddr(pParent.getApplyingInput());
353}
354
355static
356void 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
369static
370MipsGOTEntry& 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
413static
414Relocator::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
423static
424int32_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
441static
442void 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
472static
473MipsRelocator::Result none(Relocation& pReloc, MipsRelocator& pParent)
474{
475  return MipsRelocator::OK;
476}
477
478// R_MIPS_32: S + A
479static
480MipsRelocator::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
509static
510MipsRelocator::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
539static
540MipsRelocator::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
568static
569MipsRelocator::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
603static
604MipsRelocator::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
621static
622MipsRelocator::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
633static
634MipsRelocator::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
645static
646MipsRelocator::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