1//===- AArch64GOT.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 "AArch64GOT.h"
10
11#include "mcld/LD/LDSection.h"
12#include "mcld/LD/LDFileFormat.h"
13#include "mcld/Support/MsgHandling.h"
14
15#include <llvm/Support/Casting.h>
16
17namespace {
18const unsigned int AArch64GOT0Num = 3;
19}  // end of anonymous namespace
20
21namespace mcld {
22
23//===----------------------------------------------------------------------===//
24// AArch64GOT
25AArch64GOT::AArch64GOT(LDSection& pSection)
26    : GOT(pSection), m_pGOTPLTFront(NULL), m_pGOTFront(NULL) {
27}
28
29AArch64GOT::~AArch64GOT() {
30}
31
32void AArch64GOT::createGOT0() {
33  // create GOT0, and put them into m_SectionData immediately
34  for (unsigned int i = 0; i < AArch64GOT0Num; ++i)
35    new AArch64GOTEntry(0, m_SectionData);
36}
37
38bool AArch64GOT::hasGOT1() const {
39  return ((!m_GOT.empty()) || (!m_GOTPLT.empty()));
40}
41
42AArch64GOTEntry* AArch64GOT::createGOT() {
43  AArch64GOTEntry* entry = new AArch64GOTEntry(0, NULL);
44  m_GOT.push_back(entry);
45  return entry;
46}
47
48AArch64GOTEntry* AArch64GOT::createGOTPLT() {
49  AArch64GOTEntry* entry = new AArch64GOTEntry(0, NULL);
50  m_GOTPLT.push_back(entry);
51  return entry;
52}
53
54void AArch64GOT::finalizeSectionSize() {
55  uint32_t offset = 0;
56  SectionData::FragmentListType& frag_list = m_SectionData->getFragmentList();
57  // setup GOT0 offset
58  SectionData::iterator frag, fragEnd = m_SectionData->end();
59  for (frag = m_SectionData->begin(); frag != fragEnd; ++frag) {
60    frag->setOffset(offset);
61    offset += frag->size();
62  }
63
64  // push GOTPLT into the SectionData and setup the offset
65  if (!m_GOTPLT.empty()) {
66    m_pGOTPLTFront = m_GOTPLT.front();
67    entry_iterator it, end = m_GOTPLT.end();
68    for (it = m_GOTPLT.begin(); it != end; ++it) {
69      AArch64GOTEntry* entry = *it;
70      frag_list.push_back(entry);
71      entry->setParent(m_SectionData);
72      entry->setOffset(offset);
73      offset += entry->size();
74    }
75  }
76  m_GOTPLT.clear();
77
78  // push GOT into the SectionData and setup the offset
79  if (!m_GOT.empty()) {
80    m_pGOTFront = m_GOT.front();
81    entry_iterator it, end = m_GOT.end();
82    for (it = m_GOT.begin(); it != end; ++it) {
83      AArch64GOTEntry* entry = *it;
84      frag_list.push_back(entry);
85      entry->setParent(m_SectionData);
86      entry->setOffset(offset);
87      offset += entry->size();
88    }
89  }
90  m_GOT.clear();
91
92  // set section size
93  m_Section.setSize(offset);
94}
95
96void AArch64GOT::applyGOT0(uint64_t pAddress) {
97  llvm::cast<AArch64GOTEntry>(*(m_SectionData->getFragmentList().begin()))
98      .setValue(pAddress);
99}
100
101void AArch64GOT::applyGOTPLT(uint64_t pPLTBase) {
102  if (m_pGOTPLTFront == NULL)
103    return;
104
105  SectionData::iterator entry(m_pGOTPLTFront);
106  SectionData::iterator e_end;
107  if (m_pGOTFront == NULL)
108    e_end = m_SectionData->end();
109  else
110    e_end = SectionData::iterator(m_pGOTFront);
111
112  while (entry != e_end) {
113    llvm::cast<AArch64GOTEntry>(entry)->setValue(pPLTBase);
114    ++entry;
115  }
116}
117
118uint64_t AArch64GOT::emit(MemoryRegion& pRegion) {
119  uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.begin());
120
121  AArch64GOTEntry* got = NULL;
122  uint64_t result = 0x0;
123  for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) {
124    got = &(llvm::cast<AArch64GOTEntry>((*it)));
125    *buffer = static_cast<uint64_t>(got->getValue());
126    result += AArch64GOTEntry::EntrySize;
127  }
128  return result;
129}
130
131}  // namespace mcld
132