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, const LinkerConfig& pConfig, int got_size)
58   : PLT(pSection),
59     m_Config(pConfig)
60 {
61   assert(LinkerConfig::DynObj == m_Config.codeGenType() ||
62          LinkerConfig::Exec   == m_Config.codeGenType() ||
63          LinkerConfig::Binary == m_Config.codeGenType());
64 
65   if (got_size == 32) {
66     if (LinkerConfig::DynObj == m_Config.codeGenType()) {
67       m_PLT0 = x86_32_dyn_plt0;
68       m_PLT1 = x86_32_dyn_plt1;
69       m_PLT0Size = sizeof (x86_32_dyn_plt0);
70       m_PLT1Size = sizeof (x86_32_dyn_plt1);
71       // create PLT0
72       new X86_32DynPLT0(*m_pSectionData);
73     }
74     else {
75       m_PLT0 = x86_32_exec_plt0;
76       m_PLT1 = x86_32_exec_plt1;
77       m_PLT0Size = sizeof (x86_32_exec_plt0);
78       m_PLT1Size = sizeof (x86_32_exec_plt1);
79       // create PLT0
80       new X86_32ExecPLT0(*m_pSectionData);
81     }
82   }
83   else {
84     assert(got_size == 64);
85     m_PLT0 = x86_64_plt0;
86     m_PLT1 = x86_64_plt1;
87     m_PLT0Size = sizeof (x86_64_plt0);
88     m_PLT1Size = sizeof (x86_64_plt1);
89     // create PLT0
90     new X86_64PLT0(*m_pSectionData);
91   }
92 }
93 
~X86PLT()94 X86PLT::~X86PLT()
95 {
96 }
97 
finalizeSectionSize()98 void X86PLT::finalizeSectionSize()
99 {
100   uint64_t size = 0;
101   // plt0 size
102   size = getPLT0()->size();
103 
104   // get first plt1 entry
105   X86PLT::iterator it = begin();
106   ++it;
107   if (end() != it) {
108     // plt1 size
109     PLTEntryBase* plt1 = &(llvm::cast<PLTEntryBase>(*it));
110     size += (m_pSectionData->size() - 1) * plt1->size();
111   }
112   m_Section.setSize(size);
113 
114   uint32_t offset = 0;
115   SectionData::iterator frag, fragEnd = m_pSectionData->end();
116   for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
117     frag->setOffset(offset);
118     offset += frag->size();
119   }
120 }
121 
hasPLT1() const122 bool X86PLT::hasPLT1() const
123 {
124   return (m_pSectionData->size() > 1);
125 }
126 
create()127 PLTEntryBase* X86PLT::create()
128 {
129   if (LinkerConfig::DynObj == m_Config.codeGenType())
130     return new X86_32DynPLT1(*m_pSectionData);
131   else
132     return new X86_32ExecPLT1(*m_pSectionData);
133 }
134 
getPLT0() const135 PLTEntryBase* X86PLT::getPLT0() const
136 {
137   iterator first = m_pSectionData->getFragmentList().begin();
138 
139   assert(first != m_pSectionData->getFragmentList().end() &&
140          "FragmentList is empty, getPLT0 failed!");
141 
142   PLTEntryBase* plt0 = &(llvm::cast<PLTEntryBase>(*first));
143 
144   return plt0;
145 }
146 
147 //===----------------------------------------------------------------------===//
148 // X86_32PLT
149 //===----------------------------------------------------------------------===//
X86_32PLT(LDSection & pSection,X86_32GOTPLT & pGOTPLT,const LinkerConfig & pConfig)150 X86_32PLT::X86_32PLT(LDSection& pSection,
151                      X86_32GOTPLT& pGOTPLT,
152                      const LinkerConfig& pConfig)
153   : X86PLT(pSection, pConfig, 32),
154     m_GOTPLT(pGOTPLT) {
155 }
156 
157 // FIXME: It only works on little endian machine.
applyPLT0()158 void X86_32PLT::applyPLT0()
159 {
160   PLTEntryBase* plt0 = getPLT0();
161 
162   unsigned char* data = 0;
163   data = static_cast<unsigned char*>(malloc(plt0->size()));
164 
165   if (!data)
166     fatal(diag::fail_allocate_memory_plt);
167 
168   memcpy(data, m_PLT0, plt0->size());
169 
170   if (m_PLT0 == x86_32_exec_plt0) {
171     uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2);
172     *offset = m_GOTPLT.addr() + 4;
173     offset = reinterpret_cast<uint32_t*>(data + 8);
174     *offset = m_GOTPLT.addr() + 8;
175   }
176 
177   plt0->setValue(data);
178 }
179 
180 // FIXME: It only works on little endian machine.
applyPLT1()181 void X86_32PLT::applyPLT1()
182 {
183   assert(m_Section.addr() && ".plt base address is NULL!");
184 
185   X86PLT::iterator it = m_pSectionData->begin();
186   X86PLT::iterator ie = m_pSectionData->end();
187   assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
188 
189   uint64_t GOTEntrySize = X86_32GOTEntry::EntrySize;
190 
191   // Skip GOT0
192   uint64_t GOTEntryOffset = GOTEntrySize * X86GOTPLT0Num;
193   if (LinkerConfig::Exec == m_Config.codeGenType())
194     GOTEntryOffset += m_GOTPLT.addr();
195 
196   //skip PLT0
197   uint64_t PLTEntryOffset = m_PLT0Size;
198   ++it;
199 
200   PLTEntryBase* plt1 = 0;
201 
202   uint64_t PLTRelOffset = 0;
203 
204   while (it != ie) {
205     plt1 = &(llvm::cast<PLTEntryBase>(*it));
206     unsigned char *data;
207     data = static_cast<unsigned char*>(malloc(plt1->size()));
208 
209     if (!data)
210       fatal(diag::fail_allocate_memory_plt);
211 
212     memcpy(data, m_PLT1, plt1->size());
213 
214     uint32_t* offset;
215 
216     offset = reinterpret_cast<uint32_t*>(data + 2);
217     *offset = GOTEntryOffset;
218     GOTEntryOffset += GOTEntrySize;
219 
220     offset = reinterpret_cast<uint32_t*>(data + 7);
221     *offset = PLTRelOffset;
222     PLTRelOffset += sizeof (llvm::ELF::Elf32_Rel);
223 
224     offset = reinterpret_cast<uint32_t*>(data + 12);
225     *offset = -(PLTEntryOffset + 12 + 4);
226     PLTEntryOffset += m_PLT1Size;
227 
228     plt1->setValue(data);
229     ++it;
230   }
231 }
232 
233 //===----------------------------------------------------------------------===//
234 // X86_64PLT
235 //===----------------------------------------------------------------------===//
X86_64PLT(LDSection & pSection,X86_64GOTPLT & pGOTPLT,const LinkerConfig & pConfig)236 X86_64PLT::X86_64PLT(LDSection& pSection,
237                      X86_64GOTPLT& pGOTPLT,
238                      const LinkerConfig& pConfig)
239   : X86PLT(pSection, pConfig, 64),
240     m_GOTPLT(pGOTPLT) {
241 }
242 
243 // FIXME: It only works on little endian machine.
applyPLT0()244 void X86_64PLT::applyPLT0()
245 {
246   PLTEntryBase* plt0 = getPLT0();
247 
248   unsigned char* data = 0;
249   data = static_cast<unsigned char*>(malloc(plt0->size()));
250 
251   if (!data)
252     fatal(diag::fail_allocate_memory_plt);
253 
254   memcpy(data, m_PLT0, plt0->size());
255 
256   // pushq GOT + 8(%rip)
257   uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2);
258   *offset = m_GOTPLT.addr() - addr() + 8 - 6;
259   // jmq *GOT + 16(%rip)
260   offset = reinterpret_cast<uint32_t*>(data + 8);
261   *offset = m_GOTPLT.addr() - addr() + 16 - 12;
262 
263   plt0->setValue(data);
264 }
265 
266 // FIXME: It only works on little endian machine.
applyPLT1()267 void X86_64PLT::applyPLT1()
268 {
269   assert(m_Section.addr() && ".plt base address is NULL!");
270 
271   X86PLT::iterator it = m_pSectionData->begin();
272   X86PLT::iterator ie = m_pSectionData->end();
273   assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
274 
275   uint64_t GOTEntrySize = X86_64GOTEntry::EntrySize;
276 
277   // compute sym@GOTPCREL of the PLT1 entry.
278   uint64_t SymGOTPCREL = m_GOTPLT.addr();
279 
280   // Skip GOT0
281   SymGOTPCREL += GOTEntrySize * X86GOTPLT0Num;
282 
283   // skip PLT0
284   uint64_t PLTEntryOffset = m_PLT0Size;
285   ++it;
286 
287   // PC-relative to entry in PLT section.
288   SymGOTPCREL -= addr() + PLTEntryOffset + 6;
289 
290   PLTEntryBase* plt1 = 0;
291 
292   uint64_t PLTRelIndex = 0;
293 
294   while (it != ie) {
295     plt1 = &(llvm::cast<PLTEntryBase>(*it));
296     unsigned char *data;
297     data = static_cast<unsigned char*>(malloc(plt1->size()));
298 
299     if (!data)
300       fatal(diag::fail_allocate_memory_plt);
301 
302     memcpy(data, m_PLT1, plt1->size());
303 
304     uint32_t* offset;
305 
306     // jmpq *sym@GOTPCREL(%rip)
307     offset = reinterpret_cast<uint32_t*>(data + 2);
308     *offset = SymGOTPCREL;
309     SymGOTPCREL += GOTEntrySize - m_PLT1Size;
310 
311     // pushq $index
312     offset = reinterpret_cast<uint32_t*>(data + 7);
313     *offset = PLTRelIndex;
314     PLTRelIndex++;
315 
316     // jmpq plt0
317     offset = reinterpret_cast<uint32_t*>(data + 12);
318     *offset = -(PLTEntryOffset + 12 + 4);
319     PLTEntryOffset += m_PLT1Size;
320 
321     plt1->setValue(data);
322     ++it;
323   }
324 }
325 
326