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