CLI里面的秘密……总体介绍,以及CIL (转载)
2005-03-25 14:17
253 查看
CLI里面的秘密……(一)总体介绍,以及CIL
不知道大家对于Common Language Infrastructure有什么认识呢?“噢!天啊!看到那么几个英文我就头痛了!”如果真是这样,那么你就没有办法继续看下去了,因为这里面的东西基本上只能够找到英文的资料。实际上这个看似很深奥的东西并没有你想象的那么难,当然,也不是一个简单的东西。关于这方面的资料其实非常好找,虽然数量不多,但是却是非常之实用,就在你VS安装的目录里面。假如你安装的是VS2003,装在了E:/VS.NET 2003这个目录里面,那么相关的资料就在E:/VS.NET 2003/SDK/v1.1/Tool Developers Guide/里面。这个目录下面有两个子目录,一个是docs,全部都是文档,另外一个是Samples,全部都是例子,不过所有的东西都是英文的。
什么是CLI呢?中文应该翻译成“公共语言底层结构”。CLI应该包括CIL和CLR:CIL是Common Intermediate Language,中文是“公共中间语言”,也就是那个“IL汇编”;CLR是Common Language Runtime,中文是“公共语言运行库”。除了这些之外,任何一个.NET语言还收到CLS的约束,CLS——Common Language Specification,公共语言规格说明书,这个东西主要用于约束所有.NET语言,使得他们能够互相协作,不存在某种语言产生的代码不能够被另外一种语言所支持。
如果你真的有兴趣看看我说的那个目录里面的文档,那么你会发现几乎你所能够想得到的底层的东西都有了,包括CIL的语法和二进制代码,CLI可执行程序文件结构,怎么写一个调试器(Debugger),分析器(Profiler),编译器(Compiler)……什么?你不相信连编译器都有了?在 E:/VS.NET 2003/SDK/v1.1/Tool Developers Guide/Samples里面有三个编译器的文件!一个Lisp.NET,一个MyC,一个Simple Managed C。还有更多的例子呢,诸公自便。
今天首先讲讲CIL以及CIL的VM。关于CIL的文档,在Partition III CIL.doc中。如果不想看的话,我可以简单讲讲。CIL的VM是一个栈式机,和x86的依赖寄存器的机制很不一样,所谓的栈式机就是说指令所需要的数据都用堆栈保存。这种栈式机在真实的计算机当中并不多见,尤其在CISC的CPU里面是很难见到的,即使在RISC都很少见(也许我孤陋寡闻吧)。原因简单点讲就是栈式机的指令非常简单,为了进行一个计算需要多个指令来完成,甚至需要多次读出和写入数据。正是由于指令简单,所以由于虚拟机上面却非常的方便,虚拟机程序做起来可以容易许多。栈式机主要的指令有五大类:(数据)压栈、弹出、运算、转移、其他,其中前三个是栈式机的核心。以CIL为例:
int a = a + b + c + d + e + f + g + h + i; | |
80x86 ASM | CIL |
0000004c 8B 54 24 10 mov edx,dword ptr [esp+10h] 00000050 03 54 24 14 add edx,dword ptr [esp+14h] 00000054 03 54 24 18 add edx,dword ptr [esp+18h] 00000058 03 54 24 1C add edx,dword ptr [esp+1Ch] 0000005c 03 54 24 20 add edx,dword ptr [esp+20h] 00000060 03 D5 add edx,ebp 00000062 03 D6 add edx,esi 00000064 03 D3 add edx,ebx 00000066 03 D7 add edx,edi 00000068 89 54 24 10 mov dword ptr [esp+10h],edx | IL_0000: 06 ldloc.0 // a IL_0001: 07 ldloc.1 // b IL_0002: 08 ldloc.2 // c IL_0003: 09 ldloc.3 // d IL_0004: 11 04 ldloc.s e IL_0006: 11 05 ldloc.s f IL_0008: 11 06 ldloc.s g IL_000A: 11 07 ldloc.s h IL_000C: 11 08 ldloc.s i IL_000E: 58 add // stack[top] = stack[top--] + stack[top--] = stack[top] = h + i; IL_000F: 58 add // stack[top] = g + h + i IL_0010: 58 add // = f + g + h + i IL_0011: 58 add // = e + f + g + h + i IL_0012: 58 add // = d + e + f + g + h + i IL_0013: 58 add // = c + d + e + f + g + h + i IL_0014: 58 add // = b + c + d + e + f + g + h + i IL_0015: 58 add // = a + b + c + d + e + f + g + h + i IL_0016: 0A stloc.0 // a = ... |
主要操作 | 操作数范围/条件 | 操作数类型 | 操作数 | |||||||||
缩写 | 全称 | 含义 | 缩写 | 全称 | 含义 | 缩写 | 全称 | 含义 | 缩写 | 全称 | 含义 | |
ld | load | 将操作数压到堆栈当中,相当于: push ax | arg | argument | 参数 | ? | ? | 操作数中的数值 | .0 | ? | 第零个参数 * | |
.1 | ? | 第一个参数 | ||||||||||
.2 | ? | 第二个参数 | ||||||||||
.3 | ? | 第三个参数 | ||||||||||
.s xx | (short) | 参数xx | ||||||||||
a | address | 操作数的地址 | 只有 .s xx,参见ldarg.s | |||||||||
loc | local | 局部变量 | 参见ldarg | |||||||||
fld | field | 字段(类的全局变量) | 参见ldarg | xx | ? | xx字段,eg: ldfld xx | ||||||
c | const | 常量 | .i4 | int 4 bytes | C#里面的int,其他的类型例如short需要通过conv转换 | .m1 | minus 1 | -1 | ||||
.0 | ? | 0 | ||||||||||
.1 | ? | 1 | ||||||||||
…… | ||||||||||||
.8 | 8 | |||||||||||
.s | (short) | 后面跟一个字节以内的整型数值(有符号的) | ||||||||||
? | ? | 后面跟四个字节的整型数值 | ||||||||||
.i8 | int 8 bytes | C#里面的long | ? | ? | 后面跟八个字节的整型数值 | |||||||
.r4 | real 4 bytes | C#里面的float | ? | ? | 后面跟四个字节的浮点数值 | |||||||
.r8 | real 8 bytes | C#里面的double | ? | ? | 后面跟八个字节的浮点数值 | |||||||
null | null | 空值(也就是0) | ? | ? | ? | ? | ? | ? | ||||
st | store | 将堆栈内容弹出到操作数中,相当于: pop ax | 参见ld ** | |||||||||
conv | convert | 数值类型转换,仅仅用纯粹的数值类型间的转换,例如int/float等 | ? | ? | ? | .i1 | int 1 bytes | C#里面的sbyte | ? | ? | ? | |
.i2 | int 2 bytes | C#里面的short | ||||||||||
.i4 | int 4 bytes | C#里面的int | ||||||||||
.i8 | int 8 bytes | C#里面的long | ||||||||||
.r4 | real 4 bytes | C#里面的float | ||||||||||
.r8 | real 8 bytes | C#里面的double | ||||||||||
.u4 | uint 4 bytes | C#里面的uint | ||||||||||
.u8 | uint 8 bytes | C#里面的ulong | ||||||||||
b/br | branch | 条件和无条件跳转,相当于: jmp/jxx label_jump | br | ? | ? | 无条件跳转 | ? | ? | ? | ? | ? | 后面跟四个字节的偏移量(有符号) |
.s | (short) | 后面跟一个字节的偏移量(有符号) | ||||||||||
false | false | 值为零的时候跳转 | ? | ? | ? | 参见br | ||||||
true | true | 值不为零的时候跳转 | ? | ? | ? | |||||||
b | eq | equal to | 相等 | ? | ? | ? | ||||||
ne | not equal to | 不相等 | un | unsigned or unordered | 无氟好的(对于整数)或者无序的(对于浮点) | |||||||
gt | greater than | 大于 | ||||||||||
lt | less than | 小于 | ||||||||||
ge | greater than or equal to | 大于等于 | ||||||||||
le | less than or equal to | 小于等于 | ||||||||||
call | call | 调用 | ? | ? | ? | ? | ? | (非虚函数) | ? | |||
? | ? | ? | virt | virtual | 虚函数 |
** starg只有.s形式,没有.0、.1等形式,除此之外和ldarg相同。
+ 从左到右依次合并,就可以得到一个指令,例如:ld + arg + a + .s xx? =>? ldarga.s xx,即,读出参数xx的地址并压栈。上面这些只是一些比较常用的、但是稍微难理解的指令,其他的可以看Partition III CIL.doc这个文档。现在我们再回到表一的例子,是不是觉得其实CIL非常好理解呢?所以虚拟机用栈式机的形式是比较容易实现的,比起x86里面一堆的寄存器、状态/标志位以及指令对状态/标志位的影响,可简单多了!不过我们也可以看到,用80x86汇编10条指令能够完成的操作,用CIL则需要18条指令,而且这已经是经过手动优化过的CIL了,如果你用C#写,然后编译出来的很可能还要多出一些代码。如果我们数一下包含的字节数,可以看到80x86有32bytes,而CIL只有20bytes,也许会让你觉得CIL似乎更为紧凑,其实是因为这个CIL是一个优化形式,实际的情况CIL并不会比x86汇编小多少,甚至完全可能更大!栈式机另外一个问题是,每一次的操作都必须访问至少两次内存,并且这两次访问的肯定不是同一个地方:一个是某一个内存块,另外一个是堆栈。因此不可能象x86CPU那样,直接访问CPU内部存储器,甚至连访问缓存效率都会打对折(需要访问两个完全无关的地方)。而我们知道CPU内部存储器式最快的,完全没有延时,缓存次之(一级缓存延时约1到2个周期,二级缓存延时3到5个周期),最慢的就是内存了(延时约十个周期左右,甚至更长)。所以一般说来,真实的CPU是很少做成栈式机形式的。
那么我们阅读cil有些什么技巧呢?我觉得需要注意这么几点:
牢记这是一个栈式机,所有指令都和栈有关。
注意当前函数是否为静态函数
就这么多了
注:原文出自http://dotnet.mblogger.cn/sumtec/posts/193.aspx
相关文章推荐
- >>CLI里面的秘密……(一)总体介绍,以及CIL
- >>CLI里面的秘密……(二)强命名、元数据以及文件结构(上半部分)
- >>CLI里面的秘密……(二)强命名、元数据以及文件结构(下半部分)
- [转载]字节码问题--wchar和char的区别以及wchar和char之间的相互转换字符编码转换等方法及函数介绍
- sandbox沙盒介绍 以及如何取得沙盒里面各文件的路径,以及xcode5 和xcode6上路径的变化
- ArcGIS 10研究(一) 之 Desktop总体介绍 转载
- iOS5里面遇到的兼容性问题以及解决方法(转载)
- 转载一篇简单又清晰地介绍X, X Server, XFree86, KDE和Gnome以及他们之间关系的文章
- tabhost简单介绍(里面有转载别人的部分)
- 【iOS开发-3】sandbox沙盒介绍以及如何取得沙盒里面各文件的路径,图片导入方式和图片路径获取
- 手摸手教你在vue-cli里面使用vuex,以及vuex简介
- 实现一个对象验证库系列 -- 1) 接口介绍以及总体思路概述 (请大神批评)
- 监测程序详细介绍,快捷键的设置;txt文件里面一行行的读取、删除、添加字符串等;根据程序路径名以及程序名判断程序是否在运行;
- Cocos2d-x中__Dictionary容器以及实例介绍 [转载]
- python里面的单引号,双引号以及三引号的介绍
- sandbox沙盒介绍以及如何取得沙盒里面各文件的路径,图片导入方式和图片路径获取
- [转载] OMAP35x下OneNand的分析以及x-loader的介绍
- sandbox沙盒介绍以及如何取得沙盒里面各文件的路径,图片导入方式和图片路径获取
- hadoop环境配置(1)--总体软件需要介绍,以及fedora安装注意事项
- 【转载】Java虚拟机的内存组成以及堆内存介绍