0

我正在学习 x86 汇编语言,不知道如何使用 Irvine32 库打印负整数。

INCLUDE Irvine32.inc

.data

arry    SWORD   10, -20, 30

.code
main PROC
    mov     eax,    0
    mov     esi,    OFFSET arry
    mov     ax,     SWORD PTR [esi]
    add     esi,    TYPE arry
    add     ax,     SWORD PTR [esi]
    call    WriteInt
    exit
    ;call   DumpRegs
    

main ENDP
end main

我期待的结果是 -10,但控制台打印了 +65526。我不知道 WriteInt 函数是如何工作的,但似乎它将 ax 中的值识别为无符号值。

如果我像这样修改我的代码,那么 WriteInt 函数会给我正确的结果。(-10)

...
    mov     eax,    10
    sub     eax,    20
    call    WriteInt
...

我想从内存中读取数据并添加或减去整数。如果我想打印为有符号整数,我该怎么办?

4

1 回答 1

1

movsx eax, SWORD PTR [esi]将其符号扩展为 WriteInt 的双字寄存器。

WriteInt 始终查看整个 32 位,并且您给它的 32 位数字(使用 bit-pattern 0x0000fff6)解释为 32 位 2 的补码,表示一个正数。

如果有一个 WriteShort 函数,您可以调用它,它会查看第 15 位而不是第 31 位来确定数字是否为负数,但是当我们可以符号扩展至一个完整的寄存器时就不需要一个.


请注意mov eax,0您在加载 AX 之前使用的:这样做是显式地进行零扩展,这是一种低效的模拟movzx eax, word ptr [esi]. (如果你不这样做,EAX 的高 16 位将保存调用 main 的代码中的任何垃圾。)

还有其他方法可以进行 2 的补码符号扩展,即将数字的符号位复制到完整寄存器的高位。例如,cwde在已经加载到 AX 之后,甚至shl eax, 16/ sar eax, 16。但是当寄存器中没有窄值时,MOVSX是最有效的。

或者在 AX 中使用 16 位相加结果,cwde只是一种更有效的编写movsx eax, ax.

(有趣的事实:CWDE 是可追溯到 8086 的指令的 32 位版本。在 386 之前,您只能使用 AL 或 AX 中的数字有效地进行符号扩展,而不是从任何地方到任何寄存器。)


为避免在添加中出现有符号溢出的可能性,您可能希望movsx在添加之前同时输入两个输入。 例如,这可以得到 0x7fff + 0x7fff = 0x0000fffe, 65534。
不是 0xfffffffe,也就是 -2,如果在两个正数的 16 位相加溢出产生负结果后进行符号扩展,就会得到。

(两个 n 位数字的和或差最多需要 n+1 位来精确表示,因此完全扩大使得溢出不可能。要溢出 32 位和,您必须添加大约 2^16 个字。 )

于 2021-05-29T05:55:09.697 回答