ARMPLT.cpp revision d0fbbb227051be16931a1aa9b4a7722ac039c698
1//===- ARMPLT.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 "ARMGOT.h"
10#include "ARMPLT.h"
11
12#include <new>
13
14#include <llvm/Support/Casting.h>
15
16#include <mcld/LD/LDSection.h>
17#include <mcld/Support/MemoryRegion.h>
18#include <mcld/Support/MsgHandling.h>
19
20using namespace mcld;
21
22ARMPLT0::ARMPLT0(SectionData& pParent)
23  : PLT::Entry<sizeof(arm_plt0)>(pParent) {}
24
25ARMPLT1::ARMPLT1(SectionData& pParent)
26  : PLT::Entry<sizeof(arm_plt1)>(pParent) {}
27
28//===----------------------------------------------------------------------===//
29// ARMPLT
30
31ARMPLT::ARMPLT(LDSection& pSection,
32               ARMGOT &pGOTPLT)
33  : PLT(pSection), m_GOT(pGOTPLT), m_PLTEntryIterator() {
34  new ARMPLT0(*m_SectionData);
35  m_PLTEntryIterator = m_SectionData->begin();
36}
37
38ARMPLT::~ARMPLT()
39{
40}
41
42bool ARMPLT::hasPLT1() const
43{
44  return (m_SectionData->size() > 1);
45}
46
47void ARMPLT::finalizeSectionSize()
48{
49  uint64_t size = (m_SectionData->size() - 1) * sizeof(arm_plt1) +
50                     sizeof(arm_plt0);
51  m_Section.setSize(size);
52
53  uint32_t offset = 0;
54  SectionData::iterator frag, fragEnd = m_SectionData->end();
55  for (frag = m_SectionData->begin(); frag != fragEnd; ++frag) {
56    frag->setOffset(offset);
57    offset += frag->size();
58  }
59}
60
61void ARMPLT::reserveEntry(size_t pNum)
62{
63  ARMPLT1* plt1_entry = 0;
64
65  for (size_t i = 0; i < pNum; ++i) {
66    plt1_entry = new (std::nothrow) ARMPLT1(*m_SectionData);
67
68    if (!plt1_entry)
69      fatal(diag::fail_allocate_memory_plt);
70
71    m_GOT.reserveGOTPLT();
72  }
73}
74
75ARMPLT1* ARMPLT::consume()
76{
77  ++m_PLTEntryIterator;
78  assert(m_PLTEntryIterator != m_SectionData->end() &&
79         "The number of PLT Entries and ResolveInfo doesn't match");
80
81  return llvm::cast<ARMPLT1>(&(*m_PLTEntryIterator));
82}
83
84ARMPLT0* ARMPLT::getPLT0() const {
85
86  iterator first = m_SectionData->getFragmentList().begin();
87
88  assert(first != m_SectionData->getFragmentList().end() &&
89         "FragmentList is empty, getPLT0 failed!");
90
91  ARMPLT0* plt0 = &(llvm::cast<ARMPLT0>(*first));
92
93  return plt0;
94}
95
96void ARMPLT::applyPLT0() {
97
98  uint64_t plt_base = m_Section.addr();
99  assert(plt_base && ".plt base address is NULL!");
100
101  uint64_t got_base = m_GOT.addr();
102  assert(got_base && ".got base address is NULL!");
103
104  uint32_t offset = 0;
105
106  if (got_base > plt_base)
107    offset = got_base - (plt_base + 16);
108  else
109    offset = (plt_base + 16) - got_base;
110
111  iterator first = m_SectionData->getFragmentList().begin();
112
113  assert(first != m_SectionData->getFragmentList().end() &&
114         "FragmentList is empty, applyPLT0 failed!");
115
116  ARMPLT0* plt0 = &(llvm::cast<ARMPLT0>(*first));
117
118  uint32_t* data = 0;
119  data = static_cast<uint32_t*>(malloc(ARMPLT0::EntrySize));
120
121  if (!data)
122    fatal(diag::fail_allocate_memory_plt);
123
124  memcpy(data, arm_plt0, ARMPLT0::EntrySize);
125  data[4] = offset;
126
127  plt0->setValue(reinterpret_cast<unsigned char*>(data));
128}
129
130void ARMPLT::applyPLT1() {
131
132  uint64_t plt_base = m_Section.addr();
133  assert(plt_base && ".plt base address is NULL!");
134
135  uint64_t got_base = m_GOT.addr();
136  assert(got_base && ".got base address is NULL!");
137
138  ARMPLT::iterator it = m_SectionData->begin();
139  ARMPLT::iterator ie = m_SectionData->end();
140  assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
141
142  uint32_t GOTEntrySize = ARMGOTEntry::EntrySize;
143  uint32_t GOTEntryAddress =
144    got_base +  GOTEntrySize * 3;
145
146  uint64_t PLTEntryAddress =
147    plt_base + ARMPLT0::EntrySize; //Offset of PLT0
148
149  ++it; //skip PLT0
150  uint64_t PLT1EntrySize = ARMPLT1::EntrySize;
151  ARMPLT1* plt1 = NULL;
152
153  uint32_t* Out = NULL;
154  while (it != ie) {
155    plt1 = &(llvm::cast<ARMPLT1>(*it));
156    Out = static_cast<uint32_t*>(malloc(ARMPLT1::EntrySize));
157
158    if (!Out)
159      fatal(diag::fail_allocate_memory_plt);
160
161    // Offset is the distance between the last PLT entry and the associated
162    // GOT entry.
163    int32_t Offset = (GOTEntryAddress - (PLTEntryAddress + 8));
164
165    Out[0] = arm_plt1[0] | ((Offset >> 20) & 0xFF);
166    Out[1] = arm_plt1[1] | ((Offset >> 12) & 0xFF);
167    Out[2] = arm_plt1[2] | (Offset & 0xFFF);
168
169    plt1->setValue(reinterpret_cast<unsigned char*>(Out));
170    ++it;
171
172    GOTEntryAddress += GOTEntrySize;
173    PLTEntryAddress += PLT1EntrySize;
174  }
175
176  m_GOT.applyGOTPLT(plt_base);
177}
178
179uint64_t ARMPLT::emit(MemoryRegion& pRegion)
180{
181  uint64_t result = 0x0;
182  iterator it = begin();
183
184  unsigned char* buffer = pRegion.getBuffer();
185  memcpy(buffer, llvm::cast<ARMPLT0>((*it)).getValue(), ARMPLT0::EntrySize);
186  result += ARMPLT0::EntrySize;
187  ++it;
188
189  ARMPLT1* plt1 = 0;
190  ARMPLT::iterator ie = end();
191  while (it != ie) {
192    plt1 = &(llvm::cast<ARMPLT1>(*it));
193    memcpy(buffer + result, plt1->getValue(), ARMPLT1::EntrySize);
194    result += ARMPLT1::EntrySize;
195    ++it;
196  }
197  return result;
198}
199
200