There is no single IL assembly language. The standard (ECMA-335 Partition II) describes one syntax that its authors call ILAsm; the ilasm of .NET (source in dotnet/runtime, src/coreclr/ilasm) accepts a superset of it with some words spelled differently; Mono’s ilasm (mcs/ilasm) is a separate program written in C#. The disassemblers, ildasm and Mono’s monodis, each write the text in their own layout. This page lists what was found by reading their sources.
The tools
| Tool | Direction | Source read |
|---|---|---|
| ilasm (.NET) | .il to .exe or .dll | asmparse.y, grammar_after.cpp, il_kywd.h, opcode.def, main.cpp (dotnet/runtime, main branch) |
| ildasm (.NET) | assembly to .il | dasm.cpp, dis.cpp and the usage strings in dasm.rc |
| ilasm (Mono) | .il to .exe or .dll | ILTokenizer.cs, ILTables.cs, ILParser.jay (mono/mono) |
| monodis (Mono) | assembly to .il, and other dumps | mono/dis/main.c and dis-cil.c |
| ilasm and ildasm of the .NET Framework (Windows) | the same, older | not read: only the open-source descendants are available here |
The standard against ilasm
| In the standard | In ilasm (.NET) | Note |
|---|---|---|
.culture "name" | .locale "name" | the culture of an assembly; .culture is not in the keyword table of either ilasm |
compilercontrolled | privatescope | the accessibility of members that are not visible outside the compiler; Mono’s ilasm has both words |
platformapi (in pinvokeimpl) | winapi | the default calling convention of the platform |
.permission settings as 'name' = 'value' | "name" = value with typed values | see Custom attributes |
pinvokeimpl only on global methods, with native unmanaged | on any static method, with cil managed (preservesig) as the compilers write it | see Marshalling and platform invoke |
a list of top-level declarations without .namespace, .typedef, .language, .typelist, .mscorlib, .file alignment, .imagebase, .stackreserve, .interfaceimpl, .param constraint | all of these are accepted | ilasm-only directives; the preprocessor is ilasm-only too |
| class attributes as listed in II.10.1 | plus value, enum, extended, import, windowsruntime, flags(n) | Classes |
implementation attributes cil, native, runtime, managed, unmanaged, forwardref, internalcall, noinlining, nooptimization, synchronized | plus il, optil, preservesig, aggressiveinlining, aggressiveoptimization, async, flags(n) | Methods |
generic parameter attributes + - class valuetype .ctor | plus byreflike and flags(n) | Classes |
| no instruction aliases | twelve aliases (brnull, brzero, brinst, ldind.u8, ldelem.any, endfault and the rest) | The instruction set |
no. prefix | not in the opcode.def of this copy | so ilasm reads it as a plain name |
Mono’s ilasm
Mono’s tables (ILTables.cs) were compared with the keyword table of .NET’s ilasm. Mono’s lexer is a separate implementation: it reads // and /* */ comments like the other and treats a list of hex bytes the same way, but this page did not compare their number and string handling.
| Only in Mono’s tables | Words |
|---|---|
| Directives | .algorithm .backing .blob .capability .comtype .config .exeloc .implicitcom .mime .originator .os .processor .title |
| Keywords | compilercontrolled disablejitoptimizer enablejittracking fullorigin implicitcom implicitres is lateinit noappdomain nomachine noprocess not_in_gc_heap ole readonly vbbyrefstr |
| Absent from Mono’s tables (present in .NET’s) | .base .interfaceimpl .mscorlib .nester .template .this .typedef .typelist and the preprocessor words #define #undef #ifdef #ifndef #else #endif #include; aggressiveoptimization amd64 arm arm64 async byreflike callconv constraint extended flags iidparam mdtoken noplatform retainappdomain windowsruntime x86 |
The meaning of Mono’s extra words was not looked up. The words inf, nan, lcid, retval, ptr and publickey are in Mono’s table source only as commented-out lines. The viewer follows the .NET words, so the Mono-only directives are read as plain dots and names.
What the disassemblers write
| Feature | ildasm (.NET) | monodis (Mono) |
|---|---|---|
| instruction label | IL_0001: ldstr "x": two spaces after the colon, the name padded to ten characters | a tab, the label and a colon: IL_0001: ldstr "x" |
| indentation | two spaces for each level | tabs inside methods, two spaces for the members of a class |
| an assembly reference | .assembly extern with .publickeytoken, then .ver | .assembly extern with .ver first, then the attributes and .locale |
| the module line | .module Name and a comment with the MVID on the next line | .module Name // GUID = {…} on one line |
| method markers | // Code size 13 (0xd) and // end of method Class::Name | // method line 1 before each method |
| exception handling | blocks in braces; the option /RAWEH gives the ranges as offsets | not compared here |
| custom attributes | bytes by default; the option /CAVERBAL gives the verbal form | bytes (the verbal form was not looked for) |
Not described
Known, not yet covered
- Reference: the differences between the ilasm of the .NET Framework (the Windows program that Visual Studio installs) and the open-source ilasm of .NET could not be listed: only the open-source code was read. The grammar of Mono’s ilasm (
ILParser.jay) was downloaded but compared withasmparse.yonly for its keyword tables, not rule by rule. The listing layout ofmonodiswas read frommono/disfor the lines quoted in the table only.
Unknown
- Reference: what the Mono-only words mean, and whether a modern Mono build still assembles them: no documentation of them was found among the files read (the Mono project’s own manual pages were not fetched).