Most people meet IL assembly as a listing in a decompiler or the output of a disassembler; a few write it by hand for tests, for code that C# cannot express, or to patch an assembly. The two tools that define the format are ildasm (assembly to text) and ilasm (text to assembly). Both are built from the open dotnet/runtime repository (src/coreclr/ildasm and src/coreclr/ilasm), and the NuGet packages Microsoft.NETCore.ILAsm and Microsoft.NETCore.ILDAsm (and the runtime.rid.Microsoft.NETCore.ILAsm packages for each platform, for example runtime.osx-arm64) carry them; their version lists on nuget.org run up to 11.0.0.
// a round trip with the usage text of the two tools
// ildasm /OUT=Hello.il Hello.dll
// (edit Hello.il)
// ilasm Hello.il /DLL /OUTPUT=Hello2.dll
.assembly extern mscorlib {}
.assembly Hello {}
.module Hello.dll
/OUT= of ildasm, /DLL and /OUTPUT= of ilasm); the three lines of IL are the start of a listing.ilasm
ilasm [options] source file [options]. Options start with - or / and are recognised by their first three letters (except ARM and ARM64); the default source extension is .il. From the usage text of the program:
| Option | Meaning |
|---|---|
/NOLOGO, /QUIET | no logo; no progress report |
/NOAUTOINHERIT | do not make System.Object the default base type |
/DLL, /EXE | write a library, or an executable (the default) |
/OUTPUT=file | the name of the output file (with its extension) |
/PDB, /DEBUG, /DEBUG=IMPL, /DEBUG=OPT | write a PDB file; with /DEBUG the JIT optimisation is off and the sequence points come from the PDB (IMPL: implicit sequence points; OPT: optimisation stays on) |
/DET | deterministic output |
/OPTIMIZE, /FOLD | turn long instructions into short ones; merge identical method bodies |
/KEY=keyfile, /KEY=@source | sign the assembly with a strong name from a key file or key source |
/ANAME=name | override the name of the assembly |
/INCLUDE=path | folders to search for #include files |
/SUBSYSTEM=n, /SSVER=a.b, /FLAGS=n, /ALIGNMENT=n, /BASE=n, /STACK=n | the PE and CLR header fields that .subsystem, .corflags, .file alignment, .imagebase and .stackreserve set, and the subsystem version |
/MDV=version, /MSV=a.b | the metadata version string; the metadata stream version |
/PE64, /X64, /ARM, /ARM64, /32BITPREFERRED | the kind of image: PE32+; 64-bit AMD; ARM; ARM64; a 32-bit-preferred PE32 (/PE64 implies /X64 and /ARM64 implies /PE64) |
/APPCONTAINER, /HIGHENTROPYVA, /NOCORSTUB, /STRIPRELOC, /CLOCK | an AppContainer image; high-entropy address space; no CORExeMain stub; no base relocations needed; report the time of each stage |
ildasm
ildasm [options] file [options]; the options also begin with - or / and are recognised by their first three letters.
| Option | Meaning |
|---|---|
/OUT=file, /HTML, /RTF | write to a file instead of the console; HTML and rich text are valid with /OUT only |
/BYTES, /TOKENS, /SOURCE, /LINENUM | show the bytes of each instruction as comments; the metadata tokens; the source lines as comments; references to the source lines |
/RAWEH | show exception clauses in raw form |
/VISIBILITY=vis[+vis…], /PUBONLY | only items with the visibility PUB, PRI, FAM, ASM, FAA, FOA or PSC; only public items |
/QUOTEALLNAMES | put every name in single quotes |
/NOCA, /CAVERBAL | no custom attributes; custom attribute blobs in the verbal form instead of bytes |
/UTF8, /UNICODE | the encoding of the output (the default is ANSI) |
/NOIL, /FORWARD, /TYPELIST, /PROJECT | no IL code; forward class declarations; the full list of types to keep their order in a round trip; the projected view of a .winmd file |
/HEADERS, /STATS, /CLASSLIST, /ALL | file header information; statistics; the list of classes; all of /HEADER, /BYTES, /STATS, /CLASSLIST and /TOKENS |
/ITEM=class[::method[(sig)]] | disassemble one class or method |
/METADATA[=specifier], /R2RNATIVEMETADATA | show the metadata (MDHEADER, HEX, CSV, UNREX, SCHEMA, RAW, HEAPS, VALIDATE); the metadata of the ReadyToRun native manifest |
Mono and other tools
| Tool | What it does with IL |
|---|---|
Mono ilasm and monodis | Mono’s assembler and disassembler (the dialects) |
| ILSpy, dnSpy, SharpLab and similar decompilers | show an assembly as C#, Visual Basic or F# and also as IL; their IL is not always ilasm-ready text |
Mono.Cecil, System.Reflection.Emit, System.Reflection.Metadata | libraries that read or write assemblies and IL instructions without text |
| this site’s .NET assembly viewer | lists method bodies in the style of ildasm (explorer/formats/dotnet/listing.js: the .method header, // Code size, .maxstack, .locals, one instruction a line, try and handler blocks in braces); its opcode reference shares the instruction table with the .il viewer |
Not described
Known, not yet covered
- Reference: the command-line options of Mono’s
ilasmandmonodiswere not read (only their lexer tables and the listing code). The IL views of ILSpy, dnSpy and SharpLab were not compared with ilasm’s syntax.
Unknown
- Reference: none of these tools was run: there is no .NET SDK on this Mac, and the NuGet packages were looked up in the nuget.org version index only; no package was downloaded or run.