IL代码底层运行机制

<script type="text/javascript"> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
<A href="http://www.66of.com" target=_blank>IL</A><A href="http://www.66of.com" target=_blank>代码底层运行机制</A>

                               ILILy: 宋体">代码底层运行机制

                                                ILy: 宋体">刘强   

Cambest@sohu.com

2003ILy: 宋体">年5ILy: 宋体">月8ILy: 宋体">日

 

       ILy: 宋体">大家都知道,和JavaILy: 宋体">一样,C#ILy: 宋体">也是基于堆栈的语言。也许对一般人来说,底层的运行细节并不是很重要;但了解这些,对我们理解、运用C#ILy: 宋体">是很有帮助的。下面,我就通过一个很简单的例子来说明ILILy: 宋体">代码的底层运行机制,也许对你会有一些帮助。

 

       ILy: 宋体">我给出的例子表面上看是一个实现整数相减功能的函数;实际上,我也不知道究竟能够干什么。在实际当中,我们的程序当中会有很多种数据类型、引用类型,为了简便起见,我所给出的示例代码只用了一种数据类型,如下所示:

public int Sub(int i,int j)

        {

            int s;

            int t = 0;

            int r = 4;

            s=i;

            r =i – j;

            r + =s + t;

            return r;

        }

ILy: 宋体">这段代码很简单,任何学过C#ILy: 宋体">的人都能看懂。首先,传入两个整型变量iILy: 宋体">和jILy: 宋体">,然后经过内部运算,返回一个整型值。函数体内定义了三个局部变量sILy: 宋体">,tILy: 宋体">, rILy: 宋体">,分别用于保存自定义值以及结果。我们可以将它包装进一个类中,然后将它编译成.dllILy: 宋体">装配件。运用VS.NETILy: 宋体">自带的ILdasmILy: 宋体">反汇编工具进行反汇编,我们得到如下ILILy: 宋体">代码:

.method public hidebysig instance int32  Sub(int32 i,

                                       int32 j) cIL managed

{

  // Code size       22 (0x16)

  .maxstack  3

  .locals init (int32 V_0, int32 V_1, int32 V_2, int32 V_3)

    ldc.i4.0

    stloc.1

    ldc.i4.4

    stloc.2

    ldarg.1

    stloc.0

    ldarg.1

    ldarg.2

    sub

    stloc.2

    ldloc.2

    ldloc.0

    ldloc.1

    add

    add

    stloc.2

    ldloc.2

    stloc.3

    br.s       IL_0014

    ldloc.3

    ret

}

ILILy: 宋体">代码也可以由VS.NETILy: 宋体">自带的ILILy: 宋体">编译工具ILasmILy: 宋体">编译为.dllILy: 宋体">装配件或.exeILy: 宋体">可执行文件。

ILy: 宋体">这里,我要对ILILy: 宋体">中出现的符号作一下简单解释。以点号’.’ILy: 宋体">开头的标号为伪指示代码,只起指示作用,最终不会被JITILy: 宋体">编译为本地可执行代码,如“.methodILy: 宋体">”,“.localsILy: 宋体">”等。而不带点号’.’ILy: 宋体">的标号为ILILy: 宋体">汇编代码,它们在运行时将会被JITILy: 宋体">编译为本地可执行代码,如“ldarg.1ILy: 宋体">”等。

ILy: 宋体">每条语句究竟代表了什么样的操作,我们下面在详细讲解。注意:局部变量的下标从0ILy: 宋体">开始,因此要注意我下面所说的“第零个局部变量”等的含义。

ILy: 宋体">首先,让我们看一看函数体内的第一条语句:.maxstack  3ILy: 宋体">。从其本身我们也可以猜出该语句说明堆栈的大小。暂且不表,且看下文。

ILy: 宋体">第二句:.locals init (int32 V_0, int32 V_1, int32 V_2, int32 V_3) ILy: 宋体">。V_0ILy: 宋体">、V_1ILy: 宋体">、V_2ILy: 宋体">和我们在CSILy: 宋体">源程序中定义的局部变量sILy: 宋体">,tILy: 宋体">,rILy: 宋体">一一对应,我们大概也能猜到这一句是完成局部变量初始化工作的,但为什么在这里是四个呢?我们明明只定义了三个变量的。那么这由C#ILy: 宋体">编译器自动维护的第四个变量有何作用?也暂且不表,先看下文。

ldc.i4.0

ILy: 宋体">这条语句作用是在堆栈中载入常数,i4ILy: 宋体">表示该常数为双字长的32ILy: 宋体">位整型数,初始值为0ILy: 宋体">。“ldcILy: 宋体">”可以理解为“load constantILy: 宋体">”,加载常数。如图aILy: 宋体">,它完成的操作如同(top)<=0ILy: 宋体">,top=top+1ILy: 宋体">。

          stloc.1

ILy: 宋体">这条语句作用是将当前栈顶元素存入第一个局部变量。’1’ILy: 宋体">表示操作对象为第一个局部变量。“stlocILy: 宋体">”可以理解为“store to localILy: 宋体">”,保存局部变量。如图bILy: 宋体">,它完成的操作如同top=top-1ILy: 宋体">,s<=(top)ILy: 宋体">。

          ldc.i4.4

ILy: 宋体">这条语句完成的操作如同(top)<=4ILy: 宋体">,top=top+1ILy: 宋体">,如图cILy: 宋体">。

          stloc.2

ILy: 宋体">这条语句完成的操作如同top=top-1ILy: 宋体">,t<=(top)ILy: 宋体">,如图dILy: 宋体">。

          ldarg.1

          ldarg.2

ILy: 宋体">这两条语句作用是在堆栈中载入第一个参数(iILy: 宋体">)、第二个参数(jILy: 宋体">)(和局部变量不同,参数的指示下标从1ILy: 宋体">开始)。它完成的操作如同 (top)<=iILy: 宋体">,top=top+1ILy: 宋体">,(topILy: 宋体">)<=jILy: 宋体">,top=top+1ILy: 宋体">,如图eILy: 宋体">。其中,“ldargILy: 宋体">”可以理解为“load argumentILy: 宋体">”,加载参数。

          sub

ILy: 宋体">这条语句作用是将当前栈顶元素求反,再下加到第二个栈单元中,如图fILy: 宋体">。它完成的操作如同top=top-1ILy: 宋体">,temp= -ILy: 宋体">(topILy: 宋体">),top=top-1ILy: 宋体">,(topILy: 宋体">)=ILy: 宋体">(topILy: 宋体">)+ tempILy: 宋体">,top=top+1ILy: 宋体">。

 

 

 

 

top

0

 

 

 

 

top

 

 

 

top

4

 

 

 

 

top

 

 

top

j

i

 

 

 

top

i-j

   

 

 

 

 

 

     (a)             (b)            (c)           (d)          (e)             (f)

 

          stloc.2

ILy: 宋体">这条语句作用是将当前栈顶元素存入第二个局部变量(r)ILy: 宋体">。它完成的操作如同top=top-1ILy: 宋体">,r<=(top)ILy: 宋体">,即r=i-jILy: 宋体">,如图

          ldloc.2

       ldloc.0

       ldloc.1

ILy: 宋体">这三条语句作用是分别将第二、第零个、第一个局部变量加载到堆栈上,如图hILy: 宋体">。“ldlocILy: 宋体">”可以理解为“load local variableILy: 宋体">”,加载局部变量。

          add

          add

addILy: 宋体">的用发和subILy: 宋体">一样,只不过不将当前栈顶元素求反,再下加到第二个栈单元中,连续操作两次。如图iILy: 宋体">、jILy: 宋体">。

          stloc.2

ILy: 宋体">将当前栈顶元素存入第二个局部变量。如图kILy: 宋体">。

          ldloc.2

ILy: 宋体">在堆栈中载入第二个局部变量(rILy: 宋体">),如图lILy: 宋体">。

 

 

 

 

 

top

 

 

 

top

r

 

 

 

 

top

 

 

 

top

r+s+t

 

 

top

s+t

r

 

top

t

s

r

    

 

 

 

 

 

 

      (g)              (h)            (i)              (j)              (k)           (l)

 

          stloc.3

ILy: 宋体">将当前栈顶元素存入第三个局部变量,亦即保存返回值,如图mILy: 宋体">所示。

          br.s   IL_0014

ILy: 宋体">跳转到下一句(ldloc.3ILy: 宋体">)。如图nILy: 宋体">所示。

          ldloc.3

          ret

ILy: 宋体">将第三个局部变量(也即由编译器自动维护的变量)加载到堆栈上,然后返回,如图oILy: 宋体">。从这里我们也可以看出,1ILy: 宋体">、第三个变量和返回值类型相同;2ILy: 宋体">、扫尾后、返回前将第三个局部变量加载至堆栈。这可以让我们确定:第三个变量用于存储返回值。我们还要弄清楚为什么要专门分配一个局部变量来存储返回值,这一点在后面会有说明。

 

 

 

 

 

top

 

 

 

 

top

 

 

 

top

V_3

      

 

 

 

 

 

 

      (m)          (n)           (o)      

 

ILy: 宋体">综观图a~oILy: 宋体">,我们回发现,整个函数过程所用到的最大栈数目就是3ILy: 宋体">,这也就不难理解第一条语句.maxstack  3  ILy: 宋体">了。

ILy: 宋体">现在,还有一点让人迷惑的是为什么要引入变量V_3ILy: 宋体">?如上例中,倒数第二条指令ldloc.3ILy: 宋体">也可以由ldloc.2ILy: 宋体">代替,因为我们所要的结果就是存储在第二个变量rILy: 宋体">中的,这不是浪费空间嘛。要注意了,并不所有的返回值都保存在局部变量中的。

ILy: 宋体">有可能我们将参数直接返回,或者将类成员变量返回,如:

              public int Laxi(int x)

              {

                     return x;         //ILy: 宋体">直接将参数返回

              }

ILy: 宋体">或者是  int age;...

        public int GetAge()

        {

                     return age;      //ILy: 宋体">返回在类中定义的字段

        }

ILy: 宋体">或者是直接返回一个表达式:

              public int GetInteger()

              {

                     return age+4*6/2;

              }

ILy: 宋体">则必须进行这一步转换,以return rILy: 宋体">为例:ldloc.x -> stloc.y ->ldloc.y ->ret . ILy: 宋体">因为在以上三种情况当中,返回值都不存储在局部变量当中。

 

<script type="text/javascript"> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值