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, 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
94X86PLT::~X86PLT()
95{
96}
97
98void 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
122bool X86PLT::hasPLT1() const
123{
124  return (m_pSectionData->size() > 1);
125}
126
127PLTEntryBase* 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
135PLTEntryBase* 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//===----------------------------------------------------------------------===//
150X86_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.
158void 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.
181void 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//===----------------------------------------------------------------------===//
236X86_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.
244void 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.
267void 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