公共语言运行时检测到无效的程序,在生成简单的动态方法时出错

编程语言 2026-07-10

我正在为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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章