Emit学习(2) - IL - 常用指令介绍
学习Emit必不可少的, 会使用到IL中间代码. 初见IL代码, 让我有一种汇编的感觉, 让我想起了, 大学时, 学习8051的汇编语言. 多的就不扯了, 直接进入正题, OpCodes指令集是不是有一种让人望而却步的感觉, 那么多, 具体我没有数过, 但是肯定是比8051的指令多不少, 应该有200多个吧, 不过在实际使用的过程中, 肯定是用不到这么多的, 所以只要掌握一些常用的就够用了, 其余的, 查资料就可以了(大学老师当时也是这么教的, 实际使用中, 也确实是这样的)
一、示例
上一篇的结束部分, 贴出了一个中文注释版的OpCodes文件, 这部分内容跟那个文件是有很大关联的. 貌似, 贴在这一篇更合适呢...
嗯, 还是应该从示例里去开始讲
来源 : http://www.cnblogs.com/zery/p/3366175.html
static void Sum(int sum, string sumStr)
{
int a, b, c;
a = ;
b = ;
c = ;
sum = a + b + c;
sumStr = sum.ToString();
Console.WriteLine(sumStr); for (int i = ; i < c; i++)
{
if (i > b)
{
Console.WriteLine("满足条件, 跳出循环");
break;
}
}
Console.ReadKey();
}
.method private hidebysig static void Sum(int32 sum, string sumStr) cil managed
{
.maxstack //定义函数代码所用堆栈的最大深度,也指Evaluation Stackk中最多能同时存在2个值
.locals init ( //变量的声明, (此时已经把num,num2,num3,num4,flag存入了Call Stack中的Record Frame中)
[] int32 num,
[] int32 num2,
[] int32 num3,
[] int32 num4,
[] bool flag) L_0000: nop //无任何操作, 可忽略
L_0001: ldc.i4. //加载 常量1 到栈中(压栈)
L_0002: stloc. //从栈中把 常量1 拿出来, 赋值给num(出栈, 此时栈中已经没有东西了)
L_0003: ldc.i4. //加载 常量2 到栈中(压栈)
L_0004: stloc.
L_0005: ldc.i4.
L_0006: stloc. L_0007: ldloc. //将num变量压栈
L_0008: ldloc. //将变量num2压栈 (此时栈中有两个值, num2在上面, num在下面)
L_0009: add //将num,num2求和的结果压栈(求和的时候, 会把两个值都提取出来, 所以结束后, 栈中只有一个结果值)
L_000a: ldloc. //将num3压栈
L_000b: add //将num3,(num+num2)求和, 并压栈, 此时栈中, 只有最后的结果值
L_000c: starg.s sum //将栈顶的值传给传参sum(短格式) L_000e: ldarga.s sum //加载sum的地址到堆栈上(短格式)
L_0010: call instance string [mscorlib]System.Int32::ToString() //调用ToString()方法, 完成格式转换,将结果值放入堆栈中
L_0015: starg.s sumStr //将堆栈顶的值传给传参sumStr(短格式) L_0017: ldarg. //将索引为1的传参(sumStr)加载到堆栈中
L_0018: call void [mscorlib]System.Console::WriteLine(string) //调用Console.WriteLine方法 L_001d: nop
L_001e: ldc.i4.
L_001f: stloc. // i = 0
L_0020: br.s L_0043 //无条件跳转到下面, 去判断 i<c 是否成立 L_0022: nop
L_0023: ldloc. // i
L_0024: ldloc. // b
L_0025: cgt // i > b ? 1 : 0
L_0027: ldc.i4. //压栈0
L_0028: ceq //比较的结果在与0比较, (i > b ? 1 : 0) == 0 ? 1 : 0
L_002a: stloc.s flag //将结果存入本地变量flag
L_002c: ldloc.s flag //加载flag到堆栈中
L_002e: brtrue.s L_003e //为真跳转到 L_003e L_0030: nop
L_0031: ldstr "\u6ee1\u8db3\u6761\u4ef6, \u8df3\u51fa\u5faa\u73af" //"满足条件, 跳出循环"
L_0036: call void [mscorlib]System.Console::WriteLine(string)
L_003b: nop
L_003c: br.s L_004d L_003e: nop
L_003f: ldloc. // i
L_0040: ldc.i4. //
L_0041: add // i + 1
L_0042: stloc. // i = i + 1 L_0043: ldloc. // i
L_0044: ldloc. //c
L_0045: clt // i < c ? 1 : 0
L_0047: stloc.s flag //将结果传给 flag
L_0049: ldloc.s flag //加载flag变量到堆栈中
L_004b: brtrue.s L_0022 //为真跳转 L_0022 L_004d: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
L_0052: pop //移除当前位于计算堆栈顶部的值
L_0053: ret //即为 return 标记 返回值
}
ldc.i4.1: i4--int32, 1--数值, 合起来就是 加载int32的数值1到堆栈中
stloc.0: 0--前面声明的locals变量组中的第0个 将堆栈顶的值付给locals0变量
ldloc.0: 加载locals0变量到堆栈中
add : 将栈顶的两个值求和, 并将结果压栈
二、常用的指令
维基百科:https://en.wikipedia.org/wiki/List_of_CIL_instructions
来源:http://blog.csdn.net/joyhen/article/details/47276433
1. 常用的加载类指令
ldarg (及多个变化形式) |
ld -- load , arg -- argument, 对这个大家都不陌生吧, 就不多解释了 加载方法的参数的值到栈中。除了泛型ldarg(需要一个索引作为参数),还有后其他很多的变化形式。'.'有个数字后缀的ldarg操作码来指定需要加载的参数。 a -- address, s -- short ldarga/ldarga.s表示的是加载参数的地址, 而不是加载参数的值 |
ldc (及多个变化形式) |
c -- constant, const这个关键字大家肯定都很熟了, constant表示常量 加载一个常数到栈中 Ldc.I4.2 i4表示是int32的值(1个表示8位), 2表示常量 |
ldfld (及多个变化形式) | 加载一个对象实例的成员到栈中 |
ldloc (及多个变化形式) |
loc -- locals 加载一个本地变量到栈中 |
ldobj | 获得一个堆对象的所有数据,并将它们放置到栈中. OpCodes:将地址指向的值类型对象复制到计算堆栈的顶部。 |
ldstr | 加载一个字符串数据到栈中 |
2. 常用的弹出操作指令
pop | 删除当前栈顶的值,但是并不影响存储的值 |
starg |
st -- store 存储栈顶的值到给出方法的参数,根据索引确定这个参数. OpCodes:将位于计算堆栈顶部的值存储到位于指定索引的参数槽中 |
stloc (及多个变化形式) | 弹出当前栈顶的值并存储在一个本地变量列表中,根据所以确定这个参数 |
stobj | 从栈中复制一个特定的类型到指定的内存地址 |
stfld | 用从栈中获得的值替换对象成员的值 |
3. 常用的其他操作类指令
add, sub, mul, div, rem |
用于两个数加减乘除求模, 并将结果推送到计算堆栈上 |
and, or, not, xor | 用于在两个值上进行二进制操作 |
ceq, cgt, clt |
用不同的方法比较两个在栈上的值 c -- compare ceq:是否相等 -- 如果这两个值相等,则将整数值 1 (int32) 推送到计算堆栈上;否则,将 0 (int32) 推送到计算堆栈上 cgt:是否大于 -- 如果第一个值大于第二个值,则将整数值 1 (int32) 推送到计算堆栈上;反之,将 0 (int32) 推送到计算堆栈上。 cgt.un -- 比较两个无符号的或不可排序的值, un -- unsigned 无符号 clt:是否小于 -- 如果第一个值小于第二个值,则将整数值 1 (int32) 推送到计算堆栈上;反之,将 0 (int32) 推送到计算堆栈上。 |
box, unbox |
在引用类型和值类型之间转换 box: 装箱 unbox: 拆箱 |
ret | 退出方法和返回一个值 |
beq, bgt,bge,ble, blt, switch |
控制方法中的条件分支 b -- break, eq,e -- equal beq:如果两个值相等,则将控制转移到目标指令; bgt:如果第一个值 > 第二个值,则将控制转移到目标指令 bge:如果第一个值 >= 第二个值,则将控制转移到目标指令 ble:如果第一个值 <= 第二个值,则将控制转移到目标指令 blt:如果第一个值 < 第二个值,则将控制转移到目标指令 switch:实现跳转表 所有的分支控制操作码都需要给出一个CIL代码标签作为条件为真的跳转目的地 |
brtrue |
如果 value 为 true、非空或非零,则将控制转移到目标指令 |
br/br.s |
br:(无条件)中止到代码标签 br.s:无条件地将控制转移到目标指令(短格式) |
call | 调用一个成员 |
newarr, newobj |
在内存中创建一个新的数组或新的对象类型 newarr:将对新的从零开始的一维数组(其元素属于特定类型)的对象引用推送到计算堆栈上 newobj:创建一个值类型的新对象或新实例,并将对象引用(O 类型)推送到计算堆栈上 |
未完待续......
Emit学习(2) - IL - 常用指令介绍的更多相关文章
- corosync+pacemaker的crmsh的常用指令介绍
配置crmsh的yum仓库,此仓库的RPM包有openSUSE提供,将这个network:ha-clustering:Stable.repo文件直接下载到本地并且命名为crmsh.repo wget ...
- Nginx学习系列四默认负载均衡轮询及Ip_hash等常用指令介绍
一.简介 Upstream模块是Nginx中一个核心模块,当客户端访问Nginx服务器的时候,Nginx会从服务器列表中选取压力小的服务器,然后分配给客户端进行访问.这个过程,Nginx通过轮询算法轮 ...
- 新人成长之入门Vue.js常用指令介绍(一)
写在前面 作为一个刚步入职场工作的新人,对于公司中所用的技术和框架基本上不懂,只能从最基础的开始做起,进入公司接触的第一个框架就是前端框架Vue.js,几个功能做下来,觉得Vue.js首先学习起来真的 ...
- docker创建image方法以及常用指令介绍
docker -help # 显示帮助 docker COMMAND -help # 帮助信息更详细 docker start “容器名称” # 启动一个或多个容器 docker s ...
- linux学习(四)-----linux常用指令
touch 指令 touch 指令创建空文件 基本语法 touch 文件名称 应用实例 案例 1: 创建一个空文件 hello.txt cp 指令 cp 指令拷贝文件到指定目录 基本语法 cp [选项 ...
- Docker学习笔记_Dockerfile常用指令
Dockerfile常用指令
- Emit学习(2) - IL - 值类型和引用类型(补)
上周末回家去享受生活了, 工作是为了更好的生活嘛, 所以我把生活, 工作分的比较开. 这几天不是很忙, 在学习工作技能的同时, 发点博文, 也算是做一个学习笔记 上篇中, 贴出的地址里面那位哥, 也有 ...
- Emit学习(2) - IL - 对象的创建过程
上一篇的介绍中, 并没有介绍到对象的创建过程, 这一篇主要就介绍一下, 对象的创建过程. 其实熟悉了IL语法之后, 完全可以用Reflector反编译代码去查看. 而且正因为有这个工具, 可以对照着R ...
- 学习笔记_ADB常用指令
ADB 查看连接到计算机的Android设备或模拟器 adb devices 说明: 正常显示状态应该是IP:Port State. State=device说明设备已经连接到计算机, State=o ...
随机推荐
- Unity3d热更新全书-加载(二)如何在不用AssetBundle的前提下动态加载预设
Unity3D的主要构成大家都知道,首先是场景图,场景图上的节点构成一颗树. 每个节点对应一个GameObject对象 然后每个GameObject有若干个组件 有一些组件会与资源产生关系,比如Mes ...
- jQuery 绑定事件到动态创建的元素上
在进入主题之前,我们先来看一个前台页面经常用到的功能:点击页面输入框时自动选择其中文本. 很容易想到利用输入框的focus事件,当输入框获得焦点时,再调用jQuery的select()方法. Okay ...
- 诡异的 未处理的IOErrorEvent 2035
今天游戏发布上线之后,总是随机的出现卡死. 换了个safari之后,看到抛了 IOErrorEvent. 问题是,我所有的Loader都加入了contentLoaderInfo监听.而抛出来的又没有堆 ...
- Linux创建用户(转)
这篇文章总结的太好了,让我没动力新写一篇了,啊哈哈哈哈. 源自:http://www.cnblogs.com/ylan2009/articles/2321177.html Linux 系统是一个多用户 ...
- 每天一个linux命令(55):traceroute命令
通过traceroute我们可以知道信息从你的计算机到互联网另一端的主机是走的什么路径.当然每次数据包由某一同样的出发点(source)到达某一同样的目的地(destination)走的路径可能会不 ...
- ThinkPHP框架里隐藏index.php
本文所写的配置在ThinkPHP3.2.2上测试过.按理也兼容其它版本. 首先修改配置文件: 'URL_CASE_INSENSITIVE' => true, // 默认false 表示URL区分 ...
- Java程序员的日常——存储过程知识普及
存储过程是保存可以接受或返回用户提供参数的SQL语句集合.在日常的使用中,经常会遇到复杂的业务逻辑和对数据库的操作,使用存储过程可以进行封装.可以在数据库中定义子程序,然后把子程序存储在数据库服务器, ...
- MyBatis学习总结(二)——使用MyBatis对表执行CRUD操作
一.使用MyBatis对表执行CRUD操作--基于XML的实现 1.定义sql映射xml文件 userMapper.xml文件的内容如下: 1 <?xml version="1.0&q ...
- 彻底理解跨域解决方案JSONP
什么是同源策略? 同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略. 所谓同源是指,域名,协议,端口相同.当一个浏览器的两个tab页 ...
- 【WP 8.1开发】解决摄像头翻转问题(RuntimeApp篇)
昨天,我非常马虎地给大家说了有关处理物理摄像头翻转的话题,今天,还是这个话题,而且内容不差,只是为了完整性,顺便也提供了运行时API的版本,其实实现起来与SL框架版本差不多,毕竟这两个框架都有不少AP ...