321 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "RuntimeDyldELFMips.h"10#include "llvm/BinaryFormat/ELF.h"11 12#define DEBUG_TYPE "dyld"13 14void 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 else26 llvm_unreachable("Mips ABI not handled");27}28 29uint64_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 41void 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 52int64_t53RuntimeDyldELFMips::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 108int64_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 else165 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 213void 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 265void 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 274void 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 are282 // 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 303void 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