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 | |
14 | void RuntimeDyldELFMips::resolveRelocation(const RelocationEntry &RE, |
15 | uint64_t Value) { |
16 | const SectionEntry &Section = Sections[RE.SectionID]; |
17 | if (IsMipsO32ABI) |
18 | resolveMIPSO32Relocation(Section, Offset: RE.Offset, Value, Type: RE.RelType, Addend: RE.Addend); |
19 | else if (IsMipsN32ABI) { |
20 | resolveMIPSN32Relocation(Section, Offset: RE.Offset, Value, Type: RE.RelType, Addend: RE.Addend, |
21 | SymOffset: RE.SymOffset, SectionID: RE.SectionID); |
22 | } else if (IsMipsN64ABI) |
23 | resolveMIPSN64Relocation(Section, Offset: RE.Offset, Value, Type: RE.RelType, Addend: RE.Addend, |
24 | SymOffset: RE.SymOffset, SectionID: RE.SectionID); |
25 | else |
26 | llvm_unreachable("Mips ABI not handled" ); |
27 | } |
28 | |
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, Offset: RE.Offset, Value, Type: RE.RelType, |
35 | Addend, SymOffset: RE.SymOffset, SectionID: RE.SectionID); |
36 | return Value; |
37 | } |
38 | llvm_unreachable("Not reachable" ); |
39 | } |
40 | |
41 | void RuntimeDyldELFMips::applyRelocation(const RelocationEntry &RE, |
42 | uint64_t Value) { |
43 | if (IsMipsN32ABI) { |
44 | const SectionEntry &Section = Sections[RE.SectionID]; |
45 | applyMIPSRelocation(TargetPtr: Section.getAddressWithOffset(OffsetBytes: RE.Offset), CalculatedValue: Value, |
46 | Type: RE.RelType); |
47 | return; |
48 | } |
49 | llvm_unreachable("Not reachable" ); |
50 | } |
51 | |
52 | int64_t |
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(OffsetBytes: Offset); |
79 | return Value - FinalAddress; |
80 | } |
81 | case ELF::R_MIPS_PC16: { |
82 | uint32_t FinalAddress = Section.getLoadAddressWithOffset(OffsetBytes: Offset); |
83 | return (Value - FinalAddress) >> 2; |
84 | } |
85 | case ELF::R_MIPS_PC19_S2: { |
86 | uint32_t FinalAddress = Section.getLoadAddressWithOffset(OffsetBytes: Offset); |
87 | return (Value - (FinalAddress & ~0x3)) >> 2; |
88 | } |
89 | case ELF::R_MIPS_PC21_S2: { |
90 | uint32_t FinalAddress = Section.getLoadAddressWithOffset(OffsetBytes: Offset); |
91 | return (Value - FinalAddress) >> 2; |
92 | } |
93 | case ELF::R_MIPS_PC26_S2: { |
94 | uint32_t FinalAddress = Section.getLoadAddressWithOffset(OffsetBytes: Offset); |
95 | return (Value - FinalAddress) >> 2; |
96 | } |
97 | case ELF::R_MIPS_PCHI16: { |
98 | uint32_t FinalAddress = Section.getLoadAddressWithOffset(OffsetBytes: Offset); |
99 | return (Value - FinalAddress + 0x8000) >> 16; |
100 | } |
101 | case ELF::R_MIPS_PCLO16: { |
102 | uint32_t FinalAddress = Section.getLoadAddressWithOffset(OffsetBytes: Offset); |
103 | return Value - FinalAddress; |
104 | } |
105 | } |
106 | } |
107 | |
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(SectionID: 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(SectionID: SectionToGOTMap[SectionID]) + SymOffset; |
155 | uint64_t GOTEntry = readBytesUnaligned(Src: LocalGOTAddr, Size: 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, Dst: LocalGOTAddr, Size: 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(SectionID: SectionToGOTMap[SectionID]); |
175 | return Value + Addend - (GOTAddr + 0x7ff0); |
176 | } |
177 | case ELF::R_MIPS_PC16: { |
178 | uint64_t FinalAddress = Section.getLoadAddressWithOffset(OffsetBytes: Offset); |
179 | return ((Value + Addend - FinalAddress) >> 2) & 0xffff; |
180 | } |
181 | case ELF::R_MIPS_PC32: { |
182 | uint64_t FinalAddress = Section.getLoadAddressWithOffset(OffsetBytes: Offset); |
183 | return Value + Addend - FinalAddress; |
184 | } |
185 | case ELF::R_MIPS_PC18_S3: { |
186 | uint64_t FinalAddress = Section.getLoadAddressWithOffset(OffsetBytes: Offset); |
187 | return ((Value + Addend - (FinalAddress & ~0x7)) >> 3) & 0x3ffff; |
188 | } |
189 | case ELF::R_MIPS_PC19_S2: { |
190 | uint64_t FinalAddress = Section.getLoadAddressWithOffset(OffsetBytes: Offset); |
191 | return ((Value + Addend - (FinalAddress & ~0x3)) >> 2) & 0x7ffff; |
192 | } |
193 | case ELF::R_MIPS_PC21_S2: { |
194 | uint64_t FinalAddress = Section.getLoadAddressWithOffset(OffsetBytes: Offset); |
195 | return ((Value + Addend - FinalAddress) >> 2) & 0x1fffff; |
196 | } |
197 | case ELF::R_MIPS_PC26_S2: { |
198 | uint64_t FinalAddress = Section.getLoadAddressWithOffset(OffsetBytes: Offset); |
199 | return ((Value + Addend - FinalAddress) >> 2) & 0x3ffffff; |
200 | } |
201 | case ELF::R_MIPS_PCHI16: { |
202 | uint64_t FinalAddress = Section.getLoadAddressWithOffset(OffsetBytes: Offset); |
203 | return ((Value + Addend - FinalAddress + 0x8000) >> 16) & 0xffff; |
204 | } |
205 | case ELF::R_MIPS_PCLO16: { |
206 | uint64_t FinalAddress = Section.getLoadAddressWithOffset(OffsetBytes: Offset); |
207 | return (Value + Addend - FinalAddress) & 0xffff; |
208 | } |
209 | } |
210 | return 0; |
211 | } |
212 | |
213 | void RuntimeDyldELFMips::applyMIPSRelocation(uint8_t *TargetPtr, int64_t Value, |
214 | uint32_t Type) { |
215 | uint32_t Insn = readBytesUnaligned(Src: TargetPtr, Size: 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(Value: Insn, Dst: TargetPtr, Size: 4); |
235 | break; |
236 | case ELF::R_MIPS_PC18_S3: |
237 | Insn = (Insn & 0xfffc0000) | (Value & 0x0003ffff); |
238 | writeBytesUnaligned(Value: Insn, Dst: TargetPtr, Size: 4); |
239 | break; |
240 | case ELF::R_MIPS_PC19_S2: |
241 | Insn = (Insn & 0xfff80000) | (Value & 0x0007ffff); |
242 | writeBytesUnaligned(Value: Insn, Dst: TargetPtr, Size: 4); |
243 | break; |
244 | case ELF::R_MIPS_PC21_S2: |
245 | Insn = (Insn & 0xffe00000) | (Value & 0x001fffff); |
246 | writeBytesUnaligned(Value: Insn, Dst: TargetPtr, Size: 4); |
247 | break; |
248 | case ELF::R_MIPS_26: |
249 | case ELF::R_MIPS_PC26_S2: |
250 | Insn = (Insn & 0xfc000000) | (Value & 0x03ffffff); |
251 | writeBytesUnaligned(Value: Insn, Dst: TargetPtr, Size: 4); |
252 | break; |
253 | case ELF::R_MIPS_32: |
254 | case ELF::R_MIPS_GPREL32: |
255 | case ELF::R_MIPS_PC32: |
256 | writeBytesUnaligned(Value: Value & 0xffffffff, Dst: TargetPtr, Size: 4); |
257 | break; |
258 | case ELF::R_MIPS_64: |
259 | case ELF::R_MIPS_SUB: |
260 | writeBytesUnaligned(Value, Dst: TargetPtr, Size: 8); |
261 | break; |
262 | } |
263 | } |
264 | |
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(TargetPtr: Section.getAddressWithOffset(OffsetBytes: Offset), Value: CalculatedValue, |
271 | Type); |
272 | } |
273 | |
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 | Type: RelType, Addend, |
286 | SymOffset, SectionID); |
287 | if (r_type2 != ELF::R_MIPS_NONE) { |
288 | RelType = r_type2; |
289 | CalculatedValue = evaluateMIPS64Relocation(Section, Offset, Value: 0, Type: RelType, |
290 | Addend: CalculatedValue, SymOffset, |
291 | SectionID); |
292 | } |
293 | if (r_type3 != ELF::R_MIPS_NONE) { |
294 | RelType = r_type3; |
295 | CalculatedValue = evaluateMIPS64Relocation(Section, Offset, Value: 0, Type: RelType, |
296 | Addend: CalculatedValue, SymOffset, |
297 | SectionID); |
298 | } |
299 | applyMIPSRelocation(TargetPtr: Section.getAddressWithOffset(OffsetBytes: Offset), Value: CalculatedValue, |
300 | Type: RelType); |
301 | } |
302 | |
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(OffsetBytes: 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 | |