3

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?

Barry
  • 448
  • 5
  • 10

2 Answers2

9

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).

Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106
  • 3
    It's probably easier to just ensure every instruction is given a label than it is to track which labels needs to be emitted and only emit those. – Lasse V. Karlsen Dec 07 '15 at 10:46
6

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.

svick
  • 236,525
  • 50
  • 385
  • 514