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