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