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