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