1 //===- MipsRelocator.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/ELF.h> 12 #include <mcld/Support/MsgHandling.h> 13 #include <mcld/Target/OutputRelocSection.h> 14 #include <mcld/LinkerConfig.h> 15 #include <mcld/IRBuilder.h> 16 17 #include "MipsRelocator.h" 18 #include "MipsRelocationFunctions.h" 19 20 using namespace mcld; 21 22 //===----------------------------------------------------------------------===// 23 // Relocation Functions and Tables 24 //===----------------------------------------------------------------------===// 25 DECL_MIPS_APPLY_RELOC_FUNCS 26 27 /// the prototype of applying function 28 typedef Relocator::Result (*ApplyFunctionType)(Relocation&, MipsRelocator&); 29 30 // the table entry of applying functions 31 struct ApplyFunctionTriple 32 { 33 ApplyFunctionType func; 34 unsigned int type; 35 const char* name; 36 unsigned int size; 37 }; 38 39 // declare the table of applying functions 40 static const ApplyFunctionTriple ApplyFunctions[] = { 41 DECL_MIPS_APPLY_RELOC_FUNC_PTRS 42 }; 43 44 //===----------------------------------------------------------------------===// 45 // MipsRelocator 46 //===----------------------------------------------------------------------===// 47 MipsRelocator::MipsRelocator(MipsGNULDBackend& pParent, 48 const LinkerConfig& pConfig) 49 : Relocator(pConfig), 50 m_Target(pParent), 51 m_pApplyingInput(NULL), 52 m_AHL(0) 53 { 54 } 55 56 Relocator::Result 57 MipsRelocator::applyRelocation(Relocation& pRelocation) 58 { 59 Relocation::Type type = pRelocation.type(); 60 61 if (type >= sizeof(ApplyFunctions) / sizeof(ApplyFunctions[0])) { 62 return Unknown; 63 } 64 65 // apply the relocation 66 return ApplyFunctions[type].func(pRelocation, *this); 67 } 68 69 const char* MipsRelocator::getName(Relocation::Type pType) const 70 { 71 return ApplyFunctions[pType].name; 72 } 73 74 Relocator::Size MipsRelocator::getSize(Relocation::Type pType) const 75 { 76 return ApplyFunctions[pType].size; 77 } 78 79 void MipsRelocator::scanRelocation(Relocation& pReloc, 80 IRBuilder& pBuilder, 81 Module& pModule, 82 LDSection& pSection) 83 { 84 // rsym - The relocation target symbol 85 ResolveInfo* rsym = pReloc.symInfo(); 86 assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation"); 87 88 // Skip relocation against _gp_disp 89 if (NULL != getTarget().getGpDispSymbol()) { 90 if (pReloc.symInfo() == getTarget().getGpDispSymbol()->resolveInfo()) 91 return; 92 } 93 94 pReloc.updateAddend(); 95 96 assert(NULL != pSection.getLink()); 97 if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC)) 98 return; 99 100 // We test isLocal or if pInputSym is not a dynamic symbol 101 // We assume -Bsymbolic to bind all symbols internaly via !rsym->isDyn() 102 // Don't put undef symbols into local entries. 103 if ((rsym->isLocal() || !getTarget().isDynamicSymbol(*rsym) || 104 !rsym->isDyn()) && !rsym->isUndef()) 105 scanLocalReloc(pReloc, pBuilder, pSection); 106 else 107 scanGlobalReloc(pReloc, pBuilder, pSection); 108 109 // check if we shoule issue undefined reference for the relocation target 110 // symbol 111 if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull()) 112 fatal(diag::undefined_reference) << rsym->name(); 113 } 114 115 bool MipsRelocator::initializeScan(Input& pInput) 116 { 117 getTarget().getGOT().initializeScan(pInput); 118 return true; 119 } 120 121 bool MipsRelocator::finalizeScan(Input& pInput) 122 { 123 getTarget().getGOT().finalizeScan(pInput); 124 return true; 125 } 126 127 bool MipsRelocator::initializeApply(Input& pInput) 128 { 129 m_pApplyingInput = &pInput; 130 return true; 131 } 132 133 bool MipsRelocator::finalizeApply(Input& pInput) 134 { 135 m_pApplyingInput = NULL; 136 return true; 137 } 138 139 void MipsRelocator::scanLocalReloc(Relocation& pReloc, 140 IRBuilder& pBuilder, 141 const LDSection& pSection) 142 { 143 ResolveInfo* rsym = pReloc.symInfo(); 144 145 switch (pReloc.type()){ 146 case llvm::ELF::R_MIPS_NONE: 147 case llvm::ELF::R_MIPS_16: 148 break; 149 case llvm::ELF::R_MIPS_32: 150 if (LinkerConfig::DynObj == config().codeGenType()) { 151 // TODO: (simon) The gold linker does not create an entry in .rel.dyn 152 // section if the symbol section flags contains SHF_EXECINSTR. 153 // 1. Find the reason of this condition. 154 // 2. Check this condition here. 155 getTarget().getRelDyn().reserveEntry(); 156 rsym->setReserved(rsym->reserved() | ReserveRel); 157 getTarget().checkAndSetHasTextRel(*pSection.getLink()); 158 159 // Remeber this rsym is a local GOT entry (as if it needs an entry). 160 // Actually we don't allocate an GOT entry. 161 getTarget().getGOT().setLocal(rsym); 162 } 163 break; 164 case llvm::ELF::R_MIPS_REL32: 165 case llvm::ELF::R_MIPS_26: 166 case llvm::ELF::R_MIPS_HI16: 167 case llvm::ELF::R_MIPS_LO16: 168 case llvm::ELF::R_MIPS_PC16: 169 case llvm::ELF::R_MIPS_SHIFT5: 170 case llvm::ELF::R_MIPS_SHIFT6: 171 case llvm::ELF::R_MIPS_64: 172 case llvm::ELF::R_MIPS_GOT_PAGE: 173 case llvm::ELF::R_MIPS_GOT_OFST: 174 case llvm::ELF::R_MIPS_SUB: 175 case llvm::ELF::R_MIPS_INSERT_A: 176 case llvm::ELF::R_MIPS_INSERT_B: 177 case llvm::ELF::R_MIPS_DELETE: 178 case llvm::ELF::R_MIPS_HIGHER: 179 case llvm::ELF::R_MIPS_HIGHEST: 180 case llvm::ELF::R_MIPS_SCN_DISP: 181 case llvm::ELF::R_MIPS_REL16: 182 case llvm::ELF::R_MIPS_ADD_IMMEDIATE: 183 case llvm::ELF::R_MIPS_PJUMP: 184 case llvm::ELF::R_MIPS_RELGOT: 185 case llvm::ELF::R_MIPS_JALR: 186 case llvm::ELF::R_MIPS_GLOB_DAT: 187 case llvm::ELF::R_MIPS_COPY: 188 case llvm::ELF::R_MIPS_JUMP_SLOT: 189 break; 190 case llvm::ELF::R_MIPS_GOT16: 191 case llvm::ELF::R_MIPS_CALL16: 192 case llvm::ELF::R_MIPS_GOT_HI16: 193 case llvm::ELF::R_MIPS_CALL_HI16: 194 case llvm::ELF::R_MIPS_GOT_LO16: 195 case llvm::ELF::R_MIPS_CALL_LO16: 196 if (getTarget().getGOT().reserveLocalEntry(*rsym)) { 197 if (getTarget().getGOT().hasMultipleGOT()) 198 getTarget().checkAndSetHasTextRel(*pSection.getLink()); 199 // Remeber this rsym is a local GOT entry 200 getTarget().getGOT().setLocal(rsym); 201 } 202 break; 203 case llvm::ELF::R_MIPS_GPREL32: 204 case llvm::ELF::R_MIPS_GPREL16: 205 case llvm::ELF::R_MIPS_LITERAL: 206 case llvm::ELF::R_MIPS_GOT_DISP: 207 break; 208 case llvm::ELF::R_MIPS_TLS_DTPMOD32: 209 case llvm::ELF::R_MIPS_TLS_DTPREL32: 210 case llvm::ELF::R_MIPS_TLS_DTPMOD64: 211 case llvm::ELF::R_MIPS_TLS_DTPREL64: 212 case llvm::ELF::R_MIPS_TLS_GD: 213 case llvm::ELF::R_MIPS_TLS_LDM: 214 case llvm::ELF::R_MIPS_TLS_DTPREL_HI16: 215 case llvm::ELF::R_MIPS_TLS_DTPREL_LO16: 216 case llvm::ELF::R_MIPS_TLS_GOTTPREL: 217 case llvm::ELF::R_MIPS_TLS_TPREL32: 218 case llvm::ELF::R_MIPS_TLS_TPREL64: 219 case llvm::ELF::R_MIPS_TLS_TPREL_HI16: 220 case llvm::ELF::R_MIPS_TLS_TPREL_LO16: 221 break; 222 default: 223 fatal(diag::unknown_relocation) << (int)pReloc.type() 224 << pReloc.symInfo()->name(); 225 } 226 } 227 228 void MipsRelocator::scanGlobalReloc(Relocation& pReloc, 229 IRBuilder& pBuilder, 230 const LDSection& pSection) 231 { 232 ResolveInfo* rsym = pReloc.symInfo(); 233 234 switch (pReloc.type()){ 235 case llvm::ELF::R_MIPS_NONE: 236 case llvm::ELF::R_MIPS_INSERT_A: 237 case llvm::ELF::R_MIPS_INSERT_B: 238 case llvm::ELF::R_MIPS_DELETE: 239 case llvm::ELF::R_MIPS_TLS_DTPMOD64: 240 case llvm::ELF::R_MIPS_TLS_DTPREL64: 241 case llvm::ELF::R_MIPS_REL16: 242 case llvm::ELF::R_MIPS_ADD_IMMEDIATE: 243 case llvm::ELF::R_MIPS_PJUMP: 244 case llvm::ELF::R_MIPS_RELGOT: 245 case llvm::ELF::R_MIPS_TLS_TPREL64: 246 break; 247 case llvm::ELF::R_MIPS_32: 248 case llvm::ELF::R_MIPS_64: 249 case llvm::ELF::R_MIPS_HI16: 250 case llvm::ELF::R_MIPS_LO16: 251 if (getTarget().symbolNeedsDynRel(*rsym, false, true)) { 252 getTarget().getRelDyn().reserveEntry(); 253 rsym->setReserved(rsym->reserved() | ReserveRel); 254 getTarget().checkAndSetHasTextRel(*pSection.getLink()); 255 256 // Remeber this rsym is a global GOT entry (as if it needs an entry). 257 // Actually we don't allocate an GOT entry. 258 getTarget().getGOT().setGlobal(rsym); 259 } 260 break; 261 case llvm::ELF::R_MIPS_GOT16: 262 case llvm::ELF::R_MIPS_CALL16: 263 case llvm::ELF::R_MIPS_GOT_DISP: 264 case llvm::ELF::R_MIPS_GOT_HI16: 265 case llvm::ELF::R_MIPS_CALL_HI16: 266 case llvm::ELF::R_MIPS_GOT_LO16: 267 case llvm::ELF::R_MIPS_CALL_LO16: 268 case llvm::ELF::R_MIPS_GOT_PAGE: 269 case llvm::ELF::R_MIPS_GOT_OFST: 270 if (getTarget().getGOT().reserveGlobalEntry(*rsym)) { 271 if (getTarget().getGOT().hasMultipleGOT()) 272 getTarget().checkAndSetHasTextRel(*pSection.getLink()); 273 // Remeber this rsym is a global GOT entry 274 getTarget().getGOT().setGlobal(rsym); 275 } 276 break; 277 case llvm::ELF::R_MIPS_LITERAL: 278 case llvm::ELF::R_MIPS_GPREL32: 279 fatal(diag::invalid_global_relocation) << (int)pReloc.type() 280 << pReloc.symInfo()->name(); 281 break; 282 case llvm::ELF::R_MIPS_GPREL16: 283 break; 284 case llvm::ELF::R_MIPS_26: 285 case llvm::ELF::R_MIPS_PC16: 286 break; 287 case llvm::ELF::R_MIPS_16: 288 case llvm::ELF::R_MIPS_SHIFT5: 289 case llvm::ELF::R_MIPS_SHIFT6: 290 case llvm::ELF::R_MIPS_SUB: 291 case llvm::ELF::R_MIPS_HIGHER: 292 case llvm::ELF::R_MIPS_HIGHEST: 293 case llvm::ELF::R_MIPS_SCN_DISP: 294 break; 295 case llvm::ELF::R_MIPS_TLS_DTPREL32: 296 case llvm::ELF::R_MIPS_TLS_GD: 297 case llvm::ELF::R_MIPS_TLS_LDM: 298 case llvm::ELF::R_MIPS_TLS_DTPREL_HI16: 299 case llvm::ELF::R_MIPS_TLS_DTPREL_LO16: 300 case llvm::ELF::R_MIPS_TLS_GOTTPREL: 301 case llvm::ELF::R_MIPS_TLS_TPREL32: 302 case llvm::ELF::R_MIPS_TLS_TPREL_HI16: 303 case llvm::ELF::R_MIPS_TLS_TPREL_LO16: 304 break; 305 case llvm::ELF::R_MIPS_REL32: 306 break; 307 case llvm::ELF::R_MIPS_JALR: 308 break; 309 case llvm::ELF::R_MIPS_COPY: 310 case llvm::ELF::R_MIPS_GLOB_DAT: 311 case llvm::ELF::R_MIPS_JUMP_SLOT: 312 fatal(diag::dynamic_relocation) << (int)pReloc.type(); 313 break; 314 default: 315 fatal(diag::unknown_relocation) << (int)pReloc.type() 316 << pReloc.symInfo()->name(); 317 } 318 } 319 320 //===----------------------------------------------------------------------===// 321 // Relocation helper function 322 //===----------------------------------------------------------------------===// 323 static const char * const GP_DISP_NAME = "_gp_disp"; 324 325 // Find next R_MIPS_LO16 relocation paired to pReloc. 326 static 327 Relocation* helper_FindLo16Reloc(Relocation& pReloc) 328 { 329 Relocation* reloc = static_cast<Relocation*>(pReloc.getNextNode()); 330 while (NULL != reloc) 331 { 332 if (llvm::ELF::R_MIPS_LO16 == reloc->type() && 333 reloc->symInfo() == pReloc.symInfo()) 334 return reloc; 335 336 reloc = static_cast<Relocation*>(reloc->getNextNode()); 337 } 338 return NULL; 339 } 340 341 // Check the symbol is _gp_disp. 342 static 343 bool helper_isGpDisp(const Relocation& pReloc) 344 { 345 const ResolveInfo* rsym = pReloc.symInfo(); 346 return 0 == strcmp(GP_DISP_NAME, rsym->name()); 347 } 348 349 static 350 Relocator::Address helper_GetGP(MipsRelocator& pParent) 351 { 352 return pParent.getTarget().getGOT().getGPAddr(pParent.getApplyingInput()); 353 } 354 355 static 356 void helper_SetupRelDynForGOTEntry(MipsGOTEntry& got_entry, 357 Relocation& pReloc, 358 ResolveInfo* rsym, 359 MipsRelocator& pParent) 360 { 361 MipsGNULDBackend& ld_backend = pParent.getTarget(); 362 363 Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry(); 364 rel_entry.setType(llvm::ELF::R_MIPS_REL32); 365 rel_entry.targetRef() = *FragmentRef::Create(got_entry, 0); 366 rel_entry.setSymInfo(rsym); 367 } 368 369 static 370 MipsGOTEntry& helper_GetGOTEntry(Relocation& pReloc, MipsRelocator& pParent) 371 { 372 // rsym - The relocation target symbol 373 ResolveInfo* rsym = pReloc.symInfo(); 374 MipsGNULDBackend& ld_backend = pParent.getTarget(); 375 MipsGOT& got = ld_backend.getGOT(); 376 MipsGOTEntry* got_entry; 377 378 if (got.isLocal(rsym) && ResolveInfo::Section == rsym->type()) { 379 // Local section symbols consume local got entries. 380 got_entry = got.consumeLocal(); 381 if (got.isPrimaryGOTConsumed()) 382 helper_SetupRelDynForGOTEntry(*got_entry, pReloc, NULL, pParent); 383 return *got_entry; 384 } 385 386 got_entry = got.lookupEntry(rsym); 387 if (NULL != got_entry) { 388 // found a mapping, then return the mapped entry immediately 389 return *got_entry; 390 } 391 392 // not found 393 if (got.isLocal(rsym)) 394 got_entry = got.consumeLocal(); 395 else 396 got_entry = got.consumeGlobal(); 397 398 got.recordEntry(rsym, got_entry); 399 400 // If we first get this GOT entry, we should initialize it. 401 if (!got.isLocal(rsym) || ResolveInfo::Section != rsym->type()) { 402 if (!got.isPrimaryGOTConsumed()) 403 got_entry->setValue(pReloc.symValue()); 404 } 405 406 if (got.isPrimaryGOTConsumed()) 407 helper_SetupRelDynForGOTEntry(*got_entry, pReloc, 408 got.isLocal(rsym) ? NULL : rsym, pParent); 409 410 return *got_entry; 411 } 412 413 static 414 Relocator::Address helper_GetGOTOffset(Relocation& pReloc, 415 MipsRelocator& pParent) 416 { 417 MipsGNULDBackend& ld_backend = pParent.getTarget(); 418 MipsGOT& got = ld_backend.getGOT(); 419 MipsGOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent); 420 return got.getGPRelOffset(pParent.getApplyingInput(), got_entry); 421 } 422 423 static 424 int32_t helper_CalcAHL(const Relocation& pHiReloc, const Relocation& pLoReloc) 425 { 426 assert((pHiReloc.type() == llvm::ELF::R_MIPS_HI16 || 427 pHiReloc.type() == llvm::ELF::R_MIPS_GOT16) && 428 pLoReloc.type() == llvm::ELF::R_MIPS_LO16 && 429 "Incorrect type of relocation for AHL calculation"); 430 431 // Note the addend is section symbol offset here 432 assert (pHiReloc.addend() == pLoReloc.addend()); 433 434 int32_t AHI = pHiReloc.target(); 435 int32_t ALO = pLoReloc.target(); 436 int32_t AHL = ((AHI & 0xFFFF) << 16) + (int16_t)(ALO & 0xFFFF) + 437 pLoReloc.addend(); 438 return AHL; 439 } 440 441 static 442 void helper_DynRel(Relocation& pReloc, MipsRelocator& pParent) 443 { 444 ResolveInfo* rsym = pReloc.symInfo(); 445 MipsGNULDBackend& ld_backend = pParent.getTarget(); 446 MipsGOT& got = ld_backend.getGOT(); 447 448 Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry(); 449 450 rel_entry.setType(llvm::ELF::R_MIPS_REL32); 451 rel_entry.targetRef() = pReloc.targetRef(); 452 453 Relocator::DWord A = pReloc.target() + pReloc.addend(); 454 Relocator::DWord S = pReloc.symValue(); 455 456 if (got.isLocal(rsym)) { 457 rel_entry.setSymInfo(NULL); 458 pReloc.target() = A + S; 459 } 460 else { 461 rel_entry.setSymInfo(rsym); 462 // Don't add symbol value that will be resolved by the dynamic linker 463 pReloc.target() = A; 464 } 465 } 466 467 //=========================================// 468 // Relocation functions implementation // 469 //=========================================// 470 471 // R_MIPS_NONE and those unsupported/deprecated relocation type 472 static 473 MipsRelocator::Result none(Relocation& pReloc, MipsRelocator& pParent) 474 { 475 return MipsRelocator::OK; 476 } 477 478 // R_MIPS_32: S + A 479 static 480 MipsRelocator::Result abs32(Relocation& pReloc, MipsRelocator& pParent) 481 { 482 ResolveInfo* rsym = pReloc.symInfo(); 483 484 Relocator::DWord A = pReloc.target() + pReloc.addend(); 485 Relocator::DWord S = pReloc.symValue(); 486 487 LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); 488 // If the flag of target section is not ALLOC, we will not scan this relocation 489 // but perform static relocation. (e.g., applying .debug section) 490 if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) { 491 pReloc.target() = S + A; 492 return MipsRelocator::OK; 493 } 494 495 if (rsym->reserved() & MipsRelocator::ReserveRel) { 496 helper_DynRel(pReloc, pParent); 497 498 return MipsRelocator::OK; 499 } 500 501 pReloc.target() = (S + A); 502 503 return MipsRelocator::OK; 504 } 505 506 // R_MIPS_HI16: 507 // local/external: ((AHL + S) - (short)(AHL + S)) >> 16 508 // _gp_disp : ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16 509 static 510 MipsRelocator::Result hi16(Relocation& pReloc, MipsRelocator& pParent) 511 { 512 Relocation* lo_reloc = helper_FindLo16Reloc(pReloc); 513 assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_HI16"); 514 515 int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc); 516 int32_t res = 0; 517 518 pParent.setAHL(AHL); 519 520 if (helper_isGpDisp(pReloc)) { 521 int32_t P = pReloc.place(); 522 int32_t GP = helper_GetGP(pParent); 523 res = ((AHL + GP - P) - (int16_t)(AHL + GP - P)) >> 16; 524 } 525 else { 526 int32_t S = pReloc.symValue(); 527 res = ((AHL + S) - (int16_t)(AHL + S)) >> 16; 528 } 529 530 pReloc.target() &= 0xFFFF0000; 531 pReloc.target() |= (res & 0xFFFF); 532 533 return MipsRelocator::OK; 534 } 535 536 // R_MIPS_LO16: 537 // local/external: AHL + S 538 // _gp_disp : AHL + GP - P + 4 539 static 540 MipsRelocator::Result lo16(Relocation& pReloc, MipsRelocator& pParent) 541 { 542 int32_t res = 0; 543 544 if (helper_isGpDisp(pReloc)) { 545 int32_t P = pReloc.place(); 546 int32_t GP = helper_GetGP(pParent); 547 int32_t AHL = pParent.getAHL(); 548 res = AHL + GP - P + 4; 549 } 550 else { 551 int32_t S = pReloc.symValue(); 552 // The previous AHL may be for other hi/lo pairs. 553 // We need to calcuate the lo part now. It is easy. 554 // Remember to add the section offset to ALO. 555 int32_t ALO = (pReloc.target() & 0xFFFF) + pReloc.addend(); 556 res = ALO + S; 557 } 558 559 pReloc.target() &= 0xFFFF0000; 560 pReloc.target() |= (res & 0xFFFF); 561 562 return MipsRelocator::OK; 563 } 564 565 // R_MIPS_GOT16: 566 // local : G (calculate AHL and put high 16 bit to GOT) 567 // external: G 568 static 569 MipsRelocator::Result got16(Relocation& pReloc, MipsRelocator& pParent) 570 { 571 MipsGNULDBackend& ld_backend = pParent.getTarget(); 572 MipsGOT& got = ld_backend.getGOT(); 573 ResolveInfo* rsym = pReloc.symInfo(); 574 Relocator::Address G = 0; 575 576 if (rsym->isLocal()) { 577 Relocation* lo_reloc = helper_FindLo16Reloc(pReloc); 578 assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_GOT16"); 579 580 int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc); 581 int32_t S = pReloc.symValue(); 582 583 pParent.setAHL(AHL); 584 585 int32_t res = (AHL + S + 0x8000) & 0xFFFF0000; 586 MipsGOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent); 587 588 got_entry.setValue(res); 589 G = got.getGPRelOffset(pParent.getApplyingInput(), got_entry); 590 } 591 else { 592 G = helper_GetGOTOffset(pReloc, pParent); 593 } 594 595 pReloc.target() &= 0xFFFF0000; 596 pReloc.target() |= (G & 0xFFFF); 597 598 return MipsRelocator::OK; 599 } 600 601 // R_MIPS_GOTHI16: 602 // external: (G - (short)G) >> 16 + A 603 static 604 MipsRelocator::Result gothi16(Relocation& pReloc, MipsRelocator& pParent) 605 { 606 int32_t res = 0; 607 608 Relocator::Address G = helper_GetGOTOffset(pReloc, pParent); 609 int32_t A = pReloc.target() + pReloc.addend(); 610 611 res = (G - (int16_t)G) >> (16 + A); 612 613 pReloc.target() &= 0xFFFF0000; 614 pReloc.target() |= (res & 0xFFFF); 615 616 return MipsRelocator::OK; 617 } 618 619 // R_MIPS_GOTLO16: 620 // external: G & 0xffff 621 static 622 MipsRelocator::Result gotlo16(Relocation& pReloc, MipsRelocator& pParent) 623 { 624 Relocator::Address G = helper_GetGOTOffset(pReloc, pParent); 625 626 pReloc.target() &= 0xFFFF0000; 627 pReloc.target() |= (G & 0xFFFF); 628 629 return MipsRelocator::OK; 630 } 631 632 // R_MIPS_CALL16: G 633 static 634 MipsRelocator::Result call16(Relocation& pReloc, MipsRelocator& pParent) 635 { 636 Relocator::Address G = helper_GetGOTOffset(pReloc, pParent); 637 638 pReloc.target() &= 0xFFFF0000; 639 pReloc.target() |= (G & 0xFFFF); 640 641 return MipsRelocator::OK; 642 } 643 644 // R_MIPS_GPREL32: A + S + GP0 - GP 645 static 646 MipsRelocator::Result gprel32(Relocation& pReloc, MipsRelocator& pParent) 647 { 648 // Remember to add the section offset to A. 649 int32_t A = pReloc.target() + pReloc.addend(); 650 int32_t S = pReloc.symValue(); 651 int32_t GP = helper_GetGP(pParent); 652 653 // llvm does not emits SHT_MIPS_REGINFO section. 654 // Assume that GP0 is zero. 655 pReloc.target() = (A + S - GP) & 0xFFFFFFFF; 656 657 return MipsRelocator::OK; 658 } 659 660