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
15 namespace {
16
17 const 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
28 const 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
37 namespace mcld {
38
39 //===----------------------------------------------------------------------===//
40 // MipsPLT0 Entry
41 //===----------------------------------------------------------------------===//
42 class MipsPLT0 : public PLT::Entry<sizeof(PLT0)>
43 {
44 public:
MipsPLT0(SectionData & pParent)45 MipsPLT0(SectionData& pParent)
46 : PLT::Entry<sizeof(PLT0)>(pParent)
47 {}
48 };
49
50 //===----------------------------------------------------------------------===//
51 // MipsPLTA Entry
52 //===----------------------------------------------------------------------===//
53 class MipsPLTA : public PLT::Entry<sizeof(PLTA)>
54 {
55 public:
MipsPLTA(SectionData & pParent)56 MipsPLTA(SectionData& pParent)
57 : PLT::Entry<sizeof(PLTA)>(pParent)
58 {}
59 };
60
61 //===----------------------------------------------------------------------===//
62 // MipsPLT
63 //===----------------------------------------------------------------------===//
MipsPLT(LDSection & pSection)64 MipsPLT::MipsPLT(LDSection& pSection)
65 : PLT(pSection)
66 {
67 new MipsPLT0(*m_pSectionData);
68 m_Last = m_pSectionData->begin();
69 }
70
finalizeSectionSize()71 void 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
hasPLT1() const85 bool MipsPLT::hasPLT1() const
86 {
87 return m_pSectionData->size() > 1;
88 }
89
emit(MemoryRegion & pRegion)90 uint64_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
reserveEntry(size_t pNum)109 void 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
consume()119 Fragment* 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
applyAllPLT(MipsGOTPLT & pGOTPLT)127 void 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