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 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 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 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 54 RuntimeDyldELFMips::evaluateMIPS32Relocation(const SectionEntry &Section, 55 uint64_t Offset, uint64_t Value, 56 uint32_t Type) { 57 58 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 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 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" << 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 DEBUG(dbgs() << "resolveMIPSO32Relocation, LocalAddress: " 311 << Section.getAddressWithOffset(Offset) << " FinalAddress: " 312 << format("%p", Section.getLoadAddressWithOffset(Offset)) 313 << " Value: " << format("%x", Value) 314 << " Type: " << format("%x", Type) 315 << " 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