Search code examples
c#il

Why is the 'br.s' IL opcode used in this case?


For educational purposes I'm learning a bit of IL (mainly because I was curious what happens to '%' under the hood (which turns out to be rem) and started digressing...).

I wrote a method, just returning true to break things down a bit and was wondering about the 'br.s' opcode:

.method public hidebysig static bool  ReturnTrue() cil managed
{
  // Code size       7 (0x7)
  .maxstack  1
  .locals init ([0] bool CS$1$0000)
  IL_0000:  nop
  IL_0001:  ldc.i4.1
  IL_0002:  stloc.0
  IL_0003:  br.s       IL_0005
  IL_0005:  ldloc.0
  IL_0006:  ret
} // End of method Primes::ReturnTrue

After ldc.i4.1 pushes 1 on the stack and stloc.0 places this in the 0th local, br.s basically (as far as I know) does a 'goto' to ldloc.0 at line IL_0005.

Why is this? Why is there simply no IL_0004 line so this could be omitted?


Solution

  • That branch is for debugging purposes, the return value has been calculated and stored away and now the debugger can be "called". It's the same with the NOP in the method entry.

    With regards to IL_0004, as @hvd states, br.s has an address and doesn't fit in "one row", one byte here (I don't know how familiar you are with addressing, but one instruction usually is one byte, that is, 8-bit, as well as the address or offset, typically 8-, 16- or 32-bit. In this case we have an 8-bit opcode with an 8-bit offset. Wikipedia has a good article on CIL-OP-codes).

    Additionally, let's say your method has multiple returns and via for example if-branches, all of them jump to the end, IL_0005 in your case, so only one breakpoint is needed at function return.