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
17 namespace {
18 const unsigned int ARMGOT0Num = 3;
19 } // end of anonymous namespace
20
21 using namespace mcld;
22
23 //===----------------------------------------------------------------------===//
24 // ARMGOT
ARMGOT(LDSection & pSection)25 ARMGOT::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
~ARMGOT()33 ARMGOT::~ARMGOT()
34 {
35 }
36
hasGOT1() const37 bool ARMGOT::hasGOT1() const
38 {
39 return ((!m_GOT.empty()) || (!m_GOTPLT.empty()));
40 }
41
createGOT()42 ARMGOTEntry* ARMGOT::createGOT()
43 {
44 ARMGOTEntry* entry = new ARMGOTEntry(0, NULL);
45 m_GOT.push_back(entry);
46 return entry;
47 }
48
createGOTPLT()49 ARMGOTEntry* ARMGOT::createGOTPLT()
50 {
51 ARMGOTEntry* entry = new ARMGOTEntry(0, NULL);
52 m_GOTPLT.push_back(entry);
53 return entry;
54 }
55
finalizeSectionSize()56 void 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
applyGOT0(uint64_t pAddress)99 void ARMGOT::applyGOT0(uint64_t pAddress)
100 {
101 llvm::cast<ARMGOTEntry>
102 (*(m_SectionData->getFragmentList().begin())).setValue(pAddress);
103 }
104
applyGOTPLT(uint64_t pPLTBase)105 void 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
emit(MemoryRegion & pRegion)123 uint64_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