• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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