1. 程序集和CIL:

  • 程序集是由.NET语言的编译器接受源代码文件产生的输出文件,通常分为 exe和dll两类,其中exe包含Main入口方法可以双击执行,dll则需要被其他程序集调用执行。
  • CIL(Common Intermediate Language): 公共中间语言,需要被编译成二进制机器码之后才会被计算机执行。

2. 程序集包含:

  • 程序的CIL
  • 程序中使用的类型的元数据(metadata)
  • 程序集清单
  • 一些资源集

程序被编译成程序集(exe为例)之后,双击运行,程序集会被加载入CLR(Common Language Runtime),执行下面的步骤:
  1.检查程序集的安全特性。
  2.进行内存分配。
  3.把程序集中的可执行代码发送给JIT(Just-in-Time)编译器,把其中的一部分代码编译成为本机代码。
其中,JIT只会编译被调用的部分CIL代码,并把编译的结果缓存起来,以备在后面的程序中的多次调用, 这保证了编译与运行的效率。

经过JIT编译之后的代码即是本机代码,本机代码最终被CPU执行。

我们通过一段简单的代码来加深理解:

1. 打开VS,用C#编写一段如下程序:

using System;

namespace ILTest
{
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello Fred");
Console.Read();
}
}
}

2. 使用 ILASM 工具将程序集反编译为IL(也可生成为ILTest.txt,后缀名不影响文本文件内容):

ildasm ILTest.exe /output:ILTest.IL

生成文本文件如下:

 //  Microsoft (R) .NET Framework IL Disassembler.  Version 4.6.1055.0

 // Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C E0 ) // .z\V.4..
.ver :::
}
.assembly ILTest
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 4E 6F 6E // ....T..WrapNonEx
6F 6E 6F ) // ceptionThrows. // --- 下列自定义特性会自动添加,不要取消注释 -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) .custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 4C ) // ...ILTest..
.custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = ( )
.custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( )
.custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( )
.custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 4C ) // ...ILTest..
.custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 6F C2 A9 // ...Copyright ..
) // 2018..
.custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = ( )
.custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = ( )
.custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 2D // ..$84f5b40e-91ae
2D 2D 2D // -4bfc-ab89-4a0ff
) // f6d081a..
.custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 2E 2E 2E ) // ...1.0.0.0..
.custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 1C 2E 4E 6D 6F 6B // ....NETFramework
2C 6F 6E 3D 2E 2E // ,Version=v4.6.1.
0E 6D 6F 6B // .T..FrameworkDis
6C 4E 6D 2E 4E // playName..NET Fr
6D 6F 6B 2E 2E ) // amework 4.6.1
.hash algorithm 0x00008004
.ver :::
}
.module ILTest.exe
// MVID: {90543B0E-D1B4-4FFF-9260-57E27FBC4F8B}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00020003 // ILONLY 32BITPREFERRED
// Image base: 0x00960000 // =============== CLASS MEMBERS DECLARATION =================== .class public auto ansi beforefieldinit ILTest.Program
extends [mscorlib]System.Object
{
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// 代码大小 19 (0x13)
.maxstack
IL_0000: nop
IL_0001: ldstr "Hello Fred"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: call int32 [mscorlib]System.Console::Read()
IL_0011: pop
IL_0012: ret
} // end of method Program::Main .method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// 代码大小 8 (0x8)
.maxstack
IL_0000: ldarg.
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Program::.ctor } // end of class ILTest.Program //

其中包含了程序的元数据,程序集清单和一些其他资源信息。

它们描述并组成了这段程序的类型信息,安全信息,版本信息以及对其它程序集的引用信息等,使得程序集拥有了自我描述的特性。其中,元数据是反射得以实现的重要条件。

除此之外还包含了IL代码,IL是经过编译器(这里是csc)编译产生的中间语言代码。

我们可以通过修改IL代码来控制程序的执行:

打开生成的文本文件,将Main方法中的输出字符串修改为"Hello Tommy":

使用ILASM工具将IL文件重新编译成ILTest2.exe:

双击运行exe结果如下:

也许你会觉得纳闷,为什么要把源代码先翻译成CIL再翻译成本机代码,而不是一步到位呢??

因为当程序被编译成程序集之后就脱离了语言的限制,例如C#程序可以调用VB生成的程序集。

程序集将语言的特殊性转换成了CIL这一通用且规范的概念,好比全国各个地方的人讲着不同的方言,彼此之间难以沟通,但是先将方言翻译成CIL这一普通话,便消除了语言差异带来的交流障碍。

除此之外,如果直接从高级语言编译成机器语言,由于不同厂商生产的CPU会读取不同的指令集,如果有x门高级语言,有y种读取不同指令集的CPU,那么需要有x*y种编译器去将不同的语言与CPU指令一一匹配。

有了CIL之后,我们只需x种编译器将高级语言转换成CIL,再经过y种编译器将CIL转换成二进制指令,一共仅需要x+y种不同的编译器。

原创文章,转载请注明出处。


注:①公共中间语言在一些地方也被叫做MSIL(Microsoft Intermediate Language)或IL(Intermediate Language)。本文中的CIL,IL,MSIL指的都是公共中间语言这一概念。

  ②ILASM和ILDASM工具详见:.Net Framework IL汇编与反汇编工具

.Net基础——程序集与CIL的更多相关文章

  1. .Net基础——程序集与CIL HttpClient封装方法 .Net Core 编码规范 C#中invoke和beginInvoke的使用 WebServeice 动态代理类

    .Net基础——程序集与CIL   1. 程序集和CIL: 程序集是由.NET语言的编译器接受源代码文件产生的输出文件,通常分为 exe和dll两类,其中exe包含Main入口方法可以双击执行,dll ...

  2. “前.NET Core时代”如何实现跨平台代码重用 ——程序集重用

    除了在源代码层面实现共享("前.NET Core时代"如何实现跨平台代码重用 --源文件重用)之外,我们还可以跨平台共享同一个程序集,这种独立于具体平台的"中性" ...

  3. C# 从CIL代码了解委托,匿名方法,Lambda 表达式和闭包本质

    前言 C# 3.0 引入了 Lambda 表达式,程序员们很快就开始习惯并爱上这种简洁并极具表达力的函数式编程特性. 本着知其然,还要知其所以然的学习态度,笔者不禁想到了几个问题. (1)匿名函数(匿 ...

  4. CIL中间语言浅谈

    CIL中间语言 通用中间语言(Common Intermediate Language,简称CIL)(曾经被称为微软中间语言或MSIL)是一种属于通用语言架构和.NET框架的低阶(lowest-lev ...

  5. 1、.NET平台概述

        本学习主要参考Andrew Troelsen的C#与.NET4高级程序设计,这小节主要述说以下几个东西:     宏观上讨论一下.net相关的主题:程序集.CIL(Common Interme ...

  6. .NET 框架 (转载)

    转载:http://www.tracefact.net/CLR-and-Framework/DotNet-Framework.aspx .NET框架 三年前写的<.NET之美>的第六章,现 ...

  7. NET基础课--NET的一些概念0

    0.CIL--公共中间语言 VC++:经过预编译,编译,汇编和链接生成本地可执行代码,支持它运行的是OS和本地cpu指令集. C#:    在.net框架下类似c#的高级语言经过编译生成的文件叫程序集 ...

  8. .NET框架(转)

    三年前写的<.NET之美>的第六章,现在书名改为了<.NET专题解析>. 本书是一本讲解.NET技术的书籍,目标读者群也是在.NET框架(.NET Framework)下进行开 ...

  9. .NET Core跨平台的奥秘[下篇]:全新的布局

    从本质上讲,按照CLI规范设计的.NET从其出生的那一刻就具有跨平台的基因,这与Java别无二致.由于采用了统一的中间语言,微软只需要针对不同的平台设计不同的虚拟机(运行时)就能弥合不同操作系统与处理 ...

随机推荐

  1. node02

    1.使用已有的知识实现一个简单的登录和注册的界面 请求有请求接口有请求页面的,我们需要加以区分 以下是客户端代码 <!DOCTYPE html> <html lang="e ...

  2. Linux系统下如何运行.sh文件

    在Linux系统下运行.sh文件有两种方法,比如我在root目录下有个datelog.sh文件 第一种(这种办法需要用chmod使得文件具备执行条件(x): chmod u+x datelog.sh) ...

  3. Vue v-for循环添加表单v-model不重复变动的注意事项!

    正常添加,v-model,修改所有循环会得到一样的结果! 定义一个users[]的数组,不要定义全局的user,而是要在Vue里面的方法里定义局部的变量添加.

  4. 分享使用tcb-router路由开发的云函数短信平台SDK

    上篇文章我们分享了如何使用纯的云函数开发的榛子短信短信(http://smsow.zhenzikj.com)SDK,由于微信对于未付费云函数个数的限制,这种方法存在缺陷,经过改进,使用tcb-rout ...

  5. 【设计经验】5、Verilog对数据进行四舍五入(round)与饱和(saturation)截位

    一.软件平台与硬件平台 软件平台: 操作系统:Windows 8.1 64-bit 开发套件:Vivado2015.4.2  Matlab2016a 仿真工具:Vivado自带仿真器 二.引言 在利用 ...

  6. Websocket实现即时通讯

    前言 关于我和WebSocket的缘:我从大二在计算机网络课上听老师讲过之后,第一次使用就到了毕业之后的第一份工作.直到最近换了工作,到了一家是含有IM社交聊天功能的app的时候,我觉得我现在可以谈谈 ...

  7. Javascript高级编程学习笔记(89)—— Canvas(6) 变换

    变换 通过上下文的变化,可以对图像进行处理后再将其绘制到画布上 当我们创建上下文时,会以默认值初始化变化矩阵,在默认的变换矩阵下所有处理都按描述直接绘制. 而当我们为上下文应用变换时,会导致使用不同的 ...

  8. CoCos2dx开发:更换导出的app名称和图标

    要处理的文件路径如下: 1.更换图标: drawable-hdpi.drawable-ldpi.drawable-mdpi三个文件夹分别代表大.小.中三个不同宽高的图片,为了应对手机的不同分辨率,来采 ...

  9. python之Django学习笔记(一)---搭建Django开发环境和一些基本命令

    1.Django下载 官方下载地址:https://www.djangoproject.com/download/ 2.Django安装 linux/windows安装方法相同,具体有以下俩种 pip ...

  10. 浅谈Java内存模型

    Java内存模型虽说是一个老生常谈的问题 ,也是大厂面试中绕不过的,甚至初级面试也会问到.但是真正要理解起来,还是相当困难,主要这个东西看不见,摸不着.网上已经有大量的博客,但是人家的终究是人家的,自 ...