home comics writing pictures archive about

2021-02-20 - In IL: Assemblies

In IL

So far we've mostly been looking at instructions. Instructions form the smallest part of a program, but you can't execute a random IL instruction on it's own. To see how instructions fit together we need to pull up and start looking at things from the outside in. To start with we are going to look at assemblies.

A .NET program can be thought of as a collection of assemblies. Assemblies are individual files, either executable (.exe) files or library (.dll) files, that each contain a collection of types, methods, and data. We'll get to all that in a bit but first let's look at the Assembly information contained within an executable. To do this we're going to go back to part 5 and take a closer look at the compiled code. To refresh your memory here's the C# program from that part.

Program.cs
using System;
namespace Operations
{
class Program
{
static void Main(string[] args)
{
int cylinderRadius = 3;
int cylinderHeight = 15;
double cylinderVolume = 3.141592654 * cylinderRadius *
cylinderRadius * cylinderHeight;
var message = string.Format(
"A Cylinder with radius {0} m and height {1} m has a volume of {2} m^3",
cylinderRadius, cylinderHeight, cylinderVolume);
Console.WriteLine(message);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

Now we're going to compile this program and then look at the decompiled file but instead of looking at the contents of the main method we're going to look at the information added before the class is declared.

Assembly Info
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.81.0
// Copyright (c) Microsoft Corporation. All rights reserved.
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly Operations
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 0A 4F 70 65 72 61 74 69 6F 6E 73 00 00 ) // ...Operations..
.custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 0A 4F 70 65 72 61 74 69 6F 6E 73 00 00 ) // ...Operations..
.custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 01 00 12 43 6F 70 79 72 69 67 68 74 20 C2 A9 20 // ...Copyright ..
20 32 30 31 35 00 00 ) // 2015..
.custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 32 66 31 31 64 30 35 30 2D 34 33 36 37 // ..$2f11d050-4367
2D 34 65 32 36 2D 39 32 34 66 2D 30 38 32 32 38 // -4e26-924f-08228
36 34 65 61 66 66 33 00 00 ) // 64eaff3..
.custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 31 2E 30 2E 30 2E 30 00 00 ) // ...1.0.0.0..
.custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 1C 2E 4E 45 54 46 72 61 6D 65 77 6F 72 6B // ....NETFramework
2C 56 65 72 73 69 6F 6E 3D 76 34 2E 35 2E 32 01 // ,Version=v4.5.2.
00 54 0E 14 46 72 61 6D 65 77 6F 72 6B 44 69 73 // .T..FrameworkDis
70 6C 61 79 4E 61 6D 65 14 2E 4E 45 54 20 46 72 // playName..NET Fr
61 6D 65 77 6F 72 6B 20 34 2E 35 2E 32 ) // amework 4.5.2
.hash algorithm 0x00008004
.ver 1:0:0:0
}
.module Operations.exe
// MVID: {EFE0F8B9-33BD-423A-B583-D156C2B6F199}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00020003 // ILONLY 32BITPREFERRED
// Image base: 0x000001D0521B0000
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

We have two assembly declarations here. The extern declaration is used to indicate a referenced assembly. In this case the program references mscorlib which is where all the basic types and method are declared. The second declaration describes the assembly we built. You can see that the assembly directive contains a bunch of attributes that describe the assembly itself such as it's name, the version of .NET it's built for and its version. Some of these are set based on the build options of the project and some are based on the values in AssemblyInfo.cs.

Finally we have a module declaration. Assemblies are built from a collection of modules which can be thought of as files although these don't seem to map exactly to source files. It's likely that visual studio does some work to combine all the source files before actually building the assembly. There are also some other directives such as the .subsystem directive which says if this is a graphical application or a console application. These describe how the assembly was built and how it's meant to be run.

Now there's a lot of things that could be talked about with assemblies but I'm going to hold off on that for now as they aren't directly connected to the code we right. I might come back and explore the options more in the future.

Next time we will start looking at class declarations.

Comments: