1//===- ARMGOT.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 "mcld/LD/LDSection.h"
12#include "mcld/LD/LDFileFormat.h"
13#include "mcld/Support/MsgHandling.h"
14
15#include <llvm/Support/Casting.h>
16
17namespace {
18const unsigned int ARMGOT0Num = 3;
19}  // end of anonymous namespace
20
21namespace mcld {
22
23//===----------------------------------------------------------------------===//
24// ARMGOT
25ARMGOT::ARMGOT(LDSection& pSection)
26    : GOT(pSection), m_pGOTPLTFront(NULL), m_pGOTFront(NULL) {
27  // create GOT0, and put them into m_SectionData immediately
28  for (unsigned int i = 0; i < ARMGOT0Num; ++i)
29    new ARMGOTEntry(0, m_SectionData);
30}
31
32ARMGOT::~ARMGOT() {
33}
34
35bool ARMGOT::hasGOT1() const {
36  return ((!m_GOT.empty()) || (!m_GOTPLT.empty()));
37}
38
39ARMGOTEntry* ARMGOT::createGOT() {
40  ARMGOTEntry* entry = new ARMGOTEntry(0, NULL);
41  m_GOT.push_back(entry);
42  return entry;
43}
44
45ARMGOTEntry* ARMGOT::createGOTPLT() {
46  ARMGOTEntry* entry = new ARMGOTEntry(0, NULL);
47  m_GOTPLT.push_back(entry);
48  return entry;
49}
50
51void ARMGOT::finalizeSectionSize() {
52  uint32_t offset = 0;
53  SectionData::FragmentListType& frag_list = m_SectionData->getFragmentList();
54  // setup GOT0 offset
55  SectionData::iterator frag, fragEnd = m_SectionData->end();
56  for (frag = m_SectionData->begin(); frag != fragEnd; ++frag) {
57    frag->setOffset(offset);
58    offset += frag->size();
59  }
60
61  // push GOTPLT into the SectionData and setup the offset
62  if (!m_GOTPLT.empty()) {
63    m_pGOTPLTFront = m_GOTPLT.front();
64    entry_iterator it, end = m_GOTPLT.end();
65    for (it = m_GOTPLT.begin(); it != end; ++it) {
66      ARMGOTEntry* entry = *it;
67      frag_list.push_back(entry);
68      entry->setParent(m_SectionData);
69      entry->setOffset(offset);
70      offset += entry->size();
71    }
72  }
73  m_GOTPLT.clear();
74
75  // push GOT into the SectionData and setup the offset
76  if (!m_GOT.empty()) {
77    m_pGOTFront = m_GOT.front();
78    entry_iterator it, end = m_GOT.end();
79    for (it = m_GOT.begin(); it != end; ++it) {
80      ARMGOTEntry* entry = *it;
81      frag_list.push_back(entry);
82      entry->setParent(m_SectionData);
83      entry->setOffset(offset);
84      offset += entry->size();
85    }
86  }
87  m_GOT.clear();
88
89  // set section size
90  m_Section.setSize(offset);
91}
92
93void ARMGOT::applyGOT0(uint64_t pAddress) {
94  llvm::cast<ARMGOTEntry>(*(m_SectionData->getFragmentList().begin()))
95      .setValue(pAddress);
96}
97
98void ARMGOT::applyGOTPLT(uint64_t pPLTBase) {
99  if (m_pGOTPLTFront == NULL)
100    return;
101
102  SectionData::iterator entry(m_pGOTPLTFront);
103  SectionData::iterator e_end;
104  if (m_pGOTFront == NULL)
105    e_end = m_SectionData->end();
106  else
107    e_end = SectionData::iterator(m_pGOTFront);
108
109  while (entry != e_end) {
110    llvm::cast<ARMGOTEntry>(entry)->setValue(pPLTBase);
111    ++entry;
112  }
113}
114
115uint64_t ARMGOT::emit(MemoryRegion& pRegion) {
116  uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.begin());
117
118  ARMGOTEntry* got = NULL;
119  uint64_t result = 0x0;
120  for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) {
121    got = &(llvm::cast<ARMGOTEntry>((*it)));
122    *buffer = static_cast<uint32_t>(got->getValue());
123    result += ARMGOTEntry::EntrySize;
124  }
125  return result;
126}
127
128}  // namespace mcld
129