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