我对汇编很陌生,所以我不知道这是否是一个愚蠢的问题,但我有一个问题,要求我阅读以下汇编行并说出之后存储在
%rdi
中的值(%rdi
中存储的值当前为0x100
):
subq 0x228, %rdi
我的解决方案是
0xFFFFFFFFFFFFFF80
。
我首先通过从
-128
减去 0x228
得到 0x100
十六进制,然后取 2 的补码得到 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1000 0000
,我将其转换为十六进制。
我的第一个问题是这是否是正确的大小值:指令末尾有“q”,意思是四字,所以答案应该是 8 个字节,对吗?
我的第二个问题是,这是否是汇编处理负结果的方式:它是否存储该值的 2 的补码形式?
我主要对自己的答案没有信心,因为在其他每一个问题中,我的答案都在 1 到 3 个十六进制数字之间,所以这个似乎不合适。
如果您不确定,请使用调试器自行尝试,甚至可以使用 C 语言使用
uint64_t val = 0x100;
val -= 0x228;
并将结果打印为十六进制。这只是一个二进制减法:位的无符号和 2 的补码解释将给出相同的结果位模式。这就是 2 的补码的要点,它不需要单独的有符号和无符号加法指令。
所以不,该指令不会否定结果(这就是取 2 的补码所做的事情)或类似的事情。 在内部,它“通常”会像进位为 1 的 adc $~0x228, %rdi
一样处理减法,并根据进位的倒数设置 CF。 (与 ARM 不同,在 x86 中,减法后的进位标志是借位标志,而不是反转的。)
~
按位 NOT,因此添加 0xfffffffffffffdd7
加上额外的 1
,通过进位完成,因此它仍然是单个 ALU操作。
我首先得到了-128
十六进制
正确。
但是看起来您将
-0x128
重新解释为
十进制
-128
(-0x80
) 并找到了它的位模式。换成 64 位,0 - 0x128
与
(1<<64) - 0x128
相同。 这就是我通常使用计算器程序所做的事情。结果的高位(前导 0xFF...
字节)是正确的,但低 2 个字节是错误的。 结果是一个很小的负数,因此符号扩展为64位,设置了很多高位。 这很正常。
如果您的作业需要位模式,则约定的编写方式是使用二进制或无符号十六进制。0x100 - 0x228
=
-0x128
的数学值当然是 -296
,您也可以通过将输入转换为十进制并执行 256 - 552 = -296 = -0x128
来获得它。 所以这是用 RDI 表达结果的同样有效的方式。但请注意,使用除 10 以外的基数并带减号表示负数的情况并不常见,特别是在计算中,十六进制、八进制和二进制通常仅用于位模式/十六进制转储,而不用于由某些位表示的数学值。 从数学上讲,-0x128
没有任何问题,但只有当你知道它的含义时它才有用,而这个作业可能希望你证明这一点。 :P