1//===- impl.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 "ARMGOT.h"
10
11#include <new>
12
13#include <llvm/Support/Casting.h>
14
15#include <mcld/LD/LDFileFormat.h>
16#include <mcld/Support/MemoryRegion.h>
17#include <mcld/Support/MsgHandling.h>
18
19namespace {
20  const size_t ARMGOTEntrySize = 4;
21} // end of anonymous namespace
22
23using namespace mcld;
24
25//===----------------------------------------------------------------------===//
26// ARMGOT
27ARMGOT::ARMGOT(LDSection& pSection, SectionData& pSectionData)
28             : GOT(pSection, pSectionData, ARMGOTEntrySize),
29               m_NormalGOTIterator(), m_GOTPLTIterator(),
30               m_GOTPLTBegin(), m_GOTPLTEnd()
31{
32  GOTEntry* Entry = 0;
33
34  // Create GOT0 entries.
35  for (int i = 0; i < 3; i++) {
36    Entry = new (std::nothrow) GOTEntry(0, ARMGOTEntrySize,
37                                        &m_SectionData);
38
39    if (!Entry)
40      fatal(diag::fail_allocate_memory_got);
41
42    m_Section.setSize(m_Section.size() + ARMGOTEntrySize);
43  }
44
45  // Skip GOT0 entries.
46  iterator it = m_SectionData.begin();
47
48  for (int i = 1; i < ARMGOT0Num; ++i) {
49    assert((it != m_SectionData.end()) && "Generation of GOT0 entries is incomplete!");
50    ++it;
51  }
52
53  m_NormalGOTIterator = it;
54  m_GOTPLTIterator = it;
55
56  m_GOTPLTBegin = it;
57  m_GOTPLTEnd = it;
58}
59
60ARMGOT::~ARMGOT()
61{
62}
63
64void ARMGOT::reserveEntry(size_t pNum)
65{
66  GOTEntry* Entry = 0;
67
68  for (size_t i = 0; i < pNum; i++) {
69    Entry = new (std::nothrow) GOTEntry(0, ARMGOTEntrySize,
70                                        &m_SectionData);
71
72    if (!Entry)
73      fatal(diag::fail_allocate_memory_got);
74
75    m_Section.setSize(m_Section.size() + ARMGOTEntrySize);
76  }
77}
78
79void ARMGOT::reserveGOTPLTEntry()
80{
81    GOTEntry* got_entry = 0;
82
83    got_entry= new GOTEntry(0, getEntrySize(),&(getSectionData()));
84
85    if (!got_entry)
86      fatal(diag::fail_allocate_memory_got);
87
88    m_Section.setSize(m_Section.size() + getEntrySize());
89
90    ++m_GOTPLTEnd;
91    ++m_NormalGOTIterator;
92}
93
94GOTEntry* ARMGOT::getEntry(const ResolveInfo& pInfo, bool& pExist)
95{
96  GOTEntry *&Entry = m_NormalGOTMap[&pInfo];
97  pExist = 1;
98
99  if (!Entry) {
100    pExist = 0;
101
102    ++m_NormalGOTIterator;
103    assert(m_NormalGOTIterator != m_SectionData.getFragmentList().end()
104           && "The number of GOT Entries and ResolveInfo doesn't match!");
105
106    Entry = llvm::cast<GOTEntry>(&(*m_NormalGOTIterator));
107  }
108
109  return Entry;
110}
111
112void ARMGOT::applyGOT0(uint64_t pAddress)
113{
114  llvm::cast<GOTEntry>
115    (*(m_SectionData.getFragmentList().begin())).setContent(pAddress);
116}
117
118void ARMGOT::applyAllGOTPLT(uint64_t pPLTBase)
119{
120  iterator begin = getGOTPLTBegin();
121  iterator end = getGOTPLTEnd();
122
123  for (;begin != end ;++begin)
124    llvm::cast<GOTEntry>(*begin).setContent(pPLTBase);
125}
126
127GOTEntry*& ARMGOT::lookupGOTPLTMap(const ResolveInfo& pSymbol)
128{
129  return m_GOTPLTMap[&pSymbol];
130}
131
132ARMGOT::iterator ARMGOT::begin()
133{
134  return m_SectionData.getFragmentList().begin();
135}
136
137ARMGOT::const_iterator ARMGOT::begin() const
138{
139  return m_SectionData.getFragmentList().begin();
140}
141
142ARMGOT::iterator ARMGOT::end()
143{
144  return m_SectionData.getFragmentList().end();
145}
146
147ARMGOT::const_iterator ARMGOT::end() const
148{
149  return m_SectionData.getFragmentList().end();
150}
151
152ARMGOT::iterator ARMGOT::getNextGOTPLTEntry()
153{
154  return ++m_GOTPLTIterator;
155}
156
157ARMGOT::iterator ARMGOT::getGOTPLTBegin()
158{
159  // Move to the first GOTPLT entry from last GOT0 entry.
160  iterator begin = m_GOTPLTBegin;
161  return ++begin;
162}
163
164const ARMGOT::iterator ARMGOT::getGOTPLTEnd()
165{
166  // Move to end or the first normal GOT entry from the last GOTPLT entry.
167  iterator end = m_GOTPLTEnd;
168  return ++end;
169}
170
171uint64_t ARMGOT::emit(MemoryRegion& pRegion)
172{
173  uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
174
175  GOTEntry* got = 0;
176  unsigned int entry_size = getEntrySize();
177  uint64_t result = 0x0;
178  for (iterator it = begin(), ie = end();
179       it != ie; ++it, ++buffer) {
180      got = &(llvm::cast<GOTEntry>((*it)));
181      *buffer = static_cast<uint32_t>(got->getContent());
182      result += entry_size;
183  }
184  return result;
185}
186
187