MipsPLT.cpp revision 37b74a387bb3993387029859c2d9d051c41c724e
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}  // anonymous namespace
36
37namespace mcld {
38
39//===----------------------------------------------------------------------===//
40// MipsPLT0 Entry
41//===----------------------------------------------------------------------===//
42class MipsPLT0 : public PLT::Entry<sizeof(PLT0)> {
43 public:
44  MipsPLT0(SectionData& pParent) : PLT::Entry<sizeof(PLT0)>(pParent) {}
45};
46
47//===----------------------------------------------------------------------===//
48// MipsPLTA Entry
49//===----------------------------------------------------------------------===//
50class MipsPLTA : public PLT::Entry<sizeof(PLTA)> {
51 public:
52  MipsPLTA(SectionData& pParent) : PLT::Entry<sizeof(PLTA)>(pParent) {}
53};
54
55//===----------------------------------------------------------------------===//
56// MipsPLT
57//===----------------------------------------------------------------------===//
58MipsPLT::MipsPLT(LDSection& pSection) : PLT(pSection) {
59  new MipsPLT0(*m_pSectionData);
60  m_Last = m_pSectionData->begin();
61}
62
63void MipsPLT::finalizeSectionSize() {
64  uint64_t size = sizeof(PLT0) + (m_pSectionData->size() - 1) * sizeof(PLTA);
65  m_Section.setSize(size);
66
67  uint32_t offset = 0;
68  SectionData::iterator frag, fragEnd = m_pSectionData->end();
69  for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
70    frag->setOffset(offset);
71    offset += frag->size();
72  }
73}
74
75bool MipsPLT::hasPLT1() const {
76  return m_pSectionData->size() > 1;
77}
78
79uint64_t MipsPLT::emit(MemoryRegion& pRegion) {
80  uint64_t result = 0x0;
81  iterator it = begin();
82
83  unsigned char* buffer = pRegion.begin();
84  memcpy(buffer, llvm::cast<MipsPLT0>((*it)).getValue(), MipsPLT0::EntrySize);
85  result += MipsPLT0::EntrySize;
86  ++it;
87
88  MipsPLTA* plta = 0;
89  for (iterator ie = end(); it != ie; ++it) {
90    plta = &(llvm::cast<MipsPLTA>(*it));
91    memcpy(buffer + result, plta->getValue(), MipsPLTA::EntrySize);
92    result += MipsPLTA::EntrySize;
93  }
94  return result;
95}
96
97void MipsPLT::reserveEntry(size_t pNum) {
98  for (size_t i = 0; i < pNum; ++i) {
99    Fragment* entry = new (std::nothrow) MipsPLTA(*m_pSectionData);
100
101    if (entry == NULL)
102      fatal(diag::fail_allocate_memory_plt);
103  }
104}
105
106Fragment* MipsPLT::consume() {
107  ++m_Last;
108  assert(m_Last != m_pSectionData->end() &&
109         "The number of PLT Entries and ResolveInfo doesn't match");
110  return &(*m_Last);
111}
112
113void MipsPLT::applyAllPLT(MipsGOTPLT& pGOTPLT) {
114  assert(m_Section.addr() && ".plt base address is NULL!");
115
116  size_t count = 0;
117  for (iterator it = m_pSectionData->begin(); it != m_pSectionData->end();
118       ++it) {
119    PLTEntryBase* plt = &(llvm::cast<PLTEntryBase>(*it));
120
121    if (it == m_pSectionData->begin()) {
122      uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
123
124      if (!data)
125        fatal(diag::fail_allocate_memory_plt);
126
127      memcpy(data, PLT0, plt->size());
128
129      uint64_t gotAddr = pGOTPLT.addr();
130
131      data[0] |= ((gotAddr + 0x8000) >> 16) & 0xffff;
132      data[1] |= gotAddr & 0xffff;
133      data[2] |= gotAddr & 0xffff;
134
135      plt->setValue(reinterpret_cast<unsigned char*>(data));
136    } else {
137      uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
138
139      if (!data)
140        fatal(diag::fail_allocate_memory_plt);
141
142      memcpy(data, PLTA, plt->size());
143
144      uint64_t gotEntryAddr = pGOTPLT.getEntryAddr(count++);
145
146      data[0] |= ((gotEntryAddr + 0x8000) >> 16) & 0xffff;
147      data[1] |= gotEntryAddr & 0xffff;
148      data[3] |= gotEntryAddr & 0xffff;
149
150      plt->setValue(reinterpret_cast<unsigned char*>(data));
151    }
152  }
153}
154
155}  // namespace mcld
156