1 //===- AArch64Relocator.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 "mcld/LinkerConfig.h" 11 #include "mcld/IRBuilder.h" 12 #include "mcld/Support/MsgHandling.h" 13 #include "mcld/LD/LDSymbol.h" 14 #include "mcld/LD/ELFFileFormat.h" 15 #include "mcld/Object/ObjectBuilder.h" 16 17 #include "AArch64Relocator.h" 18 #include "AArch64RelocationFunctions.h" 19 #include "AArch64RelocationHelpers.h" 20 21 #include <llvm/ADT/Twine.h> 22 #include <llvm/Support/DataTypes.h> 23 #include <llvm/Support/ELF.h> 24 #include <llvm/Support/Host.h> 25 26 namespace mcld { 27 28 //===----------------------------------------------------------------------===// 29 // Relocation Functions and Tables 30 //===----------------------------------------------------------------------===// 31 DECL_AARCH64_APPLY_RELOC_FUNCS 32 33 /// the prototype of applying function 34 typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc, 35 AArch64Relocator& pParent); 36 37 // the table entry of applying functions 38 class ApplyFunctionEntry { 39 public: 40 ApplyFunctionEntry() {} 41 ApplyFunctionEntry(ApplyFunctionType pFunc, 42 const char* pName, 43 size_t pSize = 0) 44 : func(pFunc), name(pName), size(pSize) {} 45 ApplyFunctionType func; 46 const char* name; 47 size_t size; 48 }; 49 typedef std::map<Relocator::Type, ApplyFunctionEntry> ApplyFunctionMap; 50 51 static const ApplyFunctionMap::value_type ApplyFunctionList[] = { 52 DECL_AARCH64_APPLY_RELOC_FUNC_PTRS(ApplyFunctionMap::value_type, 53 ApplyFunctionEntry)}; 54 55 // declare the table of applying functions 56 static ApplyFunctionMap ApplyFunctions(ApplyFunctionList, 57 ApplyFunctionList + 58 sizeof(ApplyFunctionList) / 59 sizeof(ApplyFunctionList[0])); 60 61 //===----------------------------------------------------------------------===// 62 // AArch64Relocator 63 //===----------------------------------------------------------------------===// 64 AArch64Relocator::AArch64Relocator(AArch64GNULDBackend& pParent, 65 const LinkerConfig& pConfig) 66 : Relocator(pConfig), m_Target(pParent) { 67 } 68 69 AArch64Relocator::~AArch64Relocator() { 70 } 71 72 Relocator::Result AArch64Relocator::applyRelocation(Relocation& pRelocation) { 73 Relocation::Type type = pRelocation.type(); 74 // valid types are 0x0, 0x100-1032, and R_AARCH64_REWRITE_INSN 75 if ((type < 0x100 || type > 1032) && 76 (type != 0x0) && 77 (type != R_AARCH64_REWRITE_INSN)) { 78 return Relocator::Unknown; 79 } 80 assert(ApplyFunctions.find(type) != ApplyFunctions.end()); 81 return ApplyFunctions[type].func(pRelocation, *this); 82 } 83 84 const char* AArch64Relocator::getName(Relocator::Type pType) const { 85 assert(ApplyFunctions.find(pType) != ApplyFunctions.end()); 86 return ApplyFunctions[pType].name; 87 } 88 89 Relocator::Size AArch64Relocator::getSize(Relocation::Type pType) const { 90 return ApplyFunctions[pType].size; 91 } 92 93 void AArch64Relocator::addCopyReloc(ResolveInfo& pSym) { 94 Relocation& rel_entry = *getTarget().getRelaDyn().create(); 95 rel_entry.setType(llvm::ELF::R_AARCH64_COPY); 96 assert(pSym.outSymbol()->hasFragRef()); 97 rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef()); 98 rel_entry.setSymInfo(&pSym); 99 } 100 101 /// defineSymbolForCopyReloc 102 /// For a symbol needing copy relocation, define a copy symbol in the BSS 103 /// section and all other reference to this symbol should refer to this 104 /// copy. 105 /// This is executed at scan relocation stage. 106 LDSymbol& AArch64Relocator::defineSymbolforCopyReloc(IRBuilder& pBuilder, 107 const ResolveInfo& pSym) { 108 // get or create corresponding BSS LDSection 109 LDSection* bss_sect_hdr = NULL; 110 ELFFileFormat* file_format = getTarget().getOutputFormat(); 111 if (ResolveInfo::ThreadLocal == pSym.type()) 112 bss_sect_hdr = &file_format->getTBSS(); 113 else 114 bss_sect_hdr = &file_format->getBSS(); 115 116 // get or create corresponding BSS SectionData 117 SectionData* bss_data = NULL; 118 if (bss_sect_hdr->hasSectionData()) 119 bss_data = bss_sect_hdr->getSectionData(); 120 else 121 bss_data = IRBuilder::CreateSectionData(*bss_sect_hdr); 122 123 // Determine the alignment by the symbol value 124 // FIXME: here we use the largest alignment 125 uint32_t addralign = config().targets().bitclass() / 8; 126 127 // allocate space in BSS for the copy symbol 128 Fragment* frag = new FillFragment(0x0, 1, pSym.size()); 129 uint64_t size = ObjectBuilder::AppendFragment(*frag, *bss_data, addralign); 130 bss_sect_hdr->setSize(bss_sect_hdr->size() + size); 131 132 // change symbol binding to Global if it's a weak symbol 133 ResolveInfo::Binding binding = (ResolveInfo::Binding)pSym.binding(); 134 if (binding == ResolveInfo::Weak) 135 binding = ResolveInfo::Global; 136 137 // Define the copy symbol in the bss section and resolve it 138 LDSymbol* cpy_sym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( 139 pSym.name(), 140 (ResolveInfo::Type)pSym.type(), 141 ResolveInfo::Define, 142 binding, 143 pSym.size(), // size 144 0x0, // value 145 FragmentRef::Create(*frag, 0x0), 146 (ResolveInfo::Visibility)pSym.other()); 147 148 return *cpy_sym; 149 } 150 151 void AArch64Relocator::scanLocalReloc(Relocation& pReloc, 152 const LDSection& pSection) { 153 // rsym - The relocation target symbol 154 ResolveInfo* rsym = pReloc.symInfo(); 155 switch (pReloc.type()) { 156 case llvm::ELF::R_AARCH64_ABS64: 157 // If buiding PIC object (shared library or PIC executable), 158 // a dynamic relocations with RELATIVE type to this location is needed. 159 // Reserve an entry in .rel.dyn 160 if (config().isCodeIndep()) { 161 // set Rel bit 162 rsym->setReserved(rsym->reserved() | ReserveRel); 163 getTarget().checkAndSetHasTextRel(*pSection.getLink()); 164 // set up the dyn rel directly 165 Relocation& reloc = helper_DynRela_init(rsym, 166 *pReloc.targetRef().frag(), 167 pReloc.targetRef().offset(), 168 llvm::ELF::R_AARCH64_RELATIVE, 169 *this); 170 getRelRelMap().record(pReloc, reloc); 171 } 172 return; 173 174 case llvm::ELF::R_AARCH64_ABS32: 175 case llvm::ELF::R_AARCH64_ABS16: 176 // If buiding PIC object (shared library or PIC executable), 177 // a dynamic relocations with RELATIVE type to this location is needed. 178 // Reserve an entry in .rel.dyn 179 if (config().isCodeIndep()) { 180 // set up the dyn rel directly 181 Relocation& reloc = helper_DynRela_init(rsym, 182 *pReloc.targetRef().frag(), 183 pReloc.targetRef().offset(), 184 pReloc.type(), 185 *this); 186 getRelRelMap().record(pReloc, reloc); 187 // set Rel bit 188 rsym->setReserved(rsym->reserved() | ReserveRel); 189 getTarget().checkAndSetHasTextRel(*pSection.getLink()); 190 } 191 return; 192 193 case llvm::ELF::R_AARCH64_ADR_GOT_PAGE: 194 case llvm::ELF::R_AARCH64_LD64_GOT_LO12_NC: { 195 // Symbol needs GOT entry, reserve entry in .got 196 // return if we already create GOT for this symbol 197 if (rsym->reserved() & ReserveGOT) 198 return; 199 // If building PIC object, a dynamic relocation with 200 // type RELATIVE is needed to relocate this GOT entry. 201 if (config().isCodeIndep()) 202 helper_GOT_init(pReloc, true, *this); 203 else 204 helper_GOT_init(pReloc, false, *this); 205 // set GOT bit 206 rsym->setReserved(rsym->reserved() | ReserveGOT); 207 return; 208 } 209 210 default: 211 break; 212 } 213 } 214 215 void AArch64Relocator::scanGlobalReloc(Relocation& pReloc, 216 IRBuilder& pBuilder, 217 const LDSection& pSection) { 218 // rsym - The relocation target symbol 219 ResolveInfo* rsym = pReloc.symInfo(); 220 switch (pReloc.type()) { 221 case llvm::ELF::R_AARCH64_ABS64: 222 case llvm::ELF::R_AARCH64_ABS32: 223 case llvm::ELF::R_AARCH64_ABS16: 224 // Absolute relocation type, symbol may needs PLT entry or 225 // dynamic relocation entry 226 if (getTarget().symbolNeedsPLT(*rsym)) { 227 // create plt for this symbol if it does not have one 228 if (!(rsym->reserved() & ReservePLT)) { 229 // Symbol needs PLT entry, we need a PLT entry 230 // and the corresponding GOT and dynamic relocation entry 231 // in .got and .rel.plt. 232 helper_PLT_init(pReloc, *this); 233 // set PLT bit 234 rsym->setReserved(rsym->reserved() | ReservePLT); 235 } 236 } 237 238 if (getTarget() 239 .symbolNeedsDynRel( 240 *rsym, (rsym->reserved() & ReservePLT), true)) { 241 // symbol needs dynamic relocation entry, set up the dynrel entry 242 if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) { 243 LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym); 244 addCopyReloc(*cpy_sym.resolveInfo()); 245 } else { 246 // set Rel bit and the dyn rel 247 rsym->setReserved(rsym->reserved() | ReserveRel); 248 getTarget().checkAndSetHasTextRel(*pSection.getLink()); 249 if (llvm::ELF::R_AARCH64_ABS64 == pReloc.type() && 250 helper_use_relative_reloc(*rsym, *this)) { 251 Relocation& reloc = 252 helper_DynRela_init(rsym, 253 *pReloc.targetRef().frag(), 254 pReloc.targetRef().offset(), 255 llvm::ELF::R_AARCH64_RELATIVE, 256 *this); 257 getRelRelMap().record(pReloc, reloc); 258 } else { 259 Relocation& reloc = helper_DynRela_init(rsym, 260 *pReloc.targetRef().frag(), 261 pReloc.targetRef().offset(), 262 pReloc.type(), 263 *this); 264 getRelRelMap().record(pReloc, reloc); 265 } 266 } 267 } 268 return; 269 270 case llvm::ELF::R_AARCH64_PREL64: 271 case llvm::ELF::R_AARCH64_PREL32: 272 case llvm::ELF::R_AARCH64_PREL16: 273 if (getTarget().symbolNeedsPLT(*rsym) && 274 LinkerConfig::DynObj != config().codeGenType()) { 275 // create plt for this symbol if it does not have one 276 if (!(rsym->reserved() & ReservePLT)) { 277 // Symbol needs PLT entry, we need a PLT entry 278 // and the corresponding GOT and dynamic relocation entry 279 // in .got and .rel.plt. 280 helper_PLT_init(pReloc, *this); 281 // set PLT bit 282 rsym->setReserved(rsym->reserved() | ReservePLT); 283 } 284 } 285 286 // Only PC relative relocation against dynamic symbol needs a 287 // dynamic relocation. Only dynamic copy relocation is allowed 288 // and PC relative relocation will be resolved to the local copy. 289 // All other dynamic relocations may lead to run-time relocation 290 // overflow. 291 if (getTarget().isDynamicSymbol(*rsym) && 292 getTarget() 293 .symbolNeedsDynRel( 294 *rsym, (rsym->reserved() & ReservePLT), false) && 295 getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) { 296 LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym); 297 addCopyReloc(*cpy_sym.resolveInfo()); 298 } 299 return; 300 301 case llvm::ELF::R_AARCH64_CONDBR19: 302 case llvm::ELF::R_AARCH64_JUMP26: 303 case llvm::ELF::R_AARCH64_CALL26: { 304 // return if we already create plt for this symbol 305 if (rsym->reserved() & ReservePLT) 306 return; 307 308 // if the symbol's value can be decided at link time, then no need plt 309 if (getTarget().symbolFinalValueIsKnown(*rsym)) 310 return; 311 312 // if symbol is defined in the ouput file and it's not 313 // preemptible, no need plt 314 if (rsym->isDefine() && !rsym->isDyn() && 315 !getTarget().isSymbolPreemptible(*rsym)) { 316 return; 317 } 318 319 // Symbol needs PLT entry, we need to reserve a PLT entry 320 // and the corresponding GOT and dynamic relocation entry 321 // in .got and .rel.plt. 322 helper_PLT_init(pReloc, *this); 323 // set PLT bit 324 rsym->setReserved(rsym->reserved() | ReservePLT); 325 return; 326 } 327 328 case llvm::ELF::R_AARCH64_ADR_PREL_LO21: 329 case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21: 330 case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21_NC: 331 if (getTarget() 332 .symbolNeedsDynRel( 333 *rsym, (rsym->reserved() & ReservePLT), false)) { 334 if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) { 335 LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym); 336 addCopyReloc(*cpy_sym.resolveInfo()); 337 } 338 } 339 if (getTarget().symbolNeedsPLT(*rsym)) { 340 // create plt for this symbol if it does not have one 341 if (!(rsym->reserved() & ReservePLT)) { 342 // Symbol needs PLT entry, we need a PLT entry 343 // and the corresponding GOT and dynamic relocation entry 344 // in .got and .rel.plt. 345 helper_PLT_init(pReloc, *this); 346 // set PLT bit 347 rsym->setReserved(rsym->reserved() | ReservePLT); 348 } 349 } 350 return; 351 352 case llvm::ELF::R_AARCH64_ADR_GOT_PAGE: 353 case llvm::ELF::R_AARCH64_LD64_GOT_LO12_NC: { 354 // Symbol needs GOT entry, reserve entry in .got 355 // return if we already create GOT for this symbol 356 if (rsym->reserved() & ReserveGOT) 357 return; 358 // if the symbol cannot be fully resolved at link time, then we need a 359 // dynamic relocation 360 if (!getTarget().symbolFinalValueIsKnown(*rsym)) 361 helper_GOT_init(pReloc, true, *this); 362 else 363 helper_GOT_init(pReloc, false, *this); 364 // set GOT bit 365 rsym->setReserved(rsym->reserved() | ReserveGOT); 366 return; 367 } 368 369 default: 370 break; 371 } 372 } 373 374 void AArch64Relocator::scanRelocation(Relocation& pReloc, 375 IRBuilder& pBuilder, 376 Module& pModule, 377 LDSection& pSection, 378 Input& pInput) { 379 ResolveInfo* rsym = pReloc.symInfo(); 380 assert(rsym != NULL && 381 "ResolveInfo of relocation not set while scanRelocation"); 382 383 assert(pSection.getLink() != NULL); 384 if ((pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC) == 0) 385 return; 386 387 // Scan relocation type to determine if an GOT/PLT/Dynamic Relocation 388 // entries should be created. 389 // FIXME: Below judgements concern nothing about TLS related relocation 390 391 // rsym is local 392 if (rsym->isLocal()) 393 scanLocalReloc(pReloc, pSection); 394 // rsym is external 395 else 396 scanGlobalReloc(pReloc, pBuilder, pSection); 397 398 // check if we shoule issue undefined reference for the relocation target 399 // symbol 400 if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull()) 401 issueUndefRef(pReloc, pSection, pInput); 402 } 403 404 bool 405 AArch64Relocator::mayHaveFunctionPointerAccess(const Relocation& pReloc) const { 406 switch (pReloc.type()) { 407 case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21: 408 case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21_NC: 409 case llvm::ELF::R_AARCH64_ADD_ABS_LO12_NC: 410 case llvm::ELF::R_AARCH64_ADR_GOT_PAGE: 411 case llvm::ELF::R_AARCH64_LD64_GOT_LO12_NC: { 412 return true; 413 } 414 default: { 415 if (pReloc.symInfo()->isLocal()) { 416 // Do not fold any local symbols if building a shared object. 417 return (config().codeGenType() == LinkerConfig::DynObj); 418 } else { 419 // Do not fold any none global defualt symbols if building a shared 420 // object. 421 return ((config().codeGenType() == LinkerConfig::DynObj) && 422 (pReloc.symInfo()->visibility() != ResolveInfo::Default)); 423 } 424 } 425 } 426 return false; 427 } 428 429 uint32_t AArch64Relocator::getDebugStringOffset(Relocation& pReloc) const { 430 if (pReloc.type() != llvm::ELF::R_AARCH64_ABS32) 431 error(diag::unsupport_reloc_for_debug_string) 432 << getName(pReloc.type()) << "mclinker (at) googlegroups.com"; 433 434 if (pReloc.symInfo()->type() == ResolveInfo::Section) 435 return pReloc.target() + pReloc.addend(); 436 else 437 return pReloc.symInfo()->outSymbol()->fragRef()->offset() + 438 pReloc.target() + pReloc.addend(); 439 } 440 441 void AArch64Relocator::applyDebugStringOffset(Relocation& pReloc, 442 uint32_t pOffset) { 443 pReloc.target() = pOffset; 444 } 445 446 //===----------------------------------------------------------------------===// 447 // Each relocation function implementation 448 //===----------------------------------------------------------------------===// 449 450 // R_AARCH64_NONE 451 Relocator::Result none(Relocation& pReloc, AArch64Relocator& pParent) { 452 return Relocator::OK; 453 } 454 455 Relocator::Result unsupported(Relocation& pReloc, AArch64Relocator& pParent) { 456 return Relocator::Unsupported; 457 } 458 459 // R_AARCH64_ABS64: S + A 460 // R_AARCH64_ABS32: S + A 461 // R_AARCH64_ABS16: S + A 462 Relocator::Result abs(Relocation& pReloc, AArch64Relocator& pParent) { 463 ResolveInfo* rsym = pReloc.symInfo(); 464 Relocator::DWord A = pReloc.target() + pReloc.addend(); 465 Relocator::DWord S = pReloc.symValue(); 466 Relocation* dyn_rel = pParent.getRelRelMap().lookUp(pReloc); 467 bool has_dyn_rel = (dyn_rel != NULL); 468 469 LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); 470 // If the flag of target section is not ALLOC, we will not scan this 471 // relocation but perform static relocation. (e.g., applying .debug section) 472 if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) { 473 pReloc.target() = S + A; 474 return Relocator::OK; 475 } 476 // A local symbol may need RELATIVE Type dynamic relocation 477 if (rsym->isLocal() && has_dyn_rel) { 478 dyn_rel->setAddend(S + A); 479 } 480 481 // An external symbol may need PLT and dynamic relocation 482 if (!rsym->isLocal()) { 483 if (rsym->reserved() & AArch64Relocator::ReservePLT) { 484 S = helper_get_PLT_address(*rsym, pParent); 485 } 486 // If we generate a dynamic relocation (except R_AARCH64_64_RELATIVE) 487 // for a place, we should not perform static relocation on it 488 // in order to keep the addend store in the place correct. 489 if (has_dyn_rel) { 490 if (llvm::ELF::R_AARCH64_ABS64 == pReloc.type() && 491 llvm::ELF::R_AARCH64_RELATIVE == dyn_rel->type()) { 492 dyn_rel->setAddend(S + A); 493 } else { 494 dyn_rel->setAddend(A); 495 return Relocator::OK; 496 } 497 } 498 } 499 500 // perform static relocation 501 pReloc.target() = S + A; 502 return Relocator::OK; 503 } 504 505 // R_AARCH64_PREL64: S + A - P 506 // R_AARCH64_PREL32: S + A - P 507 // R_AARCH64_PREL16: S + A - P 508 Relocator::Result rel(Relocation& pReloc, AArch64Relocator& pParent) { 509 ResolveInfo* rsym = pReloc.symInfo(); 510 Relocator::Address S = pReloc.symValue(); 511 Relocator::DWord A = pReloc.addend(); 512 Relocator::DWord P = pReloc.place(); 513 514 if (llvm::ELF::R_AARCH64_PREL64 != pReloc.type()) 515 A += pReloc.target() & get_mask(pParent.getSize(pReloc.type())); 516 else 517 A += pReloc.target(); 518 519 LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); 520 // If the flag of target section is not ALLOC, we will not scan this 521 // relocation but perform static relocation. (e.g., applying .debug section) 522 if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) { 523 // if plt entry exists, the S value is the plt entry address 524 if (!rsym->isLocal()) { 525 if (rsym->reserved() & AArch64Relocator::ReservePLT) { 526 S = helper_get_PLT_address(*rsym, pParent); 527 } 528 } 529 } 530 531 Relocator::DWord X = S + A - P; 532 pReloc.target() = X; 533 534 if (llvm::ELF::R_AARCH64_PREL64 != pReloc.type() && 535 helper_check_signed_overflow(X, pParent.getSize(pReloc.type()))) 536 return Relocator::Overflow; 537 return Relocator::OK; 538 } 539 540 // R_AARCH64_ADD_ABS_LO12_NC: S + A 541 Relocator::Result add_abs_lo12(Relocation& pReloc, AArch64Relocator& pParent) { 542 Relocator::Address value = 0x0; 543 Relocator::Address S = pReloc.symValue(); 544 Relocator::DWord A = pReloc.addend(); 545 546 value = helper_get_page_offset(S + A); 547 pReloc.target() = helper_reencode_add_imm(pReloc.target(), value); 548 549 return Relocator::OK; 550 } 551 552 // R_AARCH64_ADR_PREL_LO21: S + A - P 553 Relocator::Result adr_prel_lo21(Relocation& pReloc, AArch64Relocator& pParent) { 554 ResolveInfo* rsym = pReloc.symInfo(); 555 Relocator::Address S = pReloc.symValue(); 556 // if plt entry exists, the S value is the plt entry address 557 if (rsym->reserved() & AArch64Relocator::ReservePLT) { 558 S = helper_get_PLT_address(*rsym, pParent); 559 } 560 Relocator::DWord A = pReloc.addend(); 561 Relocator::DWord P = pReloc.place(); 562 Relocator::DWord X = S + A - P; 563 564 pReloc.target() = helper_reencode_adr_imm(pReloc.target(), X); 565 566 return Relocator::OK; 567 } 568 569 // R_AARCH64_ADR_PREL_PG_HI21: ((PG(S + A) - PG(P)) >> 12) 570 // R_AARCH64_ADR_PREL_PG_HI21_NC: ((PG(S + A) - PG(P)) >> 12) 571 Relocator::Result adr_prel_pg_hi21(Relocation& pReloc, 572 AArch64Relocator& pParent) { 573 ResolveInfo* rsym = pReloc.symInfo(); 574 Relocator::Address S = pReloc.symValue(); 575 // if plt entry exists, the S value is the plt entry address 576 if (rsym->reserved() & AArch64Relocator::ReservePLT) { 577 S = helper_get_PLT_address(*rsym, pParent); 578 } 579 Relocator::DWord A = pReloc.addend(); 580 Relocator::DWord P = pReloc.place(); 581 Relocator::DWord X = 582 helper_get_page_address(S + A) - helper_get_page_address(P); 583 584 pReloc.target() = helper_reencode_adr_imm(pReloc.target(), (X >> 12)); 585 586 return Relocator::OK; 587 } 588 589 // R_AARCH64_CALL26: S + A - P 590 // R_AARCH64_JUMP26: S + A - P 591 Relocator::Result call(Relocation& pReloc, AArch64Relocator& pParent) { 592 // If target is undefined weak symbol, we only need to jump to the 593 // next instruction unless it has PLT entry. Rewrite instruction 594 // to NOP. 595 if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() && 596 !pReloc.symInfo()->isDyn() && 597 !(pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)) { 598 // change target to NOP 599 pReloc.target() = 0xd503201f; 600 return Relocator::OK; 601 } 602 603 Relocator::Address S = pReloc.symValue(); 604 Relocator::DWord A = pReloc.addend(); 605 Relocator::Address P = pReloc.place(); 606 607 // S depends on PLT exists or not 608 if (pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT) 609 S = helper_get_PLT_address(*pReloc.symInfo(), pParent); 610 611 Relocator::DWord X = S + A - P; 612 // TODO: check overflow.. 613 614 pReloc.target() = helper_reencode_branch_offset_26(pReloc.target(), X >> 2); 615 616 return Relocator::OK; 617 } 618 619 // R_AARCH64_CONDBR19: S + A - P 620 Relocator::Result condbr(Relocation& pReloc, AArch64Relocator& pParent) { 621 // If target is undefined weak symbol, we only need to jump to the 622 // next instruction unless it has PLT entry. Rewrite instruction 623 // to NOP. 624 if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() && 625 !pReloc.symInfo()->isDyn() && 626 !(pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)) { 627 // change target to NOP 628 pReloc.target() = 0xd503201f; 629 return Relocator::OK; 630 } 631 632 Relocator::Address S = pReloc.symValue(); 633 Relocator::DWord A = pReloc.addend(); 634 Relocator::Address P = pReloc.place(); 635 636 // S depends on PLT exists or not 637 if (pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT) 638 S = helper_get_PLT_address(*pReloc.symInfo(), pParent); 639 640 Relocator::DWord X = S + A - P; 641 // TODO: check overflow.. 642 643 pReloc.target() = helper_reencode_cond_branch_ofs_19(pReloc.target(), X >> 2); 644 645 return Relocator::OK; 646 } 647 648 // R_AARCH64_ADR_GOT_PAGE: Page(G(GDAT(S+A))) - Page(P) 649 Relocator::Result adr_got_page(Relocation& pReloc, AArch64Relocator& pParent) { 650 if (!(pReloc.symInfo()->reserved() & AArch64Relocator::ReserveGOT)) { 651 return Relocator::BadReloc; 652 } 653 654 Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent); 655 Relocator::DWord A = pReloc.addend(); 656 Relocator::Address P = pReloc.place(); 657 Relocator::DWord X = 658 helper_get_page_address(GOT_S + A) - helper_get_page_address(P); 659 660 pReloc.target() = helper_reencode_adr_imm(pReloc.target(), (X >> 12)); 661 662 // setup got entry value if needed 663 AArch64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo()); 664 if (got_entry != NULL && AArch64Relocator::SymVal == got_entry->getValue()) 665 got_entry->setValue(pReloc.symValue()); 666 // setup relocation addend if needed 667 Relocation* dyn_rela = pParent.getRelRelMap().lookUp(pReloc); 668 if ((dyn_rela != NULL) && (AArch64Relocator::SymVal == dyn_rela->addend())) { 669 dyn_rela->setAddend(pReloc.symValue()); 670 } 671 return Relocator::OK; 672 } 673 674 // R_AARCH64_LD64_GOT_LO12_NC: G(GDAT(S+A)) 675 Relocator::Result ld64_got_lo12(Relocation& pReloc, AArch64Relocator& pParent) { 676 if (!(pReloc.symInfo()->reserved() & AArch64Relocator::ReserveGOT)) { 677 return Relocator::BadReloc; 678 } 679 680 Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent); 681 Relocator::DWord A = pReloc.addend(); 682 Relocator::DWord X = helper_get_page_offset(GOT_S + A); 683 684 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 3)); 685 686 // setup got entry value if needed 687 AArch64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo()); 688 if (got_entry != NULL && AArch64Relocator::SymVal == got_entry->getValue()) 689 got_entry->setValue(pReloc.symValue()); 690 691 // setup relocation addend if needed 692 Relocation* dyn_rela = pParent.getRelRelMap().lookUp(pReloc); 693 if ((dyn_rela != NULL) && (AArch64Relocator::SymVal == dyn_rela->addend())) { 694 dyn_rela->setAddend(pReloc.symValue()); 695 } 696 697 return Relocator::OK; 698 } 699 700 // R_AARCH64_LDST8_ABS_LO12_NC: S + A 701 // R_AARCH64_LDST16_ABS_LO12_NC: S + A 702 // R_AARCH64_LDST32_ABS_LO12_NC: S + A 703 // R_AARCH64_LDST64_ABS_LO12_NC: S + A 704 // R_AARCH64_LDST128_ABS_LO12_NC: S + A 705 Relocator::Result ldst_abs_lo12(Relocation& pReloc, AArch64Relocator& pParent) { 706 Relocator::Address S = pReloc.symValue(); 707 Relocator::DWord A = pReloc.addend(); 708 Relocator::DWord X = helper_get_page_offset(S + A); 709 710 switch (pReloc.type()) { 711 case llvm::ELF::R_AARCH64_LDST8_ABS_LO12_NC: 712 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), X); 713 break; 714 case llvm::ELF::R_AARCH64_LDST16_ABS_LO12_NC: 715 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 1)); 716 break; 717 case llvm::ELF::R_AARCH64_LDST32_ABS_LO12_NC: 718 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 2)); 719 break; 720 case llvm::ELF::R_AARCH64_LDST64_ABS_LO12_NC: 721 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 3)); 722 break; 723 case llvm::ELF::R_AARCH64_LDST128_ABS_LO12_NC: 724 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 4)); 725 break; 726 default: 727 break; 728 } 729 return Relocator::OK; 730 } 731 732 } // namespace mcld 733