mono源码学习 运行程序
起因
在 使用vs2017编译mono ,一直没空闲时间,在写使用vs2017编译mono的时候,还在青岛出差,赶巧在五一在回家,青岛的工作算告一个段落了,五一之后,就在郑州出差,离家近了不少.这一段时间一直忙着新项目的事情.
c#测试程序代码,下面测试被调用的Program.exe
using System;
using System.Collections.Generic;
using System.Linq;
namespace qiufeng.tools
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
static void Main()
{
Console.WriteLine("hello mono");
Console.ReadLine();
}
}
}
进入Debug目录

因上次已经成功编译了.打开mono.sln,准备调试
选择mono项目.int
main (void)
{
TCHAR szFileName[MAX_PATH];
int argc;
gunichar2** argvw;
gchar** argv;
int i;
DWORD count;
argvw = CommandLineToArgvW (GetCommandLine (), &argc); //使用Windows API 获取参数
argv = g_new0 (gchar*, argc + 1);
for (i = 0; i < argc; i++)
argv [i] = g_utf16_to_utf8 (argvw [i], -1, NULL, NULL, NULL);
argv [argc] = NULL;
LocalFree (argvw);
if ((count = GetModuleFileName (NULL, szFileName, MAX_PATH)) != 0){
char *entry = g_utf16_to_utf8 (szFileName, count, NULL, NULL, NULL);
probe_embedded (entry, &argc, &argv);
}
return mono_main_with_options (argc, argv);
}
设置项目 调试参数
因代码较多,简单看一下调用过程
mono_defaults.corlib = mono_assembly_get_image (ass);
mono_defaults.object_class = mono_class_load_from_name (
mono_defaults.corlib, "System", "Object");
mono_defaults.void_class = mono_class_load_from_name (
mono_defaults.corlib, "System", "Void");
mono_defaults.boolean_class = mono_class_load_from_name (
mono_defaults.corlib, "System", "Boolean");
mono_defaults.byte_class = mono_class_load_from_name (
mono_defaults.corlib, "System", "Byte");
mono_defaults.sbyte_class = mono_class_load_from_name (
mono_defaults.corlib, "System", "SByte");
mono_defaults.int16_class = mono_class_load_from_name (
mono_defaults.corlib, "System", "Int16");
mono_defaults.uint16_class = mono_class_load_from_name (
mono_defaults.corlib, "System", "UInt16");
在这行代码,看到加载RunTimeType类型.
mono_defaults.runtimetype_class = mono_class_load_from_name (
mono_defaults.corlib, "System", "RuntimeType");
进入mono_class_load_from_name
MonoClass *
mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name)
{
ERROR_DECL (error);
MonoClass *klass;
klass = mono_class_from_name_checked (image, name_space, name, error);
if (!klass)
g_error ("Runtime critical type %s.%s not found", name_space, name);
mono_error_assertf_ok (error, "Could not load runtime critical type %s.%s", name_space, name);
return klass;
}
在mono_class_from_name_checked函数,没有找到RuntimeType这个Class.
在用ILSpy反编译mscorlib.dll程序集,的确没有在System命名空间下,找到Runtime这个class.推测是用这个mscorlib.dll版本旧的缘故.mono程序比较新.
所以就查看mono版本.
在编译Bcl.sln解决方案,没能编译成功,又不能.Net Framework 的程序集,只能重新下载mono安装包,只是下载的特别慢.今天无法确定这个问题.
下载Mono 5.12.0 Stable (5.12.0.226)版本.提取mscorlib.dll
下载Mono还是很慢的.可以使用这个工具进行提取. MSIExtractor , 替换mscorlib.dll
用mono-sgen.exe 调用Program.exe 看看,可以成功运行不.
发现版本还是没有对应好.使用自己编译mono-sgen.exe需要版本号为1051500003的corlib.dll,而在Mono 5.12.0.226提取的corlib.dll内部版本号是1051500002.
具体可以看代码,分别在appdomain.c和config.h这两个文件中.
在appdomain.c文件中. 在mono_check_corlib_version函数中校验corlib.dll内部版本号.
const char*
mono_check_corlib_version (void)
{
int version = mono_get_corlib_version (); /* 获取corlib.dll 版本号 */
if (version != MONO_CORLIB_VERSION)
return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
/* Check that the managed and unmanaged layout of MonoInternalThread matches */
guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
if (native_offset != managed_offset)
return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
return NULL;
}
在mono_get_corlib_version获取版本号.
static int
mono_get_corlib_version (void)
{
ERROR_DECL (error);
MonoClass *klass;
MonoClassField *field;
MonoObject *value;
//加载System命名空间下,Environment类
klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
mono_class_init (klass); //初始化Environment类
field = mono_class_get_field_from_name (klass, "mono_corlib_version"); //获取mono_corlib_version字段
if (!field)
return -1;
if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
return -1;
value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, error);
mono_error_assert_ok (error);
return *(gint32*)((gchar*)value + sizeof (MonoObject));
}
看过怎么获取版本号,还是回到mono_check_corlib_version函数中来
MONO_CORLIB_VERSION是宏, 在config.h文件中. 关于宏可以看看:了解c语言中的宏
既然确定是版本号问题.这里采用简单粗暴的方式.直接修改宏MONO_CORLIB_VERSION
重新编译mono项目.
后面就可以慢慢学习mono内部机制了.