对真正的力量一无所知。

程序执行基础概念

  • 代码
  • 翻译器
    • 编译器
    • 优化编译器
  • 中间语言
  • 执行
    • 运行时系统
      • 运行期
    • 可执行文件
    • 解释器
    • 虚拟机

  • 代码类型
    • 源代码
    • 目标代码
    • 字节码
    • 机器代码
    • 微程序

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运行一种称为通用中间语言的字节码,这个是微软的通用中间语言实现版本。

  1. CLR是一个类似JVM的虚拟机, 为.NET的程序提供运行的环境.
  2. CLR中运行的是一种字节码形态的Microsoft Intermediate Language,简称MSIL "微软中间语言".
  3. 在.Net开发平台下,所有语言(C#、VB.NET、J#、C++/CLI)都会被编译为MSIL

CLR做了什么?

  1. 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)

  1. 在编译.NET编程语言时,源代码被翻译成CIL,再由CLR负责运行
  2. IL代码有时又称为托管代码(managed code).
  3. IL代码只是面向CLR的编译器生成的其中一部分.

IL代码

  1. IL是与CPU无关的面向对象的机器语言.

非托管代码

  1. C++编译器默认生成包含非托管代码的EXE/DLL模块.
  2. 并且在运行时操纵非托管数据(native 内存).
  3. 不需要CLR就能运行.
  4. 只有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。

  1. 不同语言的编译器(Compiler)就相当于一个这种语言的代码审查者(Checker),所做的工作就是检查源码语法是否正确,然后将源码编译成CLR所需要的中间语言(IL).
  2. C#语言编译器编译C#源码文件之后生成托管模块.

C#编译器做的工作

  1. C#编译器(CSC.exe)默认将生成的托管模块转换成程序集,也就是生成的是含有清单的托管模块.
  2. 生成的是PE32(+)文件.
  3. 这个PE32(+)文件包含一个名为清单(manifest)的数据块. 清单也是元数据表的集合.

托管模块是什么?由哪些组成?

  1. 无论是什么编译器,最后都是生成托管模块
  2. 托管模块是标准的32位的可移植执行体(PE32)文件,或者是64位的(PE32+)
  3. 需要CLR才能运行。
  4. 其中托管模块中还包含完整的元数据.

  • CLR头:包含使这个模块成为托管模块的信息。
  • IL中间语言代码:编译器编译源码的时候生成的代码。运行时,CLRIL编译成本机CPU指令
  • 元数据:面向CLR的每个编译器要在每个托管模块中生成完整的元数据。元数据是一个数据表的集合。一些数据描述了模块中定义了什么,另一些描述了模块中引用了什么。由于编译器同时生成元数据和代码,把他们绑在一起,并嵌入最终生成的托管模块。所以元数据和他描述的代码不会失去同步。
    -

可移植执行体PE文件的结构

元数据是什么?

  1. 元数据简单的说是一个数据表的集合.
  2. 主要包含两种表:
    • 描述源代码中定义的类型和成员
    • 描述源代码引用的类型和成员
  3. 元数据有多种用途
    • 避免了编译时对原生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位版本

  1. 如果程序集文件只包含类型安全托管代码在32位和64位上都能运行.

    类型安全代码指访问被授权可以访问的内存位置.有的语言(尤其是C和C++)允许做一些非常“不正当”的事情。(直接访问内存的其他位置)

  2. 如果要使用不安全的代码, 需要用到/playform命令行开关.如果指定了,则只能在对应平台上使用.默认anycpu.

  3. 可执行文件执行时,Windows会检查文件头,64位系统会通过WoW64(Windows on Windows64)技术运行32位应用程序.

  1. Windows启动托管应用程序的流程.

  1. 可在代码中查询
    • Environment.Is64BitOperatingSystem属性,判断是否在64位系统上运行.
    • Environment.Is64BitProcess属性,判断是否在64位地址空间中运行

不安全的代码

C#编译器默认生成的是安全代码.

C#允许开发人员通过unsafe关键字标记包含不安全代码的方法.

保护IL代码

  1. 混淆器
  2. 在非托管模块中实现想保密的算法, 利用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中安装一个强命名程序集