X86Relocator.cpp revision d0fbbb227051be16931a1aa9b4a7722ac039c698
1//===- X86Relocator.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/DataTypes.h> 12#include <llvm/Support/ELF.h> 13#include <mcld/Fragment/FragmentLinker.h> 14#include <mcld/Support/MsgHandling.h> 15 16#include "X86Relocator.h" 17#include "X86RelocationFunctions.h" 18 19using namespace mcld; 20 21//===--------------------------------------------------------------------===// 22// Relocation Functions and Tables 23//===--------------------------------------------------------------------===// 24DECL_X86_APPLY_RELOC_FUNCS 25 26/// the prototype of applying function 27typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc, 28 X86Relocator& pParent); 29 30// the table entry of applying functions 31struct ApplyFunctionTriple 32{ 33 ApplyFunctionType func; 34 unsigned int type; 35 const char* name; 36}; 37 38// declare the table of applying functions 39static const ApplyFunctionTriple ApplyFunctions[] = { 40 DECL_X86_APPLY_RELOC_FUNC_PTRS 41}; 42 43//===--------------------------------------------------------------------===// 44// X86Relocator 45//===--------------------------------------------------------------------===// 46X86Relocator::X86Relocator(X86GNULDBackend& pParent) 47 : Relocator(), 48 m_Target(pParent) { 49} 50 51X86Relocator::~X86Relocator() 52{ 53} 54 55Relocator::Result 56X86Relocator::applyRelocation(Relocation& pRelocation) 57{ 58 Relocation::Type type = pRelocation.type(); 59 60 if (type >= sizeof (ApplyFunctions) / sizeof (ApplyFunctions[0]) ) { 61 return Unknown; 62 } 63 64 // apply the relocation 65 return ApplyFunctions[type].func(pRelocation, *this); 66} 67 68const char* X86Relocator::getName(Relocation::Type pType) const 69{ 70 return ApplyFunctions[pType].name; 71} 72 73//===--------------------------------------------------------------------===// 74// Relocation helper function 75//===--------------------------------------------------------------------===// 76 77/// helper_DynRel - Get an relocation entry in .rel.dyn 78static 79Relocation& helper_DynRel(ResolveInfo* pSym, 80 Fragment& pFrag, 81 uint64_t pOffset, 82 X86Relocator::Type pType, 83 X86Relocator& pParent) 84{ 85 X86GNULDBackend& ld_backend = pParent.getTarget(); 86 Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry(); 87 rel_entry.setType(pType); 88 rel_entry.targetRef().assign(pFrag, pOffset); 89 if (pType == llvm::ELF::R_386_RELATIVE || NULL == pSym) 90 rel_entry.setSymInfo(0); 91 else 92 rel_entry.setSymInfo(pSym); 93 94 return rel_entry; 95} 96 97 98/// helper_use_relative_reloc - Check if symbol can use relocation 99/// R_386_RELATIVE 100static bool 101helper_use_relative_reloc(const ResolveInfo& pSym, 102 const X86Relocator& pFactory) 103 104{ 105 // if symbol is dynamic or undefine or preemptible 106 if (pSym.isDyn() || 107 pSym.isUndef() || 108 pFactory.getTarget().isSymbolPreemptible(pSym)) 109 return false; 110 return true; 111} 112 113static 114X86GOTEntry& helper_get_GOT_and_init(Relocation& pReloc, 115 X86Relocator& pParent) 116{ 117 // rsym - The relocation target symbol 118 ResolveInfo* rsym = pReloc.symInfo(); 119 X86GNULDBackend& ld_backend = pParent.getTarget(); 120 121 X86GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym); 122 if (NULL != got_entry) 123 return *got_entry; 124 125 // not found 126 got_entry = ld_backend.getGOT().consume(); 127 pParent.getSymGOTMap().record(*rsym, *got_entry); 128 129 // If we first get this GOT entry, we should initialize it. 130 if (rsym->reserved() & X86GNULDBackend::ReserveGOT) { 131 // No corresponding dynamic relocation, initialize to the symbol value. 132 got_entry->setValue(pReloc.symValue()); 133 } 134 else if (rsym->reserved() & X86GNULDBackend::GOTRel) { 135 // Initialize got_entry content and the corresponding dynamic relocation. 136 if (helper_use_relative_reloc(*rsym, pParent)) { 137 helper_DynRel(rsym, *got_entry, 0x0, llvm::ELF::R_386_RELATIVE, pParent); 138 got_entry->setValue(pReloc.symValue()); 139 } 140 else { 141 helper_DynRel(rsym, *got_entry, 0x0, llvm::ELF::R_386_GLOB_DAT, pParent); 142 got_entry->setValue(0); 143 } 144 } 145 else { 146 fatal(diag::reserve_entry_number_mismatch_got); 147 } 148 return *got_entry; 149} 150 151 152static 153X86Relocator::Address helper_GOT_ORG(X86Relocator& pParent) 154{ 155 return pParent.getTarget().getGOTPLT().addr(); 156} 157 158 159static 160X86Relocator::Address helper_GOT(Relocation& pReloc, X86Relocator& pParent) 161{ 162 X86GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent); 163 X86Relocator::Address got_addr = pParent.getTarget().getGOT().addr(); 164 return got_addr + got_entry.getOffset(); 165} 166 167 168static 169PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc, X86Relocator& pParent) 170{ 171 // rsym - The relocation target symbol 172 ResolveInfo* rsym = pReloc.symInfo(); 173 X86GNULDBackend& ld_backend = pParent.getTarget(); 174 175 PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(*rsym); 176 if (NULL != plt_entry) 177 return *plt_entry; 178 179 // not found 180 plt_entry = ld_backend.getPLT().consume(); 181 pParent.getSymPLTMap().record(*rsym, *plt_entry); 182 // If we first get this PLT entry, we should initialize it. 183 if (rsym->reserved() & X86GNULDBackend::ReservePLT) { 184 X86GOTPLTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym); 185 assert(NULL == gotplt_entry && "PLT entry not exist, but DynRel entry exist!"); 186 gotplt_entry = ld_backend.getGOTPLT().consume(); 187 pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry); 188 // init the corresponding rel entry in .rel.plt 189 Relocation& rel_entry = *ld_backend.getRelPLT().consumeEntry(); 190 rel_entry.setType(llvm::ELF::R_386_JUMP_SLOT); 191 rel_entry.targetRef().assign(*gotplt_entry); 192 rel_entry.setSymInfo(rsym); 193 } 194 else { 195 fatal(diag::reserve_entry_number_mismatch_plt); 196 } 197 198 return *plt_entry; 199} 200 201 202static 203X86Relocator::Address helper_PLT_ORG(X86Relocator& pParent) 204{ 205 return pParent.getTarget().getPLT().addr(); 206} 207 208 209static 210X86Relocator::Address helper_PLT(Relocation& pReloc, X86Relocator& pParent) 211{ 212 PLTEntryBase& plt_entry = helper_get_PLT_and_init(pReloc, pParent); 213 return helper_PLT_ORG(pParent) + plt_entry.getOffset(); 214} 215 216 217//=========================================// 218// Each relocation function implementation // 219//=========================================// 220 221// R_386_NONE 222X86Relocator::Result none(Relocation& pReloc, X86Relocator& pParent) 223{ 224 return X86Relocator::OK; 225} 226 227// R_386_32: S + A 228// R_386_16 229// R_386_8 230X86Relocator::Result abs(Relocation& pReloc, X86Relocator& pParent) 231{ 232 ResolveInfo* rsym = pReloc.symInfo(); 233 Relocator::DWord A = pReloc.target() + pReloc.addend(); 234 Relocator::DWord S = pReloc.symValue(); 235 bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel( 236 pParent.getFragmentLinker(), 237 *rsym, 238 (rsym->reserved() & X86GNULDBackend::ReservePLT), 239 true); 240 241 LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); 242 // If the flag of target section is not ALLOC, we will not scan this relocation 243 // but perform static relocation. (e.g., applying .debug section) 244 if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) { 245 pReloc.target() = S + A; 246 return X86Relocator::OK; 247 } 248 249 // A local symbol may need REL Type dynamic relocation 250 if (rsym->isLocal() && has_dyn_rel) { 251 if (llvm::ELF::R_386_32 == pReloc.type()) { 252 helper_DynRel(rsym, *pReloc.targetRef().frag(), 253 pReloc.targetRef().offset(), llvm::ELF::R_386_RELATIVE, 254 pParent); 255 } 256 else { 257 // FIXME: check Section symbol 258 helper_DynRel(rsym, *pReloc.targetRef().frag(), 259 pReloc.targetRef().offset(), pReloc.type(), pParent); 260 } 261 pReloc.target() = S + A; 262 return X86Relocator::OK; 263 } 264 265 // An external symbol may need PLT and dynamic relocation 266 if (!rsym->isLocal()) { 267 if (rsym->reserved() & X86GNULDBackend::ReservePLT) { 268 S = helper_PLT(pReloc, pParent); 269 } 270 // If we generate a dynamic relocation (except R_386_RELATIVE) 271 // for a place, we should not perform static relocation on it 272 // in order to keep the addend store in the place correct. 273 if (has_dyn_rel) { 274 if (llvm::ELF::R_386_32 == pReloc.type() && 275 helper_use_relative_reloc(*rsym, pParent)) { 276 helper_DynRel(rsym, *pReloc.targetRef().frag(), 277 pReloc.targetRef().offset(), llvm::ELF::R_386_RELATIVE, pParent); 278 } 279 else { 280 helper_DynRel(rsym, *pReloc.targetRef().frag(), 281 pReloc.targetRef().offset(), pReloc.type(), pParent); 282 return X86Relocator::OK; 283 } 284 } 285 } 286 287 // perform static relocation 288 pReloc.target() = S + A; 289 return X86Relocator::OK; 290} 291 292// R_386_PC32: S + A - P 293// R_386_PC16 294// R_386_PC8 295X86Relocator::Result rel(Relocation& pReloc, X86Relocator& pParent) 296{ 297 ResolveInfo* rsym = pReloc.symInfo(); 298 Relocator::DWord A = pReloc.target() + pReloc.addend(); 299 Relocator::DWord S = pReloc.symValue(); 300 Relocator::DWord P = pReloc.place(); 301 302 LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); 303 // If the flag of target section is not ALLOC, we will not scan this relocation 304 // but perform static relocation. (e.g., applying .debug section) 305 if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) { 306 pReloc.target() = S + A - P; 307 return X86Relocator::OK; 308 } 309 310 // An external symbol may need PLT and dynamic relocation 311 if (!rsym->isLocal()) { 312 if (rsym->reserved() & X86GNULDBackend::ReservePLT) { 313 S = helper_PLT(pReloc, pParent); 314 pReloc.target() = S + A - P; 315 } 316 if (pParent.getTarget().symbolNeedsDynRel( 317 pParent.getFragmentLinker(), 318 *rsym, 319 (rsym->reserved() & X86GNULDBackend::ReservePLT), 320 false)) { 321 if (helper_use_relative_reloc(*rsym, pParent) ) { 322 helper_DynRel(rsym, *pReloc.targetRef().frag(), 323 pReloc.targetRef().offset(), llvm::ELF::R_386_RELATIVE, pParent); 324 } 325 else { 326 helper_DynRel(rsym, *pReloc.targetRef().frag(), 327 pReloc.targetRef().offset(), pReloc.type(), pParent); 328 return X86Relocator::OK; 329 } 330 } 331 } 332 333 // perform static relocation 334 pReloc.target() = S + A - P; 335 return X86Relocator::OK; 336} 337 338// R_386_GOTOFF: S + A - GOT_ORG 339X86Relocator::Result gotoff32(Relocation& pReloc, X86Relocator& pParent) 340{ 341 Relocator::DWord A = pReloc.target() + pReloc.addend(); 342 X86Relocator::Address GOT_ORG = helper_GOT_ORG(pParent); 343 X86Relocator::Address S = pReloc.symValue(); 344 345 pReloc.target() = S + A - GOT_ORG; 346 return X86Relocator::OK; 347} 348 349// R_386_GOTPC: GOT_ORG + A - P 350X86Relocator::Result gotpc32(Relocation& pReloc, X86Relocator& pParent) 351{ 352 Relocator::DWord A = pReloc.target() + pReloc.addend(); 353 X86Relocator::Address GOT_ORG = helper_GOT_ORG(pParent); 354 // Apply relocation. 355 pReloc.target() = GOT_ORG + A - pReloc.place(); 356 return X86Relocator::OK; 357} 358 359// R_386_GOT32: GOT(S) + A - GOT_ORG 360X86Relocator::Result got32(Relocation& pReloc, X86Relocator& pParent) 361{ 362 if (!(pReloc.symInfo()->reserved() 363 & (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) { 364 return X86Relocator::BadReloc; 365 } 366 X86Relocator::Address GOT_S = helper_GOT(pReloc, pParent); 367 Relocator::DWord A = pReloc.target() + pReloc.addend(); 368 X86Relocator::Address GOT_ORG = helper_GOT_ORG(pParent); 369 // Apply relocation. 370 pReloc.target() = GOT_S + A - GOT_ORG; 371 return X86Relocator::OK; 372} 373 374// R_386_PLT32: PLT(S) + A - P 375X86Relocator::Result plt32(Relocation& pReloc, X86Relocator& pParent) 376{ 377 // PLT_S depends on if there is a PLT entry. 378 X86Relocator::Address PLT_S; 379 if ((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT)) 380 PLT_S = helper_PLT(pReloc, pParent); 381 else 382 PLT_S = pReloc.symValue(); 383 Relocator::DWord A = pReloc.target() + pReloc.addend(); 384 X86Relocator::Address P = pReloc.place(); 385 pReloc.target() = PLT_S + A - P; 386 return X86Relocator::OK; 387} 388 389// R_386_TLS_GD: 390X86Relocator::Result tls_gd(Relocation& pReloc, X86Relocator& pParent) 391{ 392 // global-dynamic 393 ResolveInfo* rsym = pReloc.symInfo(); 394 // must reserve two pairs of got and dynamic relocation 395 if (!(rsym->reserved() & X86GNULDBackend::GOTRel)) { 396 return X86Relocator::BadReloc; 397 } 398 399 X86GNULDBackend& ld_backend = pParent.getTarget(); 400 ELFFileFormat* file_format = pParent.getTarget().getOutputFormat(); 401 // setup corresponding got and dynamic relocatio entries: 402 // get first got entry, if there is already a got entry for rsym, then apply 403 // this relocation to the got entry directly. If not, setup the corresponding 404 // got and dyn relocation entries 405 X86GOTEntry* got_entry1 = pParent.getSymGOTMap().lookUp(*rsym); 406 407 if (NULL == got_entry1) { 408 // get and init two got entries if not exist 409 got_entry1 = ld_backend.getGOT().consume(); 410 pParent.getSymGOTMap().record(*rsym, *got_entry1); 411 X86GOTEntry* got_entry2 = ld_backend.getGOT().consume(); 412 got_entry1->setValue(0x0); 413 got_entry2->setValue(0x0); 414 // setup dyn rel for get_entry1 415 Relocation& rel_entry1 = helper_DynRel(rsym, *got_entry1, 0x0, 416 llvm::ELF::R_386_TLS_DTPMOD32, pParent); 417 if (rsym->isLocal()) { 418 // for local symbol, set got_entry2 to symbol value 419 got_entry2->setValue(pReloc.symValue()); 420 421 // for local tls symbol, add rel entry against the section symbol this 422 // symbol belong to (.tdata or .tbss) 423 const LDSection* sym_sect = 424 &rsym->outSymbol()->fragRef()->frag()->getParent()->getSection(); 425 ResolveInfo* sect_sym = NULL; 426 if (&file_format->getTData() == sym_sect) 427 sect_sym = pParent.getTarget().getTDATASymbol().resolveInfo(); 428 else 429 sect_sym = pParent.getTarget().getTBSSSymbol().resolveInfo(); 430 rel_entry1.setSymInfo(sect_sym); 431 } 432 else { 433 // for non-local symbol, add a pair of rel entries against this symbol 434 // for those two got entries 435 helper_DynRel(rsym, *got_entry2, 0x0, 436 llvm::ELF::R_386_TLS_DTPOFF32, pParent); 437 } 438 } 439 440 // perform relocation to the first got entry 441 Relocator::DWord A = pReloc.target() + pReloc.addend(); 442 // GOT_OFF - the offset between the got_entry1 and _GLOBAL_OFFSET_TABLE (the 443 // .got.plt section) 444 X86Relocator::Address GOT_OFF = 445 file_format->getGOT().addr() + 446 got_entry1->getOffset() - 447 file_format->getGOTPLT().addr(); 448 pReloc.target() = GOT_OFF + A; 449 return X86Relocator::OK; 450} 451 452// R_386_TLS_LDM 453X86Relocator::Result tls_ldm(Relocation& pReloc, X86Relocator& pParent) 454{ 455 // FIXME: no linker optimization for TLS relocation 456 const X86GOTEntry& got_entry = pParent.getTarget().getTLSModuleID(); 457 458 // All GOT offsets are relative to the end of the GOT. 459 X86Relocator::SWord GOT_S = got_entry.getOffset() - 460 (pParent.getTarget().getGOTPLT().addr() - 461 pParent.getTarget().getGOT().addr()); 462 Relocator::DWord A = pReloc.target() + pReloc.addend(); 463 pReloc.target() = GOT_S + A; 464 465 return X86Relocator::OK; 466} 467 468// R_386_TLS_LDO_32 469X86Relocator::Result tls_ldo_32(Relocation& pReloc, X86Relocator& pParent) 470{ 471 // FIXME: no linker optimization for TLS relocation 472 Relocator::DWord A = pReloc.target() + pReloc.addend(); 473 X86Relocator::Address S = pReloc.symValue(); 474 pReloc.target() = S + A; 475 return X86Relocator::OK; 476} 477 478// R_X86_TLS_IE 479X86Relocator::Result tls_ie(Relocation& pReloc, X86Relocator& pParent) 480{ 481 ResolveInfo* rsym = pReloc.symInfo(); 482 if (!(rsym->reserved() & X86GNULDBackend::GOTRel)) { 483 return X86Relocator::BadReloc; 484 } 485 486 if (rsym->reserved() & X86GNULDBackend::ReserveRel) { 487 // when building shared object, set up a RELATIVE dynamic relocation 488 helper_DynRel(rsym, *pReloc.targetRef().frag(), pReloc.targetRef().offset(), 489 llvm::ELF::R_386_RELATIVE, pParent); 490 } 491 492 // set up the got and dynamic relocation entries if not exist 493 X86GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym); 494 if (NULL == got_entry) { 495 // set got entry 496 X86GNULDBackend& ld_backend = pParent.getTarget(); 497 got_entry = ld_backend.getGOT().consume(); 498 pParent.getSymGOTMap().record(*rsym, *got_entry); 499 got_entry->setValue(0x0); 500 // set relocation entry 501 Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry(); 502 rel_entry.setType(llvm::ELF::R_386_TLS_TPOFF); 503 rel_entry.setSymInfo(rsym); 504 rel_entry.targetRef().assign(*got_entry); 505 } 506 507 // perform relocation to the absolute address of got_entry 508 X86Relocator::Address GOT_S = 509 pParent.getTarget().getGOT().addr() + got_entry->getOffset(); 510 511 Relocator::DWord A = pReloc.target() + pReloc.addend(); 512 pReloc.target() = GOT_S + A; 513 514 return X86Relocator::OK; 515} 516 517// R_386_TLS_GOTIE 518X86Relocator::Result tls_gotie(Relocation& pReloc, X86Relocator& pParent) 519{ 520 ResolveInfo* rsym = pReloc.symInfo(); 521 if (!(rsym->reserved() & X86GNULDBackend::GOTRel)) { 522 return X86Relocator::BadReloc; 523 } 524 525 // set up the got and dynamic relocation entries if not exist 526 X86GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym); 527 if (NULL == got_entry) { 528 // set got entry 529 X86GNULDBackend& ld_backend = pParent.getTarget(); 530 got_entry = ld_backend.getGOT().consume(); 531 pParent.getSymGOTMap().record(*rsym, *got_entry); 532 got_entry->setValue(0x0); 533 // set relocation entry 534 Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry(); 535 rel_entry.setType(llvm::ELF::R_386_TLS_TPOFF); 536 rel_entry.setSymInfo(rsym); 537 rel_entry.targetRef().assign(*got_entry); 538 } 539 540 // All GOT offsets are relative to the end of the GOT. 541 X86Relocator::SWord GOT_S = got_entry->getOffset() - 542 (pParent.getTarget().getGOTPLT().addr() - pParent.getTarget().getGOT().addr()); 543 Relocator::DWord A = pReloc.target() + pReloc.addend(); 544 pReloc.target() = GOT_S + A; 545 546 return X86Relocator::OK; 547} 548 549// R_X86_TLS_LE 550X86Relocator::Result tls_le(Relocation& pReloc, X86Relocator& pParent) 551{ 552 ResolveInfo* rsym = pReloc.symInfo(); 553 if (pReloc.symInfo()->reserved() & X86GNULDBackend::ReserveRel) { 554 helper_DynRel(rsym, 555 *pReloc.targetRef().frag(), 556 pReloc.targetRef().offset(), 557 llvm::ELF::R_386_TLS_TPOFF, 558 pParent); 559 return X86Relocator::OK; 560 } 561 562 // perform static relocation 563 // get TLS segment 564 ELFSegment* tls_seg = pParent.getTarget().elfSegmentTable().find( 565 llvm::ELF::PT_TLS, llvm::ELF::PF_R, 0x0); 566 Relocator::DWord A = pReloc.target() + pReloc.addend(); 567 X86Relocator::Address S = pReloc.symValue(); 568 pReloc.target() = S + A - tls_seg->memsz(); 569 return X86Relocator::OK; 570} 571 572X86Relocator::Result unsupport(Relocation& pReloc, X86Relocator& pParent) 573{ 574 return X86Relocator::Unsupport; 575} 576 577