singrdk/base/Kernel/Singularity/Loader/ExportTable.cs

140 lines
5.3 KiB
C#

// ----------------------------------------------------------------------------
//
// 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;
}
}
}