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