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
17 namespace {
18 const unsigned int ARMGOT0Num = 3;
19 } // end of anonymous namespace
20
21 namespace mcld {
22
23 //===----------------------------------------------------------------------===//
24 // ARMGOT
ARMGOT(LDSection & pSection)25 ARMGOT::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
~ARMGOT()32 ARMGOT::~ARMGOT() {
33 }
34
hasGOT1() const35 bool ARMGOT::hasGOT1() const {
36 return ((!m_GOT.empty()) || (!m_GOTPLT.empty()));
37 }
38
createGOT()39 ARMGOTEntry* ARMGOT::createGOT() {
40 ARMGOTEntry* entry = new ARMGOTEntry(0, NULL);
41 m_GOT.push_back(entry);
42 return entry;
43 }
44
createGOTPLT()45 ARMGOTEntry* ARMGOT::createGOTPLT() {
46 ARMGOTEntry* entry = new ARMGOTEntry(0, NULL);
47 m_GOTPLT.push_back(entry);
48 return entry;
49 }
50
finalizeSectionSize()51 void 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
applyGOT0(uint64_t pAddress)93 void ARMGOT::applyGOT0(uint64_t pAddress) {
94 llvm::cast<ARMGOTEntry>(*(m_SectionData->getFragmentList().begin()))
95 .setValue(pAddress);
96 }
97
applyGOTPLT(uint64_t pPLTBase)98 void 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
emit(MemoryRegion & pRegion)115 uint64_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