.Net中的IL中间语言基本语法

更新时间:2023-07-08 15:02:27 阅读: 评论:0

.Net中的IL中间语⾔基本语法
⼀、前⾔
坨坨IL是什么?
Intermediate Language (IL)微软中间语⾔
C#代码编译过程?
C#源代码通过LC转为IL代码,IL主要包含⼀些元数据和中间语⾔指令;
JIT编译器把IL代码转为机器识别的机器代码。如下图举重比赛成语
语⾔编译器:⽆论是VB code还是C# code都会被Language Compiler转换为MSIL
MSIL的作⽤:MSIL包含⼀些元数据和中间语⾔指令
JIT编译器的作⽤:根据系统环境将MSIL中间语⾔指令转换为机器码
为什么ASP⽹站第⼀次运⾏时会较慢,⽽后⾯的执⾏速度则会相对快很多?
当你第⼀次运⾏开发的站点时,CLR会将MSIL通过JIT进⾏编译,最终转换为执⾏速度⾮常快的Native Code。这可以解释。为什么要了解IL代码?
如果想学好,IL是必须的基础,IL代码是运⾏的基础,当我们对运⾏结果有异议的时候,可以通过IL代码透过表⾯看本质;IL也是更好理解、认识CLR的基础;
⼤量的实例分析是以IL为基础的,所以了解IL,是读懂他⼈代码的必备基础,同时⾃⼰也可以获得潜移默化的提⾼;
⼆、如何把ILDasm导⼊到VS中
想要看IL代码需要使⽤ILDasm⼯具,⼯具⼀般在电脑的
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\
把ILDasm导⼊到VS⼯具中,使⽤⽅便,具体如下:⼯具 - > 外部⼯具
导⼊之后,vs⼯具⾥⾯就有ILDasm⼯具了。以后想看IL代码⽅便多了。
锡纸烫短发男
IL代码通过ILDasm反编译后(左图),ILDasm图标意义(右图)
CLR 和 Java VM 都是堆叠式虚拟机器(Stack-Bad VM),也就是說,它們的指令集(Instruction Set)都是採⽤堆叠运算的⽅式:执⾏时的资料都是先放在堆叠中,再进⾏运算。JavaVM 有約 200 個指令(Instruction),每個指令都是 1 byte 的 opcode(操作码),后⾯接不等数⽬的参数; CLR 有超過 220個指令,但是有些指令使⽤相同的 opcode,所以 opcode 的数⽬⽐指令数略少。特別注意, 的 opcode ⾧度並不固定,⼤部分的 opcode ⾧度是 1 byte,少部分是 2 byte。
下⾯是⼀個简单的 C# 原始码:
复制代码代码如下:
using System;
public class Test {
public static void Main(String[] args) {
int i=1;
int j=2;
int k=3;
int answer = i+j+k;
Console.WriteLine("i+j+k="+answer);
}
}
將此原始码编译之后,可以得到⼀個 EXE的程序。我們可以通过 ILDASM.EXE(图-0) 來反编译 EXE 以观察IL。我將 Main() 的 IL 反编译条列如下,這裡共有⼗⼋道IL 指令,有的指令(例如 ldstr 与 box)后⾯需要接参数,有的指令(例如 ldc.i4.1 與与add)后⾯不需要接参数。
图-0
ldc.i4.1
stloc.0
ldc.i4.2
stloc.1
ldc.i4.3
stloc.2
ldloc.0
ldloc.1
add
ldloc.2
add
stloc.3
ldstr      "i+j+k="
ldloc.3
box        [mscorlib]System.Int32
call      string [mscorlib]System.String::Concat(object, object)
call      void [mscorlib]System.Console::WriteLine(string)
ret
此程式执⾏時,关键的记忆体有三种,分別是:
1、Managed Heap:這是动态配置(Dynamic Allocation)的记忆体,由 Garbage Collector(GC)在执⾏時⾃動管理,整個Process 共⽤⼀個 Managed Heap。
2、Call Stack:這是由 CLR 在执⾏時⾃動管理的记忆体,每個 Thread 都有⾃⼰专属的 Call Stack。每呼叫⼀次 method,就会使得Call Stack 上多了⼀個 Record Frame;呼叫完毕之后,此 Record Frame 会被丢弃。⼀般來說,Record Frame 內记录着 method 参数(Parameter)、返回位址(Return Address)、以及区域变数(Local Variable)。Java VM 和 CLR 都是使⽤ 0, 1, 2…编号的⽅式來識別区别变数。霞帔是什么意思
3、Evaluation Stack:這是由 CLR 在执⾏時⾃動管理的记忆体,每個 Thread 都有⾃⼰专属的 Evaluation Stack。前⾯所謂的堆叠式虚拟机器,指的就是這個堆叠。
后⾯有⼀連串的⽰意图,⽤來解說在执⾏時此三种记忆体的变化。⾸先,在進⼊ Main() 之后,尚未执⾏任何指令之前,记忆体的狀況如图1 所⽰:
图1
中国英雄人物
接着要执⾏第⼀道指令 ldc.i4.1。此指令的意思是:在 Evaluation Stack 置⼊⼀個 4 byte 的常数,其值為 1。执⾏完此道指令之后,记忆体的变化如图2 所⽰:
ldc.i4.1:表⽰加载⼀个值为1到堆栈中,该条指令的语法结构是:
ldc.i4.number:ldc指令更加有效.它传输⼀个整型值-1以及0到8之间的整数给计算堆栈
图2
接着要执⾏第⼆道指令 stloc.0。此指令的意思是:从 Evaluation Stack 取出⼀個值,放到第 0 号变数(V0)中。這裡的第 0 号变数其实就是原始码中的i。执⾏完此道指令之后,记忆体的变化如图3 所⽰:
图3
后⾯的第三道指令和第五道指令雷同於第⼀道指令,且第四道指令和第六道指令雷同於第⼆道指令。為了节省篇幅,我不在此⼀⼀贅述。提醒⼤家第 1 号变数(V1)其实就是原始码中的 j,且第 2 号变数(V2)其实就是源码中的 k。图4~7 分別是执⾏完第三~六道指令之后,记忆体的变化图:
图4
图5
图6
图7
接着要执⾏第七道指令 ldloc.0 以及第⼋道指令 ldloc.1:分別將 V0(也就是 i)和 V1(也就是 j)的
值放到 Evaluation Stack,這是相加前的准备動作。图8 與图9 分別是执⾏完第七、第⼋道指令之后,记忆体的变化图:
图8
图9
接着要执⾏第九道指令 add。此指令的意思是:从 Evaluation Stack 取出兩個值(也就是 i 和 j),相加之后將結果放回
Evaluation Stack 中。执⾏完此道指令之后,记忆体的变化如图10 所⽰:
图10
接着要执⾏第⼗道指令 ldloc.2。此指令的意思是:分別將 V2(也就是 k)的值放到 Evaluation Stack,
這是相加前的准备動作。执⾏完此道指令之后,记忆体的变化如图11 所⽰:
图11
接着要执⾏第⼗⼀道指令 add。从 Evaluation Stack 取出兩個值,相加之后將結果放回 Evaluation Stack 中,此為 i+j+k 的值。执⾏完此道指令之后,记忆体的变化如图12 所⽰:
图12
股票机构接着要执⾏第⼗⼆道指令 stloc.3。从 Evaluation Stack 取出⼀個值,放到第 3 号变数(V3)中。這裡的第3号变数其实就是原始码中的answer。执⾏完此道指令之后,记忆体的变化如图13 所⽰:绿怎么组词
图13
接着要执⾏第⼗三道指令 ldstr "i+j+k="。此指令的意思是:將 "i+j+k=" 的 Reference 放進 Evaluation
Stack。执⾏完此道指令之后,记忆体的变化如图14 所⽰:
tplink网址
图14
接着要执⾏第⼗四道指令 ldloc.3。將 V3 的值放進 Evaluation Stack。执⾏完此道指令之后,记忆体的变化如图15 所⽰:
图15
接着要执⾏第⼗五道指令 box [mscorlib]System.Int32,从此处可以看出,int到string实际是进⾏了装箱操作的,所以会有性能损失,可以在以后的编码中减少装箱操作来提⾼性能。此指令的意思是:从 Evaluation Stack 中取出⼀個值,將此 Value Type 包裝(box)成為Reference Type。执⾏完此道指令之后,记忆体的变化如图16 所⽰:
图16
接着要执⾏第⼗六道指令 call string [mscorlib] System.String::Concat(object, object)。此指令的意思是:从 Evaluation Stack 中取出兩個值,此⼆值皆為 Reference Type,下⾯的值当作第⼀個参数,上⾯的值当作第⼆個参数,呼叫 mscorlib.dll 所提供的
System.String.Concat() method 來將此⼆参数進⾏字串接合(String Concatenation),將接合出來的新字串放在 Managed Heap,將其 Reference 放進 Evaluation Stack。值得注意的是:由於 System.String.Concat() 是 static method,所以此處使⽤的指令是call,⽽⾮ callvirt(呼叫虚拟)。执⾏完此道指令之后,记忆体的变化如图17 所⽰:
图17
請注意:此時 Managed Heap 中的 Int32(6) 以及 String("i+j+k=") 已經不再被參考到,所以变成垃圾,等待 GC 的回收。
接着要执⾏第⼗七道指令 call void [mscorlib] System.Console::WriteLine(string)。此指令的意思是:从 Evaluation Stack 中取出⼀個值,此值為 Reference Type,將此值当作参数,呼叫 mscorlib.dll 所提供的 System.Console.WriteLine() method 來將此字串显⽰在 Console 視窗上。System.Console.WriteLine() 也是 static method。执⾏完此道指令之后,记忆体的变化如图18 所⽰:
图18
接着要执⾏第⼗⼋道指令 ret。此指令的意思是:結束此次呼叫(也就是 Main 的呼叫)。此時会檢查 Evaluation Stack 內剩下的資料,由於 Main() 宣告不需要传出值(void),所以 Evaluation Stack 內必須是空的,本范例符合這樣的情況,所以此時可以順利結束此次呼叫。⽽ Main 的呼叫⼀結束,程式也随之結束。执⾏完此道指令之后(且在程式結束前),记忆体的变化如图19 所⽰:
图19
通过此范例,读者应该可以对于 IL 有最基本的认识。对 IL 感兴趣的读者应该⾃⾏阅读 Serge Lidin 所著的《Inside Microsoft IL Asmbler》(Microsoft Press 出版)。我认为:熟知 IL 每道指令的作⽤,是 程式員必备的知识。 程式員可以不会⽤ IL Asmbly 写程式,但是⾄少要看得懂 ILDASM 反编译出來的 IL 組合码。

本文发布于:2023-07-08 15:02:27,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/1073107.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:指令   代码   记忆体   机器   参数   变数
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图