C# 中间代码与内联汇编

中间代码(IL)是源程序的一种内部表示 举个例子C语言编译一个程序 那么C语言编
译器会把代码全部翻译为可以被机器识别的机器指令 同理C#编译器也是一样的 不
过它是被C#(CSC)编译为可以被CLR识别的指令 该指令称为中间代码。
C#可以内嵌汇编但需要通过Emit还有一种则通过Mono 但通常是Microsoft Emit.
IL Add: 
        static void Main(string[] args)
        {
            DynamicMethod add = new DynamicMethod("add", typeof(int), new Type[] { typeof(int), typeof(int) });
            ILGenerator il = add.GetILGenerator();

            il.Emit(OpCodes.Ldarg_0); // ldarg.0
            il.Emit(OpCodes.Ldarg_1); // ldarg.1
            il.Emit(OpCodes.Add); // add
            il.Emit(OpCodes.Ret); // ret

            int num = (int)add.Invoke(add, new object[] { 1, 2 });
        }
ldarg.0 压入参数0到计算堆栈
ldarg.1 压入参数1到计算堆栈
add 两数相加
ret 返回

ASM Add:
int Add(int x, int y)
{
	int ret;
	_asm
	{
		mov         eax, dword ptr[x]
		add         eax, dword ptr[y]
		mov         dword ptr[ret], eax
	}
	return ret;
}
mov 源操作数传送到目标操作数
add 两数相加
eax 32位寄存器
dword ptr 四字节地址

IL While:
        static void Main(string[] args)
        {
            DynamicMethod _while = new DynamicMethod("while", typeof(int), null);
            ILGenerator il = _while.GetILGenerator();

            il.DeclareLocal(typeof(int)); // int i

            Label IL_0004 = il.DefineLabel(); // IL_0004
            Label IL_0008 = il.DefineLabel(); // IL_0008

            il.Emit(OpCodes.Ldc_I4_0); // ldc.i4.0
            il.Emit(OpCodes.Stloc_0); // stloc.0
            il.Emit(OpCodes.Br_S, IL_0008); // br.s       IL_0008

            il.MarkLabel(IL_0004);

            il.Emit(OpCodes.Ldloc_0); // ldloc.0
            il.Emit(OpCodes.Ldc_I4_1); // ldc.i4.1
            il.Emit(OpCodes.Add); // add
            il.Emit(OpCodes.Stloc_0); // stloc.0

            il.MarkLabel(IL_0008);

            il.Emit(OpCodes.Ldloc_0); // ldloc.0
            il.Emit(OpCodes.Ldc_I4_S, 100); // ldc.i4.s   100
            il.Emit(OpCodes.Blt_S, IL_0004); // blt.s      IL_0004

            il.Emit(OpCodes.Ldloc_0); // ldloc.0
            il.Emit(OpCodes.Ret); // ret

            int num = (int)_while.Invoke(_while, null);
        }
ldc.i4.0 压入__int32 0到计算堆栈
stloc.0 从计算堆栈弹出值到局部变量0
br.s 无条件转移
ldloc.0 压入局部变量0到计算堆栈
ldc.i4.1 压入__int32 1到计算堆栈
add 两数相加
ldc.i4.s 压入__int8但作为__int32到计算堆栈
blt.s 如果小于则转移
ret 返回返回值(如果存在)压入到调用方的计算堆栈(Win32 -> eax)

ASM While:
void main(int argc, char* argv[])
{
        __int32 i;
	_asm
	{
		mov         dword ptr [i],0 
_loop_beige:
		cmp         dword ptr [i],64h
		jge         _loop_end
		mov         eax,dword ptr [i]  
		add         eax,1 
		mov         dword ptr [i],eax  
		jmp         _loop_beige 
_loop_end:
	}
}
jge 大于等于时转移
jmp 无条件转移

两者的代码并不是很难理解 不过你要它写程序会异常痛苦  不过IL是一个例外
它很强大 绕过编译器检查获取隐藏对象 的成员IL会很轻松AOP在C#中则是
利用Emit实现的有的 时候我们需要去优化代码 从中间代码是一个很好的办法。
只是乎所有指令语言都有个毛病 做一个小小的循环会涉及 大量指令会让人
感到厌烦不过中间代码相对汇编的话是好 太多了。看看上面两种不同的汇编
你是不是还是感到MDIL要轻松的多至少我如此的认为。

你可能感兴趣的:(ASM,IL,C#)