公共语言运行时检测到无效的程序,在生成简单的动态方法时出错
我正在为MIPS机器仿真开发一个JIT编译器,用来把MIPS转换成CLI。现在我在实现一个几乎完全硬编码的移位方法,但当我尝试对从内存加载的值执行运算指令时,它就失败了。
这是导致 Common Language Runtime detected an invalid program 异常信息的失败代码:
private unsafe bool Shift(ILGenerator il, MipsInstruction inst, OpCode ilOpCode)
{
long baseAddress = (long)_cpu.RegisterFile.Regs;
long regAddress = baseAddress + ((int)inst.RT * sizeof(T));
// Push Address
if (IntPtr.Size == 4) il.Emit(OpCodes.Ldc_I4, (int)regAddress);
else il.Emit(OpCodes.Ldc_I8, regAddress);
il.Emit(OpCodes.Conv_I);
// Load the value from memory
il.Emit(OpCodes.Ldind_U4);
// Load shift amount
il.Emit(OpCodes.Ldc_I4, inst.ShiftAmount);
// Apply shift
il.Emit(ilOpCode);
// Pop value (not even trying to store yet)
il.Emit(OpCodes.Pop);
return false;
}
_cpu.RegisterFile.Regs 是一个 T*,其中 T 是一个 uint 或一个 ulong,取决于所配置的MIPS版本是32位还是64位。在我的测试中,我一直在使用MIPS32R2,因此它是一个 uint。
如需更多信息,以下两个方法不会抛出异常:
private unsafe bool Shift(ILGenerator il, MipsInstruction inst, OpCode ilOpCode)
{
il.Emit(OpCodes.Ldc_I4, inst.ShiftAmount);
il.Emit(OpCodes.Ldc_I4, inst.ShiftAmount);
il.Emit(ilOpCode);
il.Emit(OpCodes.Pop);
return false;
}
private unsafe bool Shift(ILGenerator il, MipsInstruction inst, OpCode ilOpCode)
{
long baseAddress = (long)_cpu.RegisterFile.Regs;
long regAddress = baseAddress + ((int)inst.RT * sizeof(T));
// Push Address
if (IntPtr.Size == 4) il.Emit(OpCodes.Ldc_I4, (int)regAddress);
else il.Emit(OpCodes.Ldc_I8, regAddress);
il.Emit(OpCodes.Conv_I);
// Load the value from memory
il.Emit(OpCodes.Ldind_U4);
il.Emit(OpCodes.Pop);
return false;
}
最后,这是一个仍然存在问题的版本的永久链接,其中包含周边代码: permalink
解决方案
问题在于ShiftAmount是一个 byte,并按原样附加到生成的IL中。因此,所有后续指令都错位并被解释为垃圾。
若要修复这段代码,应该是这样的:
private unsafe bool Shift(ILGenerator il, MipsInstruction inst, OpCode ilOpCode)
{
long baseAddress = (long)_cpu.RegisterFile.Regs;
long regAddress = baseAddress + ((int)inst.RT * sizeof(T));
// Push Address
if (IntPtr.Size == 4) il.Emit(OpCodes.Ldc_I4, (int)regAddress);
else il.Emit(OpCodes.Ldc_I8, regAddress);
il.Emit(OpCodes.Conv_I);
// Load the value from memory
il.Emit(OpCodes.Ldind_U4);
// Load shift amount
il.Emit(OpCodes.Ldc_I4, (int)inst.ShiftAmount);
// Apply shift
il.Emit(ilOpCode);
// Pop value (not even trying to store yet)
il.Emit(OpCodes.Pop);
return false;
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。