313 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			313 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- RuntimeDyldELFMips.cpp ---- ELF/Mips specific code. -----*- C++ -*-===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "RuntimeDyldELFMips.h"
 | 
						|
#include "llvm/Support/ELF.h"
 | 
						|
 | 
						|
#define DEBUG_TYPE "dyld"
 | 
						|
 | 
						|
void RuntimeDyldELFMips::resolveRelocation(const RelocationEntry &RE,
 | 
						|
                                           uint64_t Value) {
 | 
						|
  const SectionEntry &Section = Sections[RE.SectionID];
 | 
						|
  if (IsMipsO32ABI)
 | 
						|
    resolveMIPSO32Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend);
 | 
						|
  else if (IsMipsN32ABI) {
 | 
						|
    resolveMIPSN32Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
 | 
						|
                             RE.SymOffset, RE.SectionID);
 | 
						|
  } else if (IsMipsN64ABI)
 | 
						|
    resolveMIPSN64Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
 | 
						|
                             RE.SymOffset, RE.SectionID);
 | 
						|
  else
 | 
						|
    llvm_unreachable("Mips ABI not handled");
 | 
						|
}
 | 
						|
 | 
						|
uint64_t RuntimeDyldELFMips::evaluateRelocation(const RelocationEntry &RE,
 | 
						|
                                                uint64_t Value,
 | 
						|
                                                uint64_t Addend) {
 | 
						|
  if (IsMipsN32ABI) {
 | 
						|
    const SectionEntry &Section = Sections[RE.SectionID];
 | 
						|
    Value = evaluateMIPS64Relocation(Section, RE.Offset, Value, RE.RelType,
 | 
						|
                                     Addend, RE.SymOffset, RE.SectionID);
 | 
						|
    return Value;
 | 
						|
  }
 | 
						|
  llvm_unreachable("Not reachable");
 | 
						|
}
 | 
						|
 | 
						|
void RuntimeDyldELFMips::applyRelocation(const RelocationEntry &RE,
 | 
						|
                                         uint64_t Value) {
 | 
						|
  if (IsMipsN32ABI) {
 | 
						|
    const SectionEntry &Section = Sections[RE.SectionID];
 | 
						|
    applyMIPSRelocation(Section.getAddressWithOffset(RE.Offset), Value,
 | 
						|
                        RE.RelType);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  llvm_unreachable("Not reachable");
 | 
						|
}
 | 
						|
 | 
						|
int64_t
 | 
						|
RuntimeDyldELFMips::evaluateMIPS32Relocation(const SectionEntry &Section,
 | 
						|
                                             uint64_t Offset, uint64_t Value,
 | 
						|
                                             uint32_t Type) {
 | 
						|
 | 
						|
  DEBUG(dbgs() << "evaluateMIPS32Relocation, LocalAddress: 0x"
 | 
						|
               << format("%llx", Section.getAddressWithOffset(Offset))
 | 
						|
               << " FinalAddress: 0x"
 | 
						|
               << format("%llx", Section.getLoadAddressWithOffset(Offset))
 | 
						|
               << " Value: 0x" << format("%llx", Value) << " Type: 0x"
 | 
						|
               << format("%x", Type) << "\n");
 | 
						|
 | 
						|
  switch (Type) {
 | 
						|
  default:
 | 
						|
    llvm_unreachable("Unknown relocation type!");
 | 
						|
    return Value;
 | 
						|
  case ELF::R_MIPS_32:
 | 
						|
    return Value;
 | 
						|
  case ELF::R_MIPS_26:
 | 
						|
    return Value >> 2;
 | 
						|
  case ELF::R_MIPS_HI16:
 | 
						|
    // Get the higher 16-bits. Also add 1 if bit 15 is 1.
 | 
						|
    return (Value + 0x8000) >> 16;
 | 
						|
  case ELF::R_MIPS_LO16:
 | 
						|
    return Value;
 | 
						|
  case ELF::R_MIPS_PC32: {
 | 
						|
    uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
 | 
						|
    return Value - FinalAddress;
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_PC16: {
 | 
						|
    uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
 | 
						|
    return (Value - FinalAddress) >> 2;
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_PC19_S2: {
 | 
						|
    uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
 | 
						|
    return (Value - (FinalAddress & ~0x3)) >> 2;
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_PC21_S2: {
 | 
						|
    uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
 | 
						|
    return (Value - FinalAddress) >> 2;
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_PC26_S2: {
 | 
						|
    uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
 | 
						|
    return (Value - FinalAddress) >> 2;
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_PCHI16: {
 | 
						|
    uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
 | 
						|
    return (Value - FinalAddress + 0x8000) >> 16;
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_PCLO16: {
 | 
						|
    uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
 | 
						|
    return Value - FinalAddress;
 | 
						|
  }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int64_t RuntimeDyldELFMips::evaluateMIPS64Relocation(
 | 
						|
    const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type,
 | 
						|
    int64_t Addend, uint64_t SymOffset, SID SectionID) {
 | 
						|
 | 
						|
  DEBUG(dbgs() << "evaluateMIPS64Relocation, LocalAddress: 0x"
 | 
						|
               << format("%llx", Section.getAddressWithOffset(Offset))
 | 
						|
               << " FinalAddress: 0x"
 | 
						|
               << format("%llx", Section.getLoadAddressWithOffset(Offset))
 | 
						|
               << " Value: 0x" << format("%llx", Value) << " Type: 0x"
 | 
						|
               << format("%x", Type) << " Addend: 0x" << format("%llx", Addend)
 | 
						|
               << " SymOffset: " << format("%x", SymOffset) << "\n");
 | 
						|
 | 
						|
  switch (Type) {
 | 
						|
  default:
 | 
						|
    llvm_unreachable("Not implemented relocation type!");
 | 
						|
    break;
 | 
						|
  case ELF::R_MIPS_JALR:
 | 
						|
  case ELF::R_MIPS_NONE:
 | 
						|
    break;
 | 
						|
  case ELF::R_MIPS_32:
 | 
						|
  case ELF::R_MIPS_64:
 | 
						|
    return Value + Addend;
 | 
						|
  case ELF::R_MIPS_26:
 | 
						|
    return ((Value + Addend) >> 2) & 0x3ffffff;
 | 
						|
  case ELF::R_MIPS_GPREL16: {
 | 
						|
    uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]);
 | 
						|
    return Value + Addend - (GOTAddr + 0x7ff0);
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_SUB:
 | 
						|
    return Value - Addend;
 | 
						|
  case ELF::R_MIPS_HI16:
 | 
						|
    // Get the higher 16-bits. Also add 1 if bit 15 is 1.
 | 
						|
    return ((Value + Addend + 0x8000) >> 16) & 0xffff;
 | 
						|
  case ELF::R_MIPS_LO16:
 | 
						|
    return (Value + Addend) & 0xffff;
 | 
						|
  case ELF::R_MIPS_CALL16:
 | 
						|
  case ELF::R_MIPS_GOT_DISP:
 | 
						|
  case ELF::R_MIPS_GOT_PAGE: {
 | 
						|
    uint8_t *LocalGOTAddr =
 | 
						|
        getSectionAddress(SectionToGOTMap[SectionID]) + SymOffset;
 | 
						|
    uint64_t GOTEntry = readBytesUnaligned(LocalGOTAddr, getGOTEntrySize());
 | 
						|
 | 
						|
    Value += Addend;
 | 
						|
    if (Type == ELF::R_MIPS_GOT_PAGE)
 | 
						|
      Value = (Value + 0x8000) & ~0xffff;
 | 
						|
 | 
						|
    if (GOTEntry)
 | 
						|
      assert(GOTEntry == Value &&
 | 
						|
                   "GOT entry has two different addresses.");
 | 
						|
    else
 | 
						|
      writeBytesUnaligned(Value, LocalGOTAddr, getGOTEntrySize());
 | 
						|
 | 
						|
    return (SymOffset - 0x7ff0) & 0xffff;
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_GOT_OFST: {
 | 
						|
    int64_t page = (Value + Addend + 0x8000) & ~0xffff;
 | 
						|
    return (Value + Addend - page) & 0xffff;
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_GPREL32: {
 | 
						|
    uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]);
 | 
						|
    return Value + Addend - (GOTAddr + 0x7ff0);
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_PC16: {
 | 
						|
    uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
 | 
						|
    return ((Value + Addend - FinalAddress) >> 2) & 0xffff;
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_PC32: {
 | 
						|
    uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
 | 
						|
    return Value + Addend - FinalAddress;
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_PC18_S3: {
 | 
						|
    uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
 | 
						|
    return ((Value + Addend - (FinalAddress & ~0x7)) >> 3) & 0x3ffff;
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_PC19_S2: {
 | 
						|
    uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
 | 
						|
    return ((Value + Addend - (FinalAddress & ~0x3)) >> 2) & 0x7ffff;
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_PC21_S2: {
 | 
						|
    uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
 | 
						|
    return ((Value + Addend - FinalAddress) >> 2) & 0x1fffff;
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_PC26_S2: {
 | 
						|
    uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
 | 
						|
    return ((Value + Addend - FinalAddress) >> 2) & 0x3ffffff;
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_PCHI16: {
 | 
						|
    uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
 | 
						|
    return ((Value + Addend - FinalAddress + 0x8000) >> 16) & 0xffff;
 | 
						|
  }
 | 
						|
  case ELF::R_MIPS_PCLO16: {
 | 
						|
    uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
 | 
						|
    return (Value + Addend - FinalAddress) & 0xffff;
 | 
						|
  }
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
void RuntimeDyldELFMips::applyMIPSRelocation(uint8_t *TargetPtr, int64_t Value,
 | 
						|
                                             uint32_t Type) {
 | 
						|
  uint32_t Insn = readBytesUnaligned(TargetPtr, 4);
 | 
						|
 | 
						|
  switch (Type) {
 | 
						|
  default:
 | 
						|
    llvm_unreachable("Unknown relocation type!");
 | 
						|
    break;
 | 
						|
  case ELF::R_MIPS_GPREL16:
 | 
						|
  case ELF::R_MIPS_HI16:
 | 
						|
  case ELF::R_MIPS_LO16:
 | 
						|
  case ELF::R_MIPS_PC16:
 | 
						|
  case ELF::R_MIPS_PCHI16:
 | 
						|
  case ELF::R_MIPS_PCLO16:
 | 
						|
  case ELF::R_MIPS_CALL16:
 | 
						|
  case ELF::R_MIPS_GOT_DISP:
 | 
						|
  case ELF::R_MIPS_GOT_PAGE:
 | 
						|
  case ELF::R_MIPS_GOT_OFST:
 | 
						|
    Insn = (Insn & 0xffff0000) | (Value & 0x0000ffff);
 | 
						|
    writeBytesUnaligned(Insn, TargetPtr, 4);
 | 
						|
    break;
 | 
						|
  case ELF::R_MIPS_PC18_S3:
 | 
						|
    Insn = (Insn & 0xfffc0000) | (Value & 0x0003ffff);
 | 
						|
    writeBytesUnaligned(Insn, TargetPtr, 4);
 | 
						|
    break;
 | 
						|
  case ELF::R_MIPS_PC19_S2:
 | 
						|
    Insn = (Insn & 0xfff80000) | (Value & 0x0007ffff);
 | 
						|
    writeBytesUnaligned(Insn, TargetPtr, 4);
 | 
						|
    break;
 | 
						|
  case ELF::R_MIPS_PC21_S2:
 | 
						|
    Insn = (Insn & 0xffe00000) | (Value & 0x001fffff);
 | 
						|
    writeBytesUnaligned(Insn, TargetPtr, 4);
 | 
						|
    break;
 | 
						|
  case ELF::R_MIPS_26:
 | 
						|
  case ELF::R_MIPS_PC26_S2:
 | 
						|
    Insn = (Insn & 0xfc000000) | (Value & 0x03ffffff);
 | 
						|
    writeBytesUnaligned(Insn, TargetPtr, 4);
 | 
						|
    break;
 | 
						|
  case ELF::R_MIPS_32:
 | 
						|
  case ELF::R_MIPS_GPREL32:
 | 
						|
  case ELF::R_MIPS_PC32:
 | 
						|
    writeBytesUnaligned(Value & 0xffffffff, TargetPtr, 4);
 | 
						|
    break;
 | 
						|
  case ELF::R_MIPS_64:
 | 
						|
  case ELF::R_MIPS_SUB:
 | 
						|
    writeBytesUnaligned(Value, TargetPtr, 8);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void RuntimeDyldELFMips::resolveMIPSN32Relocation(
 | 
						|
    const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type,
 | 
						|
    int64_t Addend, uint64_t SymOffset, SID SectionID) {
 | 
						|
  int64_t CalculatedValue = evaluateMIPS64Relocation(
 | 
						|
      Section, Offset, Value, Type, Addend, SymOffset, SectionID);
 | 
						|
  applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue,
 | 
						|
                      Type);
 | 
						|
}
 | 
						|
 | 
						|
void RuntimeDyldELFMips::resolveMIPSN64Relocation(
 | 
						|
    const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type,
 | 
						|
    int64_t Addend, uint64_t SymOffset, SID SectionID) {
 | 
						|
  uint32_t r_type = Type & 0xff;
 | 
						|
  uint32_t r_type2 = (Type >> 8) & 0xff;
 | 
						|
  uint32_t r_type3 = (Type >> 16) & 0xff;
 | 
						|
 | 
						|
  // RelType is used to keep information for which relocation type we are
 | 
						|
  // applying relocation.
 | 
						|
  uint32_t RelType = r_type;
 | 
						|
  int64_t CalculatedValue = evaluateMIPS64Relocation(Section, Offset, Value,
 | 
						|
                                                     RelType, Addend,
 | 
						|
                                                     SymOffset, SectionID);
 | 
						|
  if (r_type2 != ELF::R_MIPS_NONE) {
 | 
						|
    RelType = r_type2;
 | 
						|
    CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType,
 | 
						|
                                               CalculatedValue, SymOffset,
 | 
						|
                                               SectionID);
 | 
						|
  }
 | 
						|
  if (r_type3 != ELF::R_MIPS_NONE) {
 | 
						|
    RelType = r_type3;
 | 
						|
    CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType,
 | 
						|
                                               CalculatedValue, SymOffset,
 | 
						|
                                               SectionID);
 | 
						|
  }
 | 
						|
  applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue,
 | 
						|
                      RelType);
 | 
						|
}
 | 
						|
 | 
						|
void RuntimeDyldELFMips::resolveMIPSO32Relocation(const SectionEntry &Section,
 | 
						|
                                                  uint64_t Offset,
 | 
						|
                                                  uint32_t Value, uint32_t Type,
 | 
						|
                                                  int32_t Addend) {
 | 
						|
  uint8_t *TargetPtr = Section.getAddressWithOffset(Offset);
 | 
						|
  Value += Addend;
 | 
						|
 | 
						|
  DEBUG(dbgs() << "resolveMIPSO32Relocation, LocalAddress: "
 | 
						|
               << Section.getAddressWithOffset(Offset) << " FinalAddress: "
 | 
						|
               << format("%p", Section.getLoadAddressWithOffset(Offset))
 | 
						|
               << " Value: " << format("%x", Value)
 | 
						|
               << " Type: " << format("%x", Type)
 | 
						|
               << " Addend: " << format("%x", Addend) << "\n");
 | 
						|
 | 
						|
  Value = evaluateMIPS32Relocation(Section, Offset, Value, Type);
 | 
						|
 | 
						|
  applyMIPSRelocation(TargetPtr, Value, Type);
 | 
						|
}
 |