MSIL简介

来源:互联网 发布:编程算法基础电子书 编辑:程序博客网 时间:2024/06/10 19:35

在MSIL简介系列的第2部分,我将会探索局部变量的使用。如果没有变量,那么一个程序将会很无聊。为了解释如何使用变量,让我们写一个简单的求和程序。

在一个MSIL函数中,变量可以通过.locals指令声明.

.locals init (int32 first, int32 second, int32 result)

这个代码为当前函数声明了3个局部变量。本例中,它们恰好是 int32类型, 是System.Int32类型的别名。 init表示每个变量都需要被初始化成默认值。也可以忽略变量名,那样的话你需要通过从0开始的下标来引用它们。当然,使用变量名可以提高可读性。

在继续讲解之前,我希望确定你了解MSIL如何使用栈。当你想要给一个指令传值时,这些值需要被放到栈中。为了读取这些值,指令从栈中把它们拿出来。相似的,当调用一个函数时,你需要把引用依次推入栈中。然后函数会从栈中取出引用。为了把一个值推入栈中,用ldloc指令指示拥有那个值的变量。为了从栈中弹出一个值,使用stloc指令指示你要在哪个变量中存储这个值。记住,值是直接存储在栈中的,但是对象不是。对象的引用被存储在栈中,但对象在堆中被分配。

下一步是从用户那里获取数字。

ldstr "First number: "call void [mscorlib]System.Console::Write(string)call string [mscorlib]System.Console::ReadLine()call int32 [mscorlib]System.Int32::Parse(string)stloc first

就像是我在Part 1中提到的,ldstr指令把字符串推入栈中并调用Write函数,Write函数把变量从栈中弹出。下一个call指令调用返回string的ReadLine函数。返回的string被推入栈中,由于string已经在栈中,我们简单地调用 Int32::parse 函数把字符串弹出并推入等值的int32。注意,我为了讲解更清楚,忽略了错误处理。stloc指令会弹出栈中的值并把它存储在first局部变量中。从用户获取第二个数字的方法和这个相同,只是第二个数字的值需要被存储在 ‘second’ 局部变量中。

既然我们已经从标准输入中获取了两个值,是时候把它们相加。add指令可以达到我们的目的。

ldloc firstldloc secondaddstloc result

add指令从栈中弹出两个值并计算它们的和。为了把局部变量的值推入栈中,我们使用了ldloc指令(load local),当add指令完成的时候,它会把结果推入栈中。接着程序使用stloc指令(set local)从栈中弹出值,并将其存储在名为 ‘result’ 的局部变量中。

最后一步是向用户展示结果。

ldstr "{0} + {1} = {2}"ldloc firstbox int32ldloc secondbox int32ldloc resultbox int32call void [mscorlib]System.Console::WriteLine(string, object, object, object)

我们使用WriteLine重载函数。WriteLine函数的每个参数,都必须依次被推入栈中。因为数字是作为 int32值类型被存储的,我们需要为每个值装箱;否则和函数签名不匹配。

ldloc指令把每个变量推入栈中。然后为每个int32参数使用box指令。装箱会从栈中弹出值,构造一个包含值的副本的对象,然后把引用推入栈中。

下面是一个完整的程序。

.method static void main(){    .entrypoint    .maxstack 4    .locals init (int32 first,                  int32 second,                  int32 result)    ldstr "First number: "    call void [mscorlib]System.Console::Write(string)    call string [mscorlib]System.Console::ReadLine()    call int32 [mscorlib]System.Int32::Parse(string)    stloc first    ldstr "Second number: "    call void [mscorlib]System.Console::Write(string)    call string [mscorlib]System.Console::ReadLine()    call int32 [mscorlib]System.Int32::Parse(string)    stloc second    ldloc first    ldloc second    add    stloc result    ldstr "{0} + {1} = {2}"    ldloc first    box int32    ldloc second    box int32    ldloc result    box int32    call void [mscorlib]System.Console::WriteLine(string, object, object, object)       ret}

这里例子还有需要注意的一点是,我指示了main函数最多使用4个栈槽。这是为了和WriteLine函数的4个参数相匹配。

0 0
原创粉丝点击