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