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
resolveRelocation(const RelocationEntry & RE,uint64_t Value)15 void RuntimeDyldELFMips::resolveRelocation(const RelocationEntry &RE,
16 uint64_t Value) {
17 const SectionEntry &Section = Sections[RE.SectionID];
18 if (IsMipsO32ABI)
19 resolveMIPSO32Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend);
20 else if (IsMipsN32ABI) {
21 resolveMIPSN32Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
22 RE.SymOffset, RE.SectionID);
23 } else if (IsMipsN64ABI)
24 resolveMIPSN64Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
25 RE.SymOffset, RE.SectionID);
26 else
27 llvm_unreachable("Mips ABI not handled");
28 }
29
evaluateRelocation(const RelocationEntry & RE,uint64_t Value,uint64_t Addend)30 uint64_t RuntimeDyldELFMips::evaluateRelocation(const RelocationEntry &RE,
31 uint64_t Value,
32 uint64_t Addend) {
33 if (IsMipsN32ABI) {
34 const SectionEntry &Section = Sections[RE.SectionID];
35 Value = evaluateMIPS64Relocation(Section, RE.Offset, Value, RE.RelType,
36 Addend, RE.SymOffset, RE.SectionID);
37 return Value;
38 }
39 llvm_unreachable("Not reachable");
40 }
41
applyRelocation(const RelocationEntry & RE,uint64_t Value)42 void RuntimeDyldELFMips::applyRelocation(const RelocationEntry &RE,
43 uint64_t Value) {
44 if (IsMipsN32ABI) {
45 const SectionEntry &Section = Sections[RE.SectionID];
46 applyMIPSRelocation(Section.getAddressWithOffset(RE.Offset), Value,
47 RE.RelType);
48 return;
49 }
50 llvm_unreachable("Not reachable");
51 }
52
53 int64_t
evaluateMIPS32Relocation(const SectionEntry & Section,uint64_t Offset,uint64_t Value,uint32_t Type)54 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 switch (Type) {
66 default:
67 llvm_unreachable("Unknown relocation type!");
68 return Value;
69 case ELF::R_MIPS_32:
70 return Value;
71 case ELF::R_MIPS_26:
72 return Value >> 2;
73 case ELF::R_MIPS_HI16:
74 // Get the higher 16-bits. Also add 1 if bit 15 is 1.
75 return (Value + 0x8000) >> 16;
76 case ELF::R_MIPS_LO16:
77 return Value;
78 case ELF::R_MIPS_PC32: {
79 uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
80 return Value - FinalAddress;
81 }
82 case ELF::R_MIPS_PC16: {
83 uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
84 return (Value - FinalAddress) >> 2;
85 }
86 case ELF::R_MIPS_PC19_S2: {
87 uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
88 return (Value - (FinalAddress & ~0x3)) >> 2;
89 }
90 case ELF::R_MIPS_PC21_S2: {
91 uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
92 return (Value - FinalAddress) >> 2;
93 }
94 case ELF::R_MIPS_PC26_S2: {
95 uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
96 return (Value - FinalAddress) >> 2;
97 }
98 case ELF::R_MIPS_PCHI16: {
99 uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
100 return (Value - FinalAddress + 0x8000) >> 16;
101 }
102 case ELF::R_MIPS_PCLO16: {
103 uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
104 return Value - FinalAddress;
105 }
106 }
107 }
108
evaluateMIPS64Relocation(const SectionEntry & Section,uint64_t Offset,uint64_t Value,uint32_t Type,int64_t Addend,uint64_t SymOffset,SID SectionID)109 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 switch (Type) {
125 default:
126 llvm_unreachable("Not implemented relocation type!");
127 break;
128 case ELF::R_MIPS_JALR:
129 case ELF::R_MIPS_NONE:
130 break;
131 case ELF::R_MIPS_32:
132 case ELF::R_MIPS_64:
133 return Value + Addend;
134 case ELF::R_MIPS_26:
135 return ((Value + Addend) >> 2) & 0x3ffffff;
136 case ELF::R_MIPS_GPREL16: {
137 uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]);
138 return Value + Addend - (GOTAddr + 0x7ff0);
139 }
140 case ELF::R_MIPS_SUB:
141 return Value - Addend;
142 case ELF::R_MIPS_HI16:
143 // Get the higher 16-bits. Also add 1 if bit 15 is 1.
144 return ((Value + Addend + 0x8000) >> 16) & 0xffff;
145 case ELF::R_MIPS_LO16:
146 return (Value + Addend) & 0xffff;
147 case ELF::R_MIPS_HIGHER:
148 return ((Value + Addend + 0x80008000) >> 32) & 0xffff;
149 case ELF::R_MIPS_HIGHEST:
150 return ((Value + Addend + 0x800080008000) >> 48) & 0xffff;
151 case ELF::R_MIPS_CALL16:
152 case ELF::R_MIPS_GOT_DISP:
153 case ELF::R_MIPS_GOT_PAGE: {
154 uint8_t *LocalGOTAddr =
155 getSectionAddress(SectionToGOTMap[SectionID]) + SymOffset;
156 uint64_t GOTEntry = readBytesUnaligned(LocalGOTAddr, getGOTEntrySize());
157
158 Value += Addend;
159 if (Type == ELF::R_MIPS_GOT_PAGE)
160 Value = (Value + 0x8000) & ~0xffff;
161
162 if (GOTEntry)
163 assert(GOTEntry == Value &&
164 "GOT entry has two different addresses.");
165 else
166 writeBytesUnaligned(Value, LocalGOTAddr, getGOTEntrySize());
167
168 return (SymOffset - 0x7ff0) & 0xffff;
169 }
170 case ELF::R_MIPS_GOT_OFST: {
171 int64_t page = (Value + Addend + 0x8000) & ~0xffff;
172 return (Value + Addend - page) & 0xffff;
173 }
174 case ELF::R_MIPS_GPREL32: {
175 uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]);
176 return Value + Addend - (GOTAddr + 0x7ff0);
177 }
178 case ELF::R_MIPS_PC16: {
179 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
180 return ((Value + Addend - FinalAddress) >> 2) & 0xffff;
181 }
182 case ELF::R_MIPS_PC32: {
183 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
184 return Value + Addend - FinalAddress;
185 }
186 case ELF::R_MIPS_PC18_S3: {
187 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
188 return ((Value + Addend - (FinalAddress & ~0x7)) >> 3) & 0x3ffff;
189 }
190 case ELF::R_MIPS_PC19_S2: {
191 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
192 return ((Value + Addend - (FinalAddress & ~0x3)) >> 2) & 0x7ffff;
193 }
194 case ELF::R_MIPS_PC21_S2: {
195 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
196 return ((Value + Addend - FinalAddress) >> 2) & 0x1fffff;
197 }
198 case ELF::R_MIPS_PC26_S2: {
199 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
200 return ((Value + Addend - FinalAddress) >> 2) & 0x3ffffff;
201 }
202 case ELF::R_MIPS_PCHI16: {
203 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
204 return ((Value + Addend - FinalAddress + 0x8000) >> 16) & 0xffff;
205 }
206 case ELF::R_MIPS_PCLO16: {
207 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
208 return (Value + Addend - FinalAddress) & 0xffff;
209 }
210 }
211 return 0;
212 }
213
applyMIPSRelocation(uint8_t * TargetPtr,int64_t Value,uint32_t Type)214 void RuntimeDyldELFMips::applyMIPSRelocation(uint8_t *TargetPtr, int64_t Value,
215 uint32_t Type) {
216 uint32_t Insn = readBytesUnaligned(TargetPtr, 4);
217
218 switch (Type) {
219 default:
220 llvm_unreachable("Unknown relocation type!");
221 break;
222 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 Insn = (Insn & 0xffff0000) | (Value & 0x0000ffff);
235 writeBytesUnaligned(Insn, TargetPtr, 4);
236 break;
237 case ELF::R_MIPS_PC18_S3:
238 Insn = (Insn & 0xfffc0000) | (Value & 0x0003ffff);
239 writeBytesUnaligned(Insn, TargetPtr, 4);
240 break;
241 case ELF::R_MIPS_PC19_S2:
242 Insn = (Insn & 0xfff80000) | (Value & 0x0007ffff);
243 writeBytesUnaligned(Insn, TargetPtr, 4);
244 break;
245 case ELF::R_MIPS_PC21_S2:
246 Insn = (Insn & 0xffe00000) | (Value & 0x001fffff);
247 writeBytesUnaligned(Insn, TargetPtr, 4);
248 break;
249 case ELF::R_MIPS_26:
250 case ELF::R_MIPS_PC26_S2:
251 Insn = (Insn & 0xfc000000) | (Value & 0x03ffffff);
252 writeBytesUnaligned(Insn, TargetPtr, 4);
253 break;
254 case ELF::R_MIPS_32:
255 case ELF::R_MIPS_GPREL32:
256 case ELF::R_MIPS_PC32:
257 writeBytesUnaligned(Value & 0xffffffff, TargetPtr, 4);
258 break;
259 case ELF::R_MIPS_64:
260 case ELF::R_MIPS_SUB:
261 writeBytesUnaligned(Value, TargetPtr, 8);
262 break;
263 }
264 }
265
resolveMIPSN32Relocation(const SectionEntry & Section,uint64_t Offset,uint64_t Value,uint32_t Type,int64_t Addend,uint64_t SymOffset,SID SectionID)266 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 int64_t CalculatedValue = evaluateMIPS64Relocation(
270 Section, Offset, Value, Type, Addend, SymOffset, SectionID);
271 applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue,
272 Type);
273 }
274
resolveMIPSN64Relocation(const SectionEntry & Section,uint64_t Offset,uint64_t Value,uint32_t Type,int64_t Addend,uint64_t SymOffset,SID SectionID)275 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 uint32_t r_type = Type & 0xff;
279 uint32_t r_type2 = (Type >> 8) & 0xff;
280 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 int64_t CalculatedValue = evaluateMIPS64Relocation(Section, Offset, Value,
286 RelType, Addend,
287 SymOffset, SectionID);
288 if (r_type2 != ELF::R_MIPS_NONE) {
289 RelType = r_type2;
290 CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType,
291 CalculatedValue, SymOffset,
292 SectionID);
293 }
294 if (r_type3 != ELF::R_MIPS_NONE) {
295 RelType = r_type3;
296 CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType,
297 CalculatedValue, SymOffset,
298 SectionID);
299 }
300 applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue,
301 RelType);
302 }
303
resolveMIPSO32Relocation(const SectionEntry & Section,uint64_t Offset,uint32_t Value,uint32_t Type,int32_t Addend)304 void RuntimeDyldELFMips::resolveMIPSO32Relocation(const SectionEntry &Section,
305 uint64_t Offset,
306 uint32_t Value, uint32_t Type,
307 int32_t Addend) {
308 uint8_t *TargetPtr = Section.getAddressWithOffset(Offset);
309 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 Value = evaluateMIPS32Relocation(Section, Offset, Value, Type);
319
320 applyMIPSRelocation(TargetPtr, Value, Type);
321 }
322