// ---------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // ---------------------------------------------------------------------------- // // Simple PE Loader for Singularity // // Currently does not support: // x64 // sections loaded at separate addresses // loading at preferred address // #define verbose //#define SINGULARITY_ASMP namespace Microsoft.Singularity.Loader { using Microsoft.Singularity; using Microsoft.Singularity.Io; using System; using System.Runtime.InteropServices; using System.Threading; internal class Relocations { private const ushort sizeofBaseRelocation = 8; //Based relocation types. private const ushort IMAGE_REL_BASED_ABSOLUTE = 0; private const ushort IMAGE_REL_BASED_HIGH = 1; private const ushort IMAGE_REL_BASED_LOW = 2; private const ushort IMAGE_REL_BASED_HIGHLOW = 3; private const ushort IMAGE_REL_BASED_HIGHADJ = 4; private const ushort IMAGE_REL_BASED_DIR64 = 10; internal static void FixupBlocks(IoMemory relocationMemory, int relocOffset, IoMemory codeMemory, UIntPtr diff) { uint va = relocationMemory.Read32Unchecked(relocOffset); uint size = relocationMemory.Read32Unchecked(relocOffset+4); while (0 != va) { #if verbose DebugStub.WriteLine(" FixUpBlocks: addr={0:x8}, size={1:x8}, roffset={2:x8} ", __arglist(va, size,relocOffset)); #endif #if SINGULARITY_ASMP if (va == 0xffffffff || size == 0xffffffff || va >= 0xc0000000 || size >= 0xc0000000) { break; } #endif FixupBlock(relocationMemory, relocOffset, codeMemory, diff, va, (int)size); relocOffset += (int)size; va = relocationMemory.Read32Unchecked(relocOffset); size = relocationMemory.Read32Unchecked(relocOffset+4); } } private static void FixupBlock(IoMemory relocationMemory, int relocOffset, IoMemory codeMemory, UIntPtr diff, uint va, int size) { ushort fixupEntry; // Compute number of entries int numberOfEntries = (size - sizeofBaseRelocation) /2; #if verbose DebugStub.WriteLine(" FixUp: addr={0:x8}, size={1:x8}, count={2}", __arglist(va, size, numberOfEntries)); #endif int currentSize = size - sizeofBaseRelocation; relocOffset += sizeofBaseRelocation; //skip block header for (int i = 0; i < numberOfEntries; i++) { fixupEntry = relocationMemory.Read16(relocOffset); relocOffset += 2; currentSize -= 2; ushort type = (ushort) (fixupEntry >>12); //clear out the upper bits uint rVA = (uint)(fixupEntry & 0xfff)+ va; if (IMAGE_REL_BASED_ABSOLUTE == type) { //DebugStub.WriteLine(" type={0:x4} rVA={1:x8}", //__arglist(type, rVA)); // hit an alignment type. there should be no more entries //DebugStub.WriteLine(" fixup: count ={0}, loop count ={1} size={2}", //__arglist(numberOfEntries, i, currentSize)); break; } else if (IMAGE_REL_BASED_HIGHLOW == type) { // get 32-bit word pointed by rVA // mem object representing loaded image is 0 based rVA is sufficient uint fixupItem = codeMemory.Read32Unchecked((int)rVA); uint newValue = unchecked((uint) diff + (uint) fixupItem); #if verbose DebugStub.WriteLine(" Fixup: rVA={0:x8} value={1:x8} diff={2:x8}, newValue={3:x8}", __arglist(rVA, fixupItem, diff, newValue)); #endif codeMemory.Write32Unchecked((int) rVA, newValue); } else if (IMAGE_REL_BASED_DIR64 == type) { ulong OldValue; ulong NewValue; OldValue = codeMemory.Read64((int) rVA); NewValue = unchecked(OldValue + (ulong) diff); codeMemory.Write64((int) rVA, NewValue); } else { DebugStub.WriteLine("PE Bad fixup: %x", __arglist(type)); DebugStub.Break(); } } //DebugStub.WriteLine(); } } }