如何使用 DWORD PTR(汇编语言)打印负整数

Posted

技术标签:

【中文标题】如何使用 DWORD PTR(汇编语言)打印负整数【英文标题】:how to print negative integer using SWORD PTR(assembly lang) 【发布时间】:2021-05-29 05:39:26 【问题描述】:

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

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

【问题讨论】:

【参考方案1】:

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。 不是 0xffffffe,也就是 -2,如果在两个正数的 16 位相加溢出产生负结果后进行符号扩展,就会得到。

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

【讨论】:

@Jasper:另请参阅我的编辑:发布后我意识到您不仅在打印加载结果,而且还在打印添加结果。因此,您可能希望 movsx 两个输入以使溢出不可能。 谢谢,学习了很多我不知道的东西

以上是关于如何使用 DWORD PTR(汇编语言)打印负整数的主要内容,如果未能解决你的问题,请参考以下文章

(C/C++) 内联汇编“add dword ptr [address]”增加地址而不是它的值

opencv运行时,出错误,反汇编10035FDC mov eax,dword ptr [edi+10h] 是啥意思?

如何将 double 类型转换为 DWORDLONG 或 DWORD 转换为 DWORDLONG 或 DWORD_PTR 转换为 DWORDLONG

从组合框中的 DWORD_PTR 检索项目值?

将类成员回调从 __stdcall 转换为 DWORD_PTR

错误 C2065:“DWORD_PTR”:未声明的标识符