负整数的默认存储格式

Default storage format for negative integers

二进制值是否默认以 2 的补码形式存储?
我试验了代码 mov al, -1 并看到 EAX = 000000FF
这是默认的还是我们可以指定使用补码或其他格式

x86 硬件使用 2 的补码有符号整数,例如对于 movsx 符号扩展、imul/idiv 签名 multiply/divide 和 add 等的 FLAGS 设置(特别是 OF)等说明,包括 sub/cmpjle 等分支条件。并且没有一个人的补码数学指令(除了 not,一个人的补码否定,与 neg 二人的补码否定,也就是二进制 0 - x。)

另请参阅 Understanding Carry vs. Overflow conditions/flags,它准确描述了 2 的补码溢出 (OF) 与进位输出 (CF) 如何进行加法运算。

汇编程序总是1在将源代码中的负数编码为机器代码时使用 2 的补码。mov-立即在机器代码只是将位模式复制到寄存器中;在 CPU 看到它之前,所有“解释”都已经完成。 (mov reg, sign_extended_narrow_immediate 的唯一情况是 x86-64 mov r/m64, imm32 仅在 64 位模式下。)另请注意,mov al, -1 不会影响 EAX 的高位。如果您看到 0x000000FF,那是因为 EAX 的高位字节恰好已经为零。

脚注 1:您当然可以编写一个非常奇怪的 x86 汇编程序并执行其他操作。不过,不太可能有人会想要使用它,因为这意味着 add eax, -2 不会将 EAX 的值减少 2。现有 主流汇编器使用相同的数字格式为硬件,硬件为 2 的补码,不可切换。

old_timer 指出一些汇编器(例如用于简单微控制器的简单汇编器)甚至可能根本不支持负常量的语法,在这种情况下,您总是必须手动将常量编码为十六进制或其他任何形式. 0xFF$FF 之类的东西或任何语法。


如果您想使用 1 的补码位模式,请将它们手动编码为十六进制。例如mov al, 0FDh (~2) 而不是 mov al, 0FEh-2.

当然,您必须使用多条指令来实现 1 的补码数学运算。 add做二进制加法,和2的补码有符号加法是一样的操作,但是不是和1的补码一样的操作。 (这是计算机使用 2 的补码的一个主要原因:+/- 与无符号运算相同,乘法的低半部分也是如此。)

请注意,x86 机器代码具有某些形式的指令,例如 add r/m32, sign_extended_imm8,在解码时涉及 2 的补码扩展。即高 24 位是第 7 位的副本,复制立即数的最高位以填充寄存器。许多 1 的补码值与此兼容,例如add eax, 0FFFFFFFDh 可以编码为 imm8,汇编程序会为您完成。