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, 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 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 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 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 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 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 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 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 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