Compact Framework OpCode Support in a Nutshell

While the stated goal of this blog is to address issues that affect the day-to-day work of most developers, from time to time I'll publish something for the propeller-heads in the audience. This is one of those times.


The instruction set for a CLI compliant execution engine is described by ECMA's CLI Partition III (CIL Instruction Set). The Compact Framework execution engine implementation supports most, but not all, of these instructions. In general, the decision to support an opcode was based on whether it could be generated by one of the compilers supported by CF (C# and Visual Basic, at this time).

Unsupported instructions for v2

An unsupported instruction or prefix is one that will cause an InvalidProgramException if it is encountered by the execution engine. This is in contrast to an instruction or prefix that is simply ignored by the execution engine. CF 1.x had 7 unsupported instructions and 3 unsupported prefixes. CF 2.0 has 7 unsupported instructions and 2 unsupported prefixes. In addition, CF 2.0 has 1 new instruction and 3 new prefixes.

The unsupported instructions in CF 2.0 fall into four categories:

[Edited to fix table layout]



Category Instructions
indirect function calls
  • calli
  • jmp
variable-length argument list support
  • arglist
  • mkrefany
  • refanyval
  • refanytype
local dynamic memory allocation
  • localloc
  • unaligned.
  • tail.


The calli, arglist, mkrefany, refanyval, and refanytype instructions are used to support features of Managed C++. calli supports the closely coupled native/managed interop done by managed C++. The other four instructions are primarily used in the MC++ varargs implementation. Since CF doesn't support MC++, these instructions were left out.

The localloc instruction is used to allocate bytes from the local memory pool. It's use is similar to that of the standard C runtime alloca() function. It wasn't implemented because, while it can be generated by the C# compiler, it isn't widely used and can be easily avoided.

The unaligned. and tail. prefixes were omitted because CF doesn't have any customer scenarios that require them.

New instructions for v2

The unbox.any instruction and the constrained. and readonly. prefixes were added to support generics. unbox.any extracts the value contained in a boxed type and is the equivalent of an unbox followed by ldobj. readonly. optimizes access to elements of a generic array by avoiding a type check when fetching an array element by guaranteeing that the element has not been modified. constrained. was introduced to allow the callvirt instruction to work in a uniform way with both value types and references types.

The no. prefix indicates that the execution engine need not check for type, range, and/or null exceptions when the next instruction is executed. CF 2.0 ignores this instruction because it is designated as optional in the ECMA specification.


A quick trip through any subject must naturally leave out a lot of information. If you have questions about opcode specifications, the ECMA spec is the place to start. If you want to see how the compiler translates high-level code into IL opcodes, use ILDasm.exe to disassemble your executable. You can find a tutorial here. Most of what I know about IL, I've learned from ILDasm. If you still have questions, feel free to ask.




  • Legend
  • yes: instruction is supported in given version
  • no: instruction is not supported in given version
  • X: instruction did not exist in given version


Opcode Instruction V1 Support V2 Support   Opcode Instruction V1 Support V2 Support   Opcode Instruction V1 Support V2 Support
0x00 nop yes yes   0x50 ldind.ref yes yes   0xA0 stelem.r4 yes yes
0x01 break yes yes   0x51 stind.ref yes yes   0xA1 stelem.r8 yes yes
0x02 ldarg.0 yes yes   0x52 stind.i1 yes yes   0xA2 stelem.ref yes yes
0x03 ldarg.1 yes yes   0x53 stind.i2 yes yes   0xA3 ldelem yes yes
0x04 ldarg.2 yes yes   0x54 stind.i4 yes yes   0xA4 stelem yes yes
0x05 ldarg.3 yes yes   0x55 stind.i8 yes yes   0xA5 unbox.any X yes
0x06 ldloc.0 yes yes   0x56 stind.r4 yes yes   0xB3 conv.ovf.i1 yes yes
0x07 ldloc.1 yes yes   0x57 stind.r8 yes yes   0xB4 conv.ovf.u1 yes yes
0x08 ldloc.2 yes yes   0x58 add yes yes   0xB5 conv.ovf.i2 yes yes
0x09 ldloc.3 yes yes   0x59 sub yes yes   0xB6 conv.ovf.u2 yes yes
0x0A stloc.0 yes yes   0x5A mul yes yes   0xB7 conv.ovf.i4 yes yes
0x0B stloc.1 yes yes   0x5B div yes yes   0xB8 conv.ovf.u4 yes yes
0x0C stloc.2 yes yes   0x5C div.un yes yes   0xB9 conv.ovf.i8 yes yes
0x0D stloc.3 yes yes   0x5D rem yes yes   0xBA conv.ovf.u8 yes yes
0x0E ldarg.s yes yes   0x5E rem.un yes yes   0xC2 refanyval no no
0x0F ldarga.s yes yes   0x5F and yes yes   0xC3 ckfinite yes yes
0x10 starg.s yes yes   0x60 or yes yes   0xC6 mkrefany no no
0x11 ldloc.s yes yes   0x61 xor yes yes   0xD0 ldtoken yes yes
0x12 ldloca.s yes yes   0x62 shl yes yes   0xD1 conv.u2 yes yes
0x13 stloc.s yes yes   0x63 shr yes yes   0xD2 conv.u1 yes yes
0x14 ldnull yes yes   0x64 shr.un yes yes   0xD3 conv.i yes yes
0x15 ldc.i4.m1 yes yes   0x65 neg yes yes   0xD4 conv.ovf.i yes yes
0x16 ldc.i4.0 yes yes   0x66 not yes yes   0xD5 conv.ovf.u yes yes
0x17 ldc.i4.1 yes yes   0x67 conv.i1 yes yes   0xD6 add.ovf yes yes
0x18 ldc.i4.2 yes yes   0x68 conv.i2 yes yes   0xD7 add.ovf.un yes yes
0x19 ldc.i4.3 yes yes   0x69 conv.i4 yes yes   0xD8 mul.ovf yes yes
0x1A ldc.i4.4 yes yes   0x6A conv.i8 yes yes   0xD9 mul.ovf.un yes yes
0x1B ldc.i4.5 yes yes   0x6B conv.r4 yes yes   0xDA sub.ovf yes yes
0x1C ldc.i4.6 yes yes   0x6C conv.r8 yes yes   0xDB sub.ovf.un yes yes
0x1D ldc.i4.7 yes yes   0x6D conv.u4 yes yes   0xDC endfinally yes yes
0x1E ldc.i4.8 yes yes   0x6E conv.u8 yes yes   0xDD leave yes yes
0x1F ldc.i4.s yes yes   0x6F callvirt yes yes   0xDE leave.s yes yes
0x20 ldc.i4 yes yes   0x70 cpobj yes yes   0xDF stind.i yes yes
0x21 ldc.i8 yes yes   0x71 ldobj yes yes   0xE0 conv.u yes yes
0x22 ldc.r4 yes yes   0x72 ldstr yes yes   0xFE 0x00 arglist no no
0x23 ldc.r8 yes yes   0x73 newobj yes yes   0xFE 0x01 ceq yes yes
0x25 dup yes yes   0x74 castclass yes yes   0xFE 0x02 cgt yes yes
0x26 pop yes yes   0x75 isinst yes yes   0xFE 0x03 cgt.un yes yes
0x27 jmp no no   0x76 conv.r.un yes yes   0xFE 0x04 clt yes yes
0x28 call yes yes   0x79 unbox yes yes   0xFE 0x05 clt.un yes yes
0x29 calli no no   0x7A throw yes yes   0xFE 0x06 ldftn yes yes
0x2A ret yes yes   0x7B ldfld yes yes   0xFE 0x07 ldvirtftn yes yes
0x2B br.s yes yes   0x7C ldflda yes yes   0xFE 0x09 ldarg yes yes
0x2C brfalse.s yes yes   0x7D stfld yes yes   0xFE 0x0A ldarga yes yes
0x2D brtrue.s yes yes   0x7E ldsfld yes yes   0xFE 0x0B starg yes yes
0x2E beq.s yes yes   0x7F ldsflda yes yes   0xFE 0x0C ldloc yes yes
0x2F bge.s yes yes   0x80 stsfld yes yes   0xFE 0x0D ldloca yes yes
0x30 bgt.s yes yes   0x81 stobj yes yes   0xFE 0x0E stloc yes yes
0x31 ble.s yes yes   0x82 conv.ovf.i1.un yes yes   0xFE 0x0F localloc no no
0x32 blt.s yes yes   0x83 conv.ovf.i2.un yes yes   0xFE 0x11 endfilter yes yes
0x33 bne.un.s yes yes   0x84 conv.ovf.i4.un yes yes   0xFE 0x12 unaligned. no no
0x34 bge.un.s yes yes   0x85 conv.ovf.i8.un yes yes   0xFE 0x13 volatile. no yes
0x35 bgt.un.s yes yes   0x86 conv.ovf.u1.un yes yes   0xFE 0x14 tail. no no
0x36 ble.un.s yes yes   0x87 conv.ovf.u2.un yes yes   0xFE 0x15 initobj yes yes
0x37 blt.un.s yes yes   0x88 conv.ovf.u4.un yes yes   0xFE 0x16 constrained. X yes
0x38 br yes yes   0x89 conv.ovf.u8.un yes yes   0xFE 0x17 cpblk yes yes
0x39 brfalse yes yes   0x8A conv.ovf.i.un yes yes   0xFE 0x18 initblk yes yes
0x3A brtrue yes yes   0x8B conv.ovf.u.un yes yes   0xFE 0x19 no. X yes
0x3B beq yes yes   0x8C box yes yes   0xFE 0x1A rethrow yes yes
0x3C bge yes yes   0x8D newarr yes yes   0xFE 0x1C sizeof yes yes
0x3D bgt yes yes   0x8E ldlen yes yes   0xFE 0x1D refanytype no no
0x3E ble yes yes   0x8F ldelema yes yes   0xFE 0x1E readonly. X yes
0x3F blt yes yes   0x90 ldelem.i1 yes yes
0x40 bne.un yes yes   0x91 ldelem.u1 yes yes
0x41 bge.un yes yes   0x92 ldelem.i2 yes yes
0x42 bgt.un yes yes   0x93 ldelem.u2 yes yes
0x43 ble.un yes yes   0x94 ldelem.i4 yes yes
0x44 blt.un yes yes   0x95 ldelem.u4 yes yes
0x45 switch yes yes   0x96 ldelem.i8 yes yes
0x46 ldind.i1 yes yes   0x97 ldelem.i yes yes
0x47 ldind.u1 yes yes   0x98 ldelem.r4 yes yes
0x48 ldind.i2 yes yes   0x99 ldelem.r8 yes yes
0x49 ldind.u2 yes yes   0x9A ldelem.ref yes yes
0x4A ldind.i4 yes yes   0x9B stelem.i yes yes
0x4B ldind.u4 yes yes   0x9C stelem.i1 yes yes
0x4C ldind.i8 yes yes   0x9D stelem.i2 yes yes
0x4D ldind.i yes yes   0x9E stelem.i4 yes yes
0x4E ldind.r4 yes yes   0x9F stelem.i8 yes yes
0x4F ldind.r8 yes yes

[Edited to fix table layout]