1 //===- HexagonRelocator.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 "HexagonRelocator.h"
10 #include "HexagonRelocationFunctions.h"
11 #include "HexagonEncodings.h"
12
13 #include "mcld/LD/ELFFileFormat.h"
14 #include "mcld/LD/LDSymbol.h"
15 #include "mcld/Support/MsgHandling.h"
16
17 #include <llvm/ADT/Twine.h>
18 #include <llvm/Support/DataTypes.h>
19 #include <llvm/Support/ELF.h>
20
21 namespace mcld {
22
23 //===--------------------------------------------------------------------===//
24 // Relocation Helper Functions
25 //===--------------------------------------------------------------------===//
26 /// helper_DynRel - Get an relocation entry in .rela.dyn
helper_DynRel_init(ResolveInfo * pSym,Fragment & pFrag,uint64_t pOffset,Relocator::Type pType,HexagonRelocator & pParent)27 static Relocation& helper_DynRel_init(ResolveInfo* pSym,
28 Fragment& pFrag,
29 uint64_t pOffset,
30 Relocator::Type pType,
31 HexagonRelocator& pParent) {
32 HexagonLDBackend& ld_backend = pParent.getTarget();
33 Relocation& rela_entry = *ld_backend.getRelaDyn().create();
34 rela_entry.setType(pType);
35 rela_entry.targetRef().assign(pFrag, pOffset);
36 if (pType == llvm::ELF::R_HEX_RELATIVE || pSym == NULL)
37 rela_entry.setSymInfo(0);
38 else
39 rela_entry.setSymInfo(pSym);
40
41 return rela_entry;
42 }
43
44 /// helper_use_relative_reloc - Check if symbol can use relocation
45 /// R_HEX_RELATIVE
helper_use_relative_reloc(const ResolveInfo & pSym,const HexagonRelocator & pFactory)46 static bool helper_use_relative_reloc(const ResolveInfo& pSym,
47 const HexagonRelocator& pFactory) {
48 // if symbol is dynamic or undefine or preemptible
49 if (pSym.isDyn() || pSym.isUndef() ||
50 pFactory.getTarget().isSymbolPreemptible(pSym))
51 return false;
52 return true;
53 }
54
helper_GOT_init(Relocation & pReloc,bool pHasRel,HexagonRelocator & pParent)55 static HexagonGOTEntry& helper_GOT_init(Relocation& pReloc,
56 bool pHasRel,
57 HexagonRelocator& pParent) {
58 // rsym - The relocation target symbol
59 ResolveInfo* rsym = pReloc.symInfo();
60 HexagonLDBackend& ld_backend = pParent.getTarget();
61 assert(pParent.getSymGOTMap().lookUp(*rsym) == NULL);
62
63 HexagonGOTEntry* got_entry = ld_backend.getGOT().create();
64 pParent.getSymGOTMap().record(*rsym, *got_entry);
65
66 if (!pHasRel) {
67 // No corresponding dynamic relocation, initialize to the symbol value.
68 got_entry->setValue(HexagonRelocator::SymVal);
69 } else {
70 // Initialize got_entry content and the corresponding dynamic relocation.
71 if (helper_use_relative_reloc(*rsym, pParent)) {
72 helper_DynRel_init(
73 rsym, *got_entry, 0x0, llvm::ELF::R_HEX_RELATIVE, pParent);
74 got_entry->setValue(HexagonRelocator::SymVal);
75 } else {
76 helper_DynRel_init(
77 rsym, *got_entry, 0x0, llvm::ELF::R_HEX_GLOB_DAT, pParent);
78 got_entry->setValue(0);
79 }
80 }
81 return *got_entry;
82 }
83
helper_get_GOT_address(ResolveInfo & pSym,HexagonRelocator & pParent)84 static Relocator::Address helper_get_GOT_address(ResolveInfo& pSym,
85 HexagonRelocator& pParent) {
86 HexagonGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(pSym);
87 assert(got_entry != NULL);
88 return pParent.getTarget().getGOT().addr() + got_entry->getOffset();
89 }
90
helper_PLT_init(Relocation & pReloc,HexagonRelocator & pParent)91 static PLTEntryBase& helper_PLT_init(Relocation& pReloc,
92 HexagonRelocator& pParent) {
93 // rsym - The relocation target symbol
94 ResolveInfo* rsym = pReloc.symInfo();
95 HexagonLDBackend& ld_backend = pParent.getTarget();
96 assert(pParent.getSymPLTMap().lookUp(*rsym) == NULL);
97
98 PLTEntryBase* plt_entry = ld_backend.getPLT().create();
99 pParent.getSymPLTMap().record(*rsym, *plt_entry);
100
101 assert(pParent.getSymGOTPLTMap().lookUp(*rsym) == NULL &&
102 "PLT entry not exist, but DynRel entry exist!");
103 HexagonGOTEntry* gotplt_entry = ld_backend.getGOTPLT().create();
104 pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
105 // init the corresponding rel entry in .rela.plt
106 Relocation& rela_entry = *ld_backend.getRelaPLT().create();
107 rela_entry.setType(llvm::ELF::R_HEX_JMP_SLOT);
108 rela_entry.targetRef().assign(*gotplt_entry);
109 rela_entry.setSymInfo(rsym);
110
111 return *plt_entry;
112 }
113
helper_get_PLT_address(ResolveInfo & pSym,HexagonRelocator & pParent)114 static Relocator::Address helper_get_PLT_address(ResolveInfo& pSym,
115 HexagonRelocator& pParent) {
116 PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(pSym);
117 assert(plt_entry != NULL);
118 return pParent.getTarget().getPLT().addr() + plt_entry->getOffset();
119 }
120
121 //===--------------------------------------------------------------------===//
122 // Relocation Functions and Tables
123 //===--------------------------------------------------------------------===//
124 DECL_HEXAGON_APPLY_RELOC_FUNCS
125
126 /// the prototype of applying function
127 typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc,
128 HexagonRelocator& pParent);
129
130 // the table entry of applying functions
131 struct ApplyFunctionTriple {
132 ApplyFunctionType func;
133 unsigned int type;
134 const char* name;
135 };
136
137 // declare the table of applying functions
138 static const ApplyFunctionTriple ApplyFunctions[] = {
139 DECL_HEXAGON_APPLY_RELOC_FUNC_PTRS};
140
findBitMask(uint32_t insn,Instruction * encodings,int32_t numInsns)141 static uint32_t findBitMask(uint32_t insn,
142 Instruction* encodings,
143 int32_t numInsns) {
144 for (int32_t i = 0; i < numInsns; ++i) {
145 if (((insn & 0xc000) == 0) && !(encodings[i].isDuplex))
146 continue;
147
148 if (((insn & 0xc000) != 0) && (encodings[i].isDuplex))
149 continue;
150
151 if (((encodings[i].insnMask) & insn) == encodings[i].insnCmpMask)
152 return encodings[i].insnBitMask;
153 }
154 assert(0);
155 // Should not be here, but add a return for -Werror=return-type
156 // error: control reaches end of non-void function
157 return -1;
158 }
159
160 #define FINDBITMASK(INSN) \
161 findBitMask((uint32_t)INSN, \
162 insn_encodings, \
163 sizeof(insn_encodings) / sizeof(Instruction))
164
165 //===--------------------------------------------------------------------===//
166 // HexagonRelocator
167 //===--------------------------------------------------------------------===//
HexagonRelocator(HexagonLDBackend & pParent,const LinkerConfig & pConfig)168 HexagonRelocator::HexagonRelocator(HexagonLDBackend& pParent,
169 const LinkerConfig& pConfig)
170 : Relocator(pConfig), m_Target(pParent) {
171 }
172
~HexagonRelocator()173 HexagonRelocator::~HexagonRelocator() {
174 }
175
applyRelocation(Relocation & pRelocation)176 Relocator::Result HexagonRelocator::applyRelocation(Relocation& pRelocation) {
177 Relocation::Type type = pRelocation.type();
178
179 if (type > 85) { // 86-255 relocs do not exists for Hexagon
180 return Relocator::Unknown;
181 }
182
183 // apply the relocation
184 return ApplyFunctions[type].func(pRelocation, *this);
185 }
186
getName(Relocation::Type pType) const187 const char* HexagonRelocator::getName(Relocation::Type pType) const {
188 return ApplyFunctions[pType].name;
189 }
190
getSize(Relocation::Type pType) const191 Relocator::Size HexagonRelocator::getSize(Relocation::Type pType) const {
192 return 32;
193 }
194
scanRelocation(Relocation & pReloc,IRBuilder & pLinker,Module & pModule,LDSection & pSection,Input & pInput)195 void HexagonRelocator::scanRelocation(Relocation& pReloc,
196 IRBuilder& pLinker,
197 Module& pModule,
198 LDSection& pSection,
199 Input& pInput) {
200 if (LinkerConfig::Object == config().codeGenType())
201 return;
202
203 // rsym - The relocation target symbol
204 ResolveInfo* rsym = pReloc.symInfo();
205 assert(rsym != NULL &&
206 "ResolveInfo of relocation not set while scanRelocation");
207
208 if (config().isCodeStatic())
209 return;
210
211 assert(pSection.getLink() != NULL);
212 if ((pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC) == 0)
213 return;
214
215 if (rsym->isLocal()) // rsym is local
216 scanLocalReloc(pReloc, pLinker, pModule, pSection);
217 else // rsym is external
218 scanGlobalReloc(pReloc, pLinker, pModule, pSection);
219
220 // check if we should issue undefined reference for the relocation target
221 // symbol
222 if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
223 issueUndefRef(pReloc, pSection, pInput);
224 }
225
addCopyReloc(ResolveInfo & pSym,HexagonLDBackend & pTarget)226 void HexagonRelocator::addCopyReloc(ResolveInfo& pSym,
227 HexagonLDBackend& pTarget) {
228 Relocation& rel_entry = *pTarget.getRelaDyn().create();
229 rel_entry.setType(pTarget.getCopyRelType());
230 assert(pSym.outSymbol()->hasFragRef());
231 rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef());
232 rel_entry.setSymInfo(&pSym);
233 }
234
scanLocalReloc(Relocation & pReloc,IRBuilder & pBuilder,Module & pModule,LDSection & pSection)235 void HexagonRelocator::scanLocalReloc(Relocation& pReloc,
236 IRBuilder& pBuilder,
237 Module& pModule,
238 LDSection& pSection) {
239 // rsym - The relocation target symbol
240 ResolveInfo* rsym = pReloc.symInfo();
241
242 switch (pReloc.type()) {
243 case llvm::ELF::R_HEX_LO16:
244 case llvm::ELF::R_HEX_HI16:
245 case llvm::ELF::R_HEX_16:
246 case llvm::ELF::R_HEX_8:
247 case llvm::ELF::R_HEX_32_6_X:
248 case llvm::ELF::R_HEX_16_X:
249 case llvm::ELF::R_HEX_12_X:
250 case llvm::ELF::R_HEX_11_X:
251 case llvm::ELF::R_HEX_10_X:
252 case llvm::ELF::R_HEX_9_X:
253 case llvm::ELF::R_HEX_8_X:
254 case llvm::ELF::R_HEX_7_X:
255 case llvm::ELF::R_HEX_6_X:
256 assert(!(rsym->reserved() & ReserveRel) &&
257 "Cannot apply this relocation for read only section");
258 return;
259
260 case llvm::ELF::R_HEX_32:
261 // If buiding PIC object (shared library or PIC executable),
262 // a dynamic relocations with RELATIVE type to this location is needed.
263 // Reserve an entry in .rel.dyn
264 if (config().isCodeIndep()) {
265 Relocation& reloc = helper_DynRel_init(rsym,
266 *pReloc.targetRef().frag(),
267 pReloc.targetRef().offset(),
268 llvm::ELF::R_HEX_RELATIVE,
269 *this);
270 // we need to set up the relocation addend at apply relocation, record
271 // the
272 // relocation
273 getRelRelMap().record(pReloc, reloc);
274
275 // set Rel bit
276 rsym->setReserved(rsym->reserved() | ReserveRel);
277 getTarget().checkAndSetHasTextRel(*pSection.getLink());
278 }
279 return;
280
281 default:
282 return;
283 }
284 }
285
scanGlobalReloc(Relocation & pReloc,IRBuilder & pBuilder,Module & pModule,LDSection & pSection)286 void HexagonRelocator::scanGlobalReloc(Relocation& pReloc,
287 IRBuilder& pBuilder,
288 Module& pModule,
289 LDSection& pSection) {
290 // rsym - The relocation target symbol
291 ResolveInfo* rsym = pReloc.symInfo();
292 HexagonLDBackend& ld_backend = getTarget();
293
294 switch (pReloc.type()) {
295 case llvm::ELF::R_HEX_LO16:
296 case llvm::ELF::R_HEX_HI16:
297 case llvm::ELF::R_HEX_16:
298 case llvm::ELF::R_HEX_8:
299 case llvm::ELF::R_HEX_32_6_X:
300 case llvm::ELF::R_HEX_16_X:
301 case llvm::ELF::R_HEX_12_X:
302 case llvm::ELF::R_HEX_11_X:
303 case llvm::ELF::R_HEX_10_X:
304 case llvm::ELF::R_HEX_9_X:
305 case llvm::ELF::R_HEX_8_X:
306 case llvm::ELF::R_HEX_7_X:
307 case llvm::ELF::R_HEX_6_X:
308 assert(!(rsym->reserved() & ReserveRel) &&
309 "Cannot apply this relocation for read only section");
310 return;
311
312 case llvm::ELF::R_HEX_32:
313 if (ld_backend.symbolNeedsPLT(*rsym)) {
314 // create PLT for this symbol if it does not have.
315 if (!(rsym->reserved() & ReservePLT)) {
316 helper_PLT_init(pReloc, *this);
317 rsym->setReserved(rsym->reserved() | ReservePLT);
318 }
319 }
320
321 if (ld_backend.symbolNeedsDynRel(
322 *rsym, (rsym->reserved() & ReservePLT), true)) {
323 if (ld_backend.symbolNeedsCopyReloc(pReloc, *rsym)) {
324 LDSymbol& cpy_sym =
325 defineSymbolforCopyReloc(pBuilder, *rsym, ld_backend);
326 addCopyReloc(*cpy_sym.resolveInfo(), ld_backend);
327 } else {
328 Relocation& reloc = helper_DynRel_init(rsym,
329 *pReloc.targetRef().frag(),
330 pReloc.targetRef().offset(),
331 llvm::ELF::R_HEX_RELATIVE,
332 *this);
333 // we need to set up the relocation addend at apply relocation, record
334 // the
335 // relocation
336 getRelRelMap().record(pReloc, reloc);
337 rsym->setReserved(rsym->reserved() | ReserveRel);
338 ld_backend.checkAndSetHasTextRel(*pSection.getLink());
339 }
340 }
341 return;
342
343 case llvm::ELF::R_HEX_GOTREL_LO16:
344 case llvm::ELF::R_HEX_GOTREL_HI16:
345 case llvm::ELF::R_HEX_GOTREL_32:
346 case llvm::ELF::R_HEX_GOTREL_32_6_X:
347 case llvm::ELF::R_HEX_GOTREL_16_X:
348 case llvm::ELF::R_HEX_GOTREL_11_X:
349 // This assumes that GOT exists
350 return;
351
352 case llvm::ELF::R_HEX_GOT_LO16:
353 case llvm::ELF::R_HEX_GOT_HI16:
354 case llvm::ELF::R_HEX_GOT_32:
355 case llvm::ELF::R_HEX_GOT_16:
356 case llvm::ELF::R_HEX_GOT_32_6_X:
357 case llvm::ELF::R_HEX_GOT_16_X:
358 case llvm::ELF::R_HEX_GOT_11_X:
359 // Symbol needs GOT entry, reserve entry in .got
360 // return if we already create GOT for this symbol
361 if (rsym->reserved() & ReserveGOT)
362 return;
363 // If the GOT is used in statically linked binaries,
364 // the GOT entry is enough and no relocation is needed.
365 if (config().isCodeStatic())
366 helper_GOT_init(pReloc, false, *this);
367 else
368 helper_GOT_init(pReloc, true, *this);
369 // set GOT bit
370 rsym->setReserved(rsym->reserved() | ReserveGOT);
371 return;
372
373 case llvm::ELF::R_HEX_B22_PCREL:
374 case llvm::ELF::R_HEX_B15_PCREL:
375 case llvm::ELF::R_HEX_B7_PCREL:
376 case llvm::ELF::R_HEX_B13_PCREL:
377 case llvm::ELF::R_HEX_B9_PCREL:
378 case llvm::ELF::R_HEX_B32_PCREL_X:
379 case llvm::ELF::R_HEX_B22_PCREL_X:
380 case llvm::ELF::R_HEX_B15_PCREL_X:
381 case llvm::ELF::R_HEX_B13_PCREL_X:
382 case llvm::ELF::R_HEX_B9_PCREL_X:
383 case llvm::ELF::R_HEX_B7_PCREL_X:
384 case llvm::ELF::R_HEX_32_PCREL:
385 case llvm::ELF::R_HEX_6_PCREL_X:
386 case llvm::ELF::R_HEX_PLT_B22_PCREL:
387 if (rsym->reserved() & ReservePLT)
388 return;
389 if (ld_backend.symbolNeedsPLT(*rsym) ||
390 pReloc.type() == llvm::ELF::R_HEX_PLT_B22_PCREL) {
391 helper_PLT_init(pReloc, *this);
392 rsym->setReserved(rsym->reserved() | ReservePLT);
393 }
394 return;
395
396 default:
397 break;
398 } // end of switch
399 }
400
401 /// defineSymbolforCopyReloc
402 /// For a symbol needing copy relocation, define a copy symbol in the BSS
403 /// section and all other reference to this symbol should refer to this
404 /// copy.
405 /// @note This is executed at `scan relocation' stage.
defineSymbolforCopyReloc(IRBuilder & pBuilder,const ResolveInfo & pSym,HexagonLDBackend & pTarget)406 LDSymbol& HexagonRelocator::defineSymbolforCopyReloc(
407 IRBuilder& pBuilder,
408 const ResolveInfo& pSym,
409 HexagonLDBackend& pTarget) {
410 // get or create corresponding BSS LDSection
411 LDSection* bss_sect_hdr = NULL;
412 ELFFileFormat* file_format = pTarget.getOutputFormat();
413 if (ResolveInfo::ThreadLocal == pSym.type())
414 bss_sect_hdr = &file_format->getTBSS();
415 else
416 bss_sect_hdr = &file_format->getBSS();
417
418 // get or create corresponding BSS SectionData
419 assert(bss_sect_hdr != NULL);
420 SectionData* bss_section = NULL;
421 if (bss_sect_hdr->hasSectionData())
422 bss_section = bss_sect_hdr->getSectionData();
423 else
424 bss_section = IRBuilder::CreateSectionData(*bss_sect_hdr);
425
426 // Determine the alignment by the symbol value
427 // FIXME: here we use the largest alignment
428 uint32_t addralign = config().targets().bitclass() / 8;
429
430 // allocate space in BSS for the copy symbol
431 Fragment* frag = new FillFragment(0x0, 1, pSym.size());
432 uint64_t size = ObjectBuilder::AppendFragment(*frag, *bss_section, addralign);
433 bss_sect_hdr->setSize(bss_sect_hdr->size() + size);
434
435 // change symbol binding to Global if it's a weak symbol
436 ResolveInfo::Binding binding = (ResolveInfo::Binding)pSym.binding();
437 if (binding == ResolveInfo::Weak)
438 binding = ResolveInfo::Global;
439
440 // Define the copy symbol in the bss section and resolve it
441 LDSymbol* cpy_sym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
442 pSym.name(),
443 (ResolveInfo::Type)pSym.type(),
444 ResolveInfo::Define,
445 binding,
446 pSym.size(), // size
447 0x0, // value
448 FragmentRef::Create(*frag, 0x0),
449 (ResolveInfo::Visibility)pSym.other());
450
451 // output all other alias symbols if any
452 Module& pModule = pBuilder.getModule();
453 Module::AliasList* alias_list = pModule.getAliasList(pSym);
454 if (alias_list != NULL) {
455 Module::alias_iterator it, it_e = alias_list->end();
456 for (it = alias_list->begin(); it != it_e; ++it) {
457 const ResolveInfo* alias = *it;
458 if (alias != &pSym && alias->isDyn()) {
459 pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
460 alias->name(),
461 (ResolveInfo::Type)alias->type(),
462 ResolveInfo::Define,
463 binding,
464 alias->size(), // size
465 0x0, // value
466 FragmentRef::Create(*frag, 0x0),
467 (ResolveInfo::Visibility)alias->other());
468 }
469 }
470 }
471
472 return *cpy_sym;
473 }
474
partialScanRelocation(Relocation & pReloc,Module & pModule)475 void HexagonRelocator::partialScanRelocation(Relocation& pReloc,
476 Module& pModule) {
477 pReloc.updateAddend();
478 // if we meet a section symbol
479 if (pReloc.symInfo()->type() == ResolveInfo::Section) {
480 LDSymbol* input_sym = pReloc.symInfo()->outSymbol();
481
482 // 1. update the relocation target offset
483 assert(input_sym->hasFragRef());
484 // 2. get the output LDSection which the symbol defined in
485 const LDSection& out_sect =
486 input_sym->fragRef()->frag()->getParent()->getSection();
487 ResolveInfo* sym_info =
488 pModule.getSectionSymbolSet().get(out_sect)->resolveInfo();
489 // set relocation target symbol to the output section symbol's resolveInfo
490 pReloc.setSymInfo(sym_info);
491 }
492 }
493
494 //=========================================//
495 // Each relocation function implementation //
496 //=========================================//
497
498 // R_HEX_NONE
none(Relocation & pReloc,HexagonRelocator & pParent)499 Relocator::Result none(Relocation& pReloc, HexagonRelocator& pParent) {
500 return Relocator::OK;
501 }
502
503 // R_HEX_32 and its class of relocations use only addend and symbol value
504 // S + A : result is unsigned truncate.
505 // Exception: R_HEX_32_6_X : unsigned verify
applyAbs(Relocation & pReloc)506 Relocator::Result applyAbs(Relocation& pReloc) {
507 Relocator::Address S = pReloc.symValue();
508 Relocator::DWord A = pReloc.addend();
509 uint32_t result = (uint32_t)(S + A);
510 uint32_t bitMask = 0;
511 uint32_t effectiveBits = 0;
512 uint32_t alignment = 1;
513 uint32_t shift = 0;
514
515 switch (pReloc.type()) {
516 case llvm::ELF::R_HEX_LO16:
517 bitMask = 0x00c03fff;
518 break;
519
520 case llvm::ELF::R_HEX_HI16:
521 shift = 16;
522 bitMask = 0x00c03fff;
523 break;
524
525 case llvm::ELF::R_HEX_32:
526 bitMask = 0xffffffff;
527 break;
528
529 case llvm::ELF::R_HEX_16:
530 bitMask = 0x0000ffff;
531 alignment = 2;
532 break;
533
534 case llvm::ELF::R_HEX_8:
535 bitMask = 0x000000ff;
536 alignment = 1;
537 break;
538
539 case llvm::ELF::R_HEX_12_X:
540 bitMask = 0x000007e0;
541 break;
542
543 case llvm::ELF::R_HEX_32_6_X:
544 bitMask = 0xfff3fff;
545 shift = 6;
546 effectiveBits = 26;
547 break;
548
549 case llvm::ELF::R_HEX_16_X:
550 case llvm::ELF::R_HEX_11_X:
551 case llvm::ELF::R_HEX_10_X:
552 case llvm::ELF::R_HEX_9_X:
553 case llvm::ELF::R_HEX_8_X:
554 case llvm::ELF::R_HEX_7_X:
555 case llvm::ELF::R_HEX_6_X:
556 bitMask = FINDBITMASK(pReloc.target());
557 break;
558
559 default:
560 // show proper error
561 fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type())
562 << "mclinker@googlegroups.com";
563 }
564
565 if ((shift != 0) && (result % alignment != 0))
566 return Relocator::BadReloc;
567
568 result >>= shift;
569
570 if (effectiveBits) {
571 uint32_t range = 1 << effectiveBits;
572 if (result > (range - 1))
573 return Relocator::Overflow;
574 }
575
576 pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
577 return Relocator::OK;
578 }
579
580 // R_HEX_B22_PCREL and its class of relocations, use
581 // S + A - P : result is signed verify.
582 // Exception: R_HEX_B32_PCREL_X : signed truncate
583 // Another Exception: R_HEX_6_PCREL_X is unsigned truncate
applyRel(Relocation & pReloc,int64_t pResult)584 Relocator::Result applyRel(Relocation& pReloc, int64_t pResult) {
585 uint32_t bitMask = 0;
586 uint32_t effectiveBits = 0;
587 uint32_t alignment = 1;
588 uint32_t result;
589 uint32_t shift = 0;
590
591 switch (pReloc.type()) {
592 case llvm::ELF::R_HEX_B22_PCREL:
593 bitMask = 0x01ff3ffe;
594 effectiveBits = 22;
595 alignment = 4;
596 shift = 2;
597 break;
598
599 case llvm::ELF::R_HEX_B15_PCREL:
600 bitMask = 0x00df20fe;
601 effectiveBits = 15;
602 alignment = 4;
603 shift = 2;
604 break;
605
606 case llvm::ELF::R_HEX_B7_PCREL:
607 bitMask = 0x00001f18;
608 effectiveBits = 7;
609 alignment = 4;
610 shift = 2;
611 break;
612
613 case llvm::ELF::R_HEX_B13_PCREL:
614 bitMask = 0x00202ffe;
615 effectiveBits = 13;
616 alignment = 4;
617 shift = 2;
618 break;
619
620 case llvm::ELF::R_HEX_B9_PCREL:
621 bitMask = 0x003000fe;
622 effectiveBits = 9;
623 alignment = 4;
624 shift = 2;
625 break;
626
627 case llvm::ELF::R_HEX_B32_PCREL_X:
628 bitMask = 0xfff3fff;
629 shift = 6;
630 break;
631
632 case llvm::ELF::R_HEX_B22_PCREL_X:
633 bitMask = 0x01ff3ffe;
634 effectiveBits = 22;
635 pResult &= 0x3f;
636 break;
637
638 case llvm::ELF::R_HEX_B15_PCREL_X:
639 bitMask = 0x00df20fe;
640 effectiveBits = 15;
641 pResult &= 0x3f;
642 break;
643
644 case llvm::ELF::R_HEX_B13_PCREL_X:
645 bitMask = 0x00202ffe;
646 effectiveBits = 13;
647 pResult &= 0x3f;
648 break;
649
650 case llvm::ELF::R_HEX_B9_PCREL_X:
651 bitMask = 0x003000fe;
652 effectiveBits = 9;
653 pResult &= 0x3f;
654 break;
655
656 case llvm::ELF::R_HEX_B7_PCREL_X:
657 bitMask = 0x00001f18;
658 effectiveBits = 7;
659 pResult &= 0x3f;
660 break;
661
662 case llvm::ELF::R_HEX_32_PCREL:
663 bitMask = 0xffffffff;
664 effectiveBits = 32;
665 break;
666
667 case llvm::ELF::R_HEX_6_PCREL_X:
668 // This is unique since it has a unsigned operand and its truncated
669 bitMask = FINDBITMASK(pReloc.target());
670 result = pReloc.addend() + pReloc.symValue() - pReloc.place();
671 pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
672 return Relocator::OK;
673
674 default:
675 // show proper error
676 fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type())
677 << "mclinker@googlegroups.com";
678 }
679
680 if ((shift != 0) && (pResult % alignment != 0))
681 return Relocator::BadReloc;
682
683 pResult >>= shift;
684
685 if (effectiveBits) {
686 int64_t range = 1LL << (effectiveBits - 1);
687 if ((pResult > (range - 1)) || (pResult < -range))
688 return Relocator::Overflow;
689 }
690
691 pReloc.target() |= (uint32_t)ApplyMask<int32_t>(bitMask, pResult);
692 return Relocator::OK;
693 }
694
relocAbs(Relocation & pReloc,HexagonRelocator & pParent)695 Relocator::Result relocAbs(Relocation& pReloc, HexagonRelocator& pParent) {
696 ResolveInfo* rsym = pReloc.symInfo();
697 Relocator::Address S = pReloc.symValue();
698 Relocator::DWord A = pReloc.addend();
699
700 Relocation* rel_entry = pParent.getRelRelMap().lookUp(pReloc);
701 bool has_dyn_rel = (rel_entry != NULL);
702
703 // if the flag of target section is not ALLOC, we eprform only static
704 // relocation.
705 if (0 == (llvm::ELF::SHF_ALLOC &
706 pReloc.targetRef().frag()->getParent()->getSection().flag())) {
707 return applyAbs(pReloc);
708 }
709
710 // a local symbol with .rela type relocation
711 if (rsym->isLocal() && has_dyn_rel) {
712 rel_entry->setAddend(S + A);
713 return Relocator::OK;
714 }
715
716 if (!rsym->isLocal()) {
717 if (rsym->reserved() & HexagonRelocator::ReservePLT) {
718 S = helper_get_PLT_address(*rsym, pParent);
719 }
720
721 if (has_dyn_rel) {
722 if (llvm::ELF::R_HEX_32 == pReloc.type() &&
723 helper_use_relative_reloc(*rsym, pParent)) {
724 rel_entry->setAddend(S + A);
725 } else {
726 rel_entry->setAddend(A);
727 return Relocator::OK;
728 }
729 }
730 }
731
732 return applyAbs(pReloc);
733 }
734
relocPCREL(Relocation & pReloc,HexagonRelocator & pParent)735 Relocator::Result relocPCREL(Relocation& pReloc, HexagonRelocator& pParent) {
736 ResolveInfo* rsym = pReloc.symInfo();
737 int64_t result;
738
739 Relocator::Address S = pReloc.symValue();
740 Relocator::DWord A = pReloc.addend();
741 Relocator::DWord P = pReloc.place();
742
743 FragmentRef& target_fragref = pReloc.targetRef();
744 Fragment* target_frag = target_fragref.frag();
745 LDSection& target_sect = target_frag->getParent()->getSection();
746
747 result = (int64_t)(S + A - P);
748
749 // for relocs inside non ALLOC, just apply
750 if ((llvm::ELF::SHF_ALLOC & target_sect.flag()) == 0) {
751 return applyRel(pReloc, result);
752 }
753
754 if (!rsym->isLocal()) {
755 if (rsym->reserved() & HexagonRelocator::ReservePLT) {
756 S = helper_get_PLT_address(*rsym, pParent);
757 result = (int64_t)(S + A - P);
758 applyRel(pReloc, result);
759 return Relocator::OK;
760 }
761 }
762
763 return applyRel(pReloc, result);
764 }
765
766 // R_HEX_GPREL16_0 and its class : Unsigned Verify
relocGPREL(Relocation & pReloc,HexagonRelocator & pParent)767 Relocator::Result relocGPREL(Relocation& pReloc, HexagonRelocator& pParent) {
768 Relocator::Address S = pReloc.symValue();
769 Relocator::DWord A = pReloc.addend();
770 Relocator::DWord GP = pParent.getTarget().getGP();
771
772 uint32_t result = (uint32_t)(S + A - GP);
773 uint32_t shift = 0;
774 uint32_t alignment = 1;
775
776 switch (pReloc.type()) {
777 case llvm::ELF::R_HEX_GPREL16_0:
778 break;
779
780 case llvm::ELF::R_HEX_GPREL16_1:
781 shift = 1;
782 alignment = 2;
783 break;
784
785 case llvm::ELF::R_HEX_GPREL16_2:
786 shift = 2;
787 alignment = 4;
788 break;
789
790 case llvm::ELF::R_HEX_GPREL16_3:
791 shift = 3;
792 alignment = 8;
793 break;
794
795 default:
796 // show proper error
797 fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type())
798 << "mclinker@googlegroups.com";
799 }
800
801 uint32_t range = 1 << 16;
802 uint32_t bitMask = FINDBITMASK(pReloc.target());
803
804 if ((shift != 0) && (result % alignment != 0))
805 return Relocator::BadReloc;
806
807 result >>= shift;
808
809 if (result < range - 1) {
810 pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
811 return Relocator::OK;
812 }
813 return Relocator::Overflow;
814 }
815
816 // R_HEX_PLT_B22_PCREL: PLT(S) + A - P
relocPLTB22PCREL(Relocation & pReloc,HexagonRelocator & pParent)817 Relocator::Result relocPLTB22PCREL(Relocation& pReloc,
818 HexagonRelocator& pParent) {
819 // PLT_S depends on if there is a PLT entry.
820 Relocator::Address PLT_S;
821 if ((pReloc.symInfo()->reserved() & HexagonRelocator::ReservePLT))
822 PLT_S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
823 else
824 PLT_S = pReloc.symValue();
825 Relocator::Address P = pReloc.place();
826 uint32_t bitMask = FINDBITMASK(pReloc.target());
827 uint32_t result = (PLT_S + pReloc.addend() - P) >> 2;
828 pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(bitMask, result);
829 return Relocator::OK;
830 }
831
832 // R_HEX_GOT_LO16 and its class : (G) Signed Truncate
833 // Exception: R_HEX_GOT_16(_X): signed verify
834 // Exception: R_HEX_GOT_11_X : unsigned truncate
relocGOT(Relocation & pReloc,HexagonRelocator & pParent)835 Relocator::Result relocGOT(Relocation& pReloc, HexagonRelocator& pParent) {
836 if (!(pReloc.symInfo()->reserved() & HexagonRelocator::ReserveGOT)) {
837 return Relocator::BadReloc;
838 }
839
840 // set got entry value if needed
841 HexagonGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
842 assert(got_entry != NULL);
843 if (HexagonRelocator::SymVal == got_entry->getValue())
844 got_entry->setValue(pReloc.symValue());
845
846 Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent);
847 Relocator::Address GOT = pParent.getTarget().getGOTSymbolAddr();
848 int32_t result = (int32_t)(GOT_S - GOT);
849 uint32_t effectiveBits = 0;
850 uint32_t alignment = 1;
851 uint32_t bitMask = 0;
852 uint32_t result_u;
853 uint32_t shift = 0;
854
855 switch (pReloc.type()) {
856 case llvm::ELF::R_HEX_GOT_LO16:
857 bitMask = 0x00c03fff;
858 break;
859
860 case llvm::ELF::R_HEX_GOT_HI16:
861 bitMask = 0x00c03fff;
862 shift = 16;
863 alignment = 4;
864 break;
865
866 case llvm::ELF::R_HEX_GOT_32:
867 bitMask = 0xffffffff;
868 break;
869
870 case llvm::ELF::R_HEX_GOT_16:
871 bitMask = FINDBITMASK(pReloc.target());
872 effectiveBits = 16;
873 break;
874
875 case llvm::ELF::R_HEX_GOT_32_6_X:
876 bitMask = 0xfff3fff;
877 shift = 6;
878 break;
879
880 case llvm::ELF::R_HEX_GOT_16_X:
881 bitMask = FINDBITMASK(pReloc.target());
882 effectiveBits = 6;
883 break;
884
885 case llvm::ELF::R_HEX_GOT_11_X:
886 bitMask = FINDBITMASK(pReloc.target());
887 result_u = GOT_S - GOT;
888 pReloc.target() |= ApplyMask<uint32_t>(bitMask, result_u);
889 return Relocator::OK;
890
891 default:
892 // show proper error
893 fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type())
894 << "mclinker@googlegroups.com";
895 }
896
897 if ((shift != 0) && (result % alignment != 0))
898 return Relocator::BadReloc;
899
900 result >>= shift;
901
902 if (effectiveBits) {
903 int32_t range = 1 << (effectiveBits - 1);
904 if ((result > range - 1) || (result < -range))
905 return Relocator::Overflow;
906 }
907 pReloc.target() |= ApplyMask<int32_t>(bitMask, result);
908 return Relocator::OK;
909 }
910
911 // R_HEX_GOTREL_LO16: and its class of relocs
912 // (S + A - GOT) : Signed Truncate
relocGOTREL(Relocation & pReloc,HexagonRelocator & pParent)913 Relocator::Result relocGOTREL(Relocation& pReloc, HexagonRelocator& pParent) {
914 Relocator::Address S = pReloc.symValue();
915 Relocator::DWord A = pReloc.addend();
916 Relocator::Address GOT = pParent.getTarget().getGOTSymbolAddr();
917
918 uint32_t bitMask = 0;
919 uint32_t alignment = 1;
920 uint32_t shift = 0;
921
922 uint32_t result = (uint32_t)(S + A - GOT);
923
924 switch (pReloc.type()) {
925 case llvm::ELF::R_HEX_GOTREL_LO16:
926 bitMask = 0x00c03fff;
927 break;
928
929 case llvm::ELF::R_HEX_GOTREL_HI16:
930 bitMask = 0x00c03fff;
931 shift = 16;
932 alignment = 4;
933 break;
934
935 case llvm::ELF::R_HEX_GOTREL_32:
936 bitMask = 0xffffffff;
937 break;
938
939 case llvm::ELF::R_HEX_GOTREL_32_6_X:
940 bitMask = 0x0fff3fff;
941 shift = 6;
942 break;
943
944 case llvm::ELF::R_HEX_GOTREL_16_X:
945 case llvm::ELF::R_HEX_GOTREL_11_X:
946 bitMask = FINDBITMASK(pReloc.target());
947 break;
948
949 default:
950 // show proper error
951 fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type())
952 << "mclinker@googlegroups.com";
953 }
954
955 if (result % alignment != 0)
956 return Relocator::BadReloc;
957
958 result >>= shift;
959
960 pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
961 return Relocator::OK;
962 }
963
unsupported(Relocation & pReloc,HexagonRelocator & pParent)964 Relocator::Result unsupported(Relocation& pReloc, HexagonRelocator& pParent) {
965 return Relocator::Unsupported;
966 }
967
968 } // namespace mcld
969