dotnet学习笔记二 - 运行.net程序的秘密
2003-07-12 10:45
411 查看
.NET Framework给我们提供了良好的开发平台。有很好的类库,可以跨语言,跨平台等等。但是他的内部实现细节是怎样的呢?.NET编译出来的exe文件并不是机器码,它是怎样和CLR结合起来的呢?下面就让我们揭开这个小秘密。
首先做一个简单的.NET应用,把它编译成EXE文件。然后用Visual Studio 6.0带的工具Depends把它打开。如下图:
这里可以看到一个很奇怪的现象,我的.net应用程序只直接依赖于一个dll – MSCOREE.DLL。而且这个DLL输出的这么多函数中也只用到了一个_CorExeMain。我的这个APPENDLINE.EXE中还用到了自己做的一个.NET组件,在这里也看不到。
再让我们借助一些PE察看工具来分析一下这个EXE文件。这一步得到的结果是什么呢?在这个PE文件的入口函数上可以看到一条唯一的汇编语句:
JMP DS:_CorExeMain
经过上面的步骤,我们可以明确的断定所有的.net编译后的EXE文件一旦运行,就执行MSCOREE.DLL输出的一个函数_CorExeMain。而在开发过程中我们使用到的一些外部组件、控件由于是被.net编译器编译成了中间代码,在Depends中是无法看到的,所有使用外部组件的过程全部由CLR处理。
幸运的是微软这次公布了一个CLI实现的代码,我们可以看个究竟。我下载的代码中没有找到_CorExeMain,只找到了一个_CorExeMain2。参数有5个:
PBYTE pUnmappedPE, // -> memory mapped code
DWORD cUnmappedPE, // Size of memory mapped code
LPWSTR pImageNameIn, // -> Executable Name
LPWSTR pLoadersFileName, // -> Loaders Name
LPWSTR pCmdLine
一目了然,pUnmappedPE和cUnmappedPE就是.net编译后的中间代码的内存缓冲和长度。pImageNameIn就是这个EXE的名字,pLoadersFileName是载入者的名字,pCmdLine就是命令参数。有了这几个参数我们就可以猜到.net将中间代码编译后放入到PE文件中,再加入一段代码直接执行MSCOREE.DLL的_CorExeMain,参数就是中间代码的内存指针。JIT就把这段中间代码编译成机器代码执行。
_CorExeMain2代码不长,简单总结一些,做了如下的5步工作:
1. 验证签名。
2. 初始化CLR环境
3. 创建了一个代表EXE文件的PEFile对象
4. 使用SystemDomain的静态方法执行这个PEFile。
5. 执行后,做一些清除工作,退出。
很明显,上面5个步骤里最重要,最关键的就是第4步了,究竟做了什么呢?有兴趣的朋友可以去看微软的CLI代码,我在以后的文章中也会进一步分析。
首先做一个简单的.NET应用,把它编译成EXE文件。然后用Visual Studio 6.0带的工具Depends把它打开。如下图:
这里可以看到一个很奇怪的现象,我的.net应用程序只直接依赖于一个dll – MSCOREE.DLL。而且这个DLL输出的这么多函数中也只用到了一个_CorExeMain。我的这个APPENDLINE.EXE中还用到了自己做的一个.NET组件,在这里也看不到。
再让我们借助一些PE察看工具来分析一下这个EXE文件。这一步得到的结果是什么呢?在这个PE文件的入口函数上可以看到一条唯一的汇编语句:
JMP DS:_CorExeMain
经过上面的步骤,我们可以明确的断定所有的.net编译后的EXE文件一旦运行,就执行MSCOREE.DLL输出的一个函数_CorExeMain。而在开发过程中我们使用到的一些外部组件、控件由于是被.net编译器编译成了中间代码,在Depends中是无法看到的,所有使用外部组件的过程全部由CLR处理。
幸运的是微软这次公布了一个CLI实现的代码,我们可以看个究竟。我下载的代码中没有找到_CorExeMain,只找到了一个_CorExeMain2。参数有5个:
PBYTE pUnmappedPE, // -> memory mapped code
DWORD cUnmappedPE, // Size of memory mapped code
LPWSTR pImageNameIn, // -> Executable Name
LPWSTR pLoadersFileName, // -> Loaders Name
LPWSTR pCmdLine
一目了然,pUnmappedPE和cUnmappedPE就是.net编译后的中间代码的内存缓冲和长度。pImageNameIn就是这个EXE的名字,pLoadersFileName是载入者的名字,pCmdLine就是命令参数。有了这几个参数我们就可以猜到.net将中间代码编译后放入到PE文件中,再加入一段代码直接执行MSCOREE.DLL的_CorExeMain,参数就是中间代码的内存指针。JIT就把这段中间代码编译成机器代码执行。
_CorExeMain2代码不长,简单总结一些,做了如下的5步工作:
1. 验证签名。
2. 初始化CLR环境
3. 创建了一个代表EXE文件的PEFile对象
4. 使用SystemDomain的静态方法执行这个PEFile。
5. 执行后,做一些清除工作,退出。
很明显,上面5个步骤里最重要,最关键的就是第4步了,究竟做了什么呢?有兴趣的朋友可以去看微软的CLI代码,我在以后的文章中也会进一步分析。
相关文章推荐
- dotnet学习笔记二 - 运行.net程序的秘密
- dotNet学习笔记-浅谈.Net的事件代理
- MonoDroid学习笔记(十三)—— 自制任务管理器,获取正在运行的程序与服务
- JVM 学习笔记-java程序编译和运行的过程
- Redis学习笔记3-Redis5个可运行程序命令的使用
- 我的Cocos2d-x学习笔记(一)Windows下程序如何开始运行
- maven学习笔记:命令行模式创建java_spark项目并运行示例程序
- 【C++学习笔记】C++控制台程序隐藏界面运行的方法
- Spark学习笔记7-在eclipse里用scala编写spark程序(单机和集群运行)
- 【黑马程序员】C语言学习笔记之第一个C程序及编译运行(一)
- Effective C#学习笔记:适当使用.NET运行时诊断
- Java基础学习记录笔记(运行环境+程序编写)
- python学习笔记-记录程序运行时间
- 我的Cocos2d-x学习笔记(一)Windows下程序如何开始运行
- MFC视频教程(孙鑫)学习笔记1-Windows程序内部运行原理
- 【Qt学习笔记】在Qt编译好之后运行程序时提示:程序异常结束。The process was ended forcefully. ....exe crashed.
- [导入]dotNet学习笔记-浅谈.Net的事件代理
- apk程序运行过程图(学习笔记)
- VC学习笔记: 1. Window程序内部运行机制
- vc学习笔记之windows程序内部运行机制