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