我正在用ILGenerator生成一些IL,下面是我的代码:
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 (我从一个名为ILStream的VS虚拟器获得IL代码)
nops代码是从哪里来的?有没有办法摆脱它们?我正在尝试模仿一些c#代码,它没有3NOP。
发布于 2009-09-30 15:01:31
我通过将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);
}
}发布于 2011-11-15 17:23:52
你在正确的方向上摆脱了“nop”:
当您为Emit调用提供附加参数时,请始终确保检查MSDN上是否有正确的参数类型。
对于OpCodes.Ldc_I4_S、MSDN状态:
ldc.i4.s是一种更有效的编码,用于将-128到127的整数推送到>计算堆栈上。
下面的Emit方法重载可以使用ldc.i4.s操作码:
ILGenerator.Emit(OpCode,字节)
因此,代码的第二部分在运行时将有不可预测的结果(除了那些讨厌的nop),因为您试图在堆栈上加载一个"int8“,但提供了一个"int32”或"short“值:
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/short (或任何大于一个字节的值)加载到堆栈上,则应该使用Ldc_I4而不是Ldc_I4_S。这样你的代码应该看起来像这样,而不是上面的 :
else
{
gen.Emit(OpCodes.Ldc_I4, value);
}这是一个胡乱猜测,但生成的三个nop可能与int32中的额外字节有关
希望这能帮上忙。
https://stackoverflow.com/questions/1498162
复制相似问题