如何使用 SWORD PTR(assembly lang) 打印负整数

问题描述

我正在学习 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
...

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

解决方法

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

WriteInt 总是查看整个 32 位,而您提供的 32 位数字(位模式 0x0000fff6)被解释为 32 位 2 的补码,表示一个正数。

如果有一个 WriteShort 函数,你可以调用它,它会查看第 15 位而不是第 31 位来决定数字是否为负,但是当我们可以符号扩展到一个完整的注册表。


请注意您在加载 AX 之前使用的 mov eax,0:这样做是显式零扩展的,这是模拟 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。
不是 0xffffffffe,也就是 -2,如果在两个正数的 16 位相加溢出产生负结果后进行符号扩展,就会得到它。

(两个 n 位数字的和或差最多需要 n+1 位来精确表示,因此加宽根本不会导致溢出。要溢出 32 位和,您必须添加大约 2^ 16 个字。)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...