MipsGOT.cpp revision d8a752331fe7a30ce41835f139aa8a4c675ad07a
1//===- MipsGOT.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
10#include <llvm/Support/ErrorHandling.h>
11#include <mcld/LD/ResolveInfo.h>
12#include <mcld/Support/MemoryRegion.h>
13#include "MipsGOT.h"
14
15namespace {
16  const size_t MipsGOTEntrySize = 4;
17  const size_t MipsGOT0Num = 1;
18}
19
20using namespace mcld;
21
22//===----------------------------------------------------------------------===//
23// MipsGOT
24MipsGOT::MipsGOT(LDSection& pSection, llvm::MCSectionData& pSectionData)
25  : GOT(pSection, pSectionData, MipsGOTEntrySize),
26    m_pLocalNum(0)
27{
28  // Create GOT0 entries.
29  for (size_t i = 0; i < MipsGOT0Num; ++i) {
30    GOTEntry* entry =
31      new (std::nothrow) GOTEntry(0, MipsGOTEntrySize, &m_SectionData);
32
33    if (NULL == entry)
34      llvm::report_fatal_error("Allocating GOT0 entries failed!");
35
36    m_Section.setSize(m_Section.size() + MipsGOTEntrySize);
37  }
38
39  // Skip GOT0 entries.
40  iterator it = m_SectionData.begin();
41  iterator ie = m_SectionData.end();
42
43  for (size_t i = 1; i < MipsGOT0Num; ++i) {
44    if (it == ie)
45      llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
46
47    ++it;
48  }
49
50  m_LocalGOTIterator = it;
51  m_GlobalGOTIterator = it;
52  m_pLocalNum = MipsGOT0Num;
53}
54
55MipsGOT::iterator MipsGOT::begin()
56{
57  return m_SectionData.getFragmentList().begin();
58}
59
60MipsGOT::iterator MipsGOT::end()
61{
62  return m_SectionData.getFragmentList().end();
63}
64
65MipsGOT::const_iterator MipsGOT::begin() const
66{
67  return m_SectionData.getFragmentList().begin();
68}
69
70MipsGOT::const_iterator MipsGOT::end() const
71{
72  return m_SectionData.getFragmentList().end();
73}
74
75uint64_t MipsGOT::emit(MemoryRegion& pRegion)
76{
77  uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
78
79  size_t entry_size = getEntrySize();
80
81  uint64_t result = 0;
82  for (iterator it = begin(), ie = end();
83       it != ie; ++it, ++buffer) {
84    GOTEntry* got = &(llvm::cast<GOTEntry>((*it)));
85    *buffer = static_cast<uint32_t>(got->getContent());
86    result += entry_size;
87  }
88  return result;
89}
90
91void MipsGOT::reserveEntry(size_t pNum)
92{
93  for (size_t i = 0; i < pNum; ++i) {
94    GOTEntry* entry =
95      new (std::nothrow) GOTEntry(0, MipsGOTEntrySize, &m_SectionData);
96
97    if (NULL == entry)
98      llvm::report_fatal_error("Allocating new GOTEntry failed");
99
100    m_Section.setSize(m_Section.size() + MipsGOTEntrySize);
101  }
102}
103
104void MipsGOT::reserveLocalEntry()
105{
106  reserveEntry(1);
107  ++m_pLocalNum;
108
109  // Move global entries iterator forward.
110  // We need to put global GOT entries after all local ones.
111  ++m_GlobalGOTIterator;
112}
113
114void MipsGOT::reserveGlobalEntry()
115{
116  reserveEntry(1);
117}
118
119GOTEntry* MipsGOT::getEntry(const ResolveInfo& pInfo, bool& pExist)
120{
121  GOTEntry*& entry = m_GeneralGOTMap[&pInfo];
122
123  pExist = NULL != entry;
124
125  if (!pExist) {
126    iterator& it = pInfo.isLocal() ? m_LocalGOTIterator : m_GlobalGOTIterator;
127
128    ++it;
129
130    assert(it != m_SectionData.getFragmentList().end() &&
131           "The number of GOT Entries and ResolveInfo doesn't match");
132
133    entry = llvm::cast<GOTEntry>(&(*it));
134  }
135
136  return entry;
137}
138
139size_t MipsGOT::getTotalNum() const
140{
141  return m_SectionData.getFragmentList().size();
142}
143
144size_t MipsGOT::getLocalNum() const
145{
146  return m_pLocalNum;
147}
148