1//===- X86LDBackend.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#include "X86.h" 10#include "X86ELFDynamic.h" 11#include "X86LDBackend.h" 12#include "X86Relocator.h" 13#include "X86GNUInfo.h" 14 15#include <llvm/ADT/Triple.h> 16#include <llvm/Support/Casting.h> 17 18#include <mcld/LinkerConfig.h> 19#include <mcld/IRBuilder.h> 20#include <mcld/Fragment/FillFragment.h> 21#include <mcld/Fragment/RegionFragment.h> 22#include <mcld/Fragment/FragmentLinker.h> 23#include <mcld/Support/MemoryRegion.h> 24#include <mcld/Support/MsgHandling.h> 25#include <mcld/Support/TargetRegistry.h> 26#include <mcld/Object/ObjectBuilder.h> 27 28#include <cstring> 29 30using namespace mcld; 31 32//===----------------------------------------------------------------------===// 33// X86GNULDBackend 34//===----------------------------------------------------------------------===// 35X86GNULDBackend::X86GNULDBackend(const LinkerConfig& pConfig, 36 GNUInfo* pInfo, 37 Relocation::Type pCopyRel) 38 : GNULDBackend(pConfig, pInfo), 39 m_pRelocator(NULL), 40 m_pPLT(NULL), 41 m_pRelDyn(NULL), 42 m_pRelPLT(NULL), 43 m_pDynamic(NULL), 44 m_pGOTSymbol(NULL), 45 m_CopyRel(pCopyRel) 46{ 47 Triple::ArchType arch = pConfig.targets().triple().getArch(); 48 assert (arch == Triple::x86 || arch == Triple::x86_64); 49 if (arch == Triple::x86 || 50 pConfig.targets().triple().getEnvironment() == Triple::GNUX32) { 51 m_RelEntrySize = 8; 52 m_RelaEntrySize = 12; 53 if (arch == Triple::x86) 54 m_PointerRel = llvm::ELF::R_386_32; 55 else 56 m_PointerRel = llvm::ELF::R_X86_64_32; 57 } 58 else { 59 m_RelEntrySize = 16; 60 m_RelaEntrySize = 24; 61 m_PointerRel = llvm::ELF::R_X86_64_64; 62 } 63} 64 65X86GNULDBackend::~X86GNULDBackend() 66{ 67 delete m_pRelocator; 68 delete m_pPLT; 69 delete m_pRelDyn; 70 delete m_pRelPLT; 71 delete m_pDynamic; 72} 73 74Relocator* X86GNULDBackend::getRelocator() 75{ 76 assert(NULL != m_pRelocator); 77 return m_pRelocator; 78} 79 80void X86GNULDBackend::doPreLayout(IRBuilder& pBuilder) 81{ 82 // initialize .dynamic data 83 if (!config().isCodeStatic() && NULL == m_pDynamic) 84 m_pDynamic = new X86ELFDynamic(*this, config()); 85 86 // set .got.plt and .got sizes 87 // when building shared object, the .got section is must 88 if (LinkerConfig::Object != config().codeGenType()) { 89 setGOTSectionSize(pBuilder); 90 91 // set .plt size 92 if (m_pPLT->hasPLT1()) 93 m_pPLT->finalizeSectionSize(); 94 95 // set .rel.dyn/.rela.dyn size 96 if (!m_pRelDyn->empty()) { 97 assert(!config().isCodeStatic() && 98 "static linkage should not result in a dynamic relocation section"); 99 setRelDynSize(); 100 } 101 // set .rel.plt/.rela.plt size 102 if (!m_pRelPLT->empty()) { 103 assert(!config().isCodeStatic() && 104 "static linkage should not result in a dynamic relocation section"); 105 setRelPLTSize(); 106 } 107 } 108} 109 110void X86GNULDBackend::doPostLayout(Module& pModule, 111 IRBuilder& pBuilder) 112{ 113} 114 115/// dynamic - the dynamic section of the target machine. 116/// Use co-variant return type to return its own dynamic section. 117X86ELFDynamic& X86GNULDBackend::dynamic() 118{ 119 assert(NULL != m_pDynamic); 120 return *m_pDynamic; 121} 122 123/// dynamic - the dynamic section of the target machine. 124/// Use co-variant return type to return its own dynamic section. 125const X86ELFDynamic& X86GNULDBackend::dynamic() const 126{ 127 assert(NULL != m_pDynamic); 128 return *m_pDynamic; 129} 130 131void X86GNULDBackend::defineGOTSymbol(IRBuilder& pBuilder, 132 Fragment& pFrag) 133{ 134 // define symbol _GLOBAL_OFFSET_TABLE_ 135 if (m_pGOTSymbol != NULL) { 136 pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>( 137 "_GLOBAL_OFFSET_TABLE_", 138 ResolveInfo::Object, 139 ResolveInfo::Define, 140 ResolveInfo::Local, 141 0x0, // size 142 0x0, // value 143 FragmentRef::Create(pFrag, 0x0), 144 ResolveInfo::Hidden); 145 } 146 else { 147 m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( 148 "_GLOBAL_OFFSET_TABLE_", 149 ResolveInfo::Object, 150 ResolveInfo::Define, 151 ResolveInfo::Local, 152 0x0, // size 153 0x0, // value 154 FragmentRef::Create(pFrag, 0x0), 155 ResolveInfo::Hidden); 156 } 157} 158 159uint64_t X86GNULDBackend::emitSectionData(const LDSection& pSection, 160 MemoryRegion& pRegion) const 161{ 162 assert(pRegion.size() && "Size of MemoryRegion is zero!"); 163 164 const ELFFileFormat* FileFormat = getOutputFormat(); 165 assert(FileFormat && 166 "ELFFileFormat is NULL in X86GNULDBackend::emitSectionData!"); 167 168 unsigned int EntrySize = 0; 169 uint64_t RegionSize = 0; 170 171 if (&pSection == &(FileFormat->getPLT())) { 172 assert(m_pPLT && "emitSectionData failed, m_pPLT is NULL!"); 173 174 unsigned char* buffer = pRegion.getBuffer(); 175 176 m_pPLT->applyPLT0(); 177 m_pPLT->applyPLT1(); 178 X86PLT::iterator it = m_pPLT->begin(); 179 unsigned int plt0_size = llvm::cast<PLTEntryBase>((*it)).size(); 180 181 memcpy(buffer, llvm::cast<PLTEntryBase>((*it)).getValue(), plt0_size); 182 RegionSize += plt0_size; 183 ++it; 184 185 PLTEntryBase* plt1 = 0; 186 X86PLT::iterator ie = m_pPLT->end(); 187 while (it != ie) { 188 plt1 = &(llvm::cast<PLTEntryBase>(*it)); 189 EntrySize = plt1->size(); 190 memcpy(buffer + RegionSize, plt1->getValue(), EntrySize); 191 RegionSize += EntrySize; 192 ++it; 193 } 194 } 195 196 else if (&pSection == &(FileFormat->getGOT())) { 197 RegionSize += emitGOTSectionData(pRegion); 198 } 199 200 else if (&pSection == &(FileFormat->getGOTPLT())) { 201 RegionSize += emitGOTPLTSectionData(pRegion, FileFormat); 202 } 203 204 else { 205 fatal(diag::unrecognized_output_sectoin) 206 << pSection.name() 207 << "mclinker@googlegroups.com"; 208 } 209 return RegionSize; 210} 211 212X86PLT& X86GNULDBackend::getPLT() 213{ 214 assert(NULL != m_pPLT && "PLT section not exist"); 215 return *m_pPLT; 216} 217 218const X86PLT& X86GNULDBackend::getPLT() const 219{ 220 assert(NULL != m_pPLT && "PLT section not exist"); 221 return *m_pPLT; 222} 223 224OutputRelocSection& X86GNULDBackend::getRelDyn() 225{ 226 assert(NULL != m_pRelDyn && ".rel.dyn/.rela.dyn section not exist"); 227 return *m_pRelDyn; 228} 229 230const OutputRelocSection& X86GNULDBackend::getRelDyn() const 231{ 232 assert(NULL != m_pRelDyn && ".rel.dyn/.rela.dyn section not exist"); 233 return *m_pRelDyn; 234} 235 236OutputRelocSection& X86GNULDBackend::getRelPLT() 237{ 238 assert(NULL != m_pRelPLT && ".rel.plt/.rela.plt section not exist"); 239 return *m_pRelPLT; 240} 241 242const OutputRelocSection& X86GNULDBackend::getRelPLT() const 243{ 244 assert(NULL != m_pRelPLT && ".rel.plt/.rela.plt section not exist"); 245 return *m_pRelPLT; 246} 247 248unsigned int 249X86GNULDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const 250{ 251 const ELFFileFormat* file_format = getOutputFormat(); 252 253 if (&pSectHdr == &file_format->getGOT()) { 254 if (config().options().hasNow()) 255 return SHO_RELRO; 256 return SHO_RELRO_LAST; 257 } 258 259 if (&pSectHdr == &file_format->getGOTPLT()) { 260 if (config().options().hasNow()) 261 return SHO_RELRO; 262 return SHO_NON_RELRO_FIRST; 263 } 264 265 if (&pSectHdr == &file_format->getPLT()) 266 return SHO_PLT; 267 268 return SHO_UNDEFINED; 269} 270 271void X86GNULDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule) 272{ 273 if (LinkerConfig::Object != config().codeGenType()) { 274 // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the 275 // same name in input 276 m_pGOTSymbol = 277 pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( 278 "_GLOBAL_OFFSET_TABLE_", 279 ResolveInfo::Object, 280 ResolveInfo::Define, 281 ResolveInfo::Local, 282 0x0, // size 283 0x0, // value 284 FragmentRef::Null(), // FragRef 285 ResolveInfo::Hidden); 286 } 287} 288 289/// finalizeSymbol - finalize the symbol value 290bool X86GNULDBackend::finalizeTargetSymbols() 291{ 292 return true; 293} 294 295/// doCreateProgramHdrs - backend can implement this function to create the 296/// target-dependent segments 297void X86GNULDBackend::doCreateProgramHdrs(Module& pModule) 298{ 299 // TODO 300} 301 302X86_32GNULDBackend::X86_32GNULDBackend(const LinkerConfig& pConfig, 303 GNUInfo* pInfo) 304 : X86GNULDBackend(pConfig, pInfo, llvm::ELF::R_386_COPY), 305 m_pGOT (NULL), 306 m_pGOTPLT (NULL) { 307} 308 309X86_32GNULDBackend::~X86_32GNULDBackend() 310{ 311 delete m_pGOT; 312 delete m_pGOTPLT; 313} 314 315bool X86_32GNULDBackend::initRelocator() 316{ 317 if (NULL == m_pRelocator) { 318 m_pRelocator = new X86_32Relocator(*this, config()); 319 } 320 return true; 321} 322 323void X86_32GNULDBackend::initTargetSections(Module& pModule, 324 ObjectBuilder& pBuilder) 325{ 326 if (LinkerConfig::Object != config().codeGenType()) { 327 ELFFileFormat* file_format = getOutputFormat(); 328 // initialize .got 329 LDSection& got = file_format->getGOT(); 330 m_pGOT = new X86_32GOT(got); 331 332 // initialize .got.plt 333 LDSection& gotplt = file_format->getGOTPLT(); 334 m_pGOTPLT = new X86_32GOTPLT(gotplt); 335 336 // initialize .plt 337 LDSection& plt = file_format->getPLT(); 338 m_pPLT = new X86_32PLT(plt, 339 *m_pGOTPLT, 340 config()); 341 342 // initialize .rel.plt 343 LDSection& relplt = file_format->getRelPlt(); 344 relplt.setLink(&plt); 345 m_pRelPLT = new OutputRelocSection(pModule, relplt); 346 347 // initialize .rel.dyn 348 LDSection& reldyn = file_format->getRelDyn(); 349 m_pRelDyn = new OutputRelocSection(pModule, reldyn); 350 351 } 352} 353 354X86_32GOT& X86_32GNULDBackend::getGOT() 355{ 356 assert(NULL != m_pGOT); 357 return *m_pGOT; 358} 359 360const X86_32GOT& X86_32GNULDBackend::getGOT() const 361{ 362 assert(NULL != m_pGOT); 363 return *m_pGOT; 364} 365 366X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT() 367{ 368 assert(NULL != m_pGOTPLT); 369 return *m_pGOTPLT; 370} 371 372const X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT() const 373{ 374 assert(NULL != m_pGOTPLT); 375 return *m_pGOTPLT; 376} 377 378void X86_32GNULDBackend::setRelDynSize() 379{ 380 ELFFileFormat* file_format = getOutputFormat(); 381 file_format->getRelDyn().setSize 382 (m_pRelDyn->numOfRelocs() * getRelEntrySize()); 383} 384 385void X86_32GNULDBackend::setRelPLTSize() 386{ 387 ELFFileFormat* file_format = getOutputFormat(); 388 file_format->getRelPlt().setSize 389 (m_pRelPLT->numOfRelocs() * getRelEntrySize()); 390} 391 392void X86_32GNULDBackend::setGOTSectionSize(IRBuilder& pBuilder) 393{ 394 // set .got.plt size 395 if (LinkerConfig::DynObj == config().codeGenType() || 396 m_pGOTPLT->hasGOT1() || 397 NULL != m_pGOTSymbol) { 398 m_pGOTPLT->finalizeSectionSize(); 399 defineGOTSymbol(pBuilder, *(m_pGOTPLT->begin())); 400 } 401 402 // set .got size 403 if (!m_pGOT->empty()) 404 m_pGOT->finalizeSectionSize(); 405} 406 407uint64_t X86_32GNULDBackend::emitGOTSectionData(MemoryRegion& pRegion) const 408{ 409 assert(m_pGOT && "emitGOTSectionData failed, m_pGOT is NULL!"); 410 411 uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer()); 412 413 X86_32GOTEntry* got = 0; 414 unsigned int EntrySize = X86_32GOTEntry::EntrySize; 415 uint64_t RegionSize = 0; 416 417 for (X86_32GOT::iterator it = m_pGOT->begin(), 418 ie = m_pGOT->end(); it != ie; ++it, ++buffer) { 419 got = &(llvm::cast<X86_32GOTEntry>((*it))); 420 *buffer = static_cast<uint32_t>(got->getValue()); 421 RegionSize += EntrySize; 422 } 423 424 return RegionSize; 425} 426 427uint64_t X86_32GNULDBackend::emitGOTPLTSectionData(MemoryRegion& pRegion, 428 const ELFFileFormat* FileFormat) const 429{ 430 assert(m_pGOTPLT && "emitGOTPLTSectionData failed, m_pGOTPLT is NULL!"); 431 m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr()); 432 m_pGOTPLT->applyAllGOTPLT(*m_pPLT); 433 434 uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer()); 435 436 X86_32GOTEntry* got = 0; 437 unsigned int EntrySize = X86_32GOTEntry::EntrySize; 438 uint64_t RegionSize = 0; 439 440 for (X86_32GOTPLT::iterator it = m_pGOTPLT->begin(), 441 ie = m_pGOTPLT->end(); it != ie; ++it, ++buffer) { 442 got = &(llvm::cast<X86_32GOTEntry>((*it))); 443 *buffer = static_cast<uint32_t>(got->getValue()); 444 RegionSize += EntrySize; 445 } 446 447 return RegionSize; 448} 449 450X86_64GNULDBackend::X86_64GNULDBackend(const LinkerConfig& pConfig, 451 GNUInfo* pInfo) 452 : X86GNULDBackend(pConfig, pInfo, llvm::ELF::R_X86_64_COPY), 453 m_pGOT (NULL), 454 m_pGOTPLT (NULL) { 455} 456 457X86_64GNULDBackend::~X86_64GNULDBackend() 458{ 459 delete m_pGOT; 460 delete m_pGOTPLT; 461} 462 463bool X86_64GNULDBackend::initRelocator() 464{ 465 if (NULL == m_pRelocator) { 466 m_pRelocator = new X86_64Relocator(*this, config()); 467 } 468 return true; 469} 470 471X86_64GOT& X86_64GNULDBackend::getGOT() 472{ 473 assert(NULL != m_pGOT); 474 return *m_pGOT; 475} 476 477const X86_64GOT& X86_64GNULDBackend::getGOT() const 478{ 479 assert(NULL != m_pGOT); 480 return *m_pGOT; 481} 482 483X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT() 484{ 485 assert(NULL != m_pGOTPLT); 486 return *m_pGOTPLT; 487} 488 489const X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT() const 490{ 491 assert(NULL != m_pGOTPLT); 492 return *m_pGOTPLT; 493} 494 495void X86_64GNULDBackend::setRelDynSize() 496{ 497 ELFFileFormat* file_format = getOutputFormat(); 498 file_format->getRelaDyn().setSize 499 (m_pRelDyn->numOfRelocs() * getRelaEntrySize()); 500} 501 502void X86_64GNULDBackend::setRelPLTSize() 503{ 504 ELFFileFormat* file_format = getOutputFormat(); 505 file_format->getRelaPlt().setSize 506 (m_pRelPLT->numOfRelocs() * getRelaEntrySize()); 507} 508 509void X86_64GNULDBackend::initTargetSections(Module& pModule, 510 ObjectBuilder& pBuilder) 511{ 512 if (LinkerConfig::Object != config().codeGenType()) { 513 ELFFileFormat* file_format = getOutputFormat(); 514 // initialize .got 515 LDSection& got = file_format->getGOT(); 516 m_pGOT = new X86_64GOT(got); 517 518 // initialize .got.plt 519 LDSection& gotplt = file_format->getGOTPLT(); 520 m_pGOTPLT = new X86_64GOTPLT(gotplt); 521 522 // initialize .plt 523 LDSection& plt = file_format->getPLT(); 524 m_pPLT = new X86_64PLT(plt, 525 *m_pGOTPLT, 526 config()); 527 528 // initialize .rela.plt 529 LDSection& relplt = file_format->getRelaPlt(); 530 relplt.setLink(&plt); 531 m_pRelPLT = new OutputRelocSection(pModule, relplt); 532 533 // initialize .rela.dyn 534 LDSection& reldyn = file_format->getRelaDyn(); 535 m_pRelDyn = new OutputRelocSection(pModule, reldyn); 536 537 } 538} 539 540void X86_64GNULDBackend::setGOTSectionSize(IRBuilder& pBuilder) 541{ 542 // set .got.plt size 543 if (LinkerConfig::DynObj == config().codeGenType() || 544 m_pGOTPLT->hasGOT1() || 545 NULL != m_pGOTSymbol) { 546 m_pGOTPLT->finalizeSectionSize(); 547 defineGOTSymbol(pBuilder, *(m_pGOTPLT->begin())); 548 } 549 550 // set .got size 551 if (!m_pGOT->empty()) 552 m_pGOT->finalizeSectionSize(); 553} 554 555uint64_t X86_64GNULDBackend::emitGOTSectionData(MemoryRegion& pRegion) const 556{ 557 assert(m_pGOT && "emitGOTSectionData failed, m_pGOT is NULL!"); 558 559 uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.getBuffer()); 560 561 X86_64GOTEntry* got = 0; 562 unsigned int EntrySize = X86_64GOTEntry::EntrySize; 563 uint64_t RegionSize = 0; 564 565 for (X86_64GOT::iterator it = m_pGOT->begin(), 566 ie = m_pGOT->end(); it != ie; ++it, ++buffer) { 567 got = &(llvm::cast<X86_64GOTEntry>((*it))); 568 *buffer = static_cast<uint64_t>(got->getValue()); 569 RegionSize += EntrySize; 570 } 571 572 return RegionSize; 573} 574 575uint64_t X86_64GNULDBackend::emitGOTPLTSectionData(MemoryRegion& pRegion, 576 const ELFFileFormat* FileFormat) const 577{ 578 assert(m_pGOTPLT && "emitGOTPLTSectionData failed, m_pGOTPLT is NULL!"); 579 m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr()); 580 m_pGOTPLT->applyAllGOTPLT(*m_pPLT); 581 582 uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.getBuffer()); 583 584 X86_64GOTEntry* got = 0; 585 unsigned int EntrySize = X86_64GOTEntry::EntrySize; 586 uint64_t RegionSize = 0; 587 588 for (X86_64GOTPLT::iterator it = m_pGOTPLT->begin(), 589 ie = m_pGOTPLT->end(); it != ie; ++it, ++buffer) { 590 got = &(llvm::cast<X86_64GOTEntry>((*it))); 591 *buffer = static_cast<uint64_t>(got->getValue()); 592 RegionSize += EntrySize; 593 } 594 595 return RegionSize; 596} 597 598namespace mcld { 599 600//===----------------------------------------------------------------------===// 601/// createX86LDBackend - the help funtion to create corresponding X86LDBackend 602/// 603TargetLDBackend* createX86LDBackend(const llvm::Target& pTarget, 604 const LinkerConfig& pConfig) 605{ 606 if (pConfig.targets().triple().isOSDarwin()) { 607 assert(0 && "MachO linker is not supported yet"); 608 /** 609 return new X86MachOLDBackend(createX86MachOArchiveReader, 610 createX86MachOObjectReader, 611 createX86MachOObjectWriter); 612 **/ 613 } 614 if (pConfig.targets().triple().isOSWindows()) { 615 assert(0 && "COFF linker is not supported yet"); 616 /** 617 return new X86COFFLDBackend(createX86COFFArchiveReader, 618 createX86COFFObjectReader, 619 createX86COFFObjectWriter); 620 **/ 621 } 622 Triple::ArchType arch = pConfig.targets().triple().getArch(); 623 if (arch == Triple::x86) 624 return new X86_32GNULDBackend(pConfig, 625 new X86_32GNUInfo(pConfig.targets().triple())); 626 assert (arch == Triple::x86_64); 627 return new X86_64GNULDBackend(pConfig, 628 new X86_64GNUInfo(pConfig.targets().triple())); 629} 630 631} // namespace of mcld 632 633//===----------------------------------------------------------------------===// 634// Force static initialization. 635//===----------------------------------------------------------------------===// 636extern "C" void MCLDInitializeX86LDBackend() { 637 // Register the linker backend 638 mcld::TargetRegistry::RegisterTargetLDBackend(TheX86_32Target, createX86LDBackend); 639 mcld::TargetRegistry::RegisterTargetLDBackend(TheX86_64Target, createX86LDBackend); 640} 641