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