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
19 namespace {
20 const size_t ARMGOTEntrySize = 4;
21 } // end of anonymous namespace
22
23 using namespace mcld;
24
25 //===----------------------------------------------------------------------===//
26 // ARMGOT
ARMGOT(LDSection & pSection,SectionData & pSectionData)27 ARMGOT::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
~ARMGOT()60 ARMGOT::~ARMGOT()
61 {
62 }
63
reserveEntry(size_t pNum)64 void 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
reserveGOTPLTEntry()79 void 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
getEntry(const ResolveInfo & pInfo,bool & pExist)94 GOTEntry* 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
applyGOT0(uint64_t pAddress)112 void ARMGOT::applyGOT0(uint64_t pAddress)
113 {
114 llvm::cast<GOTEntry>
115 (*(m_SectionData.getFragmentList().begin())).setContent(pAddress);
116 }
117
applyAllGOTPLT(uint64_t pPLTBase)118 void 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
lookupGOTPLTMap(const ResolveInfo & pSymbol)127 GOTEntry*& ARMGOT::lookupGOTPLTMap(const ResolveInfo& pSymbol)
128 {
129 return m_GOTPLTMap[&pSymbol];
130 }
131
begin()132 ARMGOT::iterator ARMGOT::begin()
133 {
134 return m_SectionData.getFragmentList().begin();
135 }
136
begin() const137 ARMGOT::const_iterator ARMGOT::begin() const
138 {
139 return m_SectionData.getFragmentList().begin();
140 }
141
end()142 ARMGOT::iterator ARMGOT::end()
143 {
144 return m_SectionData.getFragmentList().end();
145 }
146
end() const147 ARMGOT::const_iterator ARMGOT::end() const
148 {
149 return m_SectionData.getFragmentList().end();
150 }
151
getNextGOTPLTEntry()152 ARMGOT::iterator ARMGOT::getNextGOTPLTEntry()
153 {
154 return ++m_GOTPLTIterator;
155 }
156
getGOTPLTBegin()157 ARMGOT::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
getGOTPLTEnd()164 const 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
emit(MemoryRegion & pRegion)171 uint64_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