IL程序基本结构

IL代码大致分为三部分:程序头,各类声明,代码段

程序头:主要是包括编译后生成的可执行文件的一些属性的定义,一般三个关键字

.assembly 声明本程序集名称

.assembly extern 声明外部程序集名称

.module  声明主模块名称

各类声明:

.namespace 名称空间声明

.class 类声明

.method 方法声明

.field  字段声明

.data 数据声明

.custom 自定义属性声明

代码段:

主要由MSIL指令以及个别关键字构成,通常一个IL指令由操作码(opcode)和指令参数(操作数operrand)构成,操作码长度为1或2字节,当为2字节时,第一个字节总是0xFE

  流程控制指令:

    1.直接跳转指令

     br 从当前位置移动到指定的位置

     br .s   br的短指令格式

   2.条件跳转指令

      brfalse  value为0则跳转

      brfalse.s    短指令格式

      brtrue 不为0跳转

      brtrue.s  短指令格式

  3.比较跳转

     beq  等于跳转   beq.s

     bne.un 不等于跳转   bne.nu.s  无符号

     bge[.un.s] 大于或等于 

     bgt[.un.s]     大于则跳转  

     ble[.un.s]     小于等于跳转 

     blt[.un.s]   小于跳转 

     un 标识无符号 s标识短指令

  4.选择指令

    switch

  5中断指令

    break

  6 托管异常指令

     leave[.s] 清空堆栈,跳至当前指令的偏移处。用于从try。。catch跳出

     endfilter 表示filter块的终结。

     endfinally 表示finally或fault终结,并清空堆栈

  7 返回指令

     ret  从一个方法返回

算术指令

  1.堆栈操作

     nop 空指令 无任何操作

     dup 赋值当前栈顶元素

     pop 出栈 堆栈为空时出错

   2.常数载入

      用于将常数入栈

     ldc.i4 载入int32

     ldc.i4.s 载入int8

     ldc.i4.ml 载入-1

     ldc.i4.[0 ~8] 载入0~8;

     ldc.i8 载入int64

     ldc.r4 载入float32

     ldc.r8 载入float64

3.间接载入

    间接载入指令从栈顶取出一个托管指针(&类型)或非托管指针(native int 类型),载入该指针所指向的数值,并入栈。指令中小数点后的名称表明了载入数据的类型

   ldind.i1/ ldind.u1 载入1字节无符号/有符号整数

   ldind.i2/ldind.u2  2字节

   ldind.i4/ldind.u4  4字节

   ldind.i8/ldind.u8  8字节

   ldind.i                载入native int 大小为当前系统的指针大小

    ldind.r4/ldind.r8 载入单精度/双精度浮点数据

    ldind.ref            载入引用对象

4.间接存储

间接存储从栈顶先后取出一个值和指针,并将改值存储至指针所指位置。

stind.ref  存储一个对象引用

stind.i1,i2,i4,i8 存储1.2.4.8字节整数

  stind.i存储一个指针大小的数据

  stind.r4,r8 存储单精度、双精度浮点数

5.算数运算

   add 加   sub 减  mul 乘  div除法  rem 模运算 neg 取反运算

   两个特殊值:无限(infinity)和NaN(Not a Number)  0*infinity=NaN

   0/0=NaN infinity/infinity=NaN x/infinity=0

  

6.位操作

  and 按位与 or 按位或  xor  按位异或  not 按位求反

7 移位操作

   shl 左移位 shr 右移位  shr.un无符号右移位

8.转换指令

    从栈顶取值,进行相应转换,将结果入栈。

    conv.[类型]

    conv.ovf.[类型]

9.逻辑条件检测

   ceq 是否相等  cgt[.un] 是否大于  clt [.un]是否小于  ckfiniter 取栈顶元素。当为NaN infinity抛出异常,否则入栈

10.块操作

    cpblk 复制一块内存  initblk 初始化一块内存

参数、局部变量与字段寻址

方法参数载入

  ldarg 载入一个方法参数

  ldarg.s短指令格式 

  ldarg[.0~4]载入第0~4个参数

方法参数地址载入 :ldarga[.s] 载入参数并入栈

方法参数存储:      starg[.s]   从栈顶取一个参数并存入参数

方法参数列表         arglist  取得方法参数句柄 。。

局部变量载入  ldloc[.s][.0~3]载入第n个局部变量

局部变量引用载入 ldloca[.s] 载入局部变量的引用并入栈

局部变量保存   stloc[.s] 从栈顶取值并存入局部变量

局部内存块分配  localloc  分配一块局部内存块

方法调用

  直接调用:

jmp <token> (..) 放弃当前方法执行,直接跳转至 token所指目标方法。

  call <token>(..) 以不通过v-able的方式调用一个instance或static方法

  callvirt<token>通过实例的v-table调用oken所指的方法。

间接调用

  ldftn   ldvirtftn   calli

尾部调用

tail

类与值操作

ldnull 读取空的对象引用并入栈

ldobj  从堆栈获取值类型的托管指针

stobj 依次从堆栈取得值类型的值

ldstr  读取一个字符串

newobj 分配内存创建某个类的新实例

box 装箱 unbox 拆箱

image

原文地址:https://www.cnblogs.com/ac1985482/p/1992484.html