X86PLT.cpp revision d0fbbb227051be16931a1aa9b4a7722ac039c698
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//===----------------------------------------------------------------------===//
24X86DynPLT0::X86DynPLT0(SectionData& pParent)
25  : PLT::Entry<sizeof(x86_dyn_plt0)>(pParent)
26{
27}
28
29X86DynPLT1::X86DynPLT1(SectionData& pParent)
30  : PLT::Entry<sizeof(x86_dyn_plt1)>(pParent)
31{
32}
33
34X86ExecPLT0::X86ExecPLT0(SectionData& pParent)
35  : PLT::Entry<sizeof(x86_exec_plt0)>(pParent)
36{
37}
38
39X86ExecPLT1::X86ExecPLT1(SectionData& pParent)
40  : PLT::Entry<sizeof(x86_exec_plt1)>(pParent)
41{
42}
43
44//===----------------------------------------------------------------------===//
45// X86PLT
46//===----------------------------------------------------------------------===//
47X86PLT::X86PLT(LDSection& pSection,
48               X86GOTPLT &pGOTPLT,
49               const LinkerConfig& pConfig)
50  : PLT(pSection),
51    m_GOTPLT(pGOTPLT),
52    m_Config(pConfig)
53{
54  assert(LinkerConfig::DynObj == m_Config.codeGenType() ||
55         LinkerConfig::Exec   == m_Config.codeGenType() ||
56         LinkerConfig::Binary == m_Config.codeGenType());
57
58  if (LinkerConfig::DynObj == m_Config.codeGenType()) {
59    m_PLT0 = x86_dyn_plt0;
60    m_PLT1 = x86_dyn_plt1;
61    m_PLT0Size = sizeof (x86_dyn_plt0);
62    m_PLT1Size = sizeof (x86_dyn_plt1);
63    // create PLT0
64    new X86DynPLT0(*m_SectionData);
65  }
66  else {
67    m_PLT0 = x86_exec_plt0;
68    m_PLT1 = x86_exec_plt1;
69    m_PLT0Size = sizeof (x86_exec_plt0);
70    m_PLT1Size = sizeof (x86_exec_plt1);
71    // create PLT0
72    new X86ExecPLT0(*m_SectionData);
73  }
74  m_Last = m_SectionData->begin();
75}
76
77X86PLT::~X86PLT()
78{
79}
80
81void X86PLT::finalizeSectionSize()
82{
83  uint64_t size = 0;
84  // plt0 size
85  size = getPLT0()->size();
86
87  // get first plt1 entry
88  X86PLT::iterator it = begin();
89  ++it;
90  if (end() != it) {
91    // plt1 size
92    PLTEntryBase* plt1 = &(llvm::cast<PLTEntryBase>(*it));
93    size += (m_SectionData->size() - 1) * plt1->size();
94  }
95  m_Section.setSize(size);
96
97  uint32_t offset = 0;
98  SectionData::iterator frag, fragEnd = m_SectionData->end();
99  for (frag = m_SectionData->begin(); frag != fragEnd; ++frag) {
100    frag->setOffset(offset);
101    offset += frag->size();
102  }
103}
104
105bool X86PLT::hasPLT1() const
106{
107  return (m_SectionData->size() > 1);
108}
109
110void X86PLT::reserveEntry(size_t pNum)
111{
112  PLTEntryBase* plt1_entry = NULL;
113
114  for (size_t i = 0; i < pNum; ++i) {
115
116    if (LinkerConfig::DynObj == m_Config.codeGenType())
117      plt1_entry = new X86DynPLT1(*m_SectionData);
118    else
119      plt1_entry = new X86ExecPLT1(*m_SectionData);
120
121    if (NULL == plt1_entry)
122      fatal(diag::fail_allocate_memory_plt);
123  }
124}
125
126PLTEntryBase* X86PLT::consume()
127{
128  // This will skip PLT0.
129  ++m_Last;
130  assert(m_Last != m_SectionData->end() &&
131         "The number of PLT Entries and ResolveInfo doesn't match");
132  return llvm::cast<PLTEntryBase>(&(*m_Last));
133}
134
135PLTEntryBase* X86PLT::getPLT0() const
136{
137  iterator first = m_SectionData->getFragmentList().begin();
138
139  assert(first != m_SectionData->getFragmentList().end() &&
140         "FragmentList is empty, getPLT0 failed!");
141
142  PLTEntryBase* plt0 = &(llvm::cast<PLTEntryBase>(*first));
143
144  return plt0;
145}
146
147// FIXME: It only works on little endian machine.
148void X86PLT::applyPLT0()
149{
150  PLTEntryBase* plt0 = getPLT0();
151
152  unsigned char* data = 0;
153  data = static_cast<unsigned char*>(malloc(plt0->size()));
154
155  if (!data)
156    fatal(diag::fail_allocate_memory_plt);
157
158  memcpy(data, m_PLT0, plt0->size());
159
160  if (m_PLT0 == x86_exec_plt0) {
161    uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2);
162    *offset = m_GOTPLT.addr() + 4;
163    offset = reinterpret_cast<uint32_t*>(data + 8);
164    *offset = m_GOTPLT.addr() + 8;
165  }
166
167  plt0->setValue(data);
168}
169
170// FIXME: It only works on little endian machine.
171void X86PLT::applyPLT1()
172{
173  assert(m_Section.addr() && ".plt base address is NULL!");
174
175  X86PLT::iterator it = m_SectionData->begin();
176  X86PLT::iterator ie = m_SectionData->end();
177  assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
178
179  uint64_t GOTEntrySize = X86GOTPLTEntry::EntrySize;
180
181  // Skip GOT0
182  uint64_t GOTEntryOffset = GOTEntrySize * X86GOTPLT0Num;
183  if (LinkerConfig::Exec == m_Config.codeGenType())
184    GOTEntryOffset += m_GOTPLT.addr();
185
186  //skip PLT0
187  uint64_t PLTEntryOffset = m_PLT0Size;
188  ++it;
189
190  PLTEntryBase* plt1 = 0;
191
192  uint64_t PLTRelOffset = 0;
193
194  while (it != ie) {
195    plt1 = &(llvm::cast<PLTEntryBase>(*it));
196    unsigned char *data;
197    data = static_cast<unsigned char*>(malloc(plt1->size()));
198
199    if (!data)
200      fatal(diag::fail_allocate_memory_plt);
201
202    memcpy(data, m_PLT1, plt1->size());
203
204    uint32_t* offset;
205
206    offset = reinterpret_cast<uint32_t*>(data + 2);
207    *offset = GOTEntryOffset;
208    GOTEntryOffset += GOTEntrySize;
209
210    offset = reinterpret_cast<uint32_t*>(data + 7);
211    *offset = PLTRelOffset;
212    PLTRelOffset += sizeof (llvm::ELF::Elf32_Rel);
213
214    offset = reinterpret_cast<uint32_t*>(data + 12);
215    *offset = -(PLTEntryOffset + 12 + 4);
216    PLTEntryOffset += m_PLT1Size;
217
218    plt1->setValue(data);
219    ++it;
220  }
221}
222
223