• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- ARMPLT.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 #include "ARMPLT.h"
11 
12 #include <new>
13 
14 #include <llvm/Support/Casting.h>
15 
16 #include <mcld/Support/MemoryRegion.h>
17 #include <mcld/Support/MsgHandling.h>
18 
19 namespace {
20 
21 const uint32_t arm_plt0[] = {
22   0xe52de004, // str   lr, [sp, #-4]!
23   0xe59fe004, // ldr   lr, [pc, #4]
24   0xe08fe00e, // add   lr, pc, lr
25   0xe5bef008, // ldr   pc, [lr, #8]!
26   0x00000000, // &GOT[0] - .
27 };
28 
29 const uint32_t arm_plt1[] = {
30   0xe28fc600, // add   ip, pc, #0xNN00000
31   0xe28cca00, // add   ip, ip, #0xNN000
32   0xe5bcf000, // ldr   pc, [ip, #0xNNN]!
33 };
34 
35 } // anonymous namespace
36 
37 using namespace mcld;
38 
ARMPLT0(SectionData * pParent)39 ARMPLT0::ARMPLT0(SectionData* pParent)
40   : PLTEntry(sizeof(arm_plt0), pParent) {}
41 
ARMPLT1(SectionData * pParent)42 ARMPLT1::ARMPLT1(SectionData* pParent)
43   : PLTEntry(sizeof(arm_plt1), pParent) {}
44 
45 //===----------------------------------------------------------------------===//
46 // ARMPLT
47 
ARMPLT(LDSection & pSection,SectionData & pSectionData,ARMGOT & pGOTPLT)48 ARMPLT::ARMPLT(LDSection& pSection,
49                SectionData& pSectionData,
50                ARMGOT &pGOTPLT)
51   : PLT(pSection, pSectionData), m_GOT(pGOTPLT), m_PLTEntryIterator() {
52   ARMPLT0* plt0_entry = new ARMPLT0(&m_SectionData);
53 
54   m_Section.setSize(m_Section.size() + plt0_entry->getEntrySize());
55 
56   m_PLTEntryIterator = pSectionData.begin();
57 }
58 
~ARMPLT()59 ARMPLT::~ARMPLT()
60 {
61 }
62 
reserveEntry(size_t pNum)63 void ARMPLT::reserveEntry(size_t pNum)
64 {
65   ARMPLT1* plt1_entry = 0;
66 
67   for (size_t i = 0; i < pNum; ++i) {
68     plt1_entry = new (std::nothrow) ARMPLT1(&m_SectionData);
69 
70     if (!plt1_entry)
71       fatal(diag::fail_allocate_memory_plt);
72 
73     m_Section.setSize(m_Section.size() + plt1_entry->getEntrySize());
74 
75     m_GOT.reserveGOTPLTEntry();
76   }
77 }
78 
getPLTEntry(const ResolveInfo & pSymbol,bool & pExist)79 PLTEntry* ARMPLT::getPLTEntry(const ResolveInfo& pSymbol, bool& pExist)
80 {
81    ARMPLT1 *&PLTEntry = m_PLTEntryMap[&pSymbol];
82 
83    pExist = 1;
84 
85    if (!PLTEntry) {
86      GOTEntry *&GOTPLTEntry = m_GOT.lookupGOTPLTMap(pSymbol);
87      assert(!GOTPLTEntry && "PLT entry and got.plt entry doesn't match!");
88 
89      pExist = 0;
90 
91      // This will skip PLT0.
92      ++m_PLTEntryIterator;
93      assert(m_PLTEntryIterator != m_SectionData.end() &&
94             "The number of PLT Entries and ResolveInfo doesn't match");
95 
96      ARMGOT::iterator got_it = m_GOT.getNextGOTPLTEntry();
97      assert(got_it != m_GOT.getGOTPLTEnd() && "The number of GOTPLT and PLT doesn't match");
98 
99      PLTEntry = llvm::cast<ARMPLT1>(&(*m_PLTEntryIterator));
100      GOTPLTEntry = llvm::cast<GOTEntry>(&(*got_it));
101    }
102 
103    return PLTEntry;
104 }
105 
getGOTPLTEntry(const ResolveInfo & pSymbol,bool & pExist)106 GOTEntry* ARMPLT::getGOTPLTEntry(const ResolveInfo& pSymbol, bool& pExist)
107 {
108    GOTEntry *&GOTPLTEntry = m_GOT.lookupGOTPLTMap(pSymbol);
109 
110    pExist = 1;
111 
112    if (!GOTPLTEntry) {
113      ARMPLT1 *&PLTEntry = m_PLTEntryMap[&pSymbol];
114      assert(!PLTEntry && "PLT entry and got.plt entry doesn't match!");
115 
116      pExist = 0;
117 
118      // This will skip PLT0.
119      ++m_PLTEntryIterator;
120      assert(m_PLTEntryIterator != m_SectionData.end() &&
121             "The number of PLT Entries and ResolveInfo doesn't match");
122 
123      ARMGOT::iterator got_it = m_GOT.getNextGOTPLTEntry();
124      assert(got_it != m_GOT.getGOTPLTEnd() &&
125             "The number of GOTPLT and PLT doesn't match");
126 
127      PLTEntry = llvm::cast<ARMPLT1>(&(*m_PLTEntryIterator));
128      GOTPLTEntry = llvm::cast<GOTEntry>(&(*got_it));
129    }
130 
131    return GOTPLTEntry;
132 }
133 
getPLT0() const134 ARMPLT0* ARMPLT::getPLT0() const {
135 
136   iterator first = m_SectionData.getFragmentList().begin();
137 
138   assert(first != m_SectionData.getFragmentList().end() &&
139          "FragmentList is empty, getPLT0 failed!");
140 
141   ARMPLT0* plt0 = &(llvm::cast<ARMPLT0>(*first));
142 
143   return plt0;
144 }
145 
applyPLT0()146 void ARMPLT::applyPLT0() {
147 
148   uint64_t plt_base = m_Section.addr();
149   assert(plt_base && ".plt base address is NULL!");
150 
151   uint64_t got_base = m_GOT.getSection().addr();
152   assert(got_base && ".got base address is NULL!");
153 
154   uint32_t offset = 0;
155 
156   if (got_base > plt_base)
157     offset = got_base - (plt_base + 16);
158   else
159     offset = (plt_base + 16) - got_base;
160 
161   iterator first = m_SectionData.getFragmentList().begin();
162 
163   assert(first != m_SectionData.getFragmentList().end() &&
164          "FragmentList is empty, applyPLT0 failed!");
165 
166   ARMPLT0* plt0 = &(llvm::cast<ARMPLT0>(*first));
167 
168   uint32_t* data = 0;
169   data = static_cast<uint32_t*>(malloc(plt0->getEntrySize()));
170 
171   if (!data)
172     fatal(diag::fail_allocate_memory_plt);
173 
174   memcpy(data, arm_plt0, plt0->getEntrySize());
175   data[4] = offset;
176 
177   plt0->setContent(reinterpret_cast<unsigned char*>(data));
178 }
179 
applyPLT1()180 void ARMPLT::applyPLT1() {
181 
182   uint64_t plt_base = m_Section.addr();
183   assert(plt_base && ".plt base address is NULL!");
184 
185   uint64_t got_base = m_GOT.getSection().addr();
186   assert(got_base && ".got base address is NULL!");
187 
188   ARMPLT::iterator it = m_SectionData.begin();
189   ARMPLT::iterator ie = m_SectionData.end();
190   assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
191 
192   uint32_t GOTEntrySize = m_GOT.getEntrySize();
193   uint32_t GOTEntryAddress =
194     got_base +  GOTEntrySize * 3;
195 
196   uint64_t PLTEntryAddress =
197     plt_base + llvm::cast<ARMPLT0>((*it)).getEntrySize(); //Offset of PLT0
198 
199   ++it; //skip PLT0
200   uint64_t PLT1EntrySize = llvm::cast<ARMPLT1>((*it)).getEntrySize();
201   ARMPLT1* plt1 = NULL;
202 
203   uint32_t* Out = NULL;
204   while (it != ie) {
205     plt1 = &(llvm::cast<ARMPLT1>(*it));
206     Out = static_cast<uint32_t*>(malloc(plt1->getEntrySize()));
207 
208     if (!Out)
209       fatal(diag::fail_allocate_memory_plt);
210 
211     // Offset is the distance between the last PLT entry and the associated
212     // GOT entry.
213     int32_t Offset = (GOTEntryAddress - (PLTEntryAddress + 8));
214 
215     Out[0] = arm_plt1[0] | ((Offset >> 20) & 0xFF);
216     Out[1] = arm_plt1[1] | ((Offset >> 12) & 0xFF);
217     Out[2] = arm_plt1[2] | (Offset & 0xFFF);
218 
219     plt1->setContent(reinterpret_cast<unsigned char*>(Out));
220     ++it;
221 
222     GOTEntryAddress += GOTEntrySize;
223     PLTEntryAddress += PLT1EntrySize;
224   }
225 
226   m_GOT.applyAllGOTPLT(plt_base);
227 }
228 
emit(MemoryRegion & pRegion)229 uint64_t ARMPLT::emit(MemoryRegion& pRegion)
230 {
231   uint64_t result = 0x0;
232   iterator it = begin();
233   unsigned int plt0_size = llvm::cast<ARMPLT0>((*it)).getEntrySize();
234 
235   unsigned char* buffer = pRegion.getBuffer();
236   memcpy(buffer, llvm::cast<ARMPLT0>((*it)).getContent(), plt0_size);
237   result += plt0_size;
238   ++it;
239 
240   ARMPLT1* plt1 = 0;
241   ARMPLT::iterator ie = end();
242   unsigned int entry_size = 0;
243   while (it != ie) {
244     plt1 = &(llvm::cast<ARMPLT1>(*it));
245     entry_size = plt1->getEntrySize();
246     memcpy(buffer + result, plt1->getContent(), entry_size);
247     result += entry_size;
248     ++it;
249   }
250   return result;
251 }
252 
253