I've started learning CIL today and have been using multiple tutorials to gain a basic understanding.
Currently I have 2 functions, 1 function adds 10 to the integer given as an argument and prints the answer. The second function takes 2 integers, add 5 to both of them and than multiplies the answers. Than it gets returned.
Both the functions work when only 1 of them is called, but when both are called I get the following error:
Unhandled Exception: System.InvalidProgramException: Common Language Runtime detected an invalid program.
at Bewerkingen.Program.Main(String[] args)
I do not know how to make the 2 functions work when called after each other. This is my code:
.assembly extern mscorlib {}
.assembly Bewerkingen {}
.module Bewerkingen.exe
.class public Functions
extends [mscorlib]System.Object
{
.method public specialname void .ctor()
{
ret
}
.method public void Add(int32)
{
ldarg.1
ldc.i4 10
add
call void [mscorlib]System.Console::WriteLine(int32)
ret
}
.method public int32 add5mul(int32,int32)
{
ldarg.1
ldc.i4 5
add
ldarg.2
ldc.i4 5
add
mul
ret
}
}
.class Bewerkingen.Program
extends [mscorlib]System.Object
{
.method static void Main(string[] args)
cil managed
{
.entrypoint
newobj instance void Functions::.ctor()
ldc.i4 3
call instance void Functions::Add(int32)
ldc.i4 5
ldc.i4 3
call instance int32 Functions::add5mul(int32,int32)
call void [mscorlib]System.Console::WriteLine(int32)
ret
}
}
You've got a slight problem, in that your .ctor
needs to call the base object's ctor (ldarg.0
, call instance void [System.Private.CoreLib]System.Object::.ctor()
, ref
). Both for Program and for Functions
The main problem however is that you try and call add5mul
on... nothing. There's no Functions
object on the stack to call it on.
// Push Functions instance onto stack
// Stack: [functions]
newobj instance void Functions::.ctor()
// Push 3 onto stack
// Stack: [3, functions]
ldc.i4 3
// Pop 3 and functions off the stack
// Stack: []
call instance void Functions::Add(int32)
// Push 5 and 3 onto stack
// Stack: [3, 5]
ldc.i4 5
ldc.i4 3
// Pop 5, 3, and... nothing. We're missing the Functions instance to call it on.
call instance int32 Functions::add5mul(int32,int32)
You can fix this by duplicating the Functions instance before you consume it for the first time:
newobj instance void Functions::.ctor()
dup <-- Here
ldc.i4 3
call instance void Functions::Add(int32)
ldc.i4 5
ldc.i4 3
call instance int32 Functions::add5mul(int32,int32)
call void [mscorlib]System.Console::WriteLine(int32)
ret
You can also store that Functions instance in a local slot:
.method static void Main(string[] args)
cil managed
{
.locals init (
[0] class Functions
)
.entrypoint
newobj instance void Functions::.ctor()
stloc.0
ldloc.0
ldc.i4 3
call instance void Functions::Add(int32)
ldloc.0
ldc.i4 5
ldc.i4 3
call instance int32 Functions::add5mul(int32,int32)
call void [mscorlib]System.Console::WriteLine(int32)
ret
}
SharpLab.io is a great resource for learning IL. Here's your code, translated to C# then decompiled into IL.