网站首页 > 资源文章 正文
起因
结束了一年多的出差,回到了公司上班,最近一直在想着博客的改版,连博客也没怎么写了,正好这两天不怎么忙,便想起看看mono的源码,至于为什么看mono源码而不是选择.Net Core源码,Mono源码是纯c的,看起来更容易一些,不需要c++的知识.其实.Net Core源码直接用VS调试还是很方便的.不过source insight对c++支持的不是很好.阅读Mono源码使用source insight还是很方便的.
在Github看Mono已经把zlib源码加入到Mono源码,在编译源码的时候,不用手动链接zlib静态库了
阅读源码从mini/main.c开始.
函数名以g_开头的,是eglib封装的工具函数.主要用于简化操作.如g_new0/g_free
屏蔽系统API差异
这里以mono_pagesize为例.先认识Windows的源码.
//获取系统页大小
int mono_pagesize(void)
{
SYSTEM_INFO info;
static int saved_pagesize = 0; //saved_pagesize 使用static声明
if (saved_pagesize)
return saved_pagesize; //第二次调用mono_pagesize函数,直接返回saved_pagesize
GetSystemInfo(&info); //第一次调用mono_pagesize函数,调用GetSystemInfo系统函数
saved_pagesize = info.dwPageSize; //将获取到系统页大小赋值给saved_pagesize
return saved_pagesize;
}
Linux源码:
int mono_pagesize (void)
{
static int saved_pagesize = 0;
if (saved_pagesize)
return saved_pagesize;
// Prefer sysconf () as it's signal safe.
#if defined (HAVE_SYSCONF) && defined (_SC_PAGESIZE) //判断是否有sysconf系统函数
saved_pagesize = sysconf (_SC_PAGESIZE);
#else
saved_pagesize = getpagesize (); //不支持sysconf系统函数
#endif
return saved_pagesize;
}
根据宏判断是否支持sysconf系统调用.
其实Windows默认的页大小也是4096,这里没有截取Windows系统页大小.
mono_main 主函数
main.c
int main(void) //Windows 通过CommandLineToArgvW获取参数
int main(int argc, char* argv[]) //Linux或Unix及Mac
int mono_main_with_options(argc, argv)
driver.c
//主函数
int mono_main(argc, argv)
coree.c
//加载mscoree.dll,Windows独有的, c# exe(Windows下)执行的时候通过ntdll->mscoree.dll->mscorlib.dll
void mono_load_coree(const char* exe_file_name)
mono-config.c
//设置lib和etc,具体可以看 https://www.qiufengblog.com/articles/mono-config.html
void mono_config_parse (const char *filename)
mini-runtime.c
//mono CLR运行时初始化,返回MonoDomain
MonoDomain* mini_init(const char* filename, const char* runtime_version)
dirver.c
static void main_thread_handler (gpointer user_data)
domain.c
//根据domain,加载程序集(并没有执行)
MonoAssembly* mono_domain_assembly_open(MonoDomain* domain, const char* name)
driver.c
//根据domain,执行程序集
int mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
mini-runtime.c
//清理domain,释放资源
void mini_cleanup(MonoDomain* domain)
简化之后的代码:
//函数原型
MonoDomain* mini_init(const char* filename, const char* runtime_version);
//mono 主函数
//函数去除很多代码
int mono_main(int argc, char* argv[])
{
//
//去除解析参数处理,后面用到单独说明
//
MonoThreadArgs main_args;
int i;
int mixed_mode = FALSE;
if (mixed_mode)
{
mono_load_coree(argv[i]);
}
mono_config_parse(config_file);
mono_set_defaults(mini_verbose_level, opt);
MonoDomain* domain = mini_init(argv[i], forced_version);
main_args.domain = domain;
main_args.file = aname;
main_args.argc = argc - i;
main_args.argv = argv + i;
main_args.opts = opt;
main_args.aot_options = aot_options;
main_thread_handler(&main_args);
mono_thread_manage();
mini_cleanup(domain);
i = mono_environment_exitcode_get();
return i;
}
MonoDomain* mini_init(const char* filename, const char* runtime_version)
{
//1.初始化很多东西
//2.注册回调函数
MonoDomain* domain;
//通过mono program.exe 没有指定--runtime=v4.0.30319 ,runtime_version不为真的
if (runtime_version)
{
domain = mono_init_version(filename, runtime_version);
}
else
{
domain = mono_init_from_assembly(filename, filename);
}
//还要处理很多东西
//xxx
//xxx
return domain;
}
在fixed模式下,mono如何加载mscoree.dll
基于mono_load_coree函数源码,改动而来,主要是动手练习一下.也顺便一些系统函数的调用.
typedef unsigned __int16 gunichar;
//1. 根据GetSystemDirectory系统函数,获取系统目录
//2. 将获取到系统目录和mscoree.dll进行拼接
//3. 通过LoadLibrary加载到内存
HMODULE load_coree()
{
UINT len = GetSystemDirectory(NULL, 0);
printf("%d\n", len);
printf("unsigned __int16 size:%d\n", sizeof(gunichar));
gunichar* dir = calloc(1, (len + 12) * sizeof(gunichar));
GetSystemDirectory(dir, len);
//打印系统路径
printf("system dir:%ls\n", dir);
if (dir[len - 1] != L'\\')
{
dir[len - 1] = L'\\';
}
//拼接dll路径
memcpy(&dir[len], L"mscoree.dll", 12 * sizeof(gunichar));
printf("dir :%ls\n", dir);
//LoadLibrary (将dll加载内存中,将文件的起始位置返回)
//LoadLibrary和FreeLibrary 配对使用,
HMODULE module = LoadLibraryW(dir);
return module;
}
//验证该句柄是否位pe文件的起始位置
int validate_pe(HMODULE hModule)
{
PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)hModule;
DWORD magic = dos_header->e_magic;
char* a = (char*)&magic;
printf("%s\n", a);
if (magic == IMAGE_DOS_SIGNATURE)
{
printf("pe dos header Signature:MZ\n");
}
PIMAGE_NT_HEADERS nt_header = (PIMAGE_NT_HEADERS)((char*)dos_header + dos_header->e_lfanew);
if (nt_header->Signature == IMAGE_NT_SIGNATURE)
{
printf("pe dos header Signature:PE\n");
}
return 0;
}
要不是看了源码,怎么也没想到LoadLibrary返回的HMODULE,竟然是文件在内存中的起始地址.
这是2019年所写,不是学Mono写的第一篇,只是Mono代码一直改进,现在Mono源码已经和.Net源码放在一起了,今天本想在本地用VS编译Mono的,编译失败了,现在编译Mono源码需要使用CMake生成VS解决方案.
在2021年,Mono侧重于移动端和Blazor(WebAssmebly), .Net Core侧重于服务端(说Web也不合适,因为Blazor客户端是用Mono)
猜你喜欢
- 2024-09-21 记一次 .NET某半导体CIM系统 崩溃分析
- 2024-09-21 不要把异常当做业务逻辑,这性能可能你无法承受
- 2024-09-21 使用最新的代码重用攻击绕过执行流保护(二)
- 2024-09-21 net高级调试--应用程序域(net高级程序员)
- 2024-09-21 精通c# -- .NET之道(c#语言从入门到精通)
- 2024-09-21 使用 MiFlash 刷机中出错的解决办法,喜欢自己刷机可以参考一下
- 2024-09-21 spdlog与Windows事件日志实操(windows日志事件id1000)
- 2024-09-21 除 Win11 外,微软刚发布的 KB5013942 也同样会导致 Win10 出错
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- 电脑显示器花屏 (79)
- 403 forbidden (65)
- linux怎么查看系统版本 (54)
- 补码运算 (63)
- 缓存服务器 (61)
- 定时重启 (59)
- plsql developer (73)
- 对话框打开时命令无法执行 (61)
- excel数据透视表 (72)
- oracle认证 (56)
- 网页不能复制 (84)
- photoshop外挂滤镜 (58)
- 网页无法复制粘贴 (55)
- vmware workstation 7 1 3 (78)
- jdk 64位下载 (65)
- phpstudy 2013 (66)
- 卡通形象生成 (55)
- psd模板免费下载 (67)
- shift (58)
- localhost打不开 (58)
- 检测代理服务器设置 (55)
- frequency (66)
- indesign教程 (55)
- 运行命令大全 (61)
- ping exe (64)
本文暂时没有评论,来添加一个吧(●'◡'●)