Hi there! đ
Last time I covered what assemblies are, and today I want to focus on one of the most important pieces that every assembly has - the Manifest file. And before you brush it off with âblah, who the heck cares about âManifestsââ, trust me - they can tell you A LOT. You may not need them right now, but not knowing whatâs inside will severely limit what you are able to do with CLR. So, take my word and READ through this article.
As usual, we go with infographic first and then with the more detailed explanation:
I hope that was easy to digest?
First and foremost - Manifests are NOT unique to .NET. Not at all. You can find them in C++, Java, Rust, Ships and Airplanes carrying cargo, etc. They are EVERYWHERE. Hell, thereâs even an Agile Manifesto.
Manifest is a summary of whatâs âinsideâ. What is being âcarriedâ. It can be a ship, a train, a JAR or a DLL, and Manifestâs job is to give a quick summary over it. In terms of CLR, think of it as âjust reading the Manifestâ instead of going through each line of code stored inside.
Speaking of .NET Assemblies in particular, Manifest is required to contain the following information:
Identity of the Assembly â what is the name of it, who created it, which version is it, etc. Additionally, if itâs a strong-named one (and we cover what this is in the next article!), there will be a way to confirm the identity of it.
Content inside the Assembly â remember the previous article where I said that assembly can contain one or more files? Well, Manifest tells you WHAT are the files packed inside.
External references â if you wrote a program that uses Console.Writeline, youâd be relying on existence of System.Console namespace, which is part of System.Console.dll assembly. This would be your external reference.
Now instead of bullshitting too much and given the fact that you could find all this info online anyway, let me give you some actual meat. Iâll use our friend ILDASM.exe (Intermediate Language Dissasembler) to peak into Manifest of System.Console.dll:
Thereâs a lot of content in there, and instead of pasting the images, I will paste parts of the text and then describe what each of them is:
.module extern kernel32.dll
.module extern user32.dll
These two are the native libraries (i.e. non-CLR DLLâs) that assembly requires. They are part of Windows API so feel free to google them if you want to get deeper understanding.
.assembly extern System.Runtime
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 7:0:0:0
}
.assembly extern System.Runtime.InteropServices
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 7:0:0:0
}
.assembly extern System.Threading
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 7:0:0:0
}
.assembly extern System.Memory
{
.publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) // .{...-.Q
.ver 7:0:0:0
}
.assembly extern System.Text.Encoding.Extensions
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 7:0:0:0
}
These are all the EXTERNAL REFERENCES â assemblies that this assembly requires to be loaded in order to function properly. What you see along with names are the public key tokens and versions for each. Version is probably obvious (i.e. itâs the version of assembly that is required), but if you are not familiar with Public Keys - donât worry, it will be more clear in the next article. In short - itâs part of something called âStrong-named assembliesâ and this Public Key token is a sort of fingerprint that identifies them.
.assembly System.Console
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [System.Runtime]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 [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 )
.custom instance void [System.Runtime]System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [System.Runtime]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 18 2E 4E 45 54 43 6F 72 65 41 70 70 2C 56 // ....NETCoreApp,V
65 72 73 69 6F 6E 3D 76 37 2E 30 01 00 54 0E 14 // ersion=v7.0..T..
46 72 61 6D 65 77 6F 72 6B 44 69 73 70 6C 61 79 // FrameworkDisplay
4E 61 6D 65 08 2E 4E 45 54 20 37 2E 30 ) // Name..NET 7.0
.custom instance void [System.Runtime]System.Reflection.AssemblyMetadataAttribute::.ctor(string,
string) = ( 01 00 15 2E 4E 45 54 46 72 61 6D 65 77 6F 72 6B // ....NETFramework
//
// etc.
//
.publickey = (00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00 // .$..............
00 24 00 00 52 53 41 31 00 04 00 00 01 00 01 00 // .$..RSA1........
07 D1 FA 57 C4 AE D9 F0 A3 2E 84 AA 0F AE FD 0D // ...W............
E9 E8 FD 6A EC 8F 87 FB 03 76 6C 83 4C 99 92 1E // ...j.....vl.L...
B2 3B E7 9A D9 D5 DC C1 DD 9A D2 36 13 21 02 90 // .;.........6.!..
0B 72 3C F9 80 95 7F C4 E1 77 10 8F C6 07 77 4F // .r<......w....wO
29 E8 32 0E 92 EA 05 EC E4 E8 21 C0 A5 EF E8 F1 // ).2.......!.....
64 5C 4C 0C 93 C1 AB 99 28 5D 62 2C AA 65 2C 1D // d\L.....(]b,.e,.
FA D6 3D 74 5D 6F 2D E5 F1 7E 5E AF 0F C4 96 3D // ..=t]o-..~^....=
26 1C 8A 12 43 65 18 20 6D C0 93 34 4D 5A D2 93 ) // &...Ce. m..4MZ..
.hash algorithm 0x00008004
.ver 7:0:0:0
}
These are the Attributes of our assembly (System.Console.dll) which represent various Metadata ranging from which Company published them (Microsoft) all the way to some Attributes that I have no faintest idea what they are. You can always google each one of them to see whatâs their purpose. Some of these attributes are also visible when you click on Properties of the DLL:
Also, âpublickeyâ part is, like I said above, part of something called Strong-named assemblies, and Public Key is something you can use to confirm the identity. Again, no worries if youâre not familiar, it will become much more clear in the next article!
.mresource public FxResources.System.Console.SR.resources
{
// Offset: 0x00000000 Length: 0x00001ABF
}
.mresource public ILLink.Substitutions.xml
{
// Offset: 0x00001AC3 Length: 0x000001F4
}
These two appear to be two resources that have been embedded inside the Assembly as well, but I have no clue what they are used for. What you see for each are exact coordinates of where they start and where they end.
.module System.Console.dll
// MVID: {BA4D167A-DE2E-4B21-827E-BAF8C9B71D53}
.custom instance void System.Runtime.CompilerServices.RefSafetyRulesAttribute::.ctor(int32) = ( 01 00 0B 00 00 00 00 00 )
.custom instance void System.Runtime.CompilerServices.NullablePublicOnlyAttribute::.ctor(bool) = ( 01 00 00 00 00 )
.custom instance void [System.Runtime]System.Runtime.CompilerServices.SkipLocalsInitAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x00400000
.file alignment 0x00001000
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x0000000c // IL_LIBRARY
// Image base: 0x0000020072620000
.module defines which modules exist in this Manifest, .imagebase I presume is the offset where the CLR code starts, .file alignment I have no faintest idea what it does, .stackreserve is the size of the Stack that your assembly will get (this can be controlled with /STACK linker option) and for the rest I was just too lazy to look up what it is.
So what youâve seen so far is a complete deep-dive into contents of an actual Manifest - Manifest of a System.Console.dll, which is an assembly that contains Console.Writeline command.
For reference sake, hereâs an assembly of a C# app that contains a single Console.Writeline(âHello worldâ):
All in all, I hope that Manifests are a bit more clear now. Their main purpose is to communicate who they are, whatâs inside and what they need. Thereâs another interesting piece of info that is being stored in Assemblies, called Metadata Tables. They go into even more depth, and define pretty much every single parameter, class, method and variable that exists inside CLR. But that will be a topic for another time!
Next time I will be talking about Strong-named Assemblies. Until then, if you havenât already, nowâd be a good time to subscribe :)
Thanks for reading!
Other articles in this series: