protected void RelocateRelocs(IEnumerable<Elf.Reloc> Relocs)
{
var InstructionReader = new InstructionStreamReader(ElfLoader.MemoryStream);
/*
Func<uint, Action<ref Instruction>> UpdateInstruction = (Address) =>
{
};
*/
//var Hi16List = new List<uint>();
ushort HiValue = 0;
var DeferredHi16 = new LinkedList<uint>(); // We'll use this to relocate R_MIPS_HI16 when we get a R_MIPS_LO16
int Index = 0;
foreach (var Reloc in Relocs)
{
//Console.WriteLine(Reloc.ToStringDefault());
//Console.WriteLine(" {0:X}", RelocatedAddress);
// Check if R_TYPE is 0xFF (break code) and break the loop
// immediately in order to avoid fetching non existent program headers.
// Some games (e.g.: "Final Fantasy: Dissidia") use this kind of relocation
// suggesting that the PSP's ELF Loader is capable of recognizing it and stop.
if (Reloc.Type == Elf.Reloc.TypeEnum.StopRelocation)
{
break;
}
var PointerBaseOffset = (uint)ElfLoader.ProgramHeaders[Reloc.PointerSectionHeaderBase].VirtualAddress;
var PointeeBaseOffset = (uint)ElfLoader.ProgramHeaders[Reloc.PointeeSectionHeaderBase].VirtualAddress;
// Address of data to relocate
var RelocatedPointerAddress = (uint)(BaseAddress + Reloc.PointerAddress + PointerBaseOffset);
// Value of data to relocate
var Instruction = InstructionReader[RelocatedPointerAddress];
var InstructionBefore = Instruction;
var S = (uint)BaseAddress + PointeeBaseOffset;
var GP_ADDR = (int)(BaseAddress + Reloc.PointerAddress);
var GP_OFFSET = (int)GP_ADDR - ((int)BaseAddress & 0xFFFF0000);
//Console.WriteLine(Reloc.Type);
bool DebugReloc = (RelocatedPointerAddress >= 0x08809320 && RelocatedPointerAddress <= 0x08809320 + 0x100);
//bool DebugReloc = false;
if (DebugReloc)
{
Console.WriteLine("{0:X8}[{1:X8}]: {2}", RelocatedPointerAddress, Instruction.Value, Reloc);
}
switch (Reloc.Type)
{
// Tested on PSP: R_MIPS_NONE just returns 0.
case Elf.Reloc.TypeEnum.None: // 0
{
}
break;
/*
case Elf.Reloc.TypeEnum.Mips16: // 1
{
Instruction.IMMU += S;
}
break;
*/
case Elf.Reloc.TypeEnum.Mips32: // 2
{
Instruction.Value += S;
}
break;
case Elf.Reloc.TypeEnum.MipsRel32: // 3;
{
throw (new NotImplementedException());
}
case Elf.Reloc.TypeEnum.Mips26: // 4
{
Instruction.JUMP_Real = Instruction.JUMP_Real + S;
}
break;
case Elf.Reloc.TypeEnum.MipsHi16: // 5
{
HiValue = (ushort)Instruction.IMMU;
DeferredHi16.AddLast(RelocatedPointerAddress);
}
break;
case Elf.Reloc.TypeEnum.MipsLo16: // 6
{
uint A = Instruction.IMMU;
Instruction.IMMU = ((uint)(HiValue << 16) | (uint)(A & 0x0000FFFF)) + S;
// Process deferred R_MIPS_HI16
foreach (var data_addr2 in DeferredHi16)
{
var data2 = InstructionReader[data_addr2];
uint result = ((data2.Value & 0x0000FFFF) << 16) + A + S;
// The low order 16 bits are always treated as a signed
// value. Therefore, a negative value in the low order bits
// requires an adjustment in the high order bits. We need
// to make this adjustment in two ways: once for the bits we
// took from the data, and once for the bits we are putting
// back in to the data.
if ((A & 0x8000) != 0) {
result -= 0x10000;
}
if ((result & 0x8000) != 0) {
result += 0x10000;
}
data2.IMMU = (result >> 16);
InstructionReader[data_addr2] = data2;
}
DeferredHi16.Clear();
}
break;
case Elf.Reloc.TypeEnum.MipsGpRel16: // 7
{
/*
int A = Instruction.IMM;
int result;
if (A == 0)
{
result = (int)S - (int)GP_ADDR;
}
else
{
result = (int)S + (int)GP_OFFSET + (int)(((A & 0x00008000) != 0) ? (((A & 0x00003FFF) + 0x4000) | 0xFFFF0000) : A) - (int)GP_ADDR;
}
if ((result < -32768) || (result > 32768))
{
Console.Error.WriteLine("Relocation overflow (R_MIPS_GPREL16) : '" + result + "'");
}
Instruction.IMMU = (uint)result;
*/
}
break;
default:
throw(new NotImplementedException("Handling " + Reloc.Type + " not implemented"));
}
if (RelocOutput != null) RelocOutput.WriteLine(
"RELOC %06d : 0x%08X : 0x%08X -> 0x%08X".Sprintf(
Index,
RelocatedPointerAddress, InstructionBefore.Value, Instruction.Value
)
);
if (DebugReloc)
{
Console.WriteLine(" -> {0:X8}", Instruction.Value);
}
/*
log.error(String.format(
"RELOC %06d : 0x%08X : 0x%08X -> 0x%08X\n",
i, data_addr, data_prev, data
));
*/
InstructionReader[RelocatedPointerAddress] = Instruction;
Index++;
}
}