问题
When using ILDASM.exe on a compiled C# program, it shows that there is a label for every instruction within methods.
For example:
IL_0001: ldc.i4.4
IL_0002: stloc.0
IL_0003: ldc.r8 12.34
IL_000c: stloc.1
IL_000d: ldc.r8 3.1415926535897931
IL_0016: stloc.2
IL_0017: ldstr "Ehsan"
IL_001c: stloc.3
IL_001d: ret
Why is this? Is it not inefficient to do this or does the CIL compiler optimize these labels itself?
回答1:
Labels are not present in the compiled CIL. They are displayed for your convenience in the dissassembled code.
These particular labels correspond to instruction offsets, while there is no such restriction on hand-made code (labels could be arbitrary strings).
回答2:
In compiled IL, there are no labels. Instead, jump instructions use relative offsets from the start of the following instruction.
For example, consider this trivial C# function:
public static bool IsZero(int n)
{
if (n == 0)
return true;
return false;
}
In IL, you might write it like this:
.method public hidebysig static bool IsZero(int32 n) cil managed
{
ldarg.0
brtrue.s label
ldc.i4.1
ret
label:
ldc.i4.0
ret
}
If you compile that using ilasm and then decompile it back using ildasm, with "Show bytes" enabled, you get:
.method public hidebysig static bool IsZero(int32 n) cil managed
// SIG: 00 01 02 08
{
// Method begins at RVA 0x2052
// Code size 7 (0x7)
.maxstack 8
IL_0000: /* 02 | */ ldarg.0
IL_0001: /* 2D | 02 */ brtrue.s IL_0005
IL_0003: /* 17 | */ ldc.i4.1
IL_0004: /* 2A | */ ret
IL_0005: /* 16 | */ ldc.i4.0
IL_0006: /* 2A | */ ret
} // end of method Program::IsZero
Notice how the labels are not in any way represented in the bytes (shown in comments). And that brtrue.s label
from the original IL is here shown as brtrue.s IL_0005
, where the bytes are 2D 02
. 2D
is the compiled form of brtrue.s
, and 02
is a relative offset. Since the following instruction starts at absolute offset 3, the target is at absolute offset 3 + 2 = 5.
来源:https://stackoverflow.com/questions/34131396/why-does-c-sharp-cil-have-a-label-on-every-instruction