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 ...
随机推荐
- java 多线程(ThreadPoolExecutor (补充))
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; impo ...
- 【读书笔记】.Net并行编程高级教程--Parallel
一直觉得自己对并发了解不够深入,特别是看了<代码整洁之道>觉得自己有必要好好学学并发编程,因为性能也是衡量代码整洁的一大标准.而且在<失控>这本书中也多次提到并发,不管是计算机 ...
- Unity3D热更新全书-重头再来
之前写了Unity3D热更新全书系列Blog 提出了下载.加载.脚本三个方面的开源类库 下载方面有EasyDown加载方面有GameObjParser脚本方面有C#Light另外有一个没有独立成库,但 ...
- 使用oracle的大数据工具ODCH访问HDFS数据文件
软件下载 Oracle Big Data Connectors:ODCH 下载地址: http://www.oracle.com/technetwork/bdc/big-data-connectors ...
- 如何获得PRINCE2认证
PRINCE2认证考试共有两种:基础级和从业级 一. 基础级考试 基础级考试是一种低水平的认证.如果想要进行从业级考试,必须要参加并通过该考试,或者已经获得pmp资质.基础级考试包括以下关键点: 1. ...
- MVVM架构~knockoutjs系列之级联select
返回目录 对于下拉列表框的绑定在之前的knockoutjs文章中已经介绍过,今天主要说一下级联的select,事实上,在knockoutjs里,是以数据绑定为中心的,而数据是以面向对象为前提的,而对于 ...
- Atitit ocr识别原理 与概论 attilax总结
Atitit ocr识别原理 与概论 attilax总结 1.1. Ocr的过程与流程1 1.2. OCR不同技术细分略有不同,但大概原理是一样的. 即主要技术过程是:二值化(又叫归一化)----- ...
- 23.实现一个名为Person的类和它的子类Employee,Employee有两个子类Faculty 和Staff。 具体要求如下: (1)Person类中的属性有:姓名name(String类型),地址address(String类型), 电话号码telphone(String类型)和电子邮件地址email(String类型); (2)Employee类中的属性有:办公室office(Stri
package banking; public class Person { private String name; public String address; public String tel ...
- java中IO流相关知识点
(一) 下边使用outputStream字节输出流进行写操作 package zdbIO;import java.io.File;import java.io.FileNotFoundExceptio ...
- CCNA网络工程师学习进程(3)常规网络设计模型与基本的网络协议
本节介绍分层的网络设计模型与基本的网络协议,包括ARP协议,ICMP协议和IP协议. (1)三层网络架构: 一个好的园区网设计应该是一个分层的设计.一般分为接入层.汇聚层(分布层).核 ...