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