【发布时间】:2016-03-26 05:33:14
【问题描述】:
我正在为我自己的汇编语言编写一个虚拟机,当我执行加法等操作时,我希望能够像在 x86-64 架构中设置的那样设置进位、奇偶校验、零、符号和溢出标志.
注意事项:
- 我正在使用 Microsoft Visual C++ 2015 和 Intel C++ Compiler 16.0
- 我正在编译为 Win64 应用程序。
- 我的虚拟机(当前)只对 8 位整数进行算术运算
- 我(目前)对任何其他标志(例如 AF)不感兴趣
我目前的解决方案是使用以下函数:
void update_flags(uint16_t input)
{
Registers::flags.carry = (input > UINT8_MAX);
Registers::flags.zero = (input == 0);
Registers::flags.sign = (input < 0);
Registers::flags.overflow = (int16_t(input) > INT8_MAX || int16_t(input) < INT8_MIN);
// I am assuming that overflow is handled by trunctation
uint8_t input8 = uint8_t(input);
// The parity flag
int ones = 0;
for (int i = 0; i < 8; ++i)
if (input8 & (1 << i) != 0) ++ones;
Registers::flags.parity = (ones % 2 == 0);
}
另外,我会使用如下:
uint8_t a, b;
update_flags(uint16_t(a) + uint16_t(b));
uint8_t c = a + b;
编辑: 为了澄清,我想知道是否有更有效/更简洁的方法(例如通过直接访问 RFLAGS) 此外,我的代码可能不适用于其他操作(例如乘法)
EDIT 2我现在已将我的代码更新为:
void update_flags(uint32_t result)
{
Registers::flags.carry = (result > UINT8_MAX);
Registers::flags.zero = (result == 0);
Registers::flags.sign = (int32_t(result) < 0);
Registers::flags.overflow = (int32_t(result) > INT8_MAX || int32_t(result) < INT8_MIN);
Registers::flags.parity = (_mm_popcnt_u32(uint8_t(result)) % 2 == 0);
}
还有一个问题,我的进位标志代码能正常工作吗?我还希望为减法期间发生的“借用”正确设置它。
注意:我正在虚拟化的汇编语言是我自己设计的,旨在简单并基于 Intel 的 x86-64(即 Intel64)实现,因此我希望这些标志的行为方式大致相同。
【问题讨论】:
-
您遇到的具体问题是什么?你的代码不起作用吗?
-
input < 0永远不会为真,因为input是无符号的,并且 OF 将取决于操作数,而不仅仅是结果。例如,8 位操作0x7f + 0x02 = 0x81将产生OF = 1,但0x82 + 0xff = 0x81将产生OF = 0。这段代码是错误的,所以一些正确设置标志的代码比这种方式更整洁。