1//===- AArch64LDBackend.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 "AArch64.h"
10#include "AArch64ELFDynamic.h"
11#include "AArch64GNUInfo.h"
12#include "AArch64LDBackend.h"
13#include "AArch64Relocator.h"
14
15#include "mcld/IRBuilder.h"
16#include "mcld/LinkerConfig.h"
17#include "mcld/Fragment/AlignFragment.h"
18#include "mcld/Fragment/FillFragment.h"
19#include "mcld/Fragment/NullFragment.h"
20#include "mcld/Fragment/RegionFragment.h"
21#include "mcld/Fragment/Stub.h"
22#include "mcld/LD/BranchIslandFactory.h"
23#include "mcld/LD/ELFFileFormat.h"
24#include "mcld/LD/ELFSegment.h"
25#include "mcld/LD/ELFSegmentFactory.h"
26#include "mcld/LD/LDContext.h"
27#include "mcld/LD/StubFactory.h"
28#include "mcld/Support/MemoryRegion.h"
29#include "mcld/Support/MemoryArea.h"
30#include "mcld/Support/MsgHandling.h"
31#include "mcld/Support/TargetRegistry.h"
32#include "mcld/Target/ELFAttribute.h"
33#include "mcld/Target/GNUInfo.h"
34#include "mcld/Object/ObjectBuilder.h"
35
36#include <llvm/ADT/Triple.h>
37#include <llvm/ADT/Twine.h>
38#include <llvm/Support/Casting.h>
39#include <llvm/Support/ELF.h>
40
41#include <cstring>
42
43namespace mcld {
44
45//===----------------------------------------------------------------------===//
46// AArch64GNULDBackend
47//===----------------------------------------------------------------------===//
48AArch64GNULDBackend::AArch64GNULDBackend(const LinkerConfig& pConfig,
49                                         GNUInfo* pInfo)
50    : GNULDBackend(pConfig, pInfo),
51      m_pRelocator(NULL),
52      m_pGOT(NULL),
53      m_pGOTPLT(NULL),
54      m_pPLT(NULL),
55      m_pRelaDyn(NULL),
56      m_pRelaPLT(NULL),
57      m_pDynamic(NULL),
58      m_pGOTSymbol(NULL) {
59}
60
61AArch64GNULDBackend::~AArch64GNULDBackend() {
62  if (m_pRelocator != NULL)
63    delete m_pRelocator;
64  if (m_pGOT == m_pGOTPLT) {
65    if (m_pGOT != NULL)
66      delete m_pGOT;
67  } else {
68    if (m_pGOT != NULL)
69      delete m_pGOT;
70    if (m_pGOTPLT != NULL)
71      delete m_pGOTPLT;
72  }
73  if (m_pPLT != NULL)
74    delete m_pPLT;
75  if (m_pRelaDyn != NULL)
76    delete m_pRelaDyn;
77  if (m_pRelaPLT != NULL)
78    delete m_pRelaPLT;
79  if (m_pDynamic != NULL)
80    delete m_pDynamic;
81}
82
83void AArch64GNULDBackend::initTargetSections(Module& pModule,
84                                             ObjectBuilder& pBuilder) {
85  if (LinkerConfig::Object != config().codeGenType()) {
86    ELFFileFormat* file_format = getOutputFormat();
87
88    // initialize .got
89    LDSection& got = file_format->getGOT();
90    m_pGOT = new AArch64GOT(got);
91    if (config().options().hasNow()) {
92      // when -z now is given, there will be only one .got section (contains
93      // both GOTPLT and normal GOT entries), create GOT0 for .got section and
94      // set m_pGOTPLT to the same .got
95      m_pGOT->createGOT0();
96      m_pGOTPLT = m_pGOT;
97    } else {
98      // Otherwise, got should be seperated to two sections, .got and .got.plt
99      // initialize .got.plt
100      LDSection& gotplt = file_format->getGOTPLT();
101      m_pGOTPLT = new AArch64GOT(gotplt);
102      m_pGOTPLT->createGOT0();
103    }
104
105    // initialize .plt
106    LDSection& plt = file_format->getPLT();
107    m_pPLT = new AArch64PLT(plt, *m_pGOTPLT);
108
109    // initialize .rela.plt
110    LDSection& relaplt = file_format->getRelaPlt();
111    relaplt.setLink(&plt);
112    m_pRelaPLT = new OutputRelocSection(pModule, relaplt);
113
114    // initialize .rela.dyn
115    LDSection& reladyn = file_format->getRelaDyn();
116    m_pRelaDyn = new OutputRelocSection(pModule, reladyn);
117  }
118}
119
120void AArch64GNULDBackend::initTargetSymbols(IRBuilder& pBuilder,
121                                            Module& pModule) {
122  // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
123  // same name in input
124  if (LinkerConfig::Object != config().codeGenType()) {
125    m_pGOTSymbol =
126        pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
127            "_GLOBAL_OFFSET_TABLE_",
128            ResolveInfo::Object,
129            ResolveInfo::Define,
130            ResolveInfo::Local,
131            0x0,  // size
132            0x0,  // value
133            FragmentRef::Null(),
134            ResolveInfo::Hidden);
135  }
136}
137
138bool AArch64GNULDBackend::initRelocator() {
139  if (m_pRelocator == NULL) {
140    m_pRelocator = new AArch64Relocator(*this, config());
141  }
142  return true;
143}
144
145const Relocator* AArch64GNULDBackend::getRelocator() const {
146  assert(m_pRelocator != NULL);
147  return m_pRelocator;
148}
149
150Relocator* AArch64GNULDBackend::getRelocator() {
151  assert(m_pRelocator != NULL);
152  return m_pRelocator;
153}
154
155void AArch64GNULDBackend::defineGOTSymbol(IRBuilder& pBuilder) {
156  // define symbol _GLOBAL_OFFSET_TABLE_ when .got create
157  if (m_pGOTSymbol != NULL) {
158    pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
159        "_GLOBAL_OFFSET_TABLE_",
160        ResolveInfo::Object,
161        ResolveInfo::Define,
162        ResolveInfo::Local,
163        0x0,  // size
164        0x0,  // value
165        FragmentRef::Create(*(m_pGOTPLT->begin()), 0x0),
166        ResolveInfo::Hidden);
167  } else {
168    m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
169        "_GLOBAL_OFFSET_TABLE_",
170        ResolveInfo::Object,
171        ResolveInfo::Define,
172        ResolveInfo::Local,
173        0x0,  // size
174        0x0,  // value
175        FragmentRef::Create(*(m_pGOTPLT->begin()), 0x0),
176        ResolveInfo::Hidden);
177  }
178}
179
180void AArch64GNULDBackend::doPreLayout(IRBuilder& pBuilder) {
181  // initialize .dynamic data
182  if (!config().isCodeStatic() && m_pDynamic == NULL)
183    m_pDynamic = new AArch64ELFDynamic(*this, config());
184
185  if (LinkerConfig::Object != config().codeGenType()) {
186    // set .got size
187    if (config().options().hasNow()) {
188      // when building shared object, the GOTPLT section is must
189      if (LinkerConfig::DynObj == config().codeGenType() || m_pGOT->hasGOT1() ||
190          m_pGOTSymbol != NULL) {
191        m_pGOT->finalizeSectionSize();
192        defineGOTSymbol(pBuilder);
193      }
194    } else {
195      // when building shared object, the GOTPLT section is must
196      if (LinkerConfig::DynObj == config().codeGenType() ||
197          m_pGOTPLT->hasGOT1() || m_pGOTSymbol != NULL) {
198        m_pGOTPLT->finalizeSectionSize();
199        defineGOTSymbol(pBuilder);
200      }
201      if (m_pGOT->hasGOT1())
202        m_pGOT->finalizeSectionSize();
203    }
204
205    // set .plt size
206    if (m_pPLT->hasPLT1())
207      m_pPLT->finalizeSectionSize();
208
209    ELFFileFormat* file_format = getOutputFormat();
210    // set .rela.dyn size
211    if (!m_pRelaDyn->empty()) {
212      assert(
213          !config().isCodeStatic() &&
214          "static linkage should not result in a dynamic relocation section");
215      file_format->getRelaDyn().setSize(m_pRelaDyn->numOfRelocs() *
216                                        getRelaEntrySize());
217    }
218
219    // set .rela.plt size
220    if (!m_pRelaPLT->empty()) {
221      assert(
222          !config().isCodeStatic() &&
223          "static linkage should not result in a dynamic relocation section");
224      file_format->getRelaPlt().setSize(m_pRelaPLT->numOfRelocs() *
225                                        getRelaEntrySize());
226    }
227  }
228}
229
230void AArch64GNULDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder) {
231  const ELFFileFormat* file_format = getOutputFormat();
232
233  // apply PLT
234  if (file_format->hasPLT()) {
235    assert(m_pPLT != NULL);
236    m_pPLT->applyPLT0();
237    m_pPLT->applyPLT1();
238  }
239
240  // apply GOTPLT
241  if ((config().options().hasNow() && file_format->hasGOT()) ||
242      file_format->hasGOTPLT()) {
243    assert(m_pGOTPLT != NULL);
244    if (LinkerConfig::DynObj == config().codeGenType())
245      m_pGOTPLT->applyGOT0(file_format->getDynamic().addr());
246    else {
247      // executable file and object file? should fill with zero.
248      m_pGOTPLT->applyGOT0(0);
249    }
250  }
251}
252
253AArch64ELFDynamic& AArch64GNULDBackend::dynamic() {
254  assert(m_pDynamic != NULL);
255  return *m_pDynamic;
256}
257
258const AArch64ELFDynamic& AArch64GNULDBackend::dynamic() const {
259  assert(m_pDynamic != NULL);
260  return *m_pDynamic;
261}
262
263uint64_t AArch64GNULDBackend::emitSectionData(const LDSection& pSection,
264                                              MemoryRegion& pRegion) const {
265  assert(pRegion.size() && "Size of MemoryRegion is zero!");
266
267  const ELFFileFormat* file_format = getOutputFormat();
268
269  if (file_format->hasPLT() && (&pSection == &(file_format->getPLT()))) {
270    uint64_t result = m_pPLT->emit(pRegion);
271    return result;
272  }
273
274  if (file_format->hasGOT() && (&pSection == &(file_format->getGOT()))) {
275    uint64_t result = m_pGOT->emit(pRegion);
276    return result;
277  }
278
279  if (file_format->hasGOTPLT() && (&pSection == &(file_format->getGOTPLT()))) {
280    uint64_t result = m_pGOT->emit(pRegion);
281    return result;
282  }
283
284  // TODO
285  return pRegion.size();
286}
287
288unsigned int AArch64GNULDBackend::getTargetSectionOrder(
289    const LDSection& pSectHdr) const {
290  const ELFFileFormat* file_format = getOutputFormat();
291
292  if (file_format->hasGOT() && (&pSectHdr == &file_format->getGOT())) {
293    if (config().options().hasNow())
294      return SHO_RELRO;
295    return SHO_RELRO_LAST;
296  }
297
298  if (file_format->hasGOTPLT() && (&pSectHdr == &file_format->getGOTPLT()))
299    return SHO_NON_RELRO_FIRST;
300
301  if (file_format->hasPLT() && (&pSectHdr == &file_format->getPLT()))
302    return SHO_PLT;
303
304  return SHO_UNDEFINED;
305}
306
307bool AArch64GNULDBackend::doRelax(Module& pModule,
308                                  IRBuilder& pBuilder,
309                                  bool& pFinished) {
310  // TODO
311  return false;
312}
313
314bool AArch64GNULDBackend::initTargetStubs() {
315  // TODO
316  return true;
317}
318
319void AArch64GNULDBackend::doCreateProgramHdrs(Module& pModule) {
320  // TODO
321}
322
323bool AArch64GNULDBackend::finalizeTargetSymbols() {
324  // TODO
325  return true;
326}
327
328bool AArch64GNULDBackend::mergeSection(Module& pModule,
329                                       const Input& pInput,
330                                       LDSection& pSection) {
331  // TODO
332  return true;
333}
334
335bool AArch64GNULDBackend::readSection(Input& pInput, SectionData& pSD) {
336  // TODO
337  return true;
338}
339
340AArch64GOT& AArch64GNULDBackend::getGOT() {
341  assert(m_pGOT != NULL && "GOT section not exist");
342  return *m_pGOT;
343}
344
345const AArch64GOT& AArch64GNULDBackend::getGOT() const {
346  assert(m_pGOT != NULL && "GOT section not exist");
347  return *m_pGOT;
348}
349
350AArch64GOT& AArch64GNULDBackend::getGOTPLT() {
351  assert(m_pGOTPLT != NULL && "GOTPLT section not exist");
352  return *m_pGOTPLT;
353}
354
355const AArch64GOT& AArch64GNULDBackend::getGOTPLT() const {
356  assert(m_pGOTPLT != NULL && "GOTPLT section not exist");
357  return *m_pGOTPLT;
358}
359
360AArch64PLT& AArch64GNULDBackend::getPLT() {
361  assert(m_pPLT != NULL && "PLT section not exist");
362  return *m_pPLT;
363}
364
365const AArch64PLT& AArch64GNULDBackend::getPLT() const {
366  assert(m_pPLT != NULL && "PLT section not exist");
367  return *m_pPLT;
368}
369
370OutputRelocSection& AArch64GNULDBackend::getRelaDyn() {
371  assert(m_pRelaDyn != NULL && ".rela.dyn section not exist");
372  return *m_pRelaDyn;
373}
374
375const OutputRelocSection& AArch64GNULDBackend::getRelaDyn() const {
376  assert(m_pRelaDyn != NULL && ".rela.dyn section not exist");
377  return *m_pRelaDyn;
378}
379
380OutputRelocSection& AArch64GNULDBackend::getRelaPLT() {
381  assert(m_pRelaPLT != NULL && ".rela.plt section not exist");
382  return *m_pRelaPLT;
383}
384
385const OutputRelocSection& AArch64GNULDBackend::getRelaPLT() const {
386  assert(m_pRelaPLT != NULL && ".rela.plt section not exist");
387  return *m_pRelaPLT;
388}
389
390//===----------------------------------------------------------------------===//
391//  createAArch64LDBackend - the help funtion to create corresponding
392//  AArch64LDBackend
393//===----------------------------------------------------------------------===//
394TargetLDBackend* createAArch64LDBackend(const LinkerConfig& pConfig) {
395  if (pConfig.targets().triple().isOSDarwin()) {
396    assert(0 && "MachO linker is not supported yet");
397    /**
398    return new AArch64MachOLDBackend(createAArch64MachOArchiveReader,
399                                     createAArch64MachOObjectReader,
400                                     createAArch64MachOObjectWriter);
401    **/
402  }
403  if (pConfig.targets().triple().isOSWindows()) {
404    assert(0 && "COFF linker is not supported yet");
405    /**
406    return new AArch64COFFLDBackend(createAArch64COFFArchiveReader,
407                                    createAArch64COFFObjectReader,
408                                    createAArch64COFFObjectWriter);
409    **/
410  }
411  return new AArch64GNULDBackend(
412      pConfig, new AArch64GNUInfo(pConfig.targets().triple()));
413}
414
415}  // namespace mcld
416
417//===----------------------------------------------------------------------===//
418// Force static initialization.
419//===----------------------------------------------------------------------===//
420extern "C" void MCLDInitializeAArch64LDBackend() {
421  // Register the linker backend
422  mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheAArch64Target,
423                                                mcld::createAArch64LDBackend);
424}
425