• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- X86PLT.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 "X86GOTPLT.h"
10 #include "X86PLT.h"
11 
12 #include <llvm/Support/ELF.h>
13 #include <llvm/Support/Casting.h>
14 
15 #include <mcld/LD/LDSection.h>
16 #include <mcld/LinkerConfig.h>
17 #include <mcld/Support/MsgHandling.h>
18 
19 using namespace mcld;
20 
21 //===----------------------------------------------------------------------===//
22 // PLT entry data
23 //===----------------------------------------------------------------------===//
X86_32DynPLT0(SectionData & pParent)24 X86_32DynPLT0::X86_32DynPLT0(SectionData& pParent)
25   : PLT::Entry<sizeof(x86_32_dyn_plt0)>(pParent)
26 {
27 }
28 
X86_32DynPLT1(SectionData & pParent)29 X86_32DynPLT1::X86_32DynPLT1(SectionData& pParent)
30   : PLT::Entry<sizeof(x86_32_dyn_plt1)>(pParent)
31 {
32 }
33 
X86_32ExecPLT0(SectionData & pParent)34 X86_32ExecPLT0::X86_32ExecPLT0(SectionData& pParent)
35   : PLT::Entry<sizeof(x86_32_exec_plt0)>(pParent)
36 {
37 }
38 
X86_32ExecPLT1(SectionData & pParent)39 X86_32ExecPLT1::X86_32ExecPLT1(SectionData& pParent)
40   : PLT::Entry<sizeof(x86_32_exec_plt1)>(pParent)
41 {
42 }
43 
X86_64PLT0(SectionData & pParent)44 X86_64PLT0::X86_64PLT0(SectionData& pParent)
45   : PLT::Entry<sizeof(x86_64_plt0)>(pParent)
46 {
47 }
48 
X86_64PLT1(SectionData & pParent)49 X86_64PLT1::X86_64PLT1(SectionData& pParent)
50   : PLT::Entry<sizeof(x86_64_plt1)>(pParent)
51 {
52 }
53 
54 //===----------------------------------------------------------------------===//
55 // X86PLT
56 //===----------------------------------------------------------------------===//
X86PLT(LDSection & pSection,const LinkerConfig & pConfig,int got_size)57 X86PLT::X86PLT(LDSection& pSection,
58 	       const LinkerConfig& pConfig,
59 	       int got_size)
60   : PLT(pSection),
61     m_Config(pConfig)
62 {
63   assert(LinkerConfig::DynObj == m_Config.codeGenType() ||
64          LinkerConfig::Exec   == m_Config.codeGenType() ||
65          LinkerConfig::Binary == m_Config.codeGenType());
66 
67   if (got_size == 32) {
68     if (LinkerConfig::DynObj == m_Config.codeGenType()) {
69       m_PLT0 = x86_32_dyn_plt0;
70       m_PLT1 = x86_32_dyn_plt1;
71       m_PLT0Size = sizeof (x86_32_dyn_plt0);
72       m_PLT1Size = sizeof (x86_32_dyn_plt1);
73       // create PLT0
74       new X86_32DynPLT0(*m_SectionData);
75     }
76     else {
77       m_PLT0 = x86_32_exec_plt0;
78       m_PLT1 = x86_32_exec_plt1;
79       m_PLT0Size = sizeof (x86_32_exec_plt0);
80       m_PLT1Size = sizeof (x86_32_exec_plt1);
81       // create PLT0
82       new X86_32ExecPLT0(*m_SectionData);
83     }
84   }
85   else {
86     assert(got_size == 64);
87     m_PLT0 = x86_64_plt0;
88     m_PLT1 = x86_64_plt1;
89     m_PLT0Size = sizeof (x86_64_plt0);
90     m_PLT1Size = sizeof (x86_64_plt1);
91     // create PLT0
92     new X86_64PLT0(*m_SectionData);
93     m_Last = m_SectionData->begin();
94   }
95   m_Last = m_SectionData->begin();
96 }
97 
~X86PLT()98 X86PLT::~X86PLT()
99 {
100 }
101 
finalizeSectionSize()102 void X86PLT::finalizeSectionSize()
103 {
104   uint64_t size = 0;
105   // plt0 size
106   size = getPLT0()->size();
107 
108   // get first plt1 entry
109   X86PLT::iterator it = begin();
110   ++it;
111   if (end() != it) {
112     // plt1 size
113     PLTEntryBase* plt1 = &(llvm::cast<PLTEntryBase>(*it));
114     size += (m_SectionData->size() - 1) * plt1->size();
115   }
116   m_Section.setSize(size);
117 
118   uint32_t offset = 0;
119   SectionData::iterator frag, fragEnd = m_SectionData->end();
120   for (frag = m_SectionData->begin(); frag != fragEnd; ++frag) {
121     frag->setOffset(offset);
122     offset += frag->size();
123   }
124 }
125 
hasPLT1() const126 bool X86PLT::hasPLT1() const
127 {
128   return (m_SectionData->size() > 1);
129 }
130 
reserveEntry(size_t pNum)131 void X86PLT::reserveEntry(size_t pNum)
132 {
133   PLTEntryBase* plt1_entry = NULL;
134 
135   for (size_t i = 0; i < pNum; ++i) {
136 
137     if (LinkerConfig::DynObj == m_Config.codeGenType())
138       plt1_entry = new X86_32DynPLT1(*m_SectionData);
139     else
140       plt1_entry = new X86_32ExecPLT1(*m_SectionData);
141 
142     if (NULL == plt1_entry)
143       fatal(diag::fail_allocate_memory_plt);
144   }
145 }
146 
consume()147 PLTEntryBase* X86PLT::consume()
148 {
149   // This will skip PLT0.
150   ++m_Last;
151   assert(m_Last != m_SectionData->end() &&
152          "The number of PLT Entries and ResolveInfo doesn't match");
153   return llvm::cast<PLTEntryBase>(&(*m_Last));
154 }
155 
getPLT0() const156 PLTEntryBase* X86PLT::getPLT0() const
157 {
158   iterator first = m_SectionData->getFragmentList().begin();
159 
160   assert(first != m_SectionData->getFragmentList().end() &&
161          "FragmentList is empty, getPLT0 failed!");
162 
163   PLTEntryBase* plt0 = &(llvm::cast<PLTEntryBase>(*first));
164 
165   return plt0;
166 }
167 
168 //===----------------------------------------------------------------------===//
169 // X86_32PLT
170 //===----------------------------------------------------------------------===//
X86_32PLT(LDSection & pSection,X86_32GOTPLT & pGOTPLT,const LinkerConfig & pConfig)171 X86_32PLT::X86_32PLT(LDSection& pSection,
172 		     X86_32GOTPLT& pGOTPLT,
173 		     const LinkerConfig& pConfig)
174   : X86PLT(pSection, pConfig, 32),
175     m_GOTPLT(pGOTPLT) {
176 }
177 
178 // FIXME: It only works on little endian machine.
applyPLT0()179 void X86_32PLT::applyPLT0()
180 {
181   PLTEntryBase* plt0 = getPLT0();
182 
183   unsigned char* data = 0;
184   data = static_cast<unsigned char*>(malloc(plt0->size()));
185 
186   if (!data)
187     fatal(diag::fail_allocate_memory_plt);
188 
189   memcpy(data, m_PLT0, plt0->size());
190 
191   if (m_PLT0 == x86_32_exec_plt0) {
192     uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2);
193     *offset = m_GOTPLT.addr() + 4;
194     offset = reinterpret_cast<uint32_t*>(data + 8);
195     *offset = m_GOTPLT.addr() + 8;
196   }
197 
198   plt0->setValue(data);
199 }
200 
201 // FIXME: It only works on little endian machine.
applyPLT1()202 void X86_32PLT::applyPLT1()
203 {
204   assert(m_Section.addr() && ".plt base address is NULL!");
205 
206   X86PLT::iterator it = m_SectionData->begin();
207   X86PLT::iterator ie = m_SectionData->end();
208   assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
209 
210   uint64_t GOTEntrySize = X86_32GOTEntry::EntrySize;
211 
212   // Skip GOT0
213   uint64_t GOTEntryOffset = GOTEntrySize * X86GOTPLT0Num;
214   if (LinkerConfig::Exec == m_Config.codeGenType())
215     GOTEntryOffset += m_GOTPLT.addr();
216 
217   //skip PLT0
218   uint64_t PLTEntryOffset = m_PLT0Size;
219   ++it;
220 
221   PLTEntryBase* plt1 = 0;
222 
223   uint64_t PLTRelOffset = 0;
224 
225   while (it != ie) {
226     plt1 = &(llvm::cast<PLTEntryBase>(*it));
227     unsigned char *data;
228     data = static_cast<unsigned char*>(malloc(plt1->size()));
229 
230     if (!data)
231       fatal(diag::fail_allocate_memory_plt);
232 
233     memcpy(data, m_PLT1, plt1->size());
234 
235     uint32_t* offset;
236 
237     offset = reinterpret_cast<uint32_t*>(data + 2);
238     *offset = GOTEntryOffset;
239     GOTEntryOffset += GOTEntrySize;
240 
241     offset = reinterpret_cast<uint32_t*>(data + 7);
242     *offset = PLTRelOffset;
243     PLTRelOffset += sizeof (llvm::ELF::Elf32_Rel);
244 
245     offset = reinterpret_cast<uint32_t*>(data + 12);
246     *offset = -(PLTEntryOffset + 12 + 4);
247     PLTEntryOffset += m_PLT1Size;
248 
249     plt1->setValue(data);
250     ++it;
251   }
252 }
253 
254 //===----------------------------------------------------------------------===//
255 // X86_64PLT
256 //===----------------------------------------------------------------------===//
X86_64PLT(LDSection & pSection,X86_64GOTPLT & pGOTPLT,const LinkerConfig & pConfig)257 X86_64PLT::X86_64PLT(LDSection& pSection,
258 		     X86_64GOTPLT& pGOTPLT,
259 		     const LinkerConfig& pConfig)
260   : X86PLT(pSection, pConfig, 64),
261     m_GOTPLT(pGOTPLT) {
262 }
263 
264 // FIXME: It only works on little endian machine.
applyPLT0()265 void X86_64PLT::applyPLT0()
266 {
267   PLTEntryBase* plt0 = getPLT0();
268 
269   unsigned char* data = 0;
270   data = static_cast<unsigned char*>(malloc(plt0->size()));
271 
272   if (!data)
273     fatal(diag::fail_allocate_memory_plt);
274 
275   memcpy(data, m_PLT0, plt0->size());
276 
277   // pushq GOT + 8(%rip)
278   uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2);
279   *offset = m_GOTPLT.addr() - addr() + 8 - 6;
280   // jmq *GOT + 16(%rip)
281   offset = reinterpret_cast<uint32_t*>(data + 8);
282   *offset = m_GOTPLT.addr() - addr() + 16 - 12;
283 
284   plt0->setValue(data);
285 }
286 
287 // FIXME: It only works on little endian machine.
applyPLT1()288 void X86_64PLT::applyPLT1()
289 {
290   assert(m_Section.addr() && ".plt base address is NULL!");
291 
292   X86PLT::iterator it = m_SectionData->begin();
293   X86PLT::iterator ie = m_SectionData->end();
294   assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
295 
296   uint64_t GOTEntrySize = X86_64GOTEntry::EntrySize;
297 
298   // compute sym@GOTPCREL of the PLT1 entry.
299   uint64_t SymGOTPCREL = m_GOTPLT.addr();
300 
301   // Skip GOT0
302   SymGOTPCREL += GOTEntrySize * X86GOTPLT0Num;
303 
304   // skip PLT0
305   uint64_t PLTEntryOffset = m_PLT0Size;
306   ++it;
307 
308   // PC-relative to entry in PLT section.
309   SymGOTPCREL -= addr() + PLTEntryOffset + 6;
310 
311   PLTEntryBase* plt1 = 0;
312 
313   uint64_t PLTRelIndex = 0;
314 
315   while (it != ie) {
316     plt1 = &(llvm::cast<PLTEntryBase>(*it));
317     unsigned char *data;
318     data = static_cast<unsigned char*>(malloc(plt1->size()));
319 
320     if (!data)
321       fatal(diag::fail_allocate_memory_plt);
322 
323     memcpy(data, m_PLT1, plt1->size());
324 
325     uint32_t* offset;
326 
327     // jmpq *sym@GOTPCREL(%rip)
328     offset = reinterpret_cast<uint32_t*>(data + 2);
329     *offset = SymGOTPCREL;
330     SymGOTPCREL += GOTEntrySize - m_PLT1Size;
331 
332     // pushq $index
333     offset = reinterpret_cast<uint32_t*>(data + 7);
334     *offset = PLTRelIndex;
335     PLTRelIndex++;
336 
337     // jmpq plt0
338     offset = reinterpret_cast<uint32_t*>(data + 12);
339     *offset = -(PLTEntryOffset + 12 + 4);
340     PLTEntryOffset += m_PLT1Size;
341 
342     plt1->setValue(data);
343     ++it;
344   }
345 }
346 
347