The instruction set of CIL has 219 instruction names in the table of this site (the 227 rows of cil.js without the eight reserved ones), listed here by the groups of the CIL opcode reference, which gives the byte encoding, the exact stack transition and the rules of each one (the opcode table behind both pages is explorer/formats/dotnet/cil.js, checked against System.Reflection.Emit.OpCodes and against ilasm’s own opcode.def). This page shows what you write: the mnemonic, then the operand, if any.
CIL is a stack machine. Most instructions take their operands from the evaluation stack and push a result; the stack column below reads before → after with the top of the stack on the right. A name that ends in a number or .s is a short form or macro of another instruction: ldarg.0 is ldarg 0 in one byte, br.s is br with a one-byte offset. A name ending in .un works on unsigned values (or, for floats, handles unordered values), and one with .ovf throws an OverflowException when the result does not fit.
What follows the mnemonic
Operand kind (cil.js) | Written as | Example |
|---|---|---|
none (InlineNone) | nothing | add, ldarg.0, ret |
variable (InlineVar, ShortInlineVar) | an argument or local variable: its number, or its name from the header or .locals | ldarg 2, ldarg.s count, stloc V_0 |
integer (ShortInlineI, InlineI, InlineI8) | an int8, int32 or int64 constant; ldc.i4.s takes −128 to 127 | ldc.i4 100000, ldc.i8 0x100000000 |
real (ShortInlineR, InlineR) | a real number (or an integer), or a list of hex bytes in brackets | ldc.r8 3.14, ldc.r4 (00 00 C0 7F) |
string (InlineString) | a string, a chain of strings joined with +, ansi("…") or bytearray (…) | ldstr "Hello" |
branch target (InlineBrTarget, ShortInlineBrTarget) | a label (or a number: a relative offset) | br.s done, blt IL_0020 |
switch (InlineSwitch) | a parenthesised list of labels | switch (L0, L1, L2) |
type (InlineType) | a type specification | box int32, castclass [mscorlib]System.String |
field (InlineField) | a field reference: type, class, ::, name | ldfld int32 Foo::count |
method (InlineMethod) | a method reference: calling convention, return type, class, ::, name, parameter types | call void [mscorlib]System.Console::WriteLine(string) |
token (InlineTok) | a type, or method and a method reference, or field and a field reference | ldtoken Foo, ldtoken method void Foo::M() |
signature (InlineSig) | calling convention, return type and parameter types in parentheses (a stand-alone signature) | calli int32(int32) |
The mnemonics are case-sensitive and keep their dots (ldc.i4.s, tail.); . after a prefix is part of the name. ilasm also accepts twelve aliases from its own opcode.def: brnull and brzero (for brfalse), brinst (for brtrue), their .s forms brnull.s, brzero.s and brinst.s, ldind.u8 (for ldind.i8), ldelem.u8 (for ldelem.i8), ldelem.any and stelem.any (for ldelem and stelem), ldc.i4.M1 (for ldc.i4.m1) and endfault (for endfinally).
Loads and stores
Reference: loads and stores.
| Instructions | Operand | Stack | Effect |
|---|---|---|---|
ldarg.0 ldarg.1 ldarg.2 ldarg.3 | none | … → …, value | push argument 0 to 3 (argument 0 is this in an instance method) |
ldarg.s ldarg | argument | … → …, value | push an argument |
ldarga.s ldarga | argument | … → …, address | push the address of an argument |
starg.s starg | argument | …, value → … | store into an argument |
ldloc.0 ldloc.1 ldloc.2 ldloc.3 ldloc.s ldloc | none, or local | … → …, value | push a local variable |
ldloca.s ldloca | local | … → …, address | push the address of a local |
stloc.0 stloc.1 stloc.2 stloc.3 stloc.s stloc | none, or local | …, value → … | pop into a local |
ldnull | none | … → …, null | push a null reference |
ldc.i4.m1 ldc.i4.0 ldc.i4.1 ldc.i4.2 ldc.i4.3 ldc.i4.4 ldc.i4.5 ldc.i4.6 ldc.i4.7 ldc.i4.8 | none | … → …, int32 | push −1 and 0 to 8 |
ldc.i4.s ldc.i4 ldc.i8 | int8, int32, int64 | … → …, int32 or int64 | push an integer constant |
ldc.r4 ldc.r8 | real | … → …, float | push a floating-point constant |
ldstr | string | … → …, string | push a string literal |
ldind.i1 ldind.u1 ldind.i2 ldind.u2 ldind.i4 ldind.u4 ldind.i8 ldind.i ldind.r4 ldind.r8 ldind.ref | none | …, address → …, value | load a value of that type through an address |
stind.ref stind.i1 stind.i2 stind.i4 stind.i8 stind.r4 stind.r8 stind.i | none | …, address, value → … | store a value of that type through an address |
ldobj stobj | type | …, address → …, value; …, address, value → … | load or store a value type through an address |
cpobj | type | …, dest, src → … | copy a value type from one address to another |
initobj | type | …, address → … | set a value type to zero |
cpblk initblk | none | …, dest, src or value, size → … | copy a block of bytes, or fill it with a byte |
dup pop | none | …, v → …, v, v; …, v → … | duplicate or remove the top of the stack |
Arithmetic, logic, comparison and conversion
Reference: arithmetic, logic, comparison and conversion.
| Instructions | Operand | Stack | Effect |
|---|---|---|---|
add sub mul div rem | none | …, a, b → …, result | arithmetic (rem is the remainder; div and rem signed) |
div.un rem.un shr.un | none | …, a, b → …, result | unsigned division, remainder and right shift |
add.ovf add.ovf.un sub.ovf sub.ovf.un mul.ovf mul.ovf.un | none | …, a, b → …, result | checked arithmetic, signed and unsigned |
neg not | none | …, v → …, result | arithmetic negation; bitwise complement |
and or xor shl shr | none | …, a, b → …, result | bitwise and, or, exclusive or; shift left; arithmetic shift right |
ceq cgt cgt.un clt clt.un | none | …, a, b → …, 0 or 1 | compare: equal, greater, less (signed, and unsigned or unordered) |
ckfinite | none | …, float → …, float | throws an ArithmeticException if the value is infinite or NaN |
conv.i1 conv.i2 conv.i4 conv.i8 conv.r4 conv.r8 conv.u1 conv.u2 conv.u4 conv.u8 conv.i conv.u conv.r.un | none | …, v → …, converted | convert to that type (conv.r.un converts an unsigned integer to a float); no overflow check |
conv.ovf.i1 conv.ovf.u1 conv.ovf.i2 conv.ovf.u2 conv.ovf.i4 conv.ovf.u4 conv.ovf.i8 conv.ovf.u8 conv.ovf.i conv.ovf.u | none | …, v → …, converted | convert a signed value, throwing on overflow |
conv.ovf.i1.un conv.ovf.u1.un conv.ovf.i2.un conv.ovf.u2.un conv.ovf.i4.un conv.ovf.u4.un conv.ovf.i8.un conv.ovf.u8.un conv.ovf.i.un conv.ovf.u.un | none | …, v → …, converted | convert an unsigned value, throwing on overflow |
Branches and switch
Reference: branches and switch; the rules are on the control flow page.
| Instructions | Operand | Stack | Effect |
|---|---|---|---|
br.s br | label | … → … | jump |
brfalse.s brfalse brtrue.s brtrue | label | …, v → … | jump if the value is false, null or zero, or if it is true or non-null |
beq.s beq bne.un.s bne.un | label | …, a, b → … | jump if equal, or if not equal (or unordered) |
bge.s bge bgt.s bgt ble.s ble blt.s blt | label | …, a, b → … | jump if a is greater or equal, greater, less or equal, less than b |
bge.un.s bge.un bgt.un.s bgt.un ble.un.s ble.un blt.un.s blt.un | label | …, a, b → … | the same, unsigned or unordered |
switch | (label, …) | …, index → … | jump to the label at that position, or go on |
Calls and returns
Reference: calls and returns.
| Instructions | Operand | Stack | Effect |
|---|---|---|---|
call | method | …, args → …, result | call a method directly (a constructor with instance) |
callvirt | method | …, this, args → …, result | call through the object’s type (virtual dispatch) |
calli | signature | …, args, function pointer → …, result | call through a function pointer |
ret | none | …, value → (returns) | return, with the value if the method has one |
jmp | method | … → … | transfer to another method with the same arguments |
newobj | method (a constructor) | …, args → …, object | create an object and run the constructor |
ldftn | method | … → …, pointer | push a pointer to a method |
ldvirtftn | method | …, object → …, pointer | push a pointer to the virtual method of this object |
arglist | none | … → …, handle | push the handle of the extra arguments of a vararg method |
Fields, types and boxing
Reference: fields, types and boxing.
| Instructions | Operand | Stack | Effect |
|---|---|---|---|
ldfld ldflda stfld | field | …, object → …, value or address; …, object, value → … | load, take the address of, or store an instance field |
ldsfld ldsflda stsfld | field | … → …, value or address; …, value → … | the same for a static field |
castclass isinst | type | …, object → …, object or null | cast (throws if it fails), or test (null if it fails) |
box unbox unbox.any | type | …, value → …, object; …, object → …, address or value | box a value type; get the address of the boxed value; unbox it to a value (or cast, for a reference type) |
ldtoken | token | … → …, handle | push the runtime handle of a type, method or field |
sizeof | type | … → …, size | push the size of a value type in bytes |
mkrefany refanyval refanytype | type, type, none | …, address → …, typedref; …, typedref → …, address; …, typedref → …, type handle | make a typed reference; read its address; read its type |
Arrays
Reference: arrays.
| Instructions | Operand | Stack | Effect |
|---|---|---|---|
newarr | element type | …, length → …, array | create a vector |
ldlen | none | …, array → …, length | push the length of a vector |
ldelema | type | …, array, index → …, address | push the address of an element |
ldelem.i1 ldelem.u1 ldelem.i2 ldelem.u2 ldelem.i4 ldelem.u4 ldelem.i8 ldelem.i ldelem.r4 ldelem.r8 ldelem.ref | none | …, array, index → …, value | load an element of that type |
ldelem | type | …, array, index → …, value | load an element of any type |
stelem.i stelem.i1 stelem.i2 stelem.i4 stelem.i8 stelem.r4 stelem.r8 stelem.ref | none | …, array, index, value → … | store an element of that type |
stelem | type | …, array, index, value → … | store an element of any type |
Exceptions
Reference: exceptions; the blocks are on the control flow page.
| Instructions | Operand | Stack | Effect |
|---|---|---|---|
throw | none | …, exception → … | throw an exception object |
rethrow | none | … → … | throw the exception being handled again (in a catch handler only) |
leave.s leave | label | … → (empty) | exit a protected block, running finally handlers |
endfinally | none | … → … | end a finally or fault handler |
endfilter | none | …, answer → … | end a filter with 1 (handle) or 0 (go on) |
Prefixes
Reference: prefixes. A prefix is written on its own, before the instruction it changes.
| Instructions | Operand | Effect on the next instruction |
|---|---|---|
tail. | none | make the call that follows a tail call (it must be followed by ret) |
volatile. | none | make the load or store that follows a volatile access |
unaligned. | 1, 2 or 4 | the address may be unaligned (to that many bytes) |
constrained. | type | call a virtual method on a value of a variable type without boxing it (before callvirt) |
readonly. | none | the array address ldelema pushes is for reading only |
no. | 1, 2 or 4 | the runtime may skip the type check (1), range check (2) or null check (4) of the instruction that follows; it is in the standard and in System.Reflection.Emit but not in this copy of ilasm’s opcode.def |
No operation, breakpoint and local allocation
Reference: no-operation, breakpoint, local allocation and reserved bytes.
| Instructions | Operand | Stack | Effect |
|---|---|---|---|
nop | none | … → … | do nothing |
break | none | … → … | signal the debugger |
localloc | none | …, size → …, address | allocate that many bytes on the stack frame of the method |
The table of cil.js also holds eight rows that are not instructions: the reserved prefix bytes prefix1, prefix2, prefix3, prefix4, prefix5, prefix6, prefix7 and prefixref (the opcode type is Nternal, which is the spelling of System.Reflection.Emit). The viewer does not colour them as instructions. The opcode.def of ilasm lists them and the unassigned bytes (as unused) and three pseudo rows (illegal, endmac, codelabel) too.
An example
.method public hidebysig static int32 SumTo(int32 n) cil managed
{
.maxstack 2
.locals init (int32 total, int32 i)
ldc.i4.0
stloc total
ldc.i4.1
stloc i
br.s test
body:
ldloc total
ldloc i
add
stloc total
ldloc i
ldc.i4.1
add
stloc i
test:
ldloc i
ldarg.0
ble.s body
ldloc total
ret
}
n in a loop: constants, locals by name, arithmetic, a conditional branch back, and the return value left on the stack.Not described
Known, not yet covered
- Reference: the exact stack transitions with types, the verification rules and the exceptions each instruction can throw (Partition III) are not repeated; the CIL opcode reference holds them. The stack column here is the plain-language form.
- Reference: instructions that .NET versions after the 6th edition of the standard added to the runtime but that are not in
System.Reflection.Emit.OpCodeswere not looked for.