原文链接

参考链接

IL常见指令

常见方法

Call,Calli,Callvirt

  • Call:常用于调用编译时就确定的方法,可以直接去元数据里找方法,如静态函数,实例方法,也可以call虚方法,不过只是call这个类型本身的虚方法,和实例的方法性质一样。另外,call不做null检测。

  • Calli: MSDN上讲是间接调用指针指向的函数。

  • Callvirt: 可以调用实例方法和虚方法,调用虚方法时以多态方式调用,不能调用静态方法。Callvirt调用时会做null检测,如果实例是null,会抛出NullReferenceException,所以速度上比call慢点。

加载(Id)和存储(st)

Idloc.0:

把索引为0的局部变量加载到计算栈中。

Id:load;loc:Local variable(局部变量);.0:表示索引。

  • ldstr = load string,
  • ldnull = load null,
  • ldobj = load object,
  • ldfld = load field,
  • ldflda = load field address,
  • ldsfld = load static field,
  • ldsflda = load static field address,
  • ldelem = load element in array,
  • ldarg = load argument,

ldc 则表示加载数值,如ldc.i4.0; .i[n]表示字节数,一个字节8位;i4四个字节就是int32类型;.0表示索引为0。

alt

关于后缀

  • .i[n]:[n]表示字节数,1个字节是8位,所以是8*n的int,比如i1, i2, i4, i8,i1就是int8(byte), i2是int16(short),i4是int32(int),i8是int64(long)。相似的还有.u1 .u2 .u4 .u8 分别表示unsigned int8(byte), unsigned int16(short), unsigned int32(int), unsigned int64(long);

  • .R4,.R8 表示的是float和double。

  • .ovf (overflow)则表示会进行溢出检查,溢出时会抛出异常;

  • .un (unsigned)表示无符号数;

  • .ref (reference)表示引用;

  • .s (short)表示短格式,比如说正常的是用int32,加了.s的话就是用int8;

  • .[n] 比如 .1,.2 等,如果跟在i[n]后面则表示数值,其他都表示索引。如 ldc.i4.1就是加载数值1到计算栈上,再如ldarg.0就是加载第一个参数到计算栈上。

ldarg要特别注意一个问题:如果是实例方法的话ldarg.0加载的是本身,也就是this,ldarg.1加载的才是函数的第一个参数;如果是静态函数,ldarg.0就是第一个参数。

与Id对应的就是st,可以理解为store(储藏),意思是把值从计算栈存到变量中去, ld相关的指令很多都有st对应的,比如stloc, starg, stelem(存储数组中的元素)等,

比较跳转指令,判断bool值

以b开头:beq, bge, bgt, ble, blt, bne

先把b去掉看看:

  • eq: equivalent with, == 等于
  • ge: greater than or equivalent with , >= 大于等于
  • gt: greater than , > 大于
  • le: less than or equivalent with, <= 小于等于
  • lt: less than, < 小于
  • ne: not equivalent with, != 不等于

这样是不是很好理解了,beq IL_0005就是计算栈上两个值相等的话就跳转到IL_0005, ble IL_0023是第一个值小于或等于第二个值就跳转到IL_0023。

以br(break)开头:br, brfalse, brtrue,

  • br是无条件跳转;
  • brfalse表示计算栈上的值为 false/null/0 时发生跳转;
  • brtrue表示计算栈上的值为 true/非空/非0 时发生跳转

还有一部分是c开头,算bool值的,和前面b开头的有点像:

  • ceq 比较两个值,相等则将 1 (true) 推到栈上,否则就把 0 (false)推到栈上
  • cgt 比较两个值,第一个大于第二个则将 1 (true) 推到栈上,否则就把 0 (false)推到栈上
  • clt 比较两个值,第一个小于第二个则将 1 (true) 推到栈上,否则就把 0 (false)推到栈上