Missing Members
To support
mcs I previously added some limited support for missing members. This has
now been extended substantially to allow full fidelity reading/writing of
assemblies. Normally IKVM.Reflection behaves like System.Reflection in how it
tries to resolve member and assembly references, but now it is possible to
customize this to enable reading a module without resolving any dependencies.
Roundtripping
To test this version of IKVM.Reflection, I've roundtripped 1758 (non-C++/CLI) modules from the
CLR GAC plus the Mono 2.10 directories on my system. Roundtripping here means
reading in the module and writing it back out. The original module and resulting
module are both disassembled with ildasm and the resulting IL files compared
(after going through two dozen regex replacements to filter out some trivial
differences).
The code I used for the roundtripping is an (d)evolution of the linker prototype
code. It is available here.
Note that it is very far from production quality, but does make for a good case
study in how to use the advanced IKVM.Reflection functionality.
Unmanaged Exports
A cool CLR feature is the ability to export static managed methods as unmanaged DLL exports. The only languages that support this, AFAIK, are C++/CLI and ILASM, but now you easily do it with IKVM.Reflection as well. Below is a Hello World example. Note that while this example exports a global method, you can export any static method.
Note also that the string passed in must be ASCII, may be null and that the
ordinal must be a 16 bit value that is unique (in the scope of the module).
using IKVM.Reflection;
using IKVM.Reflection.Emit;
class Demo
{
static void Main()
{
var universe = new Universe();
var name = new AssemblyName("ExportDemo");
var ab = universe.DefineDynamicAssembly(name, AssemblyBuilderAccess.Save);
var modb = ab.DefineDynamicModule("ExportDemo", "ExportDemo.dll");
var mb = modb.DefineGlobalMethod("HelloWorld", MethodAttributes.Static, null, null);
var ilgen = mb.GetILGenerator();
ilgen.EmitWriteLine("Hello World");
ilgen.Emit(OpCodes.Ret);
mb.__AddUnmanagedExport("HelloWorld", 1);
modb.CreateGlobalFunctions();
ab.Save("ExportDemo.dll", PortableExecutableKinds.Required32Bit, ImageFileMachine.I386);
}
}
The resulting ExportDemo.dll can now be called from native code in the usual ways, for example:
typedef void (__stdcall *
PROC)();
HMODULE hmod = LoadLibrary(L"ExportDemo.dll");
PROC proc = (PROC)GetProcAddress(hmod, "HelloWorld");
proc();
Creating unmanaged exports is supported for I386 and AMD64. Itanium (IA64) support has not been implemented.
What's Missing
It should now be possible to write an ILDASM clone using IKVM.Reflection, however
to be able to write ILASM there are still a couple of things missing:
- Function pointers (used by C++/CLI).
- API to create missing type.
- Preserving interleaved modopt/modreq ordering.
- Various C++/CLI quirks (e.g. custom modifiers on local variable signatures).
- Ability to set file alignment.
Changes:
- Added support for using missing members in emitted assembly.
- If you build IKVM.Reflection with the STABLE_SORT symbol defined, all metadata
sorting will be done in a stable way, thus retaining the order in which the
items are defined.
- When target is .NET 1.x adjust the type name writing algorithm to match the
quirks of the Microsoft .NET 1.x metadata writer.
- Fixed Type.StructLayoutAttribute to be (bug) compatible with .NET.
- Don't map unspecified pinvoke calling convention to winapi.
- Don't needlessly read the contents of a resource module.
- Automatically emit .NET 1.x compatible declarative security when appropriate.
- Added support for having multiple mscorlib versions in a universe.
- Added Assembly.__AssemblyFlags property.
- Added CustomAttributeBuilder.__FromBlob().
- Added CustomAttributeBuilder.__MakeTypedArgument() to make it possible to box an
enum or create an array of an enum type in a location typed as object.
- Added ILGenerator.__MaxStackSize property.
- Added EventInfo.__GetMethods().
- Added FieldBuilder.__SetReadOnlyDataAndRVA().
- Added FieldInfo.__FieldRVA property.
- Added FieldInfo.__GetFieldOnTypeDefinition().
- Added ManifestResourceInfo.__ResourceAttributes property.
- Added MethodBase.__GetMethodOnTypeDefinition().
- Added MethodBuilder.__AddUnmanagedExport().
- Added MethodBuilder.__SetCallingConvention().
- Added Module.__ImageBase property.
- Added Module.__GetCustomAttributesFor().
- Added Module.__GetExportedTypes().
- Added Module.__GetReferencedModules().
- Added Module.__GetReferencedTypes().
- Added Module.__GetSectionInfo().
- Added Module.__ModuleHash property (for resource modules).
- Added Module.__ReadDataFromRVA().
- Added Module.__ResolveReferencedAssemblies().
- Added Module.__StackReserve property.
- Added ModuleBuilder.__AddModule().
- Added ModuleBuilder.__AddModuleReference().
- Added ModuleBuilder.__AddAssemblyReference(AssemblyName, Assembly) overload.
- Added ModuleBuilder.__AddUnmanagedExportStub().
- Added ModuleBuilder.__AddVTableFixups().
- Added ModuleBuilder.__SetCustomAttributeFor().
- Added ModuleBuilder.__SetModuleVersionId().
- Added ModuleBuilder.__SetStackReserve().
- Added PropertyInfo.__CallingConvention property.
- Added Type.__GetLayout().
- Added Type.__CreateMissingMethod(), Type.__CreateMissingField() and
MissingGenericMethodBuilder.
- Added Type.__GetArraySizes() and Type.__GetArrayLowerBounds().
- Added Type.__MakeArrayType() overload that takes sizes and lower bounds.
- Added TypeBuilder.__SetLayout().
Binary available here: IKVM.Reflection-0.47.4098.zip