c#伊尔诺?

c#伊尔诺?,c#,cil,C#,Cil,我正在使用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_0

我正在使用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代码,但它没有3个NOP。

我通过将int转换为一个值来解决问题:

代码:

private static bool IsBetween(int-value、int-min、int-max)
{

return(value>=min&&value您摆脱“nop”的方向是正确的:

当您为Emit调用提供额外的参数时,请始终确保在MSDN上检查正确的参数类型

对于OpCodes.Ldc_I4_S,MSDN声明:

ldc.i4.s是一种更有效的编码,用于将整数从-128推送到>计算堆栈上

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

ILGenerator.Emit(操作码,字节)

因此,代码的第二部分在运行时将产生不可预测的结果(除了那些讨厌的nop),因为您试图在堆栈上加载“int8”,但提供了“int32”或“short”值:

如果要将int32/short(或任何大于字节的大小)正确加载到堆栈上,应使用Ldc_I4而不是Ldc_I4。因此,您的代码应如下所示,而不是上面的示例:

else
{
    gen.Emit(OpCodes.Ldc_I4, value);
}
这是一个大胆的猜测,但生成的三个nop可能与此有关 使用int32中的额外字节


希望这会有所帮助……

也许是将指令打包成一个特定大小的块,然后用NOP填充其余的部分?既然NOP没有任何危害,为什么您希望去掉它们?如果它们没有用,为什么要放在那里,生成的c代码没有任何…是的,当您使用int重载而不是字节重载时,Generator或者(看起来是盲目的)当操作码需要一个1字节的参数时,以4字节整数的形式发出该参数。由于该参数是以小尾数形式发出的,因此该数字是小于128的正值,并且nop指令恰好是一个“0x00”字节,因此具有添加3条nop指令的效果。如果该整数恰好是128,则它会将0加载到t上堆栈和第一条nop指令将被替换为中断指令。如果(IsBetween(value,sbyte.MinValue,sbyte.MaxValue))gen.Emit(OpCodes.Ldc_I4_S,(short)value);else gen.Emit(OpCodes.Ldc_I4,value)
正确,我甚至会进一步说它应该是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);
}
else
{
    gen.Emit(OpCodes.Ldc_I4, value);
}