// ---------------------------------------------------------------------------- // // 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 namespace Microsoft.Singularity.Loader { using Microsoft.Singularity; using Microsoft.Singularity.Io; using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; [CLSCompliant(false)] internal class ExportTable { private IoMemory mem; private DirectoryEntry entry; private ExportDirectory exports; private string[] names; private ushort[] ordinals; private UIntPtr[] addresses; struct ExportDirectory { internal readonly uint Characteristics; internal readonly uint NumberOfFunctions; internal readonly uint NumberOfNames; internal readonly uint AddressOfFunctions; // RVA from base of image internal readonly uint AddressOfNames; // RVA from base of image internal readonly uint AddressOfOrdinals; // RVA from base of image internal ExportDirectory(IoMemory mem, int offset) { if (offset + 40 > mem.Length) { Error.AccessOutOfRange(); } Characteristics = mem.Read32Unchecked(offset + 0); NumberOfFunctions = mem.Read32Unchecked(offset + 20); NumberOfNames = mem.Read32Unchecked(offset + 24); AddressOfFunctions = mem.Read32Unchecked(offset + 28); AddressOfNames = mem.Read32Unchecked(offset + 32); AddressOfOrdinals = mem.Read32Unchecked(offset + 36); if (AddressOfFunctions + 4 * NumberOfFunctions > mem.Length || AddressOfOrdinals + 2 * NumberOfFunctions > mem.Length || AddressOfNames + 4 * NumberOfFunctions > mem.Length) { Error.AccessOutOfRange(); } } } internal ExportTable(IoMemory mem, UIntPtr imageBase, DirectoryEntry entry) { this.mem = mem; this.entry = entry; try { exports = new ExportDirectory(mem, (int)entry.virtualAddress); if (exports.NumberOfFunctions > 0) { addresses = new UIntPtr[exports.NumberOfFunctions]; for (uint i = 0; i < exports.NumberOfFunctions; i++) { addresses[i] = imageBase + mem.Read32Unchecked((int)(exports.AddressOfFunctions + 4 * i)); } } if (exports.NumberOfNames > 0) { names = new string[exports.NumberOfNames]; ordinals = new ushort[exports.NumberOfNames]; for (uint i = 0; i < exports.NumberOfNames; i++) { ordinals[i] = mem.Read16Unchecked((int)(exports.AddressOfOrdinals + 2 * i)); uint addrOfName = mem.Read32Unchecked((int)(exports.AddressOfNames + 4 * i)); names[i] = mem.ReadAsciiZeroString((int)addrOfName); } } } catch (Exception e) { DebugStub.Print("Caught exception: {0}\n", __arglist(e.ToString())); } } [Conditional("DEBUG")] internal void Dump() { DebugStub.Print(" Ord# Function Name\n"); if (names != null) { for (int i = 0; i < names.Length; i++) { DebugStub.Print(" {0:d4} {1:x8} {2:x8}\n", __arglist(ordinals[i], addresses[i], names[i])); } } } internal UIntPtr Resolve(ushort hint, string name) { if (names != null) { // we need to put a guard here. because // hint might exceed names.Length The guard in // particular is useful when we want to resolve // imports from MP applications with abi.dll // (MpSyscalls.x86). The "hint" that is obtained from the // app.x86 is actually the hint related to kernel.x86. // Hence, when resolving imports for MP apps, we should // always fall through to the "else" block below if (hint < names.Length && names[hint] == name) { return addresses[hint]; } else { // TODO: we should probably do a binary search. for (int i = 0; i < names.Length; i++) { if (names[i] == name) { return addresses[i]; } } } } return UIntPtr.Zero; } } }