AArch64Relocator.cpp revision a6c24dff8b7fa2551a3a885e77a2e814f5b764a2
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(llvm::ELF::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 llvm::ELF::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 llvm::ELF::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_LO21: 326 case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21: 327 case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21_NC: 328 if (getTarget() 329 .symbolNeedsDynRel( 330 *rsym, (rsym->reserved() & ReservePLT), false)) { 331 if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) { 332 LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym); 333 addCopyReloc(*cpy_sym.resolveInfo()); 334 } 335 } 336 if (getTarget().symbolNeedsPLT(*rsym)) { 337 // create plt for this symbol if it does not have one 338 if (!(rsym->reserved() & ReservePLT)) { 339 // Symbol needs PLT entry, we need a PLT entry 340 // and the corresponding GOT and dynamic relocation entry 341 // in .got and .rel.plt. 342 helper_PLT_init(pReloc, *this); 343 // set PLT bit 344 rsym->setReserved(rsym->reserved() | ReservePLT); 345 } 346 } 347 return; 348 349 case llvm::ELF::R_AARCH64_ADR_GOT_PAGE: 350 case llvm::ELF::R_AARCH64_LD64_GOT_LO12_NC: { 351 // Symbol needs GOT entry, reserve entry in .got 352 // return if we already create GOT for this symbol 353 if (rsym->reserved() & ReserveGOT) 354 return; 355 // if the symbol cannot be fully resolved at link time, then we need a 356 // dynamic relocation 357 if (!getTarget().symbolFinalValueIsKnown(*rsym)) 358 helper_GOT_init(pReloc, true, *this); 359 else 360 helper_GOT_init(pReloc, false, *this); 361 // set GOT bit 362 rsym->setReserved(rsym->reserved() | ReserveGOT); 363 return; 364 } 365 366 default: 367 break; 368 } 369} 370 371void AArch64Relocator::scanRelocation(Relocation& pReloc, 372 IRBuilder& pBuilder, 373 Module& pModule, 374 LDSection& pSection, 375 Input& pInput) { 376 ResolveInfo* rsym = pReloc.symInfo(); 377 assert(rsym != NULL && 378 "ResolveInfo of relocation not set while scanRelocation"); 379 380 assert(pSection.getLink() != NULL); 381 if ((pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC) == 0) 382 return; 383 384 // Scan relocation type to determine if an GOT/PLT/Dynamic Relocation 385 // entries should be created. 386 // FIXME: Below judgements concern nothing about TLS related relocation 387 388 // rsym is local 389 if (rsym->isLocal()) 390 scanLocalReloc(pReloc, pSection); 391 // rsym is external 392 else 393 scanGlobalReloc(pReloc, pBuilder, pSection); 394 395 // check if we shoule issue undefined reference for the relocation target 396 // symbol 397 if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull()) 398 issueUndefRef(pReloc, pSection, pInput); 399} 400 401uint32_t AArch64Relocator::getDebugStringOffset(Relocation& pReloc) const { 402 if (pReloc.type() != llvm::ELF::R_AARCH64_ABS32) 403 error(diag::unsupport_reloc_for_debug_string) 404 << getName(pReloc.type()) << "mclinker@googlegroups.com"; 405 406 if (pReloc.symInfo()->type() == ResolveInfo::Section) 407 return pReloc.target(); 408 else 409 return pReloc.symInfo()->outSymbol()->fragRef()->offset() + 410 pReloc.target() + pReloc.addend(); 411} 412 413void AArch64Relocator::applyDebugStringOffset(Relocation& pReloc, 414 uint32_t pOffset) { 415 pReloc.target() = pOffset; 416} 417 418//===----------------------------------------------------------------------===// 419// Each relocation function implementation 420//===----------------------------------------------------------------------===// 421 422// R_AARCH64_NONE 423Relocator::Result none(Relocation& pReloc, AArch64Relocator& pParent) { 424 return Relocator::OK; 425} 426 427Relocator::Result unsupported(Relocation& pReloc, AArch64Relocator& pParent) { 428 return Relocator::Unsupported; 429} 430 431// R_AARCH64_ABS64: S + A 432// R_AARCH64_ABS32: S + A 433// R_AARCH64_ABS16: S + A 434Relocator::Result abs(Relocation& pReloc, AArch64Relocator& pParent) { 435 ResolveInfo* rsym = pReloc.symInfo(); 436 Relocator::DWord A = pReloc.target() + pReloc.addend(); 437 Relocator::DWord S = pReloc.symValue(); 438 Relocation* dyn_rel = pParent.getRelRelMap().lookUp(pReloc); 439 bool has_dyn_rel = (dyn_rel != NULL); 440 441 LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); 442 // If the flag of target section is not ALLOC, we will not scan this 443 // relocation but perform static relocation. (e.g., applying .debug section) 444 if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) { 445 pReloc.target() = S + A; 446 return Relocator::OK; 447 } 448 // A local symbol may need RELATIVE Type dynamic relocation 449 if (rsym->isLocal() && has_dyn_rel) { 450 dyn_rel->setAddend(S + A); 451 } 452 453 // An external symbol may need PLT and dynamic relocation 454 if (!rsym->isLocal()) { 455 if (rsym->reserved() & AArch64Relocator::ReservePLT) { 456 S = helper_get_PLT_address(*rsym, pParent); 457 } 458 // If we generate a dynamic relocation (except R_AARCH64_64_RELATIVE) 459 // for a place, we should not perform static relocation on it 460 // in order to keep the addend store in the place correct. 461 if (has_dyn_rel) { 462 if (llvm::ELF::R_AARCH64_ABS64 == pReloc.type() && 463 llvm::ELF::R_AARCH64_RELATIVE == dyn_rel->type()) { 464 dyn_rel->setAddend(S + A); 465 } else { 466 dyn_rel->setAddend(A); 467 return Relocator::OK; 468 } 469 } 470 } 471 472 // perform static relocation 473 pReloc.target() = S + A; 474 return Relocator::OK; 475} 476 477// R_AARCH64_PREL64: S + A - P 478// R_AARCH64_PREL32: S + A - P 479// R_AARCH64_PREL16: S + A - P 480Relocator::Result rel(Relocation& pReloc, AArch64Relocator& pParent) { 481 ResolveInfo* rsym = pReloc.symInfo(); 482 Relocator::Address S = pReloc.symValue(); 483 Relocator::DWord A = pReloc.addend(); 484 Relocator::DWord P = pReloc.place(); 485 486 if (llvm::ELF::R_AARCH64_PREL64 != pReloc.type()) 487 A += pReloc.target() & get_mask(pParent.getSize(pReloc.type())); 488 else 489 A += pReloc.target(); 490 491 LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); 492 // If the flag of target section is not ALLOC, we will not scan this 493 // relocation but perform static relocation. (e.g., applying .debug section) 494 if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) { 495 // if plt entry exists, the S value is the plt entry address 496 if (!rsym->isLocal()) { 497 if (rsym->reserved() & AArch64Relocator::ReservePLT) { 498 S = helper_get_PLT_address(*rsym, pParent); 499 } 500 } 501 } 502 503 Relocator::DWord X = S + A - P; 504 pReloc.target() = X; 505 506 if (llvm::ELF::R_AARCH64_PREL64 != pReloc.type() && 507 helper_check_signed_overflow(X, pParent.getSize(pReloc.type()))) 508 return Relocator::Overflow; 509 return Relocator::OK; 510} 511 512// R_AARCH64_ADD_ABS_LO12_NC: S + A 513Relocator::Result add_abs_lo12(Relocation& pReloc, AArch64Relocator& pParent) { 514 Relocator::Address value = 0x0; 515 Relocator::Address S = pReloc.symValue(); 516 Relocator::DWord A = pReloc.addend(); 517 518 value = helper_get_page_offset(S + A); 519 pReloc.target() = helper_reencode_add_imm(pReloc.target(), value); 520 521 return Relocator::OK; 522} 523 524// R_AARCH64_ADR_PREL_LO21: S + A - P 525Relocator::Result adr_prel_lo21(Relocation& pReloc, AArch64Relocator& pParent) { 526 ResolveInfo* rsym = pReloc.symInfo(); 527 Relocator::Address S = pReloc.symValue(); 528 // if plt entry exists, the S value is the plt entry address 529 if (rsym->reserved() & AArch64Relocator::ReservePLT) { 530 S = helper_get_PLT_address(*rsym, pParent); 531 } 532 Relocator::DWord A = pReloc.addend(); 533 Relocator::DWord P = pReloc.place(); 534 Relocator::DWord X = S + A - P; 535 536 pReloc.target() = helper_reencode_adr_imm(pReloc.target(), X); 537 538 return Relocator::OK; 539} 540 541// R_AARCH64_ADR_PREL_PG_HI21: ((PG(S + A) - PG(P)) >> 12) 542// R_AARCH64_ADR_PREL_PG_HI21_NC: ((PG(S + A) - PG(P)) >> 12) 543Relocator::Result adr_prel_pg_hi21(Relocation& pReloc, 544 AArch64Relocator& pParent) { 545 ResolveInfo* rsym = pReloc.symInfo(); 546 Relocator::Address S = pReloc.symValue(); 547 // if plt entry exists, the S value is the plt entry address 548 if (rsym->reserved() & AArch64Relocator::ReservePLT) { 549 S = helper_get_PLT_address(*rsym, pParent); 550 } 551 Relocator::DWord A = pReloc.addend(); 552 Relocator::DWord P = pReloc.place(); 553 Relocator::DWord X = 554 helper_get_page_address(S + A) - helper_get_page_address(P); 555 556 pReloc.target() = helper_reencode_adr_imm(pReloc.target(), (X >> 12)); 557 558 return Relocator::OK; 559} 560 561// R_AARCH64_CALL26: S + A - P 562// R_AARCH64_JUMP26: S + A - P 563Relocator::Result call(Relocation& pReloc, AArch64Relocator& pParent) { 564 // If target is undefined weak symbol, we only need to jump to the 565 // next instruction unless it has PLT entry. Rewrite instruction 566 // to NOP. 567 if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() && 568 !pReloc.symInfo()->isDyn() && 569 !(pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)) { 570 // change target to NOP 571 pReloc.target() = 0xd503201f; 572 return Relocator::OK; 573 } 574 575 Relocator::Address S = pReloc.symValue(); 576 Relocator::DWord A = pReloc.addend(); 577 Relocator::Address P = pReloc.place(); 578 579 // S depends on PLT exists or not 580 if (pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT) 581 S = helper_get_PLT_address(*pReloc.symInfo(), pParent); 582 583 Relocator::DWord X = S + A - P; 584 // TODO: check overflow.. 585 586 pReloc.target() = helper_reencode_branch_offset_26(pReloc.target(), X >> 2); 587 588 return Relocator::OK; 589} 590 591// R_AARCH64_CONDBR19: S + A - P 592Relocator::Result condbr(Relocation& pReloc, AArch64Relocator& pParent) { 593 // If target is undefined weak symbol, we only need to jump to the 594 // next instruction unless it has PLT entry. Rewrite instruction 595 // to NOP. 596 if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() && 597 !pReloc.symInfo()->isDyn() && 598 !(pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)) { 599 // change target to NOP 600 pReloc.target() = 0xd503201f; 601 return Relocator::OK; 602 } 603 604 Relocator::Address S = pReloc.symValue(); 605 Relocator::DWord A = pReloc.addend(); 606 Relocator::Address P = pReloc.place(); 607 608 // S depends on PLT exists or not 609 if (pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT) 610 S = helper_get_PLT_address(*pReloc.symInfo(), pParent); 611 612 Relocator::DWord X = S + A - P; 613 // TODO: check overflow.. 614 615 pReloc.target() = helper_reencode_cond_branch_ofs_19(pReloc.target(), X >> 2); 616 617 return Relocator::OK; 618} 619 620// R_AARCH64_ADR_GOT_PAGE: Page(G(GDAT(S+A))) - Page(P) 621Relocator::Result adr_got_page(Relocation& pReloc, AArch64Relocator& pParent) { 622 if (!(pReloc.symInfo()->reserved() & AArch64Relocator::ReserveGOT)) { 623 return Relocator::BadReloc; 624 } 625 626 Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent); 627 Relocator::DWord A = pReloc.addend(); 628 Relocator::Address P = pReloc.place(); 629 Relocator::DWord X = 630 helper_get_page_address(GOT_S + A) - helper_get_page_address(P); 631 632 pReloc.target() = helper_reencode_adr_imm(pReloc.target(), (X >> 12)); 633 634 // setup got entry value if needed 635 AArch64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo()); 636 if (got_entry != NULL && AArch64Relocator::SymVal == got_entry->getValue()) 637 got_entry->setValue(pReloc.symValue()); 638 // setup relocation addend if needed 639 Relocation* dyn_rela = pParent.getRelRelMap().lookUp(pReloc); 640 if ((dyn_rela != NULL) && (AArch64Relocator::SymVal == dyn_rela->addend())) { 641 dyn_rela->setAddend(pReloc.symValue()); 642 } 643 return Relocator::OK; 644} 645 646// R_AARCH64_LD64_GOT_LO12_NC: G(GDAT(S+A)) 647Relocator::Result ld64_got_lo12(Relocation& pReloc, AArch64Relocator& pParent) { 648 if (!(pReloc.symInfo()->reserved() & AArch64Relocator::ReserveGOT)) { 649 return Relocator::BadReloc; 650 } 651 652 Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent); 653 Relocator::DWord A = pReloc.addend(); 654 Relocator::DWord X = helper_get_page_offset(GOT_S + A); 655 656 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 3)); 657 658 // setup got entry value if needed 659 AArch64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo()); 660 if (got_entry != NULL && AArch64Relocator::SymVal == got_entry->getValue()) 661 got_entry->setValue(pReloc.symValue()); 662 663 // setup relocation addend if needed 664 Relocation* dyn_rela = pParent.getRelRelMap().lookUp(pReloc); 665 if ((dyn_rela != NULL) && (AArch64Relocator::SymVal == dyn_rela->addend())) { 666 dyn_rela->setAddend(pReloc.symValue()); 667 } 668 669 return Relocator::OK; 670} 671 672// R_AARCH64_LDST8_ABS_LO12_NC: S + A 673// R_AARCH64_LDST16_ABS_LO12_NC: S + A 674// R_AARCH64_LDST32_ABS_LO12_NC: S + A 675// R_AARCH64_LDST64_ABS_LO12_NC: S + A 676// R_AARCH64_LDST128_ABS_LO12_NC: S + A 677Relocator::Result ldst_abs_lo12(Relocation& pReloc, AArch64Relocator& pParent) { 678 Relocator::Address S = pReloc.symValue(); 679 Relocator::DWord A = pReloc.addend(); 680 Relocator::DWord X = helper_get_page_offset(S + A); 681 682 switch (pReloc.type()) { 683 case llvm::ELF::R_AARCH64_LDST8_ABS_LO12_NC: 684 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), X); 685 break; 686 case llvm::ELF::R_AARCH64_LDST16_ABS_LO12_NC: 687 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 1)); 688 break; 689 case llvm::ELF::R_AARCH64_LDST32_ABS_LO12_NC: 690 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 2)); 691 break; 692 case llvm::ELF::R_AARCH64_LDST64_ABS_LO12_NC: 693 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 3)); 694 break; 695 case llvm::ELF::R_AARCH64_LDST128_ABS_LO12_NC: 696 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 4)); 697 break; 698 default: 699 break; 700 } 701 return Relocator::OK; 702} 703 704} // namespace mcld 705