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