ARMGOT.cpp revision d0fbbb227051be16931a1aa9b4a7722ac039c698
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 <llvm/Support/Casting.h>
12
13#include <mcld/LD/LDSection.h>
14#include <mcld/LD/LDFileFormat.h>
15#include <mcld/Support/MemoryRegion.h>
16#include <mcld/Support/MsgHandling.h>
17
18namespace {
19  const unsigned int ARMGOT0Num = 3;
20} // end of anonymous namespace
21
22using namespace mcld;
23
24//===----------------------------------------------------------------------===//
25// ARMGOT
26ARMGOT::ARMGOT(LDSection& pSection)
27  : GOT(pSection), m_pLast(NULL)
28{
29  // Create GOT0 entries.
30  reserve(ARMGOT0Num);
31
32  // Skip GOT0 entries.
33  for (unsigned int i = 0; i < ARMGOT0Num; ++i) {
34    consume();
35  }
36}
37
38ARMGOT::~ARMGOT()
39{
40}
41
42bool ARMGOT::hasGOT1() const
43{
44  return (m_SectionData->size() > ARMGOT0Num);
45}
46
47void ARMGOT::reserve(size_t pNum)
48{
49  for (size_t i = 0; i < pNum; i++) {
50    new ARMGOTEntry(0, m_SectionData);
51  }
52}
53
54ARMGOTEntry* ARMGOT::consume()
55{
56  if (NULL == m_pLast) {
57    assert(!empty() && "Consume empty GOT entry!");
58    m_pLast = llvm::cast<ARMGOTEntry>(&m_SectionData->front());
59    return m_pLast;
60  }
61
62  m_pLast = llvm::cast<ARMGOTEntry>(m_pLast->getNextNode());
63  return m_pLast;
64}
65
66void ARMGOT::reserveGOTPLT()
67{
68  ARMGOTEntry* entry = new ARMGOTEntry(0, m_SectionData);
69  if (NULL == m_GOTPLT.front) {
70    // GOTPLT is empty
71    if (NULL == m_GOT.front) {
72      // GOT part is also empty. Since entry is the last entry, we can assign
73      // it to GOTPLT directly.
74      m_GOTPLT.front = entry;
75    }
76    else {
77      // GOTn is not empty. Shift GOTn backward by one entry.
78      m_GOTPLT.front = m_GOT.front;
79      m_GOT.front = llvm::cast<ARMGOTEntry>(m_GOT.front->getNextNode());
80    }
81  }
82  else {
83    // GOTPLT is not empty
84    if (NULL != m_GOT.front)
85      m_GOT.front = llvm::cast<ARMGOTEntry>(m_GOT.front->getNextNode());
86  }
87}
88
89void ARMGOT::reserveGOT()
90{
91  ARMGOTEntry* entry = new ARMGOTEntry(0, m_SectionData);
92  if (NULL == m_GOT.front) {
93    // Entry must be the last entry. We can directly assign it to GOT part.
94    m_GOT.front = entry;
95  }
96}
97
98ARMGOTEntry* ARMGOT::consumeGOTPLT()
99{
100  assert(NULL != m_GOTPLT.front && "Consuming empty GOTPLT section!");
101
102  if (NULL == m_GOTPLT.last_used) {
103    m_GOTPLT.last_used = m_GOTPLT.front;
104  }
105  else {
106    m_GOTPLT.last_used = llvm::cast<ARMGOTEntry>(m_GOTPLT.last_used->getNextNode());
107    assert(m_GOTPLT.last_used != m_GOT.front && "No GOT/PLT entry to consume!");
108  }
109  return m_GOTPLT.last_used;
110}
111
112ARMGOTEntry* ARMGOT::consumeGOT()
113{
114  assert(NULL != m_GOT.front && "Consuming empty GOT section!");
115
116  if (NULL == m_GOT.last_used) {
117    m_GOT.last_used = m_GOT.front;
118  }
119  else {
120    m_GOT.last_used = llvm::cast<ARMGOTEntry>(m_GOT.last_used->getNextNode());
121    assert(m_GOT.last_used != NULL && "No GOTn entry to consume!");
122  }
123  return m_GOT.last_used;
124}
125
126void ARMGOT::applyGOT0(uint64_t pAddress)
127{
128  llvm::cast<ARMGOTEntry>
129    (*(m_SectionData->getFragmentList().begin())).setValue(pAddress);
130}
131
132void ARMGOT::applyGOTPLT(uint64_t pPLTBase)
133{
134  if (NULL == m_GOTPLT.front)
135    return;
136
137  SectionData::iterator entry(m_GOTPLT.front);
138  SectionData::iterator e_end;
139  if (NULL == m_GOT.front)
140    e_end = m_SectionData->end();
141  else
142    e_end = SectionData::iterator(m_GOT.front);
143
144  while (entry != e_end) {
145    llvm::cast<ARMGOTEntry>(entry)->setValue(pPLTBase);
146    ++entry;
147  }
148}
149
150uint64_t ARMGOT::emit(MemoryRegion& pRegion)
151{
152  uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
153
154  ARMGOTEntry* got = NULL;
155  uint64_t result = 0x0;
156  for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) {
157      got = &(llvm::cast<ARMGOTEntry>((*it)));
158      *buffer = static_cast<uint32_t>(got->getValue());
159      result += ARMGOTEntry::EntrySize;
160  }
161  return result;
162}
163
164