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