MipsPLT.cpp revision 551ae4ebd3e9d137ea668fb83ae4a55b8cfba451
1//===- MipsPLT.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 <llvm/Support/Casting.h>
10#include <llvm/Support/ELF.h>
11#include <mcld/Support/MsgHandling.h>
12#include "MipsGOTPLT.h"
13#include "MipsPLT.h"
14
15namespace {
16
17const uint32_t PLT0[] = {
18  0x3c1c0000,         // lui $28, %hi(&GOTPLT[0])
19  0x8f990000,         // lw $25, %lo(&GOTPLT[0])($28)
20  0x279c0000,         // addiu $28, $28, %lo(&GOTPLT[0])
21  0x031cc023,         // subu $24, $24, $28
22  0x03e07821,         // move $15, $31
23  0x0018c082,         // srl $24, $24, 2
24  0x0320f809,         // jalr $25
25  0x2718fffe          // subu $24, $24, 2
26};
27
28const uint32_t PLTA[] = {
29  0x3c0f0000,         // lui $15, %hi(.got.plt entry)
30  0x8df90000,         // l[wd] $25, %lo(.got.plt entry)($15)
31  0x03200008,         // jr $25
32  0x25f80000          // addiu $24, $15, %lo(.got.plt entry)
33};
34
35}
36
37namespace mcld {
38
39//===----------------------------------------------------------------------===//
40// MipsPLT0 Entry
41//===----------------------------------------------------------------------===//
42class MipsPLT0 : public PLT::Entry<sizeof(PLT0)>
43{
44public:
45  MipsPLT0(SectionData& pParent)
46    : PLT::Entry<sizeof(PLT0)>(pParent)
47  {}
48};
49
50//===----------------------------------------------------------------------===//
51// MipsPLTA Entry
52//===----------------------------------------------------------------------===//
53class MipsPLTA : public PLT::Entry<sizeof(PLTA)>
54{
55public:
56  MipsPLTA(SectionData& pParent)
57    : PLT::Entry<sizeof(PLTA)>(pParent)
58  {}
59};
60
61//===----------------------------------------------------------------------===//
62// MipsPLT
63//===----------------------------------------------------------------------===//
64MipsPLT::MipsPLT(LDSection& pSection)
65  : PLT(pSection)
66{
67  new MipsPLT0(*m_pSectionData);
68  m_Last = m_pSectionData->begin();
69}
70
71void MipsPLT::finalizeSectionSize()
72{
73  uint64_t size = sizeof(PLT0) +
74                  (m_pSectionData->size() - 1) * sizeof(PLTA);
75  m_Section.setSize(size);
76
77  uint32_t offset = 0;
78  SectionData::iterator frag, fragEnd = m_pSectionData->end();
79  for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
80    frag->setOffset(offset);
81    offset += frag->size();
82  }
83}
84
85bool MipsPLT::hasPLT1() const
86{
87  return m_pSectionData->size() > 1;
88}
89
90uint64_t MipsPLT::emit(MemoryRegion& pRegion)
91{
92  uint64_t result = 0x0;
93  iterator it = begin();
94
95  unsigned char* buffer = pRegion.begin();
96  memcpy(buffer, llvm::cast<MipsPLT0>((*it)).getValue(), MipsPLT0::EntrySize);
97  result += MipsPLT0::EntrySize;
98  ++it;
99
100  MipsPLTA* plta = 0;
101  for (iterator ie = end(); it != ie; ++it) {
102    plta = &(llvm::cast<MipsPLTA>(*it));
103    memcpy(buffer + result, plta->getValue(), MipsPLTA::EntrySize);
104    result += MipsPLTA::EntrySize;
105  }
106  return result;
107}
108
109void MipsPLT::reserveEntry(size_t pNum)
110{
111  for (size_t i = 0; i < pNum; ++i) {
112    Fragment* entry = new (std::nothrow) MipsPLTA(*m_pSectionData);
113
114    if (NULL == entry)
115      fatal(diag::fail_allocate_memory_plt);
116  }
117}
118
119Fragment* MipsPLT::consume()
120{
121  ++m_Last;
122  assert(m_Last != m_pSectionData->end() &&
123         "The number of PLT Entries and ResolveInfo doesn't match");
124  return &(*m_Last);
125}
126
127void MipsPLT::applyAllPLT(MipsGOTPLT& pGOTPLT)
128{
129  assert(m_Section.addr() && ".plt base address is NULL!");
130
131  size_t count = 0;
132  for (iterator it = m_pSectionData->begin(); it != m_pSectionData->end(); ++it) {
133    PLTEntryBase* plt = &(llvm::cast<PLTEntryBase>(*it));
134
135    if (it == m_pSectionData->begin()) {
136      uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
137
138      if (!data)
139        fatal(diag::fail_allocate_memory_plt);
140
141      memcpy(data, PLT0, plt->size());
142
143      uint64_t gotAddr = pGOTPLT.addr();
144
145      data[0] |= ((gotAddr + 0x8000) >> 16) & 0xffff;
146      data[1] |= gotAddr & 0xffff;
147      data[2] |= gotAddr & 0xffff;
148
149      plt->setValue(reinterpret_cast<unsigned char*>(data));
150    } else {
151      uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
152
153      if (!data)
154        fatal(diag::fail_allocate_memory_plt);
155
156      memcpy(data, PLTA, plt->size());
157
158      uint64_t gotEntryAddr = pGOTPLT.getEntryAddr(count++);
159
160      data[0] |= ((gotEntryAddr + 0x8000) >> 16) & 0xffff;
161      data[1] |= gotEntryAddr & 0xffff;
162      data[3] |= gotEntryAddr & 0xffff;
163
164      plt->setValue(reinterpret_cast<unsigned char*>(data));
165    }
166  }
167}
168
169} //end mcld namespace
170