1 //===-- RuntimeDyldELFMips.cpp ---- ELF/Mips specific code. -----*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "RuntimeDyldELFMips.h"
10 #include "llvm/BinaryFormat/ELF.h"
11
12 #define DEBUG_TYPE "dyld"
13
resolveRelocation(const RelocationEntry & RE,uint64_t Value)14 void RuntimeDyldELFMips::resolveRelocation(const RelocationEntry &RE,
15 uint64_t Value) {
16 const SectionEntry &Section = Sections[RE.SectionID];
17 if (IsMipsO32ABI)
18 resolveMIPSO32Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend);
19 else if (IsMipsN32ABI) {
20 resolveMIPSN32Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
21 RE.SymOffset, RE.SectionID);
22 } else if (IsMipsN64ABI)
23 resolveMIPSN64Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
24 RE.SymOffset, RE.SectionID);
25 else
26 llvm_unreachable("Mips ABI not handled");
27 }
28
evaluateRelocation(const RelocationEntry & RE,uint64_t Value,uint64_t Addend)29 uint64_t RuntimeDyldELFMips::evaluateRelocation(const RelocationEntry &RE,
30 uint64_t Value,
31 uint64_t Addend) {
32 if (IsMipsN32ABI) {
33 const SectionEntry &Section = Sections[RE.SectionID];
34 Value = evaluateMIPS64Relocation(Section, RE.Offset, Value, RE.RelType,
35 Addend, RE.SymOffset, RE.SectionID);
36 return Value;
37 }
38 llvm_unreachable("Not reachable");
39 }
40
applyRelocation(const RelocationEntry & RE,uint64_t Value)41 void RuntimeDyldELFMips::applyRelocation(const RelocationEntry &RE,
42 uint64_t Value) {
43 if (IsMipsN32ABI) {
44 const SectionEntry &Section = Sections[RE.SectionID];
45 applyMIPSRelocation(Section.getAddressWithOffset(RE.Offset), Value,
46 RE.RelType);
47 return;
48 }
49 llvm_unreachable("Not reachable");
50 }
51
52 int64_t
evaluateMIPS32Relocation(const SectionEntry & Section,uint64_t Offset,uint64_t Value,uint32_t Type)53 RuntimeDyldELFMips::evaluateMIPS32Relocation(const SectionEntry &Section,
54 uint64_t Offset, uint64_t Value,
55 uint32_t Type) {
56
57 LLVM_DEBUG(dbgs() << "evaluateMIPS32Relocation, LocalAddress: 0x"
58 << format("%llx", Section.getAddressWithOffset(Offset))
59 << " FinalAddress: 0x"
60 << format("%llx", Section.getLoadAddressWithOffset(Offset))
61 << " Value: 0x" << format("%llx", Value) << " Type: 0x"
62 << format("%x", Type) << "\n");
63
64 switch (Type) {
65 default:
66 llvm_unreachable("Unknown relocation type!");
67 return Value;
68 case ELF::R_MIPS_32:
69 return Value;
70 case ELF::R_MIPS_26:
71 return Value >> 2;
72 case ELF::R_MIPS_HI16:
73 // Get the higher 16-bits. Also add 1 if bit 15 is 1.
74 return (Value + 0x8000) >> 16;
75 case ELF::R_MIPS_LO16:
76 return Value;
77 case ELF::R_MIPS_PC32: {
78 uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
79 return Value - FinalAddress;
80 }
81 case ELF::R_MIPS_PC16: {
82 uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
83 return (Value - FinalAddress) >> 2;
84 }
85 case ELF::R_MIPS_PC19_S2: {
86 uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
87 return (Value - (FinalAddress & ~0x3)) >> 2;
88 }
89 case ELF::R_MIPS_PC21_S2: {
90 uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
91 return (Value - FinalAddress) >> 2;
92 }
93 case ELF::R_MIPS_PC26_S2: {
94 uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
95 return (Value - FinalAddress) >> 2;
96 }
97 case ELF::R_MIPS_PCHI16: {
98 uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
99 return (Value - FinalAddress + 0x8000) >> 16;
100 }
101 case ELF::R_MIPS_PCLO16: {
102 uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
103 return Value - FinalAddress;
104 }
105 }
106 }
107
evaluateMIPS64Relocation(const SectionEntry & Section,uint64_t Offset,uint64_t Value,uint32_t Type,int64_t Addend,uint64_t SymOffset,SID SectionID)108 int64_t RuntimeDyldELFMips::evaluateMIPS64Relocation(
109 const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type,
110 int64_t Addend, uint64_t SymOffset, SID SectionID) {
111
112 LLVM_DEBUG(dbgs() << "evaluateMIPS64Relocation, LocalAddress: 0x"
113 << format("%llx", Section.getAddressWithOffset(Offset))
114 << " FinalAddress: 0x"
115 << format("%llx", Section.getLoadAddressWithOffset(Offset))
116 << " Value: 0x" << format("%llx", Value) << " Type: 0x"
117 << format("%x", Type) << " Addend: 0x"
118 << format("%llx", Addend)
119 << " Offset: " << format("%llx" PRIx64, Offset)
120 << " SID: " << format("%d", SectionID)
121 << " SymOffset: " << format("%x", SymOffset) << "\n");
122
123 switch (Type) {
124 default:
125 llvm_unreachable("Not implemented relocation type!");
126 break;
127 case ELF::R_MIPS_JALR:
128 case ELF::R_MIPS_NONE:
129 break;
130 case ELF::R_MIPS_32:
131 case ELF::R_MIPS_64:
132 return Value + Addend;
133 case ELF::R_MIPS_26:
134 return ((Value + Addend) >> 2) & 0x3ffffff;
135 case ELF::R_MIPS_GPREL16: {
136 uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]);
137 return Value + Addend - (GOTAddr + 0x7ff0);
138 }
139 case ELF::R_MIPS_SUB:
140 return Value - Addend;
141 case ELF::R_MIPS_HI16:
142 // Get the higher 16-bits. Also add 1 if bit 15 is 1.
143 return ((Value + Addend + 0x8000) >> 16) & 0xffff;
144 case ELF::R_MIPS_LO16:
145 return (Value + Addend) & 0xffff;
146 case ELF::R_MIPS_HIGHER:
147 return ((Value + Addend + 0x80008000) >> 32) & 0xffff;
148 case ELF::R_MIPS_HIGHEST:
149 return ((Value + Addend + 0x800080008000) >> 48) & 0xffff;
150 case ELF::R_MIPS_CALL16:
151 case ELF::R_MIPS_GOT_DISP:
152 case ELF::R_MIPS_GOT_PAGE: {
153 uint8_t *LocalGOTAddr =
154 getSectionAddress(SectionToGOTMap[SectionID]) + SymOffset;
155 uint64_t GOTEntry = readBytesUnaligned(LocalGOTAddr, getGOTEntrySize());
156
157 Value += Addend;
158 if (Type == ELF::R_MIPS_GOT_PAGE)
159 Value = (Value + 0x8000) & ~0xffff;
160
161 if (GOTEntry)
162 assert(GOTEntry == Value &&
163 "GOT entry has two different addresses.");
164 else
165 writeBytesUnaligned(Value, LocalGOTAddr, getGOTEntrySize());
166
167 return (SymOffset - 0x7ff0) & 0xffff;
168 }
169 case ELF::R_MIPS_GOT_OFST: {
170 int64_t page = (Value + Addend + 0x8000) & ~0xffff;
171 return (Value + Addend - page) & 0xffff;
172 }
173 case ELF::R_MIPS_GPREL32: {
174 uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]);
175 return Value + Addend - (GOTAddr + 0x7ff0);
176 }
177 case ELF::R_MIPS_PC16: {
178 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
179 return ((Value + Addend - FinalAddress) >> 2) & 0xffff;
180 }
181 case ELF::R_MIPS_PC32: {
182 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
183 return Value + Addend - FinalAddress;
184 }
185 case ELF::R_MIPS_PC18_S3: {
186 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
187 return ((Value + Addend - (FinalAddress & ~0x7)) >> 3) & 0x3ffff;
188 }
189 case ELF::R_MIPS_PC19_S2: {
190 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
191 return ((Value + Addend - (FinalAddress & ~0x3)) >> 2) & 0x7ffff;
192 }
193 case ELF::R_MIPS_PC21_S2: {
194 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
195 return ((Value + Addend - FinalAddress) >> 2) & 0x1fffff;
196 }
197 case ELF::R_MIPS_PC26_S2: {
198 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
199 return ((Value + Addend - FinalAddress) >> 2) & 0x3ffffff;
200 }
201 case ELF::R_MIPS_PCHI16: {
202 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
203 return ((Value + Addend - FinalAddress + 0x8000) >> 16) & 0xffff;
204 }
205 case ELF::R_MIPS_PCLO16: {
206 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
207 return (Value + Addend - FinalAddress) & 0xffff;
208 }
209 }
210 return 0;
211 }
212
applyMIPSRelocation(uint8_t * TargetPtr,int64_t Value,uint32_t Type)213 void RuntimeDyldELFMips::applyMIPSRelocation(uint8_t *TargetPtr, int64_t Value,
214 uint32_t Type) {
215 uint32_t Insn = readBytesUnaligned(TargetPtr, 4);
216
217 switch (Type) {
218 default:
219 llvm_unreachable("Unknown relocation type!");
220 break;
221 case ELF::R_MIPS_GPREL16:
222 case ELF::R_MIPS_HI16:
223 case ELF::R_MIPS_LO16:
224 case ELF::R_MIPS_HIGHER:
225 case ELF::R_MIPS_HIGHEST:
226 case ELF::R_MIPS_PC16:
227 case ELF::R_MIPS_PCHI16:
228 case ELF::R_MIPS_PCLO16:
229 case ELF::R_MIPS_CALL16:
230 case ELF::R_MIPS_GOT_DISP:
231 case ELF::R_MIPS_GOT_PAGE:
232 case ELF::R_MIPS_GOT_OFST:
233 Insn = (Insn & 0xffff0000) | (Value & 0x0000ffff);
234 writeBytesUnaligned(Insn, TargetPtr, 4);
235 break;
236 case ELF::R_MIPS_PC18_S3:
237 Insn = (Insn & 0xfffc0000) | (Value & 0x0003ffff);
238 writeBytesUnaligned(Insn, TargetPtr, 4);
239 break;
240 case ELF::R_MIPS_PC19_S2:
241 Insn = (Insn & 0xfff80000) | (Value & 0x0007ffff);
242 writeBytesUnaligned(Insn, TargetPtr, 4);
243 break;
244 case ELF::R_MIPS_PC21_S2:
245 Insn = (Insn & 0xffe00000) | (Value & 0x001fffff);
246 writeBytesUnaligned(Insn, TargetPtr, 4);
247 break;
248 case ELF::R_MIPS_26:
249 case ELF::R_MIPS_PC26_S2:
250 Insn = (Insn & 0xfc000000) | (Value & 0x03ffffff);
251 writeBytesUnaligned(Insn, TargetPtr, 4);
252 break;
253 case ELF::R_MIPS_32:
254 case ELF::R_MIPS_GPREL32:
255 case ELF::R_MIPS_PC32:
256 writeBytesUnaligned(Value & 0xffffffff, TargetPtr, 4);
257 break;
258 case ELF::R_MIPS_64:
259 case ELF::R_MIPS_SUB:
260 writeBytesUnaligned(Value, TargetPtr, 8);
261 break;
262 }
263 }
264
resolveMIPSN32Relocation(const SectionEntry & Section,uint64_t Offset,uint64_t Value,uint32_t Type,int64_t Addend,uint64_t SymOffset,SID SectionID)265 void RuntimeDyldELFMips::resolveMIPSN32Relocation(
266 const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type,
267 int64_t Addend, uint64_t SymOffset, SID SectionID) {
268 int64_t CalculatedValue = evaluateMIPS64Relocation(
269 Section, Offset, Value, Type, Addend, SymOffset, SectionID);
270 applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue,
271 Type);
272 }
273
resolveMIPSN64Relocation(const SectionEntry & Section,uint64_t Offset,uint64_t Value,uint32_t Type,int64_t Addend,uint64_t SymOffset,SID SectionID)274 void RuntimeDyldELFMips::resolveMIPSN64Relocation(
275 const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type,
276 int64_t Addend, uint64_t SymOffset, SID SectionID) {
277 uint32_t r_type = Type & 0xff;
278 uint32_t r_type2 = (Type >> 8) & 0xff;
279 uint32_t r_type3 = (Type >> 16) & 0xff;
280
281 // RelType is used to keep information for which relocation type we are
282 // applying relocation.
283 uint32_t RelType = r_type;
284 int64_t CalculatedValue = evaluateMIPS64Relocation(Section, Offset, Value,
285 RelType, Addend,
286 SymOffset, SectionID);
287 if (r_type2 != ELF::R_MIPS_NONE) {
288 RelType = r_type2;
289 CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType,
290 CalculatedValue, SymOffset,
291 SectionID);
292 }
293 if (r_type3 != ELF::R_MIPS_NONE) {
294 RelType = r_type3;
295 CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType,
296 CalculatedValue, SymOffset,
297 SectionID);
298 }
299 applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue,
300 RelType);
301 }
302
resolveMIPSO32Relocation(const SectionEntry & Section,uint64_t Offset,uint32_t Value,uint32_t Type,int32_t Addend)303 void RuntimeDyldELFMips::resolveMIPSO32Relocation(const SectionEntry &Section,
304 uint64_t Offset,
305 uint32_t Value, uint32_t Type,
306 int32_t Addend) {
307 uint8_t *TargetPtr = Section.getAddressWithOffset(Offset);
308 Value += Addend;
309
310 LLVM_DEBUG(dbgs() << "resolveMIPSO32Relocation, LocalAddress: "
311 << Section.getAddressWithOffset(Offset) << " FinalAddress: "
312 << format("%p", Section.getLoadAddressWithOffset(Offset))
313 << " Value: " << format("%x", Value) << " Type: "
314 << format("%x", Type) << " Addend: " << format("%x", Addend)
315 << " SymOffset: " << format("%x", Offset) << "\n");
316
317 Value = evaluateMIPS32Relocation(Section, Offset, Value, Type);
318
319 applyMIPSRelocation(TargetPtr, Value, Type);
320 }
321