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