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