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