C#的ILGenerator NOP?(c# ILGenerator nop?)

2019-08-17 01:49发布

林产生一些IL与这里的ILGenerator是我的代码:

DynamicMethod method = new DynamicMethod("test", null, Type.EmptyTypes);
ILGenerator gen = method.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Ldc_I4_S, 100);

此生成此IL:

IL_0000:  ldarg.0    
IL_0001:  ldarg.1    
IL_0002:  ldc.i4.s   100
IL_0004:  nop        
IL_0005:  nop        
IL_0006:  nop        

(我从VS Virtulizer名为ILStream获得IL代码)

从哪里做的NOP代码? 有没有什么办法来摆脱他们的? 我试着去模仿一些C#代码,它不会有3个空指令。

Answer 1:

你是在正确的方向,以摆脱“NOP” S的:

当您提供一个额外的参数给发送调用,总是一定要检查MSDN上的适当的参数类型。

对于OpCodes.Ldc_I4_S,MSDN指出:

ldc.i4.s为从-128推动整数127到>计算堆栈的更有效的编码。

下面的Emit方法重载可以使用ldc.i4.s操作码:

ILGenerator.Emit(操作码,字节)

所以,你的代码的第二部分将在运行时无法预料的结果(除了那些讨厌的NOP的),因为你试图加载在堆栈上“INT8”,而是提供了一个“INT32”或“短”值:

else if (IsBetween(value, short.MinValue, short.MaxValue))
{
    gen.Emit(OpCodes.Ldc_I4_S, (short)value);
}
else
{
    gen.Emit(OpCodes.Ldc_I4_S, value);
}

如果你要正确地加载INT32 /短(更大的幅度比字节或任何)压入堆栈,您应该使用Ldc_I4代替Ldc_I4_S。 所以,你的代码应该是这样的,而不是上面的示例:

else
{
    gen.Emit(OpCodes.Ldc_I4, value);
}

这是一种野生的猜测,但生成的三个NOP的大概有东西从你的INT32做额外的字节

希望可以帮助...



Answer 2:

我通过铸造的int值解决了这个问题:

码:

private static bool IsBetween(int value, int min, int max)
{
    return (value >= min && value <= max);
}

private static void WriteInt(ILGenerator gen, int value)
{
    gen.Emit(OpCodes.Ldarg_1);
    if (IsBetween(value, sbyte.MinValue, sbyte.MaxValue))
    {
        gen.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
    }
    else if (IsBetween(value, byte.MinValue, byte.MaxValue))
    {
        gen.Emit(OpCodes.Ldc_I4_S, (byte)value);
    }
    else if (IsBetween(value, short.MinValue, short.MaxValue))
    {
        gen.Emit(OpCodes.Ldc_I4_S, (short)value);
    }
    else
    {
        gen.Emit(OpCodes.Ldc_I4_S, value);
    }
}


文章来源: c# ILGenerator nop?
标签: c# cil