• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //===----------------------------------------------------------------------===//
X86GNULDBackend(const LinkerConfig & pConfig,GNUInfo * pInfo,Relocation::Type pCopyRel)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 
~X86GNULDBackend()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 
getRelocator()74 Relocator* X86GNULDBackend::getRelocator()
75 {
76   assert(NULL != m_pRelocator);
77   return m_pRelocator;
78 }
79 
doPreLayout(IRBuilder & pBuilder)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 
doPostLayout(Module & pModule,IRBuilder & pBuilder)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.
dynamic()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.
dynamic() const125 const X86ELFDynamic& X86GNULDBackend::dynamic() const
126 {
127   assert(NULL != m_pDynamic);
128   return *m_pDynamic;
129 }
130 
defineGOTSymbol(IRBuilder & pBuilder,Fragment & pFrag)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 
emitSectionData(const LDSection & pSection,MemoryRegion & pRegion) const159 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@googlegroups.com";
208   }
209   return RegionSize;
210 }
211 
getPLT()212 X86PLT& X86GNULDBackend::getPLT()
213 {
214   assert(NULL != m_pPLT && "PLT section not exist");
215   return *m_pPLT;
216 }
217 
getPLT() const218 const X86PLT& X86GNULDBackend::getPLT() const
219 {
220   assert(NULL != m_pPLT && "PLT section not exist");
221   return *m_pPLT;
222 }
223 
getRelDyn()224 OutputRelocSection& X86GNULDBackend::getRelDyn()
225 {
226   assert(NULL != m_pRelDyn && ".rel.dyn/.rela.dyn section not exist");
227   return *m_pRelDyn;
228 }
229 
getRelDyn() const230 const OutputRelocSection& X86GNULDBackend::getRelDyn() const
231 {
232   assert(NULL != m_pRelDyn && ".rel.dyn/.rela.dyn section not exist");
233   return *m_pRelDyn;
234 }
235 
getRelPLT()236 OutputRelocSection& X86GNULDBackend::getRelPLT()
237 {
238   assert(NULL != m_pRelPLT && ".rel.plt/.rela.plt section not exist");
239   return *m_pRelPLT;
240 }
241 
getRelPLT() const242 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
getTargetSectionOrder(const LDSection & pSectHdr) const249 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 
initTargetSymbols(IRBuilder & pBuilder,Module & pModule)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
finalizeTargetSymbols()290 bool X86GNULDBackend::finalizeTargetSymbols()
291 {
292   return true;
293 }
294 
295 /// doCreateProgramHdrs - backend can implement this function to create the
296 /// target-dependent segments
doCreateProgramHdrs(Module & pModule)297 void X86GNULDBackend::doCreateProgramHdrs(Module& pModule)
298 {
299   // TODO
300 }
301 
X86_32GNULDBackend(const LinkerConfig & pConfig,GNUInfo * pInfo)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 
~X86_32GNULDBackend()309 X86_32GNULDBackend::~X86_32GNULDBackend()
310 {
311   delete m_pGOT;
312   delete m_pGOTPLT;
313 }
314 
initRelocator()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 
initTargetSections(Module & pModule,ObjectBuilder & pBuilder)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 
getGOT()354 X86_32GOT& X86_32GNULDBackend::getGOT()
355 {
356   assert(NULL != m_pGOT);
357   return *m_pGOT;
358 }
359 
getGOT() const360 const X86_32GOT& X86_32GNULDBackend::getGOT() const
361 {
362   assert(NULL != m_pGOT);
363   return *m_pGOT;
364 }
365 
getGOTPLT()366 X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT()
367 {
368   assert(NULL != m_pGOTPLT);
369   return *m_pGOTPLT;
370 }
371 
getGOTPLT() const372 const X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT() const
373 {
374   assert(NULL != m_pGOTPLT);
375   return *m_pGOTPLT;
376 }
377 
setRelDynSize()378 void X86_32GNULDBackend::setRelDynSize()
379 {
380   ELFFileFormat* file_format = getOutputFormat();
381   file_format->getRelDyn().setSize
382     (m_pRelDyn->numOfRelocs() * getRelEntrySize());
383 }
384 
setRelPLTSize()385 void X86_32GNULDBackend::setRelPLTSize()
386 {
387   ELFFileFormat* file_format = getOutputFormat();
388   file_format->getRelPlt().setSize
389     (m_pRelPLT->numOfRelocs() * getRelEntrySize());
390 }
391 
setGOTSectionSize(IRBuilder & pBuilder)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 
emitGOTSectionData(MemoryRegion & pRegion) const407 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 
emitGOTPLTSectionData(MemoryRegion & pRegion,const ELFFileFormat * FileFormat) const427 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 
X86_64GNULDBackend(const LinkerConfig & pConfig,GNUInfo * pInfo)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 
~X86_64GNULDBackend()457 X86_64GNULDBackend::~X86_64GNULDBackend()
458 {
459   delete m_pGOT;
460   delete m_pGOTPLT;
461 }
462 
initRelocator()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 
getGOT()471 X86_64GOT& X86_64GNULDBackend::getGOT()
472 {
473   assert(NULL != m_pGOT);
474   return *m_pGOT;
475 }
476 
getGOT() const477 const X86_64GOT& X86_64GNULDBackend::getGOT() const
478 {
479   assert(NULL != m_pGOT);
480   return *m_pGOT;
481 }
482 
getGOTPLT()483 X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT()
484 {
485   assert(NULL != m_pGOTPLT);
486   return *m_pGOTPLT;
487 }
488 
getGOTPLT() const489 const X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT() const
490 {
491   assert(NULL != m_pGOTPLT);
492   return *m_pGOTPLT;
493 }
494 
setRelDynSize()495 void X86_64GNULDBackend::setRelDynSize()
496 {
497   ELFFileFormat* file_format = getOutputFormat();
498   file_format->getRelaDyn().setSize
499     (m_pRelDyn->numOfRelocs() * getRelaEntrySize());
500 }
501 
setRelPLTSize()502 void X86_64GNULDBackend::setRelPLTSize()
503 {
504   ELFFileFormat* file_format = getOutputFormat();
505   file_format->getRelaPlt().setSize
506     (m_pRelPLT->numOfRelocs() * getRelaEntrySize());
507 }
508 
initTargetSections(Module & pModule,ObjectBuilder & pBuilder)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 
setGOTSectionSize(IRBuilder & pBuilder)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 
emitGOTSectionData(MemoryRegion & pRegion) const555 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 
emitGOTPLTSectionData(MemoryRegion & pRegion,const ELFFileFormat * FileFormat) const575 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 ///
createX86LDBackend(const llvm::Target & pTarget,const LinkerConfig & pConfig)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 //===----------------------------------------------------------------------===//
MCLDInitializeX86LDBackend()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