【问题标题】:Comparing 16 bit numbers in nasm produces wrong results比较 nasm 中的 16 位数字会产生错误的结果
【发布时间】:2014-10-26 05:54:11
【问题描述】:

我刚开始学习汇编。我正在以 32 位模式编码 nasm。我正在尝试比较用户输入的 3 个数字并打印最大的数字。但是,如果我只使用 resb 2 为每个数字保留 16 位,我似乎无法正确比较这些数字。但是,当我使用 resw 2 为数字保留 32 位时,我确实得到了正确的结果。我不明白为什么这是案子。这是我的代码:

SYS_EXIT equ 1
SYS_WRITE equ 4
SYS_READ equ 3
STD_IN equ 0
STD_OUT equ 1

segment .data

    msg1 db "Enter first number",0xA
    msg1_len equ $- msg1

    msg2 db "Enter second number",0xA
    msg2_len equ $- msg2

    msg3 db "Enter third number",0xA
    msg3_len equ $- msg3

    msg4 db "Largest number is ",0xA
    msg4_len equ $- msg4

segment .bss

    num1 resb 2
    num2 resb 2
    num3 resb 2
    res resb 2

section .text

    global _start

_start:

    mov eax, SYS_WRITE
    mov ebx, STD_OUT
    mov ecx, msg1
    mov edx, msg1_len
    int 0x80

    mov eax, SYS_READ
    mov ebx, STD_IN
    mov ecx, num1
    mov edx, 2
    int 0x80

    mov eax, SYS_WRITE
    mov ebx, STD_OUT
    mov ecx, msg2
    mov edx, msg2_len
    int 0x80

    mov eax, SYS_READ
    mov ebx, STD_IN
    mov ecx, num2
    mov edx, 2
    int 0x80

    mov eax, SYS_WRITE
    mov ebx, STD_OUT
    mov ecx, msg3
    mov edx, msg3_len
    int 0x80

    mov eax, SYS_READ
    mov ebx, STD_IN
    mov ecx, num3
    mov edx, 2
    int 0x80

    mov ecx, [num1]
    cmp ecx, [num2]
    jg check_third
    mov ecx, [num2]


check_third:

    cmp ecx, [num3]
    jg result
    mov ecx, [num3]

result:
    mov [res], ecx
    mov eax, SYS_WRITE
    mov ebx, STD_OUT
    mov ecx, msg4
    mov edx, msg4_len
    int 0x80

    mov eax, SYS_WRITE
    mov ebx, STD_OUT
    mov ecx, res
    mov edx, 2
    int 0x80

exit:
    mov eax, SYS_EXIT
    int 0x80

对不起,如果它有很多重复的代码。我理解为什么我需要 2 个字节来存储键盘输入,而据说 ascii 字符的长度只有 8 位(因为标准输入也会读取除数字之外的换行符)。但是,我不太了解 nasm 的工作原理,例如当我将 16 位内存移动到 32 位寄存器时它如何反应,它如何比较 32 位和 16 位值(它会做有符号扩展还是只是填充0 在二进制减法之前)。如果有人可以向我推荐有关 nasm 技术细节的资源,我将不胜感激,除了解释为什么我需要保留 2 个词来进行比较。

【问题讨论】:

  • 您是否已经使用调试器单步执行您的程序?你可以使用我去年开发的这个:sourceforge.net/projects/bindbg
  • 谢谢马丁!!! MykelXIII,你从键盘得到的是一个 8 位字符。你从mov ecx, [num1](等)得到的是 32 位——即使你只保留了 16 位! movzx ecx, byte [num1]mov cl, [num1] 应该会有所帮助 - 尽管您仍在比较字符,而不是数字。这不是“Nasm 问题”(但您可以在 Nasm 论坛中找到示例)。
  • @MartinRosenau 谢谢分享,我试试看。
  • @FrankKotler 我知道我只是比较字符,但是由于 0 - 9 的 ascii 等价物的值在上升,我认为它仍然可以正确比较而不将它们转换为它们的数字等价物。最后,移动 32 位而不是 16 位是否意味着我正在传输不属于我保留的部分的内存?谢谢你的回答:)
  • 是的。移动 32 位将同时获取 num1num2。这就是为什么你的结果很奇怪。切换到cl 而不是ecx,它应该“工作”。

标签: linux assembly x86 nasm x86-64


【解决方案1】:

Nasm 不像其他一些汇编程序那样在标签处记录数据的大小。假设您输入 1、2 和 3。存储在标签中的字节将为:

num1: db 0x31, 0x0A
num2: db 0x32, 0x0A
num3: db 0x33, 0x0A

当您从标签 num1 移动 32 位数据时,实际上您也在从 num2 移动数据。因为小端机器首先存储最低有效字节,所以您会得到如下内容:

    mov ecx, 0x0A320A31 ; high bytes contain num2 and low bytes contain num1
    cmp ecx, 0x0A330A32 ; high bytes contain num3 and low bytes contain num2
    jg check_third
    mov ecx, 0x0A330A32  
check_third:
    cmp ecx, 0x00000A33 ; high bytes contain res and low bytes contain num3
    jg result
    .....

resw 2(或resd 1)可以工作,因为保留的内存被初始化为零。正如 Frank 在评论中所说,您应该使用 cl 而不是 ecx,因为在这种情况下您只需要处理 8 位。

【讨论】:

  • 接受这个答案。非常清楚和很好的解释。谢谢:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-07
相关资源
最近更新 更多