负十六进制表示
Negative hexadecimal representation
我有一个问题是这样的:
mov r15, 0x407116EF3867BBCA
sub r15, 0x95F67F70A1BCEE9D
What value is in r15 after this code executes?
(Be careful about integer overflow/underflows)
解决方案: python 3 用于调试的数学字符串:(i64 - i64_2) % (2**64)
当我按照这个公式解决这个问题时,我得到了 0xaa7a977e96aacd2d.
我怀疑答案应该是否定的,但我认为它已转换为 2 的补码。但如果是这样的话,还需要将其转换为 2 的补码吗?那么,我的思考方向是否正确?如果不是,请纠正我。另外,这个公式背后的逻辑是什么(取模 2^64)。
是的,在汇编中,一个 64 位寄存器值总是可以用 16 个十六进制数字表示。没有单独的 plus/minus 位; 最好把加/减这样的二元操作想成无符号的1,只担心最终结果的2's complement解释2.
这意味着使用像 Python 3 个整数或 calc
aka apcalc
这样的任意精度计算器有点不方便,当减法下溢超过 0
.
有两种方法可以考虑将结果固定为您想要的结果(在 [0 .. 2**64-1]
范围内):
Modulo 将其降低回该范围。 这就是 Python 中的 %
所做的。(不同于某些其他语言,如 C,或 x86-64 asm 中的 idiv
指令,Python % 给你模数,总是正数,而不是余数。例如 -1 % 2
是 1
,但在 C 中对于 signed int 它是 -1
.
您甚至可以 手动 通过将 2**64
添加到负数来进行减少,以获得 2 的补码二进制表示。因为您知道任何加法或减法结果都将不小于 2**64
在该范围之外,所以只需要一次加法(或减法以进行进位加法)。
按位将其截断为 64 位,取 Python 内部扩展精度 2 的补码表示的低 64 位。这取决于 Python 在内部使用 2 的补码,这可能是有保证的,并且在实践中肯定有效(大概至少当 Python 是 运行 在任何本身使用 2 的补码的正常系统上。)
三个都给出相同的正确结果。在交互式 Python 3.9 会话中:
>>> (0x407116EF3867BBCA - 0x95F67F70A1BCEE9D)
-6162446570153652947
>>> hex (0x407116EF3867BBCA - 0x95F67F70A1BCEE9D)
'-0x55856881695532d3'
>>> hex( (0x407116EF3867BBCA - 0x95F67F70A1BCEE9D) % (2**64) )
'0xaa7a977e96aacd2d'
>>> hex( (0x407116EF3867BBCA - 0x95F67F70A1BCEE9D) + 2**64 )
'0xaa7a977e96aacd2d'
>>> hex( (0x407116EF3867BBCA - 0x95F67F70A1BCEE9D) & (2**64-1) )
'0xaa7a977e96aacd2d'
此外,如果这应该是 x86-64,那 sub
不会 assemble:只有 mov
可以使用64 位立即数,并且 0x95F67F70A1BCEE9D
不适合(不能表示为)32 位符号扩展立即数。
但如果是这样,那么 CF 将被设置,因为从高位借位(因为 0x4... - 0x9... = 0xa... 绕过零:左手操作数减法在右侧下方没有符号)。
并且 OF 将被设置,因为在带符号的解释中(我们将 MSB 视为具有 - 2^63
而不是 + 2^63
的位值),正数减去较大的-magnitude 负数产生了如此大的正结果,以至于它溢出到负数。 (即 positive - negative = negative 意味着有符号溢出,就像 positive + positive = negative 一样)
根据结果的MSB,SF=1。
脚注 1:
一般加宽乘法和除法的高半部分,关心MSB的位值; add/sub 不要:2 的补码加法与无符号的二进制运算相同,包括回绕。这就是为什么 x86-64 只有一个 sub
指令,但有 div
和 idiv
,并且对于单操作数扩展乘法有 mul
与通常的 [=32= 分开].但是像 imul eax, r9d
这样的 imul 的非扩展形式对于有符号或无符号都是相同的。
脚注 2:
如果设置了高位,那么如果将位模式解释为 2 的补码有符号整数而不是无符号整数,则它为负。参见 Wikipedia's article about 2's complement。如果第一个十六进制数字是 8 到 F,则设置高位,因此在您的情况下 0x9...
和 0xa...
表示负数,而 0x4...
表示正数。
我有一个问题是这样的:
mov r15, 0x407116EF3867BBCA sub r15, 0x95F67F70A1BCEE9D
What value is in r15 after this code executes?
(Be careful about integer overflow/underflows)
解决方案: python 3 用于调试的数学字符串:(i64 - i64_2) % (2**64)
当我按照这个公式解决这个问题时,我得到了 0xaa7a977e96aacd2d.
我怀疑答案应该是否定的,但我认为它已转换为 2 的补码。但如果是这样的话,还需要将其转换为 2 的补码吗?那么,我的思考方向是否正确?如果不是,请纠正我。另外,这个公式背后的逻辑是什么(取模 2^64)。
是的,在汇编中,一个 64 位寄存器值总是可以用 16 个十六进制数字表示。没有单独的 plus/minus 位; 最好把加/减这样的二元操作想成无符号的1,只担心最终结果的2's complement解释2.
这意味着使用像 Python 3 个整数或 calc
aka apcalc
这样的任意精度计算器有点不方便,当减法下溢超过 0
.
有两种方法可以考虑将结果固定为您想要的结果(在 [0 .. 2**64-1]
范围内):
Modulo 将其降低回该范围。 这就是 Python 中的
%
所做的。(不同于某些其他语言,如 C,或 x86-64 asm 中的idiv
指令,Python % 给你模数,总是正数,而不是余数。例如-1 % 2
是1
,但在 C 中对于 signed int 它是-1
.您甚至可以 手动 通过将
2**64
添加到负数来进行减少,以获得 2 的补码二进制表示。因为您知道任何加法或减法结果都将不小于2**64
在该范围之外,所以只需要一次加法(或减法以进行进位加法)。按位将其截断为 64 位,取 Python 内部扩展精度 2 的补码表示的低 64 位。这取决于 Python 在内部使用 2 的补码,这可能是有保证的,并且在实践中肯定有效(大概至少当 Python 是 运行 在任何本身使用 2 的补码的正常系统上。)
三个都给出相同的正确结果。在交互式 Python 3.9 会话中:
>>> (0x407116EF3867BBCA - 0x95F67F70A1BCEE9D)
-6162446570153652947
>>> hex (0x407116EF3867BBCA - 0x95F67F70A1BCEE9D)
'-0x55856881695532d3'
>>> hex( (0x407116EF3867BBCA - 0x95F67F70A1BCEE9D) % (2**64) )
'0xaa7a977e96aacd2d'
>>> hex( (0x407116EF3867BBCA - 0x95F67F70A1BCEE9D) + 2**64 )
'0xaa7a977e96aacd2d'
>>> hex( (0x407116EF3867BBCA - 0x95F67F70A1BCEE9D) & (2**64-1) )
'0xaa7a977e96aacd2d'
此外,如果这应该是 x86-64,那 sub
不会 assemble:只有 mov
可以使用64 位立即数,并且 0x95F67F70A1BCEE9D
不适合(不能表示为)32 位符号扩展立即数。
但如果是这样,那么 CF 将被设置,因为从高位借位(因为 0x4... - 0x9... = 0xa... 绕过零:左手操作数减法在右侧下方没有符号)。
并且 OF 将被设置,因为在带符号的解释中(我们将 MSB 视为具有 - 2^63
而不是 + 2^63
的位值),正数减去较大的-magnitude 负数产生了如此大的正结果,以至于它溢出到负数。 (即 positive - negative = negative 意味着有符号溢出,就像 positive + positive = negative 一样)
根据结果的MSB,SF=1。
脚注 1:
一般加宽乘法和除法的高半部分,关心MSB的位值; add/sub 不要:2 的补码加法与无符号的二进制运算相同,包括回绕。这就是为什么 x86-64 只有一个 sub
指令,但有 div
和 idiv
,并且对于单操作数扩展乘法有 mul
与通常的 [=32= 分开].但是像 imul eax, r9d
这样的 imul 的非扩展形式对于有符号或无符号都是相同的。
脚注 2:
如果设置了高位,那么如果将位模式解释为 2 的补码有符号整数而不是无符号整数,则它为负。参见 Wikipedia's article about 2's complement。如果第一个十六进制数字是 8 到 F,则设置高位,因此在您的情况下 0x9...
和 0xa...
表示负数,而 0x4...
表示正数。