I'm currently studying a bit of MSIL/CIL code, and I'm trying to compile a basic Hello World written in MSIL. However I'm having some troubles.
At first I've read this article. Then I put the code in the article within an file and use this Stack Overflow answer as a reference as to how to use ilasm.exe and PEVerify.exe in order to make that code into an executable.
This is what I've started with:
.method static void main()
{
.entrypoint
.maxstack 1
ldstr "Hello world!"
call void [mscorlib]System.Console::WriteLine(string)
ret
}
ilasm.exe makes the executable, however when I run PEVerify I get this output:
PS C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools> .\PEVerify.exe /MD /IL C:\clr_code\hello_world_cil.exe
Microsoft (R) .NET Framework PE Verifier. Version 4.0.30319.0
Copyright (c) Microsoft Corporation. All rights reserved.
The module 'C:\clr_code\hello_world_cil.exe' was expected to contain an assembly manifest.
1 Error(s) Verifying C:\clr_code\hello_world_cil.exe
I've searched for this error but only find references about dynamic code generation using reflection, which didn't help.
Then I decided to build a simple hello world Console Application in Visual Studio and used dotPeek to get the IL code. I then changed the hello world message and tried to compile the output, this is the code I've used:
.class private auto ansi beforefieldinit
HelloMSILV472.Program
extends [mscorlib]System.Object
{
.method private hidebysig static void
Main(
string[] args
) cil managed
{
.entrypoint
.maxstack 8
// [6 9 - 6 10]
IL_0000: nop
// [7 13 - 7 53]
IL_0001: ldstr "Hello MSIL!"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
// [8 13 - 8 35]
IL_000c: call int32 [mscorlib]System.Console::Read()
IL_0011: pop
// [9 9 - 9 10]
IL_0012: ret
} // end of method Program::Main
.method public hidebysig specialname rtspecialname instance void
.ctor() cil managed
{
.maxstack 8
IL_0000: ldarg.0 // this
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Program::.ctor
} // end of class HelloMSILV472.Program
However I've got the same error. I also don't yet if there's difference between .NET Framework IL and .NET Core IL, and if the target framework affects how ilasm.exe deals with the code, so I tried the output IL of a .NET Framework application and the output IL of a .NET Core application. However I've got the same error.
How can I build a MSIL/CIL basic hello world console application from scratch, using something like Notepad++ and then compile it and have a running executable?
Your initial sample is fine - you just need to declare an assembly for your code to reside in by putting this line at the top:
.assembly MyTestAssembly {}
Additionally, you should reference any external assemblies that your code relies on. In this case since it's only mscorlib
, ilasm
will find it after displaying a warning, so not mandatory, but it would be mandatory in order to call other custom code:
.assembly extern mscorlib {}
Final code:
.assembly extern mscorlib {}
.assembly MyTestAssembly {}
.method static void main()
{
.entrypoint
.maxstack 1
ldstr "Hello world!"
call void [mscorlib]System.Console::WriteLine(string)
ret
}