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

236 lines
9.7 KiB
C#

///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// 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 ImportTable
{
private IoMemory mem;
private DirectoryEntry entry;
internal ImportTable(IoMemory mem, DirectoryEntry entry)
{
this.mem = mem;
this.entry = entry;
if (entry.size == 0)
{
DebugStub.WriteLine("// No import table.");
return;
}
}
#if verbose
[Conditional("DEBUG")]
public void DumpIAT(String title)
{
Tracing.Log(Tracing.Debug, "// {0}", title);
if (entry.size == 0)
{
Tracing.Log(Tracing.Debug, "// No data.");
return;
}
int importOffset = (int)entry.virtualAddress;
Tracing.Log(Tracing.Debug, " import offset={0:x8}", importOffset);
//
// start at the importOffset specified above creating and filling out ImportDescriptors
// There is no indication in the header as to how many descriptors are present.
// In the last descriptor all fields will be 0; this code checks just the firstChunk field.
//
for (;;)
{
ImportDescriptor importDescriptor =
new ImportDescriptor(mem, ref importOffset);
//Use hit/Name array pointed to by "characteristics"
// FirstChunk points to the IAT table which is modified at load time to
// to reflect the fixed-up thunk to access the function
if (importDescriptor.characteristics == 0) {
return;
}
String name = null;
if (importDescriptor.name != 0) {
name = mem.ReadAsciiZeroString((int)importDescriptor.name);
}
Tracing.Log(Tracing.Debug, "// {0}", name);
importDescriptor.DumpToStream();
Tracing.Log(Tracing.Debug, "//");
int importTableOffset = (int)importDescriptor.characteristics;
for (;;)
{
int importTableID = (int) mem.Read32(importTableOffset);
if (importTableID == 0) {
break;
}
Tracing.Log(Tracing.Debug, "importTableID is {0:x8}", importTableID);
int nameStringOffset =
importTableID & 0x7fffffff;
importTableOffset += 4;
if ((importTableID & 0x8000000) != 0) {
Tracing.Log(Tracing.Debug, "// {0:x8} by ordinal {1:x8}",
mem.Read16(importTableOffset),
(importTableID & 0x7ffffff));
}
else {
Tracing.Log(Tracing.Debug, "// {1:x8} {0:x8}",
mem.ReadAsciiZeroString(nameStringOffset+2),
mem.Read16(importTableOffset));
}
}
Tracing.Log(Tracing.Debug, "");
}
//throw new BadImageFormatException("");
}
#endif
public void ResolveImports(ExportTable exports)
{
if (entry.size == 0)
{
Tracing.Log(Tracing.Debug, "// No imports to resolve.");
return;
}
int importOffset = (int)entry.virtualAddress;
//Tracing.Log(Tracing.Debug, " import offset={0:x8}", importOffset);
//
// start at the importOffset specified above creating and filling out ImportDescriptors
// There is no indication in the header as to how many descriptors are present.
// In the last descriptor all fields will be 0; this code checks just the firstChunk field.
//
for (;;) {
ImportDescriptor importDescriptor =
new ImportDescriptor(mem, ref importOffset);
if (importDescriptor.firstChunk == 0) {
return;
}
ushort hint = 0;
String name = null;
if (importDescriptor.name != 0) {
name = mem.ReadAsciiZeroString((int)importDescriptor.name);
}
#if verbose
Tracing.Log(Tracing.Debug, "// {0}", name);
importDescriptor.DumpToStream("// ");
Tracing.Log(Tracing.Debug, "//");
#endif
UIntPtr offsetHintTable = UIntPtr.Zero;
if (0 == importDescriptor.characteristics) {
offsetHintTable = (UIntPtr)importDescriptor.characteristics;
}
else {
offsetHintTable = (UIntPtr)importDescriptor.firstChunk;
}
UIntPtr offsetIAT = (UIntPtr)importDescriptor.firstChunk;
for (;;) {
// read elements in the hint array for processing
// the hint array terminates when the its content is 0
int importByNameEntry = (int) mem.Read32((int)offsetHintTable);
if (importByNameEntry == 0) break;
#if verbose
Tracing.Log(Tracing.Debug, "importByName entry is {0:x8}",
importByNameEntry);
#endif
int nameStringOffset = importByNameEntry & 0x7fffffff;
if ((importByNameEntry & 0x8000000) != 0) {
// should never happen in Singularity (no Ordinals)
throw new BadImageFormatException("Import Ordinal encountered");
}
else {
name = mem.ReadAsciiZeroString((int)nameStringOffset+2);
hint = mem.Read16Unchecked(nameStringOffset);
//Tracing.Log(Tracing.Debug, " function to lookup is {0}", name);
UIntPtr addr = exports.Resolve(hint, name);
if (0 != addr)
{
//Overwrite ptr in IAT with address of function in the
// IAT thunk table
#if verbose
int meth = name.IndexOf('@');
int rest = name.IndexOf('@', meth + 1) + 1;
int clas = name.LastIndexOf('_', rest, rest - meth) + 1;
Tracing.Log(Tracing.Debug, " import: {1:x8} is {2:x8} {0}",
name.Substring(0, meth) + "@" + name.Substring(clas, rest - clas) + "@" name.Substring(rest)
(uint)offsetIAT, (uint)addr);
#endif
mem.Write32((int) offsetIAT,(uint)addr);
}
else
{
Tracing.Log(Tracing.Debug, " Import not found: {0}", name);
throw new BadImageFormatException("Import Ordinal encountered");
}
}
// increment "array indices"
offsetIAT += 4;
offsetHintTable +=4;
}
//Tracing.Log(Tracing.Debug, "");
}
//throw new BadImageFormatException("");
}
internal struct ImportDescriptor
{
internal ImportDescriptor(IoMemory mem, ref int offset)
{
if (offset + 20 > mem.Length) {
Error.AccessOutOfRange();
}
this.characteristics = mem.Read32Unchecked(offset + 0);
this.timeDateStamp = mem.Read32Unchecked(offset + 4);
this.forwarderChain = mem.Read32Unchecked(offset + 8);
this.name = mem.Read32Unchecked(offset + 12);
this.firstChunk = mem.Read32Unchecked(offset + 16);
offset += 20;
}
[Conditional("DEBUG")]
internal void DumpToStream()
{
Tracing.Log(Tracing.Debug, "{0:x8} Import Address Table", firstChunk);
Tracing.Log(Tracing.Debug, "{0:x8} Import Name Table", name);
Tracing.Log(Tracing.Debug, "{0:x8} Time date stamp", timeDateStamp);
Tracing.Log(Tracing.Debug, "{0:x8} Index of first forwarder reference",
forwarderChain);
}
// State
internal readonly uint characteristics;
internal readonly uint timeDateStamp;
internal readonly uint forwarderChain;
internal readonly uint name;
internal readonly uint firstChunk;
}
} // ImportTable class
}