blob: c0a02f6bb5724b35c7d5b0dfd6e47d1cf5cbc765 [file] [log] [blame]
Stephen Hines87f34652014-02-14 18:00:16 -08001//===- 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>
Stephen Hines37b74a32014-11-26 18:48:20 -080011#include "mcld/Support/MsgHandling.h"
Stephen Hines87f34652014-02-14 18:00:16 -080012#include "MipsGOTPLT.h"
13#include "MipsPLT.h"
14
15namespace {
16
17const uint32_t PLT0[] = {
Stephen Hines37b74a32014-11-26 18:48:20 -080018 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
Stephen Hines87f34652014-02-14 18:00:16 -080026};
27
28const uint32_t PLTA[] = {
Stephen Hines37b74a32014-11-26 18:48:20 -080029 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)
Stephen Hines87f34652014-02-14 18:00:16 -080033};
34
Stephen Hines37b74a32014-11-26 18:48:20 -080035} // anonymous namespace
Stephen Hines87f34652014-02-14 18:00:16 -080036
37namespace mcld {
38
39//===----------------------------------------------------------------------===//
40// MipsPLT0 Entry
41//===----------------------------------------------------------------------===//
Stephen Hines37b74a32014-11-26 18:48:20 -080042class MipsPLT0 : public PLT::Entry<sizeof(PLT0)> {
43 public:
44 MipsPLT0(SectionData& pParent) : PLT::Entry<sizeof(PLT0)>(pParent) {}
Stephen Hines87f34652014-02-14 18:00:16 -080045};
46
47//===----------------------------------------------------------------------===//
48// MipsPLTA Entry
49//===----------------------------------------------------------------------===//
Stephen Hines37b74a32014-11-26 18:48:20 -080050class MipsPLTA : public PLT::Entry<sizeof(PLTA)> {
51 public:
52 MipsPLTA(SectionData& pParent) : PLT::Entry<sizeof(PLTA)>(pParent) {}
Stephen Hines87f34652014-02-14 18:00:16 -080053};
54
55//===----------------------------------------------------------------------===//
56// MipsPLT
57//===----------------------------------------------------------------------===//
Stephen Hines37b74a32014-11-26 18:48:20 -080058MipsPLT::MipsPLT(LDSection& pSection) : PLT(pSection) {
Stephen Hines551ae4e2014-04-24 14:41:24 -070059 new MipsPLT0(*m_pSectionData);
Stephen Hines87f34652014-02-14 18:00:16 -080060}
61
Stephen Hines37b74a32014-11-26 18:48:20 -080062void MipsPLT::finalizeSectionSize() {
63 uint64_t size = sizeof(PLT0) + (m_pSectionData->size() - 1) * sizeof(PLTA);
Stephen Hines87f34652014-02-14 18:00:16 -080064 m_Section.setSize(size);
65
66 uint32_t offset = 0;
Stephen Hines551ae4e2014-04-24 14:41:24 -070067 SectionData::iterator frag, fragEnd = m_pSectionData->end();
68 for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
Stephen Hines87f34652014-02-14 18:00:16 -080069 frag->setOffset(offset);
70 offset += frag->size();
71 }
72}
73
Stephen Hines37b74a32014-11-26 18:48:20 -080074bool MipsPLT::hasPLT1() const {
Stephen Hines551ae4e2014-04-24 14:41:24 -070075 return m_pSectionData->size() > 1;
Stephen Hines87f34652014-02-14 18:00:16 -080076}
77
Stephen Hines37b74a32014-11-26 18:48:20 -080078uint64_t MipsPLT::emit(MemoryRegion& pRegion) {
Stephen Hines87f34652014-02-14 18:00:16 -080079 uint64_t result = 0x0;
80 iterator it = begin();
81
82 unsigned char* buffer = pRegion.begin();
83 memcpy(buffer, llvm::cast<MipsPLT0>((*it)).getValue(), MipsPLT0::EntrySize);
84 result += MipsPLT0::EntrySize;
85 ++it;
86
87 MipsPLTA* plta = 0;
88 for (iterator ie = end(); it != ie; ++it) {
89 plta = &(llvm::cast<MipsPLTA>(*it));
90 memcpy(buffer + result, plta->getValue(), MipsPLTA::EntrySize);
91 result += MipsPLTA::EntrySize;
92 }
93 return result;
94}
95
Stephen Hinescfcb2242016-03-08 00:18:09 -080096PLTEntryBase* MipsPLT::create() {
97 return new MipsPLTA(*m_pSectionData);
Stephen Hines87f34652014-02-14 18:00:16 -080098}
99
Stephen Hines37b74a32014-11-26 18:48:20 -0800100void MipsPLT::applyAllPLT(MipsGOTPLT& pGOTPLT) {
Stephen Hines87f34652014-02-14 18:00:16 -0800101 assert(m_Section.addr() && ".plt base address is NULL!");
102
103 size_t count = 0;
Stephen Hines37b74a32014-11-26 18:48:20 -0800104 for (iterator it = m_pSectionData->begin(); it != m_pSectionData->end();
105 ++it) {
Stephen Hines87f34652014-02-14 18:00:16 -0800106 PLTEntryBase* plt = &(llvm::cast<PLTEntryBase>(*it));
107
Stephen Hines551ae4e2014-04-24 14:41:24 -0700108 if (it == m_pSectionData->begin()) {
Stephen Hines87f34652014-02-14 18:00:16 -0800109 uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
110
111 if (!data)
112 fatal(diag::fail_allocate_memory_plt);
113
114 memcpy(data, PLT0, plt->size());
115
116 uint64_t gotAddr = pGOTPLT.addr();
117
118 data[0] |= ((gotAddr + 0x8000) >> 16) & 0xffff;
119 data[1] |= gotAddr & 0xffff;
120 data[2] |= gotAddr & 0xffff;
121
122 plt->setValue(reinterpret_cast<unsigned char*>(data));
123 } else {
124 uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
125
126 if (!data)
127 fatal(diag::fail_allocate_memory_plt);
128
129 memcpy(data, PLTA, plt->size());
130
131 uint64_t gotEntryAddr = pGOTPLT.getEntryAddr(count++);
132
133 data[0] |= ((gotEntryAddr + 0x8000) >> 16) & 0xffff;
134 data[1] |= gotEntryAddr & 0xffff;
135 data[3] |= gotEntryAddr & 0xffff;
136
137 plt->setValue(reinterpret_cast<unsigned char*>(data));
138 }
139 }
140}
141
Stephen Hines37b74a32014-11-26 18:48:20 -0800142} // namespace mcld