1 //===- ARMRelocator.cpp ----------------------------------------===// 2 // 3 // The MCLinker Project 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===--------------------------------------------------------------------===// 9 10 #include <llvm/ADT/Twine.h> 11 #include <llvm/Support/DataTypes.h> 12 #include <llvm/Support/ELF.h> 13 #include <llvm/Support/Host.h> 14 #include <mcld/Support/MsgHandling.h> 15 #include "ARMRelocator.h" 16 #include "ARMRelocationFunctions.h" 17 18 using namespace mcld; 19 20 //===--------------------------------------------------------------------===// 21 // Relocation Functions and Tables 22 //===--------------------------------------------------------------------===// 23 DECL_ARM_APPLY_RELOC_FUNCS 24 25 /// the prototype of applying function 26 typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc, 27 ARMRelocator& pParent); 28 29 // the table entry of applying functions 30 struct ApplyFunctionTriple 31 { 32 ApplyFunctionType func; 33 unsigned int type; 34 const char* name; 35 }; 36 37 // declare the table of applying functions 38 static const ApplyFunctionTriple ApplyFunctions[] = { 39 DECL_ARM_APPLY_RELOC_FUNC_PTRS 40 }; 41 42 //===--------------------------------------------------------------------===// 43 // ARMRelocator 44 //===--------------------------------------------------------------------===// 45 ARMRelocator::ARMRelocator(ARMGNULDBackend& pParent) 46 : Relocator(), 47 m_Target(pParent) { 48 } 49 50 ARMRelocator::~ARMRelocator() 51 { 52 } 53 54 Relocator::Result 55 ARMRelocator::applyRelocation(Relocation& pRelocation) 56 { 57 Relocation::Type type = pRelocation.type(); 58 if (type > 130) { // 131-255 doesn't noted in ARM spec 59 return Relocator::Unknown; 60 } 61 62 return ApplyFunctions[type].func(pRelocation, *this); 63 } 64 65 const char* ARMRelocator::getName(Relocator::Type pType) const 66 { 67 return ApplyFunctions[pType].name; 68 } 69 70 Relocator::Size ARMRelocator::getSize(Relocation::Type pType) const 71 { 72 return 32; 73 } 74 75 //===--------------------------------------------------------------------===// 76 // non-member functions 77 //===--------------------------------------------------------------------===// 78 static Relocator::DWord getThumbBit(const Relocation& pReloc) 79 { 80 // Set thumb bit if 81 // - symbol has type of STT_FUNC, is defined and with bit 0 of its value set 82 Relocator::DWord thumbBit = 83 ((!pReloc.symInfo()->isUndef() || pReloc.symInfo()->isDyn()) && 84 (pReloc.symInfo()->type() == ResolveInfo::Function) && 85 ((pReloc.symValue() & 0x1) != 0))? 86 1:0; 87 return thumbBit; 88 } 89 90 91 92 93 //=========================================// 94 // Relocation helper function // 95 //=========================================// 96 97 // Using uint64_t to make sure those complicate operations won't cause 98 // undefined behavior. 99 static 100 uint64_t helper_sign_extend(uint64_t pVal, uint64_t pOri_width) 101 { 102 assert(pOri_width <= 64); 103 uint64_t sign_bit = 1 << (pOri_width - 1); 104 return (pVal ^ sign_bit) - sign_bit; 105 // Reverse sign bit, then subtract sign bit. 106 } 107 108 static 109 uint64_t helper_bit_select(uint64_t pA, uint64_t pB, uint64_t pMask) 110 { 111 return (pA & ~pMask) | (pB & pMask) ; 112 } 113 114 // Check if symbol can use relocation R_ARM_RELATIVE 115 static bool 116 helper_use_relative_reloc(const ResolveInfo& pSym, 117 const ARMRelocator& pFactory) 118 { 119 // if symbol is dynamic or undefine or preemptible 120 if (pSym.isDyn() || 121 pSym.isUndef() || 122 pFactory.getTarget().isSymbolPreemptible(pSym)) 123 return false; 124 return true; 125 } 126 127 static 128 ARMGOTEntry& helper_get_GOT_and_init(Relocation& pReloc, 129 ARMRelocator& pParent) 130 { 131 // rsym - The relocation target symbol 132 ResolveInfo* rsym = pReloc.symInfo(); 133 ARMGNULDBackend& ld_backend = pParent.getTarget(); 134 135 ARMGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym); 136 if (NULL == got_entry) { 137 got_entry = ld_backend.getGOT().consumeGOT(); 138 pParent.getSymGOTMap().record(*rsym, *got_entry); 139 // If we first get this GOT entry, we should initialize it. 140 if (rsym->reserved() & ARMGNULDBackend::ReserveGOT) { 141 // No corresponding dynamic relocation, initialize to the symbol value. 142 got_entry->setValue(pReloc.symValue()); 143 } 144 else if (rsym->reserved() & ARMGNULDBackend::GOTRel) { 145 146 // Initialize corresponding dynamic relocation. 147 Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry(); 148 if ( rsym->isLocal() || 149 helper_use_relative_reloc(*rsym, pParent)) { 150 // Initialize got entry to target symbol address 151 got_entry->setValue(pReloc.symValue()); 152 rel_entry.setType(llvm::ELF::R_ARM_RELATIVE); 153 rel_entry.setSymInfo(0); 154 } 155 else { 156 // Initialize got entry to 0 for corresponding dynamic relocation. 157 got_entry->setValue(0); 158 rel_entry.setType(llvm::ELF::R_ARM_GLOB_DAT); 159 rel_entry.setSymInfo(rsym); 160 } 161 rel_entry.targetRef().assign(*got_entry); 162 } 163 else { 164 fatal(diag::reserve_entry_number_mismatch_got); 165 } 166 } 167 return *got_entry; 168 } 169 170 static 171 ARMRelocator::Address helper_GOT_ORG(ARMRelocator& pParent) 172 { 173 return pParent.getTarget().getGOT().addr(); 174 } 175 176 177 static 178 ARMRelocator::Address helper_GOT(Relocation& pReloc, ARMRelocator& pParent) 179 { 180 ARMGOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent); 181 return helper_GOT_ORG(pParent) + got_entry.getOffset(); 182 } 183 184 185 static 186 ARMPLT1& helper_get_PLT_and_init(Relocation& pReloc, ARMRelocator& pParent) 187 { 188 // rsym - The relocation target symbol 189 ResolveInfo* rsym = pReloc.symInfo(); 190 ARMGNULDBackend& ld_backend = pParent.getTarget(); 191 192 ARMPLT1* plt_entry = pParent.getSymPLTMap().lookUp(*rsym); 193 if (NULL != plt_entry) 194 return *plt_entry; 195 196 plt_entry = ld_backend.getPLT().consume(); 197 pParent.getSymPLTMap().record(*rsym, *plt_entry); 198 199 // If we first get this PLT entry, we should initialize it. 200 if (rsym->reserved() & ARMGNULDBackend::ReservePLT) { 201 ARMGOTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym); 202 assert(NULL == gotplt_entry && "PLT entry not exist, but DynRel entry exist!"); 203 gotplt_entry = ld_backend.getGOT().consumeGOTPLT(); 204 pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry); 205 206 // Initialize corresponding dynamic relocation. 207 Relocation& rel_entry = *ld_backend.getRelPLT().consumeEntry(); 208 rel_entry.setType(llvm::ELF::R_ARM_JUMP_SLOT); 209 rel_entry.targetRef().assign(*gotplt_entry); 210 rel_entry.setSymInfo(rsym); 211 } 212 else { 213 fatal(diag::reserve_entry_number_mismatch_plt); 214 } 215 216 return *plt_entry; 217 } 218 219 static 220 ARMRelocator::Address helper_PLT_ORG(ARMRelocator& pParent) 221 { 222 return pParent.getTarget().getPLT().addr(); 223 } 224 225 226 static 227 ARMRelocator::Address helper_PLT(Relocation& pReloc, ARMRelocator& pParent) 228 { 229 ARMPLT1& plt_entry = helper_get_PLT_and_init(pReloc, pParent); 230 return helper_PLT_ORG(pParent) + plt_entry.getOffset(); 231 } 232 233 // Get an relocation entry in .rel.dyn and set its type to pType, 234 // its FragmentRef to pReloc->targetFrag() and its ResolveInfo to 235 // pReloc->symInfo() 236 static 237 void helper_DynRel(Relocation& pReloc, 238 ARMRelocator::Type pType, 239 ARMRelocator& pParent) 240 { 241 // rsym - The relocation target symbol 242 ResolveInfo* rsym = pReloc.symInfo(); 243 ARMGNULDBackend& ld_backend = pParent.getTarget(); 244 245 Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry(); 246 rel_entry.setType(pType); 247 rel_entry.targetRef() = pReloc.targetRef(); 248 249 if (pType == llvm::ELF::R_ARM_RELATIVE) 250 rel_entry.setSymInfo(0); 251 else 252 rel_entry.setSymInfo(rsym); 253 } 254 255 static ARMRelocator::DWord 256 helper_extract_movw_movt_addend(ARMRelocator::DWord pTarget) 257 { 258 // imm16: [19-16][11-0] 259 return helper_sign_extend((((pTarget >> 4)) & 0xf000U) | (pTarget & 0xfffU), 260 16); 261 } 262 263 static ARMRelocator::DWord 264 helper_insert_val_movw_movt_inst(ARMRelocator::DWord pTarget, 265 ARMRelocator::DWord pImm) 266 { 267 // imm16: [19-16][11-0] 268 pTarget &= 0xfff0f000U; 269 pTarget |= pImm & 0x0fffU; 270 pTarget |= (pImm & 0xf000U) << 4; 271 return pTarget; 272 } 273 274 static ARMRelocator::DWord 275 helper_extract_thumb_movw_movt_addend(ARMRelocator::DWord pValue) 276 { 277 // imm16: [19-16][26][14-12][7-0] 278 return helper_sign_extend((((pValue >> 4) & 0xf000U) | 279 ((pValue >> 15) & 0x0800U) | 280 ((pValue >> 4) & 0x0700U) | 281 (pValue& 0x00ffU)), 282 16); 283 } 284 285 static ARMRelocator::DWord 286 helper_insert_val_thumb_movw_movt_inst(ARMRelocator::DWord pValue, 287 ARMRelocator::DWord pImm) 288 { 289 // imm16: [19-16][26][14-12][7-0] 290 pValue &= 0xfbf08f00U; 291 pValue |= (pImm & 0xf000U) << 4; 292 pValue |= (pImm & 0x0800U) << 15; 293 pValue |= (pImm & 0x0700U) << 4; 294 pValue |= (pImm & 0x00ffU); 295 return pValue; 296 } 297 298 static ARMRelocator::DWord 299 helper_thumb32_branch_offset(ARMRelocator::DWord pUpper16, 300 ARMRelocator::DWord pLower16) 301 { 302 ARMRelocator::DWord s = (pUpper16 & (1U << 10)) >> 10, // 26 bit 303 u = pUpper16 & 0x3ffU, // 25-16 304 l = pLower16 & 0x7ffU, // 10-0 305 j1 = (pLower16 & (1U << 13)) >> 13, // 13 306 j2 = (pLower16 & (1U << 11)) >> 11; // 11 307 ARMRelocator::DWord i1 = j1 ^ s? 0: 1, 308 i2 = j2 ^ s? 0: 1; 309 310 // [31-25][24][23][22][21-12][11-1][0] 311 // 0 s i1 i2 u l 0 312 return helper_sign_extend((s << 24) | (i1 << 23) | (i2 << 22) | 313 (u << 12) | (l << 1), 314 25); 315 } 316 317 static ARMRelocator::DWord 318 helper_thumb32_branch_upper(ARMRelocator::DWord pUpper16, 319 ARMRelocator::DWord pOffset) 320 { 321 uint32_t sign = ((pOffset & 0x80000000U) >> 31); 322 return (pUpper16 & ~0x7ffU) | ((pOffset >> 12) & 0x3ffU) | (sign << 10); 323 } 324 325 static ARMRelocator::DWord 326 helper_thumb32_branch_lower(ARMRelocator::DWord pLower16, 327 ARMRelocator::DWord pOffset) 328 { 329 uint32_t sign = ((pOffset & 0x80000000U) >> 31); 330 return ((pLower16 & ~0x2fffU) | 331 ((((pOffset >> 23) & 1) ^ !sign) << 13) | 332 ((((pOffset >> 22) & 1) ^ !sign) << 11) | 333 ((pOffset >> 1) & 0x7ffU)); 334 } 335 336 // Return true if overflow 337 static bool 338 helper_check_signed_overflow(ARMRelocator::DWord pValue, 339 unsigned bits) 340 { 341 int32_t signed_val = static_cast<int32_t>(pValue); 342 int32_t max = (1 << (bits - 1)) - 1; 343 int32_t min = -(1 << (bits - 1)); 344 if (signed_val > max || signed_val < min) { 345 return true; 346 } else { 347 return false; 348 } 349 } 350 351 352 //=========================================// 353 // Each relocation function implementation // 354 //=========================================// 355 356 // R_ARM_NONE 357 ARMRelocator::Result none(Relocation& pReloc, ARMRelocator& pParent) 358 { 359 return ARMRelocator::OK; 360 } 361 362 // R_ARM_ABS32: (S + A) | T 363 ARMRelocator::Result abs32(Relocation& pReloc, ARMRelocator& pParent) 364 { 365 ResolveInfo* rsym = pReloc.symInfo(); 366 ARMRelocator::DWord T = getThumbBit(pReloc); 367 ARMRelocator::DWord A = pReloc.target() + pReloc.addend(); 368 ARMRelocator::DWord S = pReloc.symValue(); 369 370 LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); 371 372 // If the flag of target section is not ALLOC, we will not scan this relocation 373 // but perform static relocation. (e.g., applying .debug section) 374 if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) { 375 pReloc.target() = (S + A) | T; 376 return ARMRelocator::OK; 377 } 378 379 // A local symbol may need REL Type dynamic relocation 380 if (rsym->isLocal() && (rsym->reserved() & ARMGNULDBackend::ReserveRel)) { 381 helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent); 382 pReloc.target() = (S + A) | T ; 383 return ARMRelocator::OK; 384 } 385 386 // An external symbol may need PLT and dynamic relocation 387 if (!rsym->isLocal()) { 388 if (rsym->reserved() & ARMGNULDBackend::ReservePLT) { 389 S = helper_PLT(pReloc, pParent); 390 T = 0 ; // PLT is not thumb 391 } 392 // If we generate a dynamic relocation (except R_ARM_RELATIVE) 393 // for a place, we should not perform static relocation on it 394 // in order to keep the addend store in the place correct. 395 if (rsym->reserved() & ARMGNULDBackend::ReserveRel) { 396 if (helper_use_relative_reloc(*rsym, pParent)) { 397 helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent); 398 } 399 else { 400 helper_DynRel(pReloc, pReloc.type(), pParent); 401 return ARMRelocator::OK; 402 } 403 } 404 } 405 406 407 // perform static relocation 408 pReloc.target() = (S + A) | T; 409 return ARMRelocator::OK; 410 } 411 412 // R_ARM_REL32: ((S + A) | T) - P 413 ARMRelocator::Result rel32(Relocation& pReloc, ARMRelocator& pParent) 414 { 415 // perform static relocation 416 ARMRelocator::Address S = pReloc.symValue(); 417 ARMRelocator::DWord T = getThumbBit(pReloc); 418 ARMRelocator::DWord A = pReloc.target() + pReloc.addend(); 419 420 // An external symbol may need PLT (this reloc is from stub) 421 if (!pReloc.symInfo()->isLocal()) { 422 if (pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) { 423 S = helper_PLT(pReloc, pParent); 424 T = 0; // PLT is not thumb. 425 } 426 } 427 428 // perform relocation 429 pReloc.target() = ((S + A) | T) - pReloc.place(); 430 431 return ARMRelocator::OK; 432 } 433 434 // R_ARM_BASE_PREL: B(S) + A - P 435 ARMRelocator::Result base_prel(Relocation& pReloc, ARMRelocator& pParent) 436 { 437 // perform static relocation 438 ARMRelocator::DWord A = pReloc.target() + pReloc.addend(); 439 pReloc.target() = pReloc.symValue() + A - pReloc.place(); 440 return ARMRelocator::OK; 441 } 442 443 // R_ARM_GOTOFF32: ((S + A) | T) - GOT_ORG 444 ARMRelocator::Result gotoff32(Relocation& pReloc, ARMRelocator& pParent) 445 { 446 ARMRelocator::DWord T = getThumbBit(pReloc); 447 ARMRelocator::DWord A = pReloc.target() + pReloc.addend(); 448 ARMRelocator::Address GOT_ORG = helper_GOT_ORG(pParent); 449 ARMRelocator::Address S = pReloc.symValue(); 450 451 pReloc.target() = ((S + A) | T) - GOT_ORG; 452 return ARMRelocator::OK; 453 } 454 455 // R_ARM_GOT_BREL: GOT(S) + A - GOT_ORG 456 ARMRelocator::Result got_brel(Relocation& pReloc, ARMRelocator& pParent) 457 { 458 if (!(pReloc.symInfo()->reserved() & 459 (ARMGNULDBackend::ReserveGOT | ARMGNULDBackend::GOTRel))) { 460 return ARMRelocator::BadReloc; 461 } 462 ARMRelocator::Address GOT_S = helper_GOT(pReloc, pParent); 463 ARMRelocator::DWord A = pReloc.target() + pReloc.addend(); 464 ARMRelocator::Address GOT_ORG = helper_GOT_ORG(pParent); 465 // Apply relocation. 466 pReloc.target() = GOT_S + A - GOT_ORG; 467 return ARMRelocator::OK; 468 } 469 470 // R_ARM_GOT_PREL: GOT(S) + A - P 471 ARMRelocator::Result got_prel(Relocation& pReloc, ARMRelocator& pParent) 472 { 473 if (!(pReloc.symInfo()->reserved() & 474 (ARMGNULDBackend::ReserveGOT | ARMGNULDBackend::GOTRel))) { 475 return ARMRelocator::BadReloc; 476 } 477 ARMRelocator::Address GOT_S = helper_GOT(pReloc, pParent); 478 ARMRelocator::DWord A = pReloc.target() + pReloc.addend(); 479 ARMRelocator::Address P = pReloc.place(); 480 481 // Apply relocation. 482 pReloc.target() = GOT_S + A - P; 483 return ARMRelocator::OK; 484 } 485 486 // R_ARM_PLT32: ((S + A) | T) - P 487 // R_ARM_JUMP24: ((S + A) | T) - P 488 // R_ARM_CALL: ((S + A) | T) - P 489 ARMRelocator::Result call(Relocation& pReloc, ARMRelocator& pParent) 490 { 491 // If target is undefined weak symbol, we only need to jump to the 492 // next instruction unless it has PLT entry. Rewrite instruction 493 // to NOP. 494 if (pReloc.symInfo()->isWeak() && 495 pReloc.symInfo()->isUndef() && 496 !pReloc.symInfo()->isDyn() && 497 !(pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT)) { 498 // change target to NOP : mov r0, r0 499 pReloc.target() = (pReloc.target() & 0xf0000000U) | 0x01a00000; 500 return ARMRelocator::OK; 501 } 502 503 ARMRelocator::Address S; // S depends on PLT exists or not. 504 ARMRelocator::DWord T = getThumbBit(pReloc); 505 ARMRelocator::DWord A = 506 helper_sign_extend((pReloc.target() & 0x00FFFFFFu) << 2, 26) 507 + pReloc.addend(); 508 ARMRelocator::Address P = pReloc.place(); 509 510 S = pReloc.symValue(); 511 if (pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) { 512 S = helper_PLT(pReloc, pParent); 513 T = 0; // PLT is not thumb. 514 } 515 516 // At this moment (after relaxation), if the jump target is thumb instruction, 517 // switch mode is needed, rewrite the instruction to BLX 518 // FIXME: check if we can use BLX instruction (check from .ARM.attribute 519 // CPU ARCH TAG, which should be ARMv5 or above) 520 if (T != 0) { 521 // cannot rewrite to blx for R_ARM_JUMP24 522 if (pReloc.type() == llvm::ELF::R_ARM_JUMP24) 523 return ARMRelocator::BadReloc; 524 525 pReloc.target() = (pReloc.target() & 0xffffff) | 526 0xfa000000 | 527 (((S + A - P) & 2) << 23); 528 } 529 530 ARMRelocator::DWord X = ((S + A) | T) - P; 531 // Check X is 24bit sign int. If not, we should use stub or PLT before apply. 532 if (helper_check_signed_overflow(X, 26)) 533 return ARMRelocator::Overflow; 534 // Make sure the Imm is 0. Result Mask. 535 pReloc.target() = (pReloc.target() & 0xFF000000u) | ((X & 0x03FFFFFEu) >> 2); 536 return ARMRelocator::OK; 537 } 538 539 // R_ARM_THM_CALL: ((S + A) | T) - P 540 // R_ARM_THM_JUMP24: (((S + A) | T) - P) 541 ARMRelocator::Result thm_call(Relocation& pReloc, ARMRelocator& pParent) 542 { 543 // If target is undefined weak symbol, we only need to jump to the 544 // next instruction unless it has PLT entry. Rewrite instruction 545 // to NOP. 546 if (pReloc.symInfo()->isWeak() && 547 pReloc.symInfo()->isUndef() && 548 !pReloc.symInfo()->isDyn() && 549 !(pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT)) { 550 pReloc.target() = (0xe000U << 16) | 0xbf00U; 551 return ARMRelocator::OK; 552 } 553 554 // get lower and upper 16 bit instructions from relocation targetData 555 uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target())); 556 uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1); 557 558 ARMRelocator::DWord T = getThumbBit(pReloc); 559 ARMRelocator::DWord A = helper_thumb32_branch_offset(upper_inst, 560 lower_inst); 561 ARMRelocator::Address P = pReloc.place(); 562 ARMRelocator::Address S; 563 564 // if symbol has plt 565 if (pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) { 566 S = helper_PLT(pReloc, pParent); 567 T = 0; // PLT is not thumb. 568 } 569 else { 570 S = pReloc.symValue(); 571 } 572 573 S = S + A; 574 575 // At this moment (after relaxation), if the jump target is arm 576 // instruction, switch mode is needed, rewrite the instruction to BLX 577 // FIXME: check if we can use BLX instruction (check from .ARM.attribute 578 // CPU ARCH TAG, which should be ARMv5 or above) 579 if (T == 0) { 580 // cannot rewrite to blx for R_ARM_THM_JUMP24 581 if (pReloc.type() == llvm::ELF::R_ARM_THM_JUMP24) 582 return ARMRelocator::BadReloc; 583 584 // for BLX, select bit 1 from relocation base address to jump target 585 // address 586 S = helper_bit_select(S, P, 0x2); 587 // rewrite instruction to BLX 588 lower_inst &= ~0x1000U; 589 } 590 else { 591 // otherwise, the instruction should be BL 592 lower_inst |= 0x1000U; 593 } 594 595 ARMRelocator::DWord X = (S | T) - P; 596 597 // FIXME: Check bit size is 24(thumb2) or 22? 598 if (helper_check_signed_overflow(X, 25)) { 599 return ARMRelocator::Overflow; 600 } 601 602 upper_inst = helper_thumb32_branch_upper(upper_inst, X); 603 lower_inst = helper_thumb32_branch_lower(lower_inst, X); 604 605 *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst; 606 *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst; 607 608 return ARMRelocator::OK; 609 } 610 611 // R_ARM_MOVW_ABS_NC: (S + A) | T 612 ARMRelocator::Result movw_abs_nc(Relocation& pReloc, ARMRelocator& pParent) 613 { 614 ResolveInfo* rsym = pReloc.symInfo(); 615 ARMRelocator::Address S = pReloc.symValue(); 616 ARMRelocator::DWord T = getThumbBit(pReloc); 617 ARMRelocator::DWord A = 618 helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend(); 619 ARMRelocator::DWord X; 620 621 LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); 622 623 // If the flag of target section is not ALLOC, we will not scan this 624 // relocation but perform static relocation. (e.g., applying .debug section) 625 if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) { 626 // use plt 627 if (rsym->reserved() & ARMGNULDBackend::ReservePLT) { 628 S = helper_PLT(pReloc, pParent); 629 T = 0 ; // PLT is not thumb 630 } 631 } 632 633 // perform static relocation 634 X = (S + A) | T; 635 pReloc.target() = helper_insert_val_movw_movt_inst( 636 pReloc.target() + pReloc.addend(), X); 637 return ARMRelocator::OK; 638 } 639 640 // R_ARM_MOVW_PREL_NC: ((S + A) | T) - P 641 ARMRelocator::Result movw_prel_nc(Relocation& pReloc, ARMRelocator& pParent) 642 { 643 ARMRelocator::Address S = pReloc.symValue(); 644 ARMRelocator::DWord T = getThumbBit(pReloc); 645 ARMRelocator::DWord P = pReloc.place(); 646 ARMRelocator::DWord A = 647 helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend(); 648 ARMRelocator::DWord X; 649 650 X = ((S + A) | T) - P; 651 652 if (helper_check_signed_overflow(X, 16)) { 653 return ARMRelocator::Overflow; 654 } else { 655 pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X); 656 return ARMRelocator::OK; 657 } 658 } 659 660 // R_ARM_MOVT_ABS: S + A 661 ARMRelocator::Result movt_abs(Relocation& pReloc, ARMRelocator& pParent) 662 { 663 ResolveInfo* rsym = pReloc.symInfo(); 664 ARMRelocator::Address S = pReloc.symValue(); 665 ARMRelocator::DWord A = 666 helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend(); 667 ARMRelocator::DWord X; 668 669 LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); 670 671 // If the flag of target section is not ALLOC, we will not scan this relocation 672 // but perform static relocation. (e.g., applying .debug section) 673 if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) { 674 // use plt 675 if (rsym->reserved() & ARMGNULDBackend::ReservePLT) { 676 S = helper_PLT(pReloc, pParent); 677 } 678 } 679 680 X = S + A; 681 X >>= 16; 682 // perform static relocation 683 pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X); 684 return ARMRelocator::OK; 685 } 686 687 // R_ARM_MOVT_PREL: S + A - P 688 ARMRelocator::Result movt_prel(Relocation& pReloc, ARMRelocator& pParent) 689 { 690 ARMRelocator::Address S = pReloc.symValue(); 691 ARMRelocator::DWord P = pReloc.place(); 692 ARMRelocator::DWord A = 693 helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend(); 694 ARMRelocator::DWord X; 695 696 X = S + A - P; 697 X >>= 16; 698 699 pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X); 700 return ARMRelocator::OK; 701 } 702 703 // R_ARM_THM_MOVW_ABS_NC: (S + A) | T 704 ARMRelocator::Result thm_movw_abs_nc(Relocation& pReloc, ARMRelocator& pParent) 705 { 706 ResolveInfo* rsym = pReloc.symInfo(); 707 ARMRelocator::Address S = pReloc.symValue(); 708 ARMRelocator::DWord T = getThumbBit(pReloc); 709 710 // get lower and upper 16 bit instructions from relocation targetData 711 uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target())); 712 uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1); 713 ARMRelocator::DWord val = ((upper_inst) << 16) | (lower_inst); 714 ARMRelocator::DWord A = 715 helper_extract_thumb_movw_movt_addend(val) + pReloc.addend(); 716 ARMRelocator::DWord X; 717 718 LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); 719 // If the flag of target section is not ALLOC, we will not scan this relocation 720 // but perform static relocation. (e.g., applying .debug section) 721 if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) { 722 // use plt 723 if (rsym->reserved() & ARMGNULDBackend::ReservePLT) { 724 S = helper_PLT(pReloc, pParent); 725 T = 0; // PLT is not thumb 726 } 727 } 728 X = (S + A) | T; 729 730 val = helper_insert_val_thumb_movw_movt_inst(val, X); 731 *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst; 732 *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst; 733 734 return ARMRelocator::OK; 735 } 736 737 // R_ARM_THM_MOVW_PREL_NC: ((S + A) | T) - P 738 ARMRelocator::Result thm_movw_prel_nc(Relocation& pReloc, ARMRelocator& pParent) 739 { 740 ARMRelocator::Address S = pReloc.symValue(); 741 ARMRelocator::DWord T = getThumbBit(pReloc); 742 ARMRelocator::DWord P = pReloc.place(); 743 744 // get lower and upper 16 bit instructions from relocation targetData 745 uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target())); 746 uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1); 747 ARMRelocator::DWord val = ((upper_inst) << 16) | (lower_inst); 748 ARMRelocator::DWord A = 749 helper_extract_thumb_movw_movt_addend(val) + pReloc.addend(); 750 ARMRelocator::DWord X; 751 752 X = ((S + A) | T) - P; 753 754 val = helper_insert_val_thumb_movw_movt_inst(val, X); 755 *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst; 756 *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst; 757 758 return ARMRelocator::OK; 759 } 760 761 // R_ARM_THM_MOVW_BREL_NC: ((S + A) | T) - B(S) 762 // R_ARM_THM_MOVW_BREL: ((S + A) | T) - B(S) 763 ARMRelocator::Result thm_movw_brel(Relocation& pReloc, ARMRelocator& pParent) 764 { 765 ARMRelocator::Address S = pReloc.symValue(); 766 ARMRelocator::DWord T = getThumbBit(pReloc); 767 ARMRelocator::DWord P = pReloc.place(); 768 769 // get lower and upper 16 bit instructions from relocation targetData 770 uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target())); 771 uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1); 772 ARMRelocator::DWord val = ((upper_inst) << 16) | (lower_inst); 773 ARMRelocator::DWord A = 774 helper_extract_thumb_movw_movt_addend(val) + pReloc.addend(); 775 ARMRelocator::DWord X; 776 777 X = ((S + A) | T) - P; 778 779 val = helper_insert_val_thumb_movw_movt_inst(val, X); 780 *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst; 781 *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst; 782 783 return ARMRelocator::OK; 784 } 785 786 // R_ARM_THM_MOVT_ABS: S + A 787 ARMRelocator::Result thm_movt_abs(Relocation& pReloc, ARMRelocator& pParent) 788 { 789 ResolveInfo* rsym = pReloc.symInfo(); 790 ARMRelocator::Address S = pReloc.symValue(); 791 792 // get lower and upper 16 bit instructions from relocation targetData 793 uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target())); 794 uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1); 795 ARMRelocator::DWord val = ((upper_inst) << 16) | (lower_inst); 796 ARMRelocator::DWord A = 797 helper_extract_thumb_movw_movt_addend(val) + pReloc.addend(); 798 ARMRelocator::DWord X; 799 800 LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); 801 // If the flag of target section is not ALLOC, we will not scan this relocation 802 // but perform static relocation. (e.g., applying .debug section) 803 if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) { 804 // use plt 805 if (rsym->reserved() & ARMGNULDBackend::ReservePLT) { 806 S = helper_PLT(pReloc, pParent); 807 } 808 } 809 810 X = S + A; 811 X >>= 16; 812 813 // check 16-bit overflow 814 if (helper_check_signed_overflow(X, 16)) { 815 return ARMRelocator::Overflow; 816 } else { 817 val = helper_insert_val_thumb_movw_movt_inst(val, X); 818 *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst; 819 *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst; 820 return ARMRelocator::OK; 821 } 822 } 823 824 // R_ARM_THM_MOVT_PREL: S + A - P 825 // R_ARM_THM_MOVT_BREL: S + A - B(S) 826 ARMRelocator::Result thm_movt_prel(Relocation& pReloc, ARMRelocator& pParent) 827 { 828 ARMRelocator::Address S = pReloc.symValue(); 829 ARMRelocator::DWord P = pReloc.place(); 830 831 // get lower and upper 16 bit instructions from relocation targetData 832 uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target())); 833 uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1); 834 ARMRelocator::DWord val = ((upper_inst) << 16) | (lower_inst); 835 ARMRelocator::DWord A = 836 helper_extract_thumb_movw_movt_addend(val) + pReloc.addend(); 837 ARMRelocator::DWord X; 838 839 X = S + A - P; 840 X >>= 16; 841 842 val = helper_insert_val_thumb_movw_movt_inst(val, X); 843 *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst; 844 *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst; 845 846 return ARMRelocator::OK; 847 } 848 849 // R_ARM_PREL31: ((S + A) | T) - P 850 ARMRelocator::Result prel31(Relocation& pReloc, ARMRelocator& pParent) 851 { 852 ARMRelocator::DWord target = pReloc.target(); 853 ARMRelocator::DWord T = getThumbBit(pReloc); 854 ARMRelocator::DWord A = helper_sign_extend(target, 31) + 855 pReloc.addend(); 856 ARMRelocator::DWord P = pReloc.place(); 857 ARMRelocator::Address S; 858 859 S = pReloc.symValue(); 860 // if symbol has plt 861 if ( pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) { 862 S = helper_PLT(pReloc, pParent); 863 T = 0; // PLT is not thumb. 864 } 865 866 ARMRelocator::DWord X = ((S + A) | T) - P; 867 pReloc.target() = helper_bit_select(target, X, 0x7fffffffU); 868 if (helper_check_signed_overflow(X, 31)) 869 return ARMRelocator::Overflow; 870 return ARMRelocator::OK; 871 } 872 873 // R_ARM_TLS_GD32: GOT(S) + A - P 874 // R_ARM_TLS_IE32: GOT(S) + A - P 875 // R_ARM_TLS_LE32: S + A - tp 876 ARMRelocator::Result tls(Relocation& pReloc, ARMRelocator& pParent) 877 { 878 return ARMRelocator::Unsupport; 879 } 880 881 ARMRelocator::Result unsupport(Relocation& pReloc, ARMRelocator& pParent) 882 { 883 return ARMRelocator::Unsupport; 884 } 885