对真正的力量一无所知。
程序执行基础概念
- 代码
- 翻译器
- 编译器
- 优化编译器
- 中间语言
- 执行
- 运行时系统
- 运行期
- 可执行文件
- 解释器
- 虚拟机
- 运行时系统
- 代码类型
- 源代码
- 目标代码
- 字节码
- 机器代码
- 微程序
CLR和 .Net Framework的关系
.NET框架 (.NET Framework) 是由微软开发,一个致力于敏捷软件开发(Agile software development)、快速应用开发(Rapid application development)、平台无关性和网络透明化的软件开发平台。.NET框架是以一种采用系统虚拟机运行的编程平台,以通用语言运行库(Common Language Runtime)为基础,支持多种语言(C#、VB.NET、C++、Python等)的开发。
由此可见,.Net Framework
是一个支持多种开发语言的开发平台,而这种多语言支持的特性又要以CLR为基础。CLR是一个.Net产品的运行环境。公共语言运行时(Common Language Runtime)
和 .Net Framework Library(FCL)
是.Net Framework
的两个主要组成部分。
什么是CLR?
通用语言运行平台(Common Language Runtime,简称CLR)是微软为他们的.NET的虚拟机所选用的名称。它是微软对通用语言架构(CLI)的实现版本,它定义了一个代码运行的环境。CLR运行一种称为通用中间语言的字节码,这个是微软的通用中间语言实现版本。
CLR
是一个类似JVM
的虚拟机, 为.NET的程序提供运行的环境.CLR
中运行的是一种字节码形态的Microsoft Intermediate Language,简称MSIL "微软中间语言"
.- 在.Net开发平台下,所有语言(C#、VB.NET、J#、C++/CLI)都会被编译为
MSIL
CLR做了什么?
- 将
IL
代码在运行时
编译成本机代码Native Code
.(JIT(just-in-time 运行时编译技术)
)本机代码Native Code,是面向特定CPU架构(x86,x64,ARM)的代码
CLR有哪些功能?
- 基类库支持 Base Class Library Support
- 内存管理 Memory Management
- 线程管理 Thread Management
- 垃圾回收 Garbage Collection
- 安全性 Security
- 类型检查 Type Checker
- 异常管理 Exception Manager
- 调试管理 Debug Engine
- 中间码(MSIL)到机器代码(Native)编译 (即时编译 (JIT just-in-time))
- 类别装载 Class Loader
CIL是什么?如何生成?
字节码现在已经官方地成为了CIL (通用中间语言(Common Intermediate Language,简称CIL)
- 在编译.NET编程语言时,源代码被翻译成
CIL
,再由CLR
负责运行 IL代码
有时又称为托管代码(managed code)
.IL代码
只是面向CLR的编译器
生成的其中一部分.
IL代码
IL
是与CPU无关的面向对象的机器语言.
非托管代码
- C++编译器默认生成包含
非托管代码
的EXE/DLL模块. - 并且在运行时操纵非托管数据(
native 内存
). - 不需要CLR就能运行.
- 只有C++编译器允许开发人员同时写
托管代码
和非托管代码
,并生成到同一模块中.
非托管代码和托管代码的互操作性
- 托管代码能调用DLL中的非托管函数:托管代码通过
P/invoke机制
调用DLL中的函数 - 托管代码可以使用现有的COM组件:详情可参考 .NET Framework SDK提供的TlbImp.exe
- 非托管代码可以使用托管类型:可用C#创建ActiveX控件或Shell扩展。详情可以参考 .NET Framework SDK提供的TlbExp.exe和RegAsm.exe工具。
面向CLR的编译器生成了什么?
微软已经为多种语言开发了基于CLR的编译器,这些语言包括:C++/CLI、C#、Visual Basic、F#、Iron Python、 Iron Ruby和IL。
- 不同语言的
编译器(Compiler)
就相当于一个这种语言的代码审查者(Checker),所做的工作就是检查源码语法是否正确,然后将源码编译成CLR
所需要的中间语言(IL)
. C#语言编译器
编译C#源码文件之后生成托管模块
.
C#编译器做的工作
- C#编译器(CSC.exe)默认将生成的托管模块转换成程序集,也就是生成的是含有清单的托管模块.
- 生成的是PE32(+)文件.
- 这个PE32(+)文件包含一个名为
清单(manifest)
的数据块.清单
也是元数据表
的集合.
托管模块是什么?由哪些组成?
- 无论是什么编译器,最后都是生成
托管模块
。 托管模块
是标准的32位的可移植执行体(PE32)文件,或者是64位的(PE32+)- 需要
CLR
才能运行。 - 其中托管模块中还包含完整的
元数据
.
CLR头
:包含使这个模块成为托管模块的信息。IL中间语言代码
:编译器编译源码的时候生成的代码。运行时,CLR
将IL
编译成本机CPU指令
元数据
:面向CLR的每个编译器要在每个托管模块中生成完整的元数据。元数据是一个数据表的集合。一些数据描述了模块中定义了什么,另一些描述了模块中引用了什么。由于编译器同时生成元数据和代码,把他们绑在一起,并嵌入最终生成的托管模块。所以元数据和他描述的代码不会失去同步。
-
可移植执行体PE文件的结构
元数据是什么?
元数据
简单的说是一个数据表的集合.- 主要包含两种表:
- 描述源代码中定义的类型和成员
- 描述源代码
引用的
类型和成员
- 元数据有多种用途
- 避免了编译时对原生C/C++数据头和库文件的需求. 因为IL代码中已经包含了全部信息.编译器直接读取元数据.
智能感知IntelliSense
技术解析元数据,提示帮助写代码.- CLR验证代码使用元数据确保只执行
类型安全
的操作. 元数据
允许将对象的字段序列化到内存块,发到另一台机器反序列化,重建对象状态.元数据
允许垃圾回收器跟踪对象的生存期.
CTS通用类型系统是什么?
通用类型系统 (Common Type System) 定义了运行期引擎如果使用程序中的数据类型,以及如何配置数据在存储器中的一种标准,依照此种标准所撰写的编程语言,都可以在同一个运行期引擎中使用,因此它是跨语言支持的重要部分,亦即匹配 CTS 规范的编程语言所撰写出的程序,都可以在 CLR 中使用。
CTS与CLI规格都是由微软所发展,当前已标准化为 ECMA 335 标准:“Common Language Infrastructure (CLI) Partitions I to VI.”,并且由 Microsoft 在 .NET Framework 中完全的实现。
由于类型是CLR的根本,微软专门为如何定义、使用和管理类型定义了一个正式的规范– 通用类型系统(Common Type System),即CTS。
事实上, 不根本不需要专门学习CTS规则本身,因为你选择的余元会采用你熟悉的方式公开它自己的语言语法
与类型规则
,通过编译来生成程序集时,会将语言特有的语法映射到IL—也就是CLR的语言
.
无论使用哪一种语言,类型的行为都完全一致,因为最终是由CLR的CTS来定义类型的行为.
类型可见性和访问规则
private
: 成员只能由同一个类(class)类型中的其他成员访问.protected
: 成员可以从派生类型访问,不管是不是在同一个程序集中.internal
: 成员可以由同一个程序集中的任何代码访问.protected internal
: 可以由任何程序集中的派生类型访问.public
: 成员可由任何程序集中的任何代码访问.
CLS通用语言规范是什么?
定义了一个最小公共集,任何编译器只有支持这个功能集,生成的类型才能兼容其他符合CLS、面向CLR的语言生成的组件
在开发类型和方法的时候,如果希望它们对外“可见”,能够从符合 CLS 的任何一种编程语言中访问,就必须遵守由 CLS 定义的规则。注意, 假如代码只是从定义(这些代码的)程序集的内部访问,CLS 规则就不适用了。
using System
//告诉编译器检查CLS相容性
[assembly:CLSCompliant(true)]
namespace SomeLibrary
{
//因为是public类,所以会显示警告
public sealed class SomeLibrarytype
{
//警告:SomeLibrary.SomeLibraryType.Abc()的返回类型不符合CLS
public UInt32 Abc(){return 0;}
//警告:仅大小写不同的标识符SomeLibrary.SomeLibraryType.abc()不符合CLS
public void abc(){ }
//不显示警告:该方法是私有的
private UInt32 ABC(){return 0;}
}
}
- 第一个警告是因为Abc方法返回了无符号整数,一些语言是不能操作无符号整数值的
- 第二个警告是因为该类型公开了两个public方法,这两个方法只是大小写和返回类型有别,VB和其他一些语言无法区分这两个方法。
关于window32位和64位版本
如果程序集文件只包含
类型安全
的托管代码
在32位和64位上都能运行.类型安全代码指访问被授权可以访问的内存位置.有的语言(尤其是C和C++)允许做一些非常“不正当”的事情。(直接访问内存的其他位置)
如果要使用
不安全的代码
, 需要用到/playform
命令行开关.如果指定了,则只能在对应平台上使用.默认anycpu
.- 可执行文件执行时,Windows会检查文件头,64位系统会通过
WoW64(Windows on Windows64)
技术运行32位应用程序.
- Windows启动托管应用程序的流程.
- 可在代码中查询
Environment.Is64BitOperatingSystem
属性,判断是否在64位系统上运行.Environment.Is64BitProcess
属性,判断是否在64位地址空间中运行
不安全的代码
C#编译器默认生成的是安全代码.
C#允许开发人员通过unsafe
关键字标记包含不安全代码的方法.
保护IL代码
- 混淆器
- 在非托管模块中实现想保密的算法, 利用CLR的互操作功能实现应用程序的托管和非托管部分之间的通讯.
一些微软提供的实用工具
- CSC.exe C#编译器:将多个托管模块和资源文件合并成程序集的工具.
- AL.exe 程序集链接器:将一组文件合并到程序集中.
- CLRVer.exe 列出机器上安装的所有CLR版本
-all
或者指定目标进程ID
列出正在允许的进程使用的CLR版本号.
- DumpBin.exe 和 CorFlags.exe:可以用来检查编译器生成的托管模块所嵌入的信息.
- ILAsm.exe IL汇编器
ILDasm.exe IL反汇编器
用IL反编译工具查看生成的IL代码。这里使用的是ILDasm.exe,当然,你也可以使用一些其他的工具,例如.Net Reflector、ILSpy等。
NGen.exe 本机代码生成器: 将程序集的所有IL代码编译成本机代码.并将本机代码保存到一个磁盘文件中.
- PEVerify.exe 检查一个程序集的所有方法,并报告其中含有不安全代码的方法.
- MPGO.exe 分析客户端应用程序启动需要哪些东西,会写入一个profile并嵌入程序集中.NGen能根据这个更好的优化生成本机映像.
- TlbImp.exe 托管代码可以使用现有的COM组件.
- TlbExp.exe和RegAsm.exe 非托管代码可以使用托管类型:可用C#创建ActiveX控件或Shell扩展。
- FusLogVw.exe 帮助你了解CLR在运行时与程序集的绑定.
- SN.exe 获取秘钥(生成公钥/私钥对),未提供显示私钥的功能.
- GACUtil.exe在GAC中安装一个强命名程序集