我在C#中有以下代码
// test.Program
private static void Main()
{
int x = 5;
int y = 100;
Console.WriteLine(y + ", " + x);
}
我正在阅读IL代码,我以前从未对汇编进行过编程,所以我在问我每行所做的是否正确。
.method private hidebysig static
void Main () cil managed
{
// Method begins at RVA 0x2058
// Code size 33 (0x21)
.maxstack 3 // maximum stack in this method is 3
.entrypoint // method is initial entry point
.locals init ( // reserves memory for x and y variables
[0] int32 x, // x variable is reserved on position 0 of the stack
[1] int32 y // y variable is reserved on position 1 of the stack
)
IL_0000: ldc.i4.5 // integer of 4 bytes in size and the value of 5 is loaded onto the evaluation stack position 0
IL_0001: stloc.0 // put evaluation stack position 0 into the stack position 0, the evaluation stack is emptied
IL_0002: ldc.i4.s 100 // integer of 4 bytes in size and the value of 100 is loaded onto the evaluation stack position 0
IL_0004: stloc.1 // put evaluation stack position 0 onto the stack position 1, the evaluation stack is emptied
IL_0005: ldloc.1 // load stack position 1 into the evaluation stack position 0
IL_0006: box [mscorlib]System.Int32 // box last valuetype placed on evaluation stack, replace valuetype with reference on evaluation stack position 0, do not empty stack
IL_000b: ldstr ", " // put reference to string on evaluation stack position 1
IL_0010: ldloc.0 // load stack position 0 into the evaluation stack position 2
IL_0011: box [mscorlib]System.Int32 // box last valuetype placed on evaluation stack, replace valuetype with reference on evaluation stack position 0, do not empty stack
IL_0016: call string [mscorlib]System.String::Concat(object, object, object) // call Concat, pass values on evaluation stack, empty evaluation stack, put result of concat on evaluationstack
IL_001b: call void [mscorlib]System.Console::WriteLine(string) // pass first value in evaluation stack
IL_0020: ret // return
} // end of method Program::Main
我正确理解这个程序吗?
差不多;我要澄清的唯一一件事是,框(IL_0006和IL_0011)是类型特定的,所以它显式地构建了一个类型为int
的框(它不仅仅是"最后一个值类型")。
此外,"空评估堆栈"具有误导性;这并不完全正确-例如,call
消耗给定数量的位置-它不会"清空"它。从来没有"空评估堆栈"语义-它总是"消耗多个值,放回多个值"(其中任何一个都可能为零)。
是的,您的理解几乎完全正确。有一点:IL_0010不是从堆栈加载的,而是从本地加载的。(局部变量最终出现在运行时堆栈上,但在IL级别,它们被称为局部变量)。
这是正确的,尽管我会用一些不清楚的措辞进行争论,例如:
将评估堆栈位置0放入堆栈位置0,评估堆栈清空
我会说
将堆栈顶部的第0个条目放入堆栈变量第0,然后弹出
只是因为我认为"不太正式"的措辞在大多数情况下读起来更清楚,但在其他方面,它似乎还可以。
edit:嗯。事后想想,我想说没有"堆栈"one_answers"评估堆栈"这两个东西。只有"堆栈"。堆栈可见部分开始的标记部分,具有局部变量的部分可以称为"槽"。我想,对于IL,你可以只说"局部变量Nth",一切通常都会很清楚,但我认为几个不同的变量可能被映射到同一个槽,所以这可能会引起一些混乱。此外,在使用堆栈时,没有像"清空"这样的操作。只有明确指定要复制的条目数的推送/弹出。