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 21namespace mcld { 22 23//===--------------------------------------------------------------------===// 24// Relocation Helper Functions 25//===--------------------------------------------------------------------===// 26/// helper_DynRel - Get an relocation entry in .rela.dyn 27static 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 46static 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 55static 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 84static 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 91static 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 114static 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//===--------------------------------------------------------------------===// 124DECL_HEXAGON_APPLY_RELOC_FUNCS 125 126/// the prototype of applying function 127typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc, 128 HexagonRelocator& pParent); 129 130// the table entry of applying functions 131struct ApplyFunctionTriple { 132 ApplyFunctionType func; 133 unsigned int type; 134 const char* name; 135}; 136 137// declare the table of applying functions 138static const ApplyFunctionTriple ApplyFunctions[] = { 139 DECL_HEXAGON_APPLY_RELOC_FUNC_PTRS}; 140 141static 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//===--------------------------------------------------------------------===// 168HexagonRelocator::HexagonRelocator(HexagonLDBackend& pParent, 169 const LinkerConfig& pConfig) 170 : Relocator(pConfig), m_Target(pParent) { 171} 172 173HexagonRelocator::~HexagonRelocator() { 174} 175 176Relocator::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 187const char* HexagonRelocator::getName(Relocation::Type pType) const { 188 return ApplyFunctions[pType].name; 189} 190 191Relocator::Size HexagonRelocator::getSize(Relocation::Type pType) const { 192 return 32; 193} 194 195void 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 226void 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 235void 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 286void 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. 406LDSymbol& 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 475void 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 499Relocator::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 506Relocator::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 584Relocator::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 695Relocator::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 735Relocator::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 767Relocator::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 817Relocator::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 835Relocator::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 913Relocator::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 964Relocator::Result unsupported(Relocation& pReloc, HexagonRelocator& pParent) { 965 return Relocator::Unsupported; 966} 967 968} // namespace mcld 969