我正在java下试验x86指令仿真(只是为了好玩)并遇到问题"覆盖前缀"指令可能有的。
前缀可以改变指令的行为 例如,"操作数大小覆盖前缀"你可以改变操作数的大小。 16位到32位,反之亦然。 现在的问题是:当程序以16位模式运行时,所有操作都是用字符(char为16位宽)完成的,当操作数大小变为32位时,我想用整数运行操作。所以我有冗余代码。我的想法是现在实现一个字节数组操作,例如我可以实现一个添加两个字节数组的算法。这里的优点是:你可以简单地在128位之间切换不同的模式,依此类推。但另一方面,添加一个bytearray作为两个整数的加法可能不是很有效...
你知道更好的方法吗? 你觉得怎么样?
答案 0 :(得分:1)
我认为你需要将内存建模为一个字节数组,因为x86支持未对齐的加载/存储。您应该将指令解码为load / ALU / store(其中每个部分都是可选的,例如add eax, ecx
只需要ALU,而不是加载或存储)。
您只需编写一次代码即可从4个字节创建int32
,或者从int32
存储4个字节。或者,如果Java允许您对任意对齐的4个字节进行Int
引用,那么当操作数大小为32位时,您可以将其用作源或目标操作数。
如果您可以在Java中编写add
,sub
等类型通用版本,则可以为每个操作数大小重复使用相同的代码。所以你在解码器中的操作数大小上有一个switch()
,并从那里发送到每个指令的处理函数。如果使用指针表(或带有方法的对象),则相同的对象可能出现在8位表和32位表中(如果它是通用的)。 (与div
或mul
不同,他们使用AH:AL表示8位,但所有更宽的操作数大小都使用(E|R)DX:(E|R)AX
。
BTW,x86支持的可能加载/存储大小是字节/字/双字/ qword(x87和i486 cmpxchg8b)/ xmm / ymm / zmm,以及6字节(段+ 32位指针les
或far jmp [mem]
)。还有10字节x87或段+ 64位指针(例如远jmp)。
最后两个在内部处理为两个单独的负载,例如6字节的负载不保证是原子的:MDN Web docs。只有2个2字节的大小才能保证原子性(具有一些对齐限制)。
有关模拟x86的更多想法,请参阅一些BOCHS设计文档,例如: Why is integer assignment on a naturally aligned variable atomic on x86?。它是一个解释模拟器,没有JIT /动态重新编译,就像你正在编写的那样。
它涵盖了一些重要的想法,如懒惰的标志处理。一些想法使得模拟器的整体设计更加复杂以获得性能,但是懒惰的标志是非常有限的复杂性并且应该有很多帮助。