了解 CIL 和 ldelem.ref 的工作原理
Understanding CIL & the workings of ldelem.ref
我想解释一下 ldelem.ref
的作用。到目前为止,我已经将索引处的元素作为 O.
加载到堆栈顶部
索引是什么?我认为类型 O 意味着对象的类型将保持不变,例如,如果它是一个字符串,它将保持一个字符串。
下面是我正在处理的一些代码的示例,非常感谢您的理解。我评论了我相信我知道的。
所以在这种情况下是
.locals init (
string V_0,
bool V_1,
string V_2,
bool V_3,
string V_4,
string V_5,
string V_6) // Declared 6 variables
.try
{
IL_0000: nop
IL_0001: nop // Does nothing - Debug build
IL_0002: ldarg.0 // Loads Argument 0 into memory/stack
IL_0003: ldc.i4.0 // Push Constant Value 0 into memory [Possibly from a variable]
IL_0004: ldelem.ref // Loads element at index onto the top of the stack as an O
IL_0005: stloc.0 // Pop value from stack into local Variable 0
IL_0006: ldloc.0 // Load local variable 0 onto stack
IL_0007: ldstr "del" // Loads string "del" in to top of stack
IL_000c: call bool [mscorlib]System.String::op_Equality(string, string) // Compares strings to see if they are equal
IL_0011: stloc.1 // Pop value from stack into local variable 1
IL_0012: ldloc.1 // Load local variable 1 onto the stack
IL_0013: brfalse.s IL_004e // If variable 1 is true keep going else jump to IL_004e
ldelem.ref
在这里做什么?
op_Equality
是在比较字符串 "del" 和变量 0 的内容吗?
我认为调用完成后,操作的布尔值然后存储在堆栈的顶部并且 stloc.1
弹出布尔值并将其存储在变量 1 中,然后 ldloc.1
加载将该变量压入堆栈并 brfalse.s
检查 Bool 值,如果 "jumps" 为 IL_004e
为假,是这种情况吗?
ldelem.ref 将对数组元素的引用压入堆栈。这意味着它制作了它的副本,而不是实际存储的引用。阅读 System.Reflection.Emit documentation 以了解更多信息可能会有用。
另一件可能有助于理解的事情是,每条 MSIL 指令都需要来自堆栈的 N 个值,其中 N 由所使用的特定指令(除其他事项外)决定。这可以用来在心理上对事物进行分组以便于理解。
IL_0002: ldarg.0
IL_0003: ldc.i4.0
IL_0004: ldelem.ref
ldelem.ref 要求堆栈按顺序具有:数组引用,该数组的索引。它将弹出这些值,然后将引用压入堆栈。堆栈现在只包含一个东西。
IL_0005: stloc.0
堆栈上的唯一值现在被弹出并放入本地存储。堆栈为空。
IL_0006: ldloc.0
IL_0007: ldstr "del"
IL_000c: call bool [mscorlib]System.String::op_Equality(string, string)
调用指令将在堆栈中弹出与参数一样多的项(如果调用的方法是实例方法,则包括实例)。在这种情况下,它需要两个字符串参数,并将弹出局部变量的内容以及文字字符串 "del"。静态方法op_Equality returns 一个bool,这样就会被压入栈中。堆栈现在只包含一个东西。
IL_0011: stloc.1
堆栈上的唯一值现在被弹出并放入本地存储。堆栈为空。
IL_0012: ldloc.1
IL_0013: brfalse.s IL_004e
然后加载值并应用分支逻辑。
在 C# 中,MSIL 正在执行与以下内容等效的操作:
if (array[0] == "del")
MSIL 中的一切都是一种平衡行为。由于这是一个调试版本,与优化版本相比,可能有更多的 nop 指令和更多的局部变量使用(这对你有好处,因为你可以更容易地理解事情)。
我想解释一下 ldelem.ref
的作用。到目前为止,我已经将索引处的元素作为 O.
索引是什么?我认为类型 O 意味着对象的类型将保持不变,例如,如果它是一个字符串,它将保持一个字符串。
下面是我正在处理的一些代码的示例,非常感谢您的理解。我评论了我相信我知道的。 所以在这种情况下是
.locals init (
string V_0,
bool V_1,
string V_2,
bool V_3,
string V_4,
string V_5,
string V_6) // Declared 6 variables
.try
{
IL_0000: nop
IL_0001: nop // Does nothing - Debug build
IL_0002: ldarg.0 // Loads Argument 0 into memory/stack
IL_0003: ldc.i4.0 // Push Constant Value 0 into memory [Possibly from a variable]
IL_0004: ldelem.ref // Loads element at index onto the top of the stack as an O
IL_0005: stloc.0 // Pop value from stack into local Variable 0
IL_0006: ldloc.0 // Load local variable 0 onto stack
IL_0007: ldstr "del" // Loads string "del" in to top of stack
IL_000c: call bool [mscorlib]System.String::op_Equality(string, string) // Compares strings to see if they are equal
IL_0011: stloc.1 // Pop value from stack into local variable 1
IL_0012: ldloc.1 // Load local variable 1 onto the stack
IL_0013: brfalse.s IL_004e // If variable 1 is true keep going else jump to IL_004e
ldelem.ref
在这里做什么?
op_Equality
是在比较字符串 "del" 和变量 0 的内容吗?
我认为调用完成后,操作的布尔值然后存储在堆栈的顶部并且 stloc.1
弹出布尔值并将其存储在变量 1 中,然后 ldloc.1
加载将该变量压入堆栈并 brfalse.s
检查 Bool 值,如果 "jumps" 为 IL_004e
为假,是这种情况吗?
ldelem.ref 将对数组元素的引用压入堆栈。这意味着它制作了它的副本,而不是实际存储的引用。阅读 System.Reflection.Emit documentation 以了解更多信息可能会有用。
另一件可能有助于理解的事情是,每条 MSIL 指令都需要来自堆栈的 N 个值,其中 N 由所使用的特定指令(除其他事项外)决定。这可以用来在心理上对事物进行分组以便于理解。
IL_0002: ldarg.0
IL_0003: ldc.i4.0
IL_0004: ldelem.ref
ldelem.ref 要求堆栈按顺序具有:数组引用,该数组的索引。它将弹出这些值,然后将引用压入堆栈。堆栈现在只包含一个东西。
IL_0005: stloc.0
堆栈上的唯一值现在被弹出并放入本地存储。堆栈为空。
IL_0006: ldloc.0
IL_0007: ldstr "del"
IL_000c: call bool [mscorlib]System.String::op_Equality(string, string)
调用指令将在堆栈中弹出与参数一样多的项(如果调用的方法是实例方法,则包括实例)。在这种情况下,它需要两个字符串参数,并将弹出局部变量的内容以及文字字符串 "del"。静态方法op_Equality returns 一个bool,这样就会被压入栈中。堆栈现在只包含一个东西。
IL_0011: stloc.1
堆栈上的唯一值现在被弹出并放入本地存储。堆栈为空。
IL_0012: ldloc.1
IL_0013: brfalse.s IL_004e
然后加载值并应用分支逻辑。
在 C# 中,MSIL 正在执行与以下内容等效的操作:
if (array[0] == "del")
MSIL 中的一切都是一种平衡行为。由于这是一个调试版本,与优化版本相比,可能有更多的 nop 指令和更多的局部变量使用(这对你有好处,因为你可以更容易地理解事情)。