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/Support/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 << " SymOffset: " << format("%x", SymOffset) << "\n"); 120 121 switch (Type) { 122 default: 123 llvm_unreachable("Not implemented relocation type!"); 124 break; 125 case ELF::R_MIPS_JALR: 126 case ELF::R_MIPS_NONE: 127 break; 128 case ELF::R_MIPS_32: 129 case ELF::R_MIPS_64: 130 return Value + Addend; 131 case ELF::R_MIPS_26: 132 return ((Value + Addend) >> 2) & 0x3ffffff; 133 case ELF::R_MIPS_GPREL16: { 134 uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]); 135 return Value + Addend - (GOTAddr + 0x7ff0); 136 } 137 case ELF::R_MIPS_SUB: 138 return Value - Addend; 139 case ELF::R_MIPS_HI16: 140 // Get the higher 16-bits. Also add 1 if bit 15 is 1. 141 return ((Value + Addend + 0x8000) >> 16) & 0xffff; 142 case ELF::R_MIPS_LO16: 143 return (Value + Addend) & 0xffff; 144 case ELF::R_MIPS_CALL16: 145 case ELF::R_MIPS_GOT_DISP: 146 case ELF::R_MIPS_GOT_PAGE: { 147 uint8_t *LocalGOTAddr = 148 getSectionAddress(SectionToGOTMap[SectionID]) + SymOffset; 149 uint64_t GOTEntry = readBytesUnaligned(LocalGOTAddr, getGOTEntrySize()); 150 151 Value += Addend; 152 if (Type == ELF::R_MIPS_GOT_PAGE) 153 Value = (Value + 0x8000) & ~0xffff; 154 155 if (GOTEntry) 156 assert(GOTEntry == Value && 157 "GOT entry has two different addresses."); 158 else 159 writeBytesUnaligned(Value, LocalGOTAddr, getGOTEntrySize()); 160 161 return (SymOffset - 0x7ff0) & 0xffff; 162 } 163 case ELF::R_MIPS_GOT_OFST: { 164 int64_t page = (Value + Addend + 0x8000) & ~0xffff; 165 return (Value + Addend - page) & 0xffff; 166 } 167 case ELF::R_MIPS_GPREL32: { 168 uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]); 169 return Value + Addend - (GOTAddr + 0x7ff0); 170 } 171 case ELF::R_MIPS_PC16: { 172 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); 173 return ((Value + Addend - FinalAddress) >> 2) & 0xffff; 174 } 175 case ELF::R_MIPS_PC32: { 176 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); 177 return Value + Addend - FinalAddress; 178 } 179 case ELF::R_MIPS_PC18_S3: { 180 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); 181 return ((Value + Addend - (FinalAddress & ~0x7)) >> 3) & 0x3ffff; 182 } 183 case ELF::R_MIPS_PC19_S2: { 184 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); 185 return ((Value + Addend - (FinalAddress & ~0x3)) >> 2) & 0x7ffff; 186 } 187 case ELF::R_MIPS_PC21_S2: { 188 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); 189 return ((Value + Addend - FinalAddress) >> 2) & 0x1fffff; 190 } 191 case ELF::R_MIPS_PC26_S2: { 192 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); 193 return ((Value + Addend - FinalAddress) >> 2) & 0x3ffffff; 194 } 195 case ELF::R_MIPS_PCHI16: { 196 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); 197 return ((Value + Addend - FinalAddress + 0x8000) >> 16) & 0xffff; 198 } 199 case ELF::R_MIPS_PCLO16: { 200 uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); 201 return (Value + Addend - FinalAddress) & 0xffff; 202 } 203 } 204 return 0; 205 } 206 207 void RuntimeDyldELFMips::applyMIPSRelocation(uint8_t *TargetPtr, int64_t Value, 208 uint32_t Type) { 209 uint32_t Insn = readBytesUnaligned(TargetPtr, 4); 210 211 switch (Type) { 212 default: 213 llvm_unreachable("Unknown relocation type!"); 214 break; 215 case ELF::R_MIPS_GPREL16: 216 case ELF::R_MIPS_HI16: 217 case ELF::R_MIPS_LO16: 218 case ELF::R_MIPS_PC16: 219 case ELF::R_MIPS_PCHI16: 220 case ELF::R_MIPS_PCLO16: 221 case ELF::R_MIPS_CALL16: 222 case ELF::R_MIPS_GOT_DISP: 223 case ELF::R_MIPS_GOT_PAGE: 224 case ELF::R_MIPS_GOT_OFST: 225 Insn = (Insn & 0xffff0000) | (Value & 0x0000ffff); 226 writeBytesUnaligned(Insn, TargetPtr, 4); 227 break; 228 case ELF::R_MIPS_PC18_S3: 229 Insn = (Insn & 0xfffc0000) | (Value & 0x0003ffff); 230 writeBytesUnaligned(Insn, TargetPtr, 4); 231 break; 232 case ELF::R_MIPS_PC19_S2: 233 Insn = (Insn & 0xfff80000) | (Value & 0x0007ffff); 234 writeBytesUnaligned(Insn, TargetPtr, 4); 235 break; 236 case ELF::R_MIPS_PC21_S2: 237 Insn = (Insn & 0xffe00000) | (Value & 0x001fffff); 238 writeBytesUnaligned(Insn, TargetPtr, 4); 239 break; 240 case ELF::R_MIPS_26: 241 case ELF::R_MIPS_PC26_S2: 242 Insn = (Insn & 0xfc000000) | (Value & 0x03ffffff); 243 writeBytesUnaligned(Insn, TargetPtr, 4); 244 break; 245 case ELF::R_MIPS_32: 246 case ELF::R_MIPS_GPREL32: 247 case ELF::R_MIPS_PC32: 248 writeBytesUnaligned(Value & 0xffffffff, TargetPtr, 4); 249 break; 250 case ELF::R_MIPS_64: 251 case ELF::R_MIPS_SUB: 252 writeBytesUnaligned(Value, TargetPtr, 8); 253 break; 254 } 255 } 256 257 void RuntimeDyldELFMips::resolveMIPSN32Relocation( 258 const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, 259 int64_t Addend, uint64_t SymOffset, SID SectionID) { 260 int64_t CalculatedValue = evaluateMIPS64Relocation( 261 Section, Offset, Value, Type, Addend, SymOffset, SectionID); 262 applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue, 263 Type); 264 } 265 266 void RuntimeDyldELFMips::resolveMIPSN64Relocation( 267 const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, 268 int64_t Addend, uint64_t SymOffset, SID SectionID) { 269 uint32_t r_type = Type & 0xff; 270 uint32_t r_type2 = (Type >> 8) & 0xff; 271 uint32_t r_type3 = (Type >> 16) & 0xff; 272 273 // RelType is used to keep information for which relocation type we are 274 // applying relocation. 275 uint32_t RelType = r_type; 276 int64_t CalculatedValue = evaluateMIPS64Relocation(Section, Offset, Value, 277 RelType, Addend, 278 SymOffset, SectionID); 279 if (r_type2 != ELF::R_MIPS_NONE) { 280 RelType = r_type2; 281 CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType, 282 CalculatedValue, SymOffset, 283 SectionID); 284 } 285 if (r_type3 != ELF::R_MIPS_NONE) { 286 RelType = r_type3; 287 CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType, 288 CalculatedValue, SymOffset, 289 SectionID); 290 } 291 applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue, 292 RelType); 293 } 294 295 void RuntimeDyldELFMips::resolveMIPSO32Relocation(const SectionEntry &Section, 296 uint64_t Offset, 297 uint32_t Value, uint32_t Type, 298 int32_t Addend) { 299 uint8_t *TargetPtr = Section.getAddressWithOffset(Offset); 300 Value += Addend; 301 302 DEBUG(dbgs() << "resolveMIPSO32Relocation, LocalAddress: " 303 << Section.getAddressWithOffset(Offset) << " FinalAddress: " 304 << format("%p", Section.getLoadAddressWithOffset(Offset)) 305 << " Value: " << format("%x", Value) 306 << " Type: " << format("%x", Type) 307 << " Addend: " << format("%x", Addend) << "\n"); 308 309 Value = evaluateMIPS32Relocation(Section, Offset, Value, Type); 310 311 applyMIPSRelocation(TargetPtr, Value, Type); 312 } 313