Home | History | Annotate | Download | only in X86
      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 
     30 using namespace mcld;
     31 
     32 //===----------------------------------------------------------------------===//
     33 // X86GNULDBackend
     34 //===----------------------------------------------------------------------===//
     35 X86GNULDBackend::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 
     65 X86GNULDBackend::~X86GNULDBackend()
     66 {
     67   delete m_pRelocator;
     68   delete m_pPLT;
     69   delete m_pRelDyn;
     70   delete m_pRelPLT;
     71   delete m_pDynamic;
     72 }
     73 
     74 Relocator* X86GNULDBackend::getRelocator()
     75 {
     76   assert(NULL != m_pRelocator);
     77   return m_pRelocator;
     78 }
     79 
     80 void 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 
    110 void 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.
    117 X86ELFDynamic& 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.
    125 const X86ELFDynamic& X86GNULDBackend::dynamic() const
    126 {
    127   assert(NULL != m_pDynamic);
    128   return *m_pDynamic;
    129 }
    130 
    131 void 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 
    159 uint64_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 (at) googlegroups.com";
    208   }
    209   return RegionSize;
    210 }
    211 
    212 X86PLT& X86GNULDBackend::getPLT()
    213 {
    214   assert(NULL != m_pPLT && "PLT section not exist");
    215   return *m_pPLT;
    216 }
    217 
    218 const X86PLT& X86GNULDBackend::getPLT() const
    219 {
    220   assert(NULL != m_pPLT && "PLT section not exist");
    221   return *m_pPLT;
    222 }
    223 
    224 OutputRelocSection& X86GNULDBackend::getRelDyn()
    225 {
    226   assert(NULL != m_pRelDyn && ".rel.dyn/.rela.dyn section not exist");
    227   return *m_pRelDyn;
    228 }
    229 
    230 const OutputRelocSection& X86GNULDBackend::getRelDyn() const
    231 {
    232   assert(NULL != m_pRelDyn && ".rel.dyn/.rela.dyn section not exist");
    233   return *m_pRelDyn;
    234 }
    235 
    236 OutputRelocSection& X86GNULDBackend::getRelPLT()
    237 {
    238   assert(NULL != m_pRelPLT && ".rel.plt/.rela.plt section not exist");
    239   return *m_pRelPLT;
    240 }
    241 
    242 const OutputRelocSection& X86GNULDBackend::getRelPLT() const
    243 {
    244   assert(NULL != m_pRelPLT && ".rel.plt/.rela.plt section not exist");
    245   return *m_pRelPLT;
    246 }
    247 
    248 unsigned int
    249 X86GNULDBackend::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 
    271 void 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
    290 bool X86GNULDBackend::finalizeTargetSymbols()
    291 {
    292   return true;
    293 }
    294 
    295 /// doCreateProgramHdrs - backend can implement this function to create the
    296 /// target-dependent segments
    297 void X86GNULDBackend::doCreateProgramHdrs(Module& pModule)
    298 {
    299   // TODO
    300 }
    301 
    302 X86_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 
    309 X86_32GNULDBackend::~X86_32GNULDBackend()
    310 {
    311   delete m_pGOT;
    312   delete m_pGOTPLT;
    313 }
    314 
    315 bool X86_32GNULDBackend::initRelocator()
    316 {
    317   if (NULL == m_pRelocator) {
    318     m_pRelocator = new X86_32Relocator(*this, config());
    319   }
    320   return true;
    321 }
    322 
    323 void 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 
    354 X86_32GOT& X86_32GNULDBackend::getGOT()
    355 {
    356   assert(NULL != m_pGOT);
    357   return *m_pGOT;
    358 }
    359 
    360 const X86_32GOT& X86_32GNULDBackend::getGOT() const
    361 {
    362   assert(NULL != m_pGOT);
    363   return *m_pGOT;
    364 }
    365 
    366 X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT()
    367 {
    368   assert(NULL != m_pGOTPLT);
    369   return *m_pGOTPLT;
    370 }
    371 
    372 const X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT() const
    373 {
    374   assert(NULL != m_pGOTPLT);
    375   return *m_pGOTPLT;
    376 }
    377 
    378 void X86_32GNULDBackend::setRelDynSize()
    379 {
    380   ELFFileFormat* file_format = getOutputFormat();
    381   file_format->getRelDyn().setSize
    382     (m_pRelDyn->numOfRelocs() * getRelEntrySize());
    383 }
    384 
    385 void X86_32GNULDBackend::setRelPLTSize()
    386 {
    387   ELFFileFormat* file_format = getOutputFormat();
    388   file_format->getRelPlt().setSize
    389     (m_pRelPLT->numOfRelocs() * getRelEntrySize());
    390 }
    391 
    392 void 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 
    407 uint64_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 
    427 uint64_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 
    450 X86_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 
    457 X86_64GNULDBackend::~X86_64GNULDBackend()
    458 {
    459   delete m_pGOT;
    460   delete m_pGOTPLT;
    461 }
    462 
    463 bool X86_64GNULDBackend::initRelocator()
    464 {
    465   if (NULL == m_pRelocator) {
    466     m_pRelocator = new X86_64Relocator(*this, config());
    467   }
    468   return true;
    469 }
    470 
    471 X86_64GOT& X86_64GNULDBackend::getGOT()
    472 {
    473   assert(NULL != m_pGOT);
    474   return *m_pGOT;
    475 }
    476 
    477 const X86_64GOT& X86_64GNULDBackend::getGOT() const
    478 {
    479   assert(NULL != m_pGOT);
    480   return *m_pGOT;
    481 }
    482 
    483 X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT()
    484 {
    485   assert(NULL != m_pGOTPLT);
    486   return *m_pGOTPLT;
    487 }
    488 
    489 const X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT() const
    490 {
    491   assert(NULL != m_pGOTPLT);
    492   return *m_pGOTPLT;
    493 }
    494 
    495 void X86_64GNULDBackend::setRelDynSize()
    496 {
    497   ELFFileFormat* file_format = getOutputFormat();
    498   file_format->getRelaDyn().setSize
    499     (m_pRelDyn->numOfRelocs() * getRelaEntrySize());
    500 }
    501 
    502 void X86_64GNULDBackend::setRelPLTSize()
    503 {
    504   ELFFileFormat* file_format = getOutputFormat();
    505   file_format->getRelaPlt().setSize
    506     (m_pRelPLT->numOfRelocs() * getRelaEntrySize());
    507 }
    508 
    509 void 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 
    540 void 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 
    555 uint64_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 
    575 uint64_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 
    598 namespace mcld {
    599 
    600 //===----------------------------------------------------------------------===//
    601 /// createX86LDBackend - the help funtion to create corresponding X86LDBackend
    602 ///
    603 TargetLDBackend* 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 //===----------------------------------------------------------------------===//
    636 extern "C" void MCLDInitializeX86LDBackend() {
    637   // Register the linker backend
    638   mcld::TargetRegistry::RegisterTargetLDBackend(TheX86_32Target, createX86LDBackend);
    639   mcld::TargetRegistry::RegisterTargetLDBackend(TheX86_64Target, createX86LDBackend);
    640 }
    641