You've already forked linux-packaging-mono
							
							
		
			
	
	
		
			322 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			322 lines
		
	
	
		
			12 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/BinaryFormat/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) | ||
|  |                << " Offset: " << format("%llx" PRIx64, Offset) | ||
|  |                << " SID: " << format("%d", SectionID) | ||
|  |                << " 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_HIGHER: | ||
|  |     return ((Value + Addend + 0x80008000) >> 32) & 0xffff; | ||
|  |   case ELF::R_MIPS_HIGHEST: | ||
|  |     return ((Value + Addend + 0x800080008000) >> 48) & 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_HIGHER: | ||
|  |   case ELF::R_MIPS_HIGHEST: | ||
|  |   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) | ||
|  |                << " SymOffset: " << format("%x", Offset) << "\n"); | ||
|  | 
 | ||
|  |   Value = evaluateMIPS32Relocation(Section, Offset, Value, Type); | ||
|  | 
 | ||
|  |   applyMIPSRelocation(TargetPtr, Value, Type); | ||
|  | } |