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 "AArch64CA53Erratum835769Stub.h"
11#include "AArch64CA53Erratum843419Stub.h"
12#include "AArch64CA53Erratum843419Stub2.h"
13#include "AArch64ELFDynamic.h"
14#include "AArch64GNUInfo.h"
15#include "AArch64InsnHelpers.h"
16#include "AArch64LDBackend.h"
17#include "AArch64LongBranchStub.h"
18#include "AArch64Relocator.h"
19
20#include "mcld/IRBuilder.h"
21#include "mcld/LinkerConfig.h"
22#include "mcld/Fragment/AlignFragment.h"
23#include "mcld/Fragment/FillFragment.h"
24#include "mcld/Fragment/NullFragment.h"
25#include "mcld/Fragment/RegionFragment.h"
26#include "mcld/Fragment/Stub.h"
27#include "mcld/LD/BranchIslandFactory.h"
28#include "mcld/LD/ELFFileFormat.h"
29#include "mcld/LD/ELFSegment.h"
30#include "mcld/LD/ELFSegmentFactory.h"
31#include "mcld/LD/LDContext.h"
32#include "mcld/LD/StubFactory.h"
33#include "mcld/Support/MemoryRegion.h"
34#include "mcld/Support/MemoryArea.h"
35#include "mcld/Support/MsgHandling.h"
36#include "mcld/Support/TargetRegistry.h"
37#include "mcld/Target/ELFAttribute.h"
38#include "mcld/Target/GNUInfo.h"
39#include "mcld/Object/ObjectBuilder.h"
40
41#include <llvm/ADT/Triple.h>
42#include <llvm/ADT/Twine.h>
43#include <llvm/Support/Casting.h>
44#include <llvm/Support/ELF.h>
45
46#include <cstring>
47
48namespace mcld {
49
50//===----------------------------------------------------------------------===//
51// AArch64GNULDBackend
52//===----------------------------------------------------------------------===//
53AArch64GNULDBackend::AArch64GNULDBackend(const LinkerConfig& pConfig,
54                                         GNUInfo* pInfo)
55    : GNULDBackend(pConfig, pInfo),
56      m_pRelocator(NULL),
57      m_pGOT(NULL),
58      m_pGOTPLT(NULL),
59      m_pPLT(NULL),
60      m_pRelaDyn(NULL),
61      m_pRelaPLT(NULL),
62      m_pDynamic(NULL),
63      m_pGOTSymbol(NULL) {
64}
65
66AArch64GNULDBackend::~AArch64GNULDBackend() {
67  if (m_pRelocator != NULL)
68    delete m_pRelocator;
69  if (m_pGOT == m_pGOTPLT) {
70    if (m_pGOT != NULL)
71      delete m_pGOT;
72  } else {
73    if (m_pGOT != NULL)
74      delete m_pGOT;
75    if (m_pGOTPLT != NULL)
76      delete m_pGOTPLT;
77  }
78  if (m_pPLT != NULL)
79    delete m_pPLT;
80  if (m_pRelaDyn != NULL)
81    delete m_pRelaDyn;
82  if (m_pRelaPLT != NULL)
83    delete m_pRelaPLT;
84  if (m_pDynamic != NULL)
85    delete m_pDynamic;
86}
87
88void AArch64GNULDBackend::initTargetSections(Module& pModule,
89                                             ObjectBuilder& pBuilder) {
90  if (LinkerConfig::Object != config().codeGenType()) {
91    ELFFileFormat* file_format = getOutputFormat();
92
93    // initialize .got
94    LDSection& got = file_format->getGOT();
95    m_pGOT = new AArch64GOT(got);
96    if (config().options().hasNow()) {
97      // when -z now is given, there will be only one .got section (contains
98      // both GOTPLT and normal GOT entries), create GOT0 for .got section and
99      // set m_pGOTPLT to the same .got
100      m_pGOT->createGOT0();
101      m_pGOTPLT = m_pGOT;
102    } else {
103      // Otherwise, got should be seperated to two sections, .got and .got.plt
104      // initialize .got.plt
105      LDSection& gotplt = file_format->getGOTPLT();
106      m_pGOTPLT = new AArch64GOT(gotplt);
107      m_pGOTPLT->createGOT0();
108    }
109
110    // initialize .plt
111    LDSection& plt = file_format->getPLT();
112    m_pPLT = new AArch64PLT(plt, *m_pGOTPLT);
113
114    // initialize .rela.plt
115    LDSection& relaplt = file_format->getRelaPlt();
116    relaplt.setLink(&plt);
117    m_pRelaPLT = new OutputRelocSection(pModule, relaplt);
118
119    // initialize .rela.dyn
120    LDSection& reladyn = file_format->getRelaDyn();
121    m_pRelaDyn = new OutputRelocSection(pModule, reladyn);
122  }
123}
124
125void AArch64GNULDBackend::initTargetSymbols(IRBuilder& pBuilder,
126                                            Module& pModule) {
127  // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
128  // same name in input
129  if (LinkerConfig::Object != config().codeGenType()) {
130    m_pGOTSymbol =
131        pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
132            "_GLOBAL_OFFSET_TABLE_",
133            ResolveInfo::Object,
134            ResolveInfo::Define,
135            ResolveInfo::Local,
136            0x0,  // size
137            0x0,  // value
138            FragmentRef::Null(),
139            ResolveInfo::Hidden);
140  }
141}
142
143bool AArch64GNULDBackend::initRelocator() {
144  if (m_pRelocator == NULL) {
145    m_pRelocator = new AArch64Relocator(*this, config());
146  }
147  return true;
148}
149
150const Relocator* AArch64GNULDBackend::getRelocator() const {
151  assert(m_pRelocator != NULL);
152  return m_pRelocator;
153}
154
155Relocator* AArch64GNULDBackend::getRelocator() {
156  assert(m_pRelocator != NULL);
157  return m_pRelocator;
158}
159
160void AArch64GNULDBackend::defineGOTSymbol(IRBuilder& pBuilder) {
161  // define symbol _GLOBAL_OFFSET_TABLE_ when .got create
162  if (m_pGOTSymbol != NULL) {
163    pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
164        "_GLOBAL_OFFSET_TABLE_",
165        ResolveInfo::Object,
166        ResolveInfo::Define,
167        ResolveInfo::Local,
168        0x0,  // size
169        0x0,  // value
170        FragmentRef::Create(*(m_pGOTPLT->begin()), 0x0),
171        ResolveInfo::Hidden);
172  } else {
173    m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
174        "_GLOBAL_OFFSET_TABLE_",
175        ResolveInfo::Object,
176        ResolveInfo::Define,
177        ResolveInfo::Local,
178        0x0,  // size
179        0x0,  // value
180        FragmentRef::Create(*(m_pGOTPLT->begin()), 0x0),
181        ResolveInfo::Hidden);
182  }
183}
184
185void AArch64GNULDBackend::doPreLayout(IRBuilder& pBuilder) {
186  // initialize .dynamic data
187  if (!config().isCodeStatic() && m_pDynamic == NULL)
188    m_pDynamic = new AArch64ELFDynamic(*this, config());
189
190  if (LinkerConfig::Object != config().codeGenType()) {
191    // set .got size
192    if (config().options().hasNow()) {
193      // when building shared object, the GOTPLT section is must
194      if (LinkerConfig::DynObj == config().codeGenType() || m_pGOT->hasGOT1() ||
195          m_pGOTSymbol != NULL) {
196        m_pGOT->finalizeSectionSize();
197        defineGOTSymbol(pBuilder);
198      }
199    } else {
200      // when building shared object, the GOTPLT section is must
201      if (LinkerConfig::DynObj == config().codeGenType() ||
202          m_pGOTPLT->hasGOT1() || m_pGOTSymbol != NULL) {
203        m_pGOTPLT->finalizeSectionSize();
204        defineGOTSymbol(pBuilder);
205      }
206      if (m_pGOT->hasGOT1())
207        m_pGOT->finalizeSectionSize();
208    }
209
210    // set .plt size
211    if (m_pPLT->hasPLT1())
212      m_pPLT->finalizeSectionSize();
213
214    ELFFileFormat* file_format = getOutputFormat();
215    // set .rela.dyn size
216    if (!m_pRelaDyn->empty()) {
217      assert(
218          !config().isCodeStatic() &&
219          "static linkage should not result in a dynamic relocation section");
220      file_format->getRelaDyn().setSize(m_pRelaDyn->numOfRelocs() *
221                                        getRelaEntrySize());
222    }
223
224    // set .rela.plt size
225    if (!m_pRelaPLT->empty()) {
226      assert(
227          !config().isCodeStatic() &&
228          "static linkage should not result in a dynamic relocation section");
229      file_format->getRelaPlt().setSize(m_pRelaPLT->numOfRelocs() *
230                                        getRelaEntrySize());
231    }
232  }
233}
234
235void AArch64GNULDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder) {
236  const ELFFileFormat* file_format = getOutputFormat();
237
238  // apply PLT
239  if (file_format->hasPLT()) {
240    assert(m_pPLT != NULL);
241    m_pPLT->applyPLT0();
242    m_pPLT->applyPLT1();
243  }
244
245  // apply GOTPLT
246  if ((config().options().hasNow() && file_format->hasGOT()) ||
247      file_format->hasGOTPLT()) {
248    assert(m_pGOTPLT != NULL);
249    if (LinkerConfig::DynObj == config().codeGenType())
250      m_pGOTPLT->applyGOT0(file_format->getDynamic().addr());
251    else {
252      // executable file and object file? should fill with zero.
253      m_pGOTPLT->applyGOT0(0);
254    }
255  }
256}
257
258AArch64ELFDynamic& AArch64GNULDBackend::dynamic() {
259  assert(m_pDynamic != NULL);
260  return *m_pDynamic;
261}
262
263const AArch64ELFDynamic& AArch64GNULDBackend::dynamic() const {
264  assert(m_pDynamic != NULL);
265  return *m_pDynamic;
266}
267
268uint64_t AArch64GNULDBackend::emitSectionData(const LDSection& pSection,
269                                              MemoryRegion& pRegion) const {
270  assert(pRegion.size() && "Size of MemoryRegion is zero!");
271
272  const ELFFileFormat* file_format = getOutputFormat();
273
274  if (file_format->hasPLT() && (&pSection == &(file_format->getPLT()))) {
275    uint64_t result = m_pPLT->emit(pRegion);
276    return result;
277  }
278
279  if (file_format->hasGOT() && (&pSection == &(file_format->getGOT()))) {
280    uint64_t result = m_pGOT->emit(pRegion);
281    return result;
282  }
283
284  if (file_format->hasGOTPLT() && (&pSection == &(file_format->getGOTPLT()))) {
285    uint64_t result = m_pGOT->emit(pRegion);
286    return result;
287  }
288
289  return pRegion.size();
290}
291
292unsigned int AArch64GNULDBackend::getTargetSectionOrder(
293    const LDSection& pSectHdr) const {
294  const ELFFileFormat* file_format = getOutputFormat();
295
296  if (file_format->hasGOT() && (&pSectHdr == &file_format->getGOT())) {
297    if (config().options().hasNow())
298      return SHO_RELRO;
299    return SHO_RELRO_LAST;
300  }
301
302  if (file_format->hasGOTPLT() && (&pSectHdr == &file_format->getGOTPLT()))
303    return SHO_NON_RELRO_FIRST;
304
305  if (file_format->hasPLT() && (&pSectHdr == &file_format->getPLT()))
306    return SHO_PLT;
307
308  return SHO_UNDEFINED;
309}
310
311void AArch64GNULDBackend::scanErrata(Module& pModule,
312                                     IRBuilder& pBuilder,
313                                     size_t& num_new_stubs,
314                                     size_t& stubs_strlen) {
315  // TODO: Implement AArch64 ErrataStubFactory to create the specific erratum
316  //       stub and simplify the logics.
317  for (Module::iterator sect = pModule.begin(), sectEnd = pModule.end();
318       sect != sectEnd; ++sect) {
319    if (((*sect)->kind() == LDFileFormat::TEXT) && (*sect)->hasSectionData()) {
320      SectionData* sd = (*sect)->getSectionData();
321      for (SectionData::iterator it = sd->begin(), ie = sd->end(); it != ie;
322           ++it) {
323        Fragment* frag = llvm::dyn_cast<RegionFragment>(it);
324        if (frag != NULL) {
325          FragmentRef* frag_ref = FragmentRef::Create(*frag, 0);
326          for (unsigned offset = 0; offset < frag->size();
327               offset += AArch64InsnHelpers::InsnSize) {
328            Stub* stub = getStubFactory()->create(*frag_ref,
329                                                  pBuilder,
330                                                  *getBRIslandFactory());
331            if (stub != NULL) {
332              // A stub symbol should be local
333              assert(stub->symInfo() != NULL && stub->symInfo()->isLocal());
334              const AArch64CA53ErratumStub* erratum_stub =
335                  reinterpret_cast<const AArch64CA53ErratumStub*>(stub);
336              assert(erratum_stub != NULL);
337              // Rewrite the erratum instruction as a branch to the stub.
338              uint64_t offset = frag_ref->offset() +
339                                erratum_stub->getErratumInsnOffset();
340              Relocation* reloc =
341                  Relocation::Create(llvm::ELF::R_AARCH64_JUMP26,
342                                     *(FragmentRef::Create(*frag, offset)),
343                                     /* pAddend */0);
344              reloc->setSymInfo(stub->symInfo());
345              reloc->target() = AArch64InsnHelpers::buildBranchInsn();
346              addExtraRelocation(reloc);
347
348              ++num_new_stubs;
349              stubs_strlen += stub->symInfo()->nameSize() + 1;
350            }
351
352            frag_ref->assign(*frag, offset + AArch64InsnHelpers::InsnSize);
353          }  // for each INSN
354        }
355      }  // for each FRAGMENT
356    }
357  }  // for each TEXT section
358}
359
360bool AArch64GNULDBackend::doRelax(Module& pModule,
361                                  IRBuilder& pBuilder,
362                                  bool& pFinished) {
363  assert(getStubFactory() != NULL && getBRIslandFactory() != NULL);
364
365  // Number of new stubs added
366  size_t num_new_stubs = 0;
367  // String lengh to hold new stub symbols
368  size_t stubs_strlen = 0;
369
370  if (config().targets().fixCA53Erratum835769() ||
371      config().targets().fixCA53Erratum843419()) {
372    scanErrata(pModule, pBuilder, num_new_stubs, stubs_strlen);
373  }
374
375  ELFFileFormat* file_format = getOutputFormat();
376  // check branch relocs and create the related stubs if needed
377  Module::obj_iterator input, inEnd = pModule.obj_end();
378  for (input = pModule.obj_begin(); input != inEnd; ++input) {
379    LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
380    for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
381      if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData())
382        continue;
383      RelocData::iterator reloc, rEnd = (*rs)->getRelocData()->end();
384      for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) {
385        Relocation* relocation = llvm::cast<Relocation>(reloc);
386
387        switch (relocation->type()) {
388          case llvm::ELF::R_AARCH64_CALL26:
389          case llvm::ELF::R_AARCH64_JUMP26: {
390            // calculate the possible symbol value
391            uint64_t sym_value = 0x0;
392            LDSymbol* symbol = relocation->symInfo()->outSymbol();
393            if (symbol->hasFragRef()) {
394              uint64_t value = symbol->fragRef()->getOutputOffset();
395              uint64_t addr =
396                  symbol->fragRef()->frag()->getParent()->getSection().addr();
397              sym_value = addr + value;
398            }
399            if ((relocation->symInfo()->reserved() &
400                 AArch64Relocator::ReservePLT) != 0x0) {
401              // FIXME: we need to find out the address of the specific plt
402              // entry
403              assert(file_format->hasPLT());
404              sym_value = file_format->getPLT().addr();
405            }
406            Stub* stub = getStubFactory()->create(*relocation,  // relocation
407                                                  sym_value,    // symbol value
408                                                  pBuilder,
409                                                  *getBRIslandFactory());
410            if (stub != NULL) {
411              // a stub symbol should be local
412              assert(stub->symInfo() != NULL && stub->symInfo()->isLocal());
413              // reset the branch target of the reloc to this stub instead
414              relocation->setSymInfo(stub->symInfo());
415
416              ++num_new_stubs;
417              stubs_strlen += stub->symInfo()->nameSize() + 1;
418            }
419            break;
420          }
421          default: {
422            break;
423          }
424        }  // end of switch
425      }  // for all relocations
426    }  // for all relocation section
427  }  // for all inputs
428
429  // Find the first fragment w/ invalid offset due to stub insertion.
430  std::vector<Fragment*> invalid_frags;
431  pFinished = true;
432  for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(),
433                                     island_end = getBRIslandFactory()->end();
434       island != island_end;
435       ++island) {
436    if ((*island).size() > stubGroupSize()) {
437      error(diag::err_no_space_to_place_stubs) << stubGroupSize();
438      return false;
439    }
440
441    if ((*island).numOfStubs() == 0) {
442      continue;
443    }
444
445    Fragment* exit = &*(*island).end();
446    if (exit == (*island).begin()->getParent()->end()) {
447      continue;
448    }
449
450    if (((*island).offset() + (*island).size()) > exit->getOffset()) {
451      if (invalid_frags.empty() ||
452          (invalid_frags.back()->getParent() != (*island).getParent())) {
453        invalid_frags.push_back(exit);
454        pFinished = false;
455      }
456      continue;
457    }
458  }
459
460  // Reset the offset of invalid fragments.
461  for (auto it = invalid_frags.begin(), ie = invalid_frags.end(); it != ie;
462       ++it) {
463    Fragment* invalid = *it;
464    while (invalid != NULL) {
465      invalid->setOffset(invalid->getPrevNode()->getOffset() +
466                         invalid->getPrevNode()->size());
467      invalid = invalid->getNextNode();
468    }
469  }
470
471  // Fix up the size of .symtab, .strtab, and TEXT sections
472  if (num_new_stubs == 0) {
473    return false;
474  } else {
475    switch (config().options().getStripSymbolMode()) {
476      case GeneralOptions::StripSymbolMode::StripAllSymbols:
477      case GeneralOptions::StripSymbolMode::StripLocals:
478        break;
479      default: {
480        LDSection& symtab = file_format->getSymTab();
481        LDSection& strtab = file_format->getStrTab();
482
483        symtab.setSize(symtab.size() +
484                       sizeof(llvm::ELF::Elf64_Sym) * num_new_stubs);
485        symtab.setInfo(symtab.getInfo() + num_new_stubs);
486        strtab.setSize(strtab.size() + stubs_strlen);
487      }
488    }  // switch (config().options().getStripSymbolMode())
489
490    SectionData* prev = NULL;
491    for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(),
492                                       island_end = getBRIslandFactory()->end();
493         island != island_end;
494         ++island) {
495      SectionData* sd = (*island).begin()->getParent();
496      if ((*island).numOfStubs() != 0) {
497        if (sd != prev) {
498          sd->getSection().setSize(sd->back().getOffset() + sd->back().size());
499        }
500      }
501      prev = sd;
502    }
503    return true;
504  }  // if (num_new_stubs == 0)
505}
506
507bool AArch64GNULDBackend::initTargetStubs() {
508  StubFactory* factory = getStubFactory();
509  if (factory != NULL) {
510    factory->addPrototype(new AArch64LongBranchStub(config().isCodeIndep()));
511    if (config().targets().fixCA53Erratum835769()) {
512      factory->addPrototype(new AArch64CA53Erratum835769Stub());
513    }
514    if (config().targets().fixCA53Erratum843419()) {
515      factory->addPrototype(new AArch64CA53Erratum843419Stub());
516      factory->addPrototype(new AArch64CA53Erratum843419Stub2());
517    }
518    return true;
519  }
520  return false;
521}
522
523void AArch64GNULDBackend::doCreateProgramHdrs(Module& pModule) {
524}
525
526bool AArch64GNULDBackend::finalizeTargetSymbols() {
527  return true;
528}
529
530bool AArch64GNULDBackend::mergeSection(Module& pModule,
531                                       const Input& pInput,
532                                       LDSection& pSection) {
533  return true;
534}
535
536bool AArch64GNULDBackend::readSection(Input& pInput, SectionData& pSD) {
537  return true;
538}
539
540AArch64GOT& AArch64GNULDBackend::getGOT() {
541  assert(m_pGOT != NULL && "GOT section not exist");
542  return *m_pGOT;
543}
544
545const AArch64GOT& AArch64GNULDBackend::getGOT() const {
546  assert(m_pGOT != NULL && "GOT section not exist");
547  return *m_pGOT;
548}
549
550AArch64GOT& AArch64GNULDBackend::getGOTPLT() {
551  assert(m_pGOTPLT != NULL && "GOTPLT section not exist");
552  return *m_pGOTPLT;
553}
554
555const AArch64GOT& AArch64GNULDBackend::getGOTPLT() const {
556  assert(m_pGOTPLT != NULL && "GOTPLT section not exist");
557  return *m_pGOTPLT;
558}
559
560AArch64PLT& AArch64GNULDBackend::getPLT() {
561  assert(m_pPLT != NULL && "PLT section not exist");
562  return *m_pPLT;
563}
564
565const AArch64PLT& AArch64GNULDBackend::getPLT() const {
566  assert(m_pPLT != NULL && "PLT section not exist");
567  return *m_pPLT;
568}
569
570OutputRelocSection& AArch64GNULDBackend::getRelaDyn() {
571  assert(m_pRelaDyn != NULL && ".rela.dyn section not exist");
572  return *m_pRelaDyn;
573}
574
575const OutputRelocSection& AArch64GNULDBackend::getRelaDyn() const {
576  assert(m_pRelaDyn != NULL && ".rela.dyn section not exist");
577  return *m_pRelaDyn;
578}
579
580OutputRelocSection& AArch64GNULDBackend::getRelaPLT() {
581  assert(m_pRelaPLT != NULL && ".rela.plt section not exist");
582  return *m_pRelaPLT;
583}
584
585const OutputRelocSection& AArch64GNULDBackend::getRelaPLT() const {
586  assert(m_pRelaPLT != NULL && ".rela.plt section not exist");
587  return *m_pRelaPLT;
588}
589
590//===----------------------------------------------------------------------===//
591//  createAArch64LDBackend - the help funtion to create corresponding
592//  AArch64LDBackend
593//===----------------------------------------------------------------------===//
594TargetLDBackend* createAArch64LDBackend(const LinkerConfig& pConfig) {
595  if (pConfig.targets().triple().isOSDarwin()) {
596    assert(0 && "MachO linker is not supported yet");
597    /**
598    return new AArch64MachOLDBackend(createAArch64MachOArchiveReader,
599                                     createAArch64MachOObjectReader,
600                                     createAArch64MachOObjectWriter);
601    **/
602  }
603  if (pConfig.targets().triple().isOSWindows()) {
604    assert(0 && "COFF linker is not supported yet");
605    /**
606    return new AArch64COFFLDBackend(createAArch64COFFArchiveReader,
607                                    createAArch64COFFObjectReader,
608                                    createAArch64COFFObjectWriter);
609    **/
610  }
611  return new AArch64GNULDBackend(
612      pConfig, new AArch64GNUInfo(pConfig.targets().triple()));
613}
614
615}  // namespace mcld
616
617//===----------------------------------------------------------------------===//
618// Force static initialization.
619//===----------------------------------------------------------------------===//
620extern "C" void MCLDInitializeAArch64LDBackend() {
621  // Register the linker backend
622  mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheAArch64Target,
623                                                mcld::createAArch64LDBackend);
624}
625