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