比较nasm中的16位数会产生错误的结果

时间:2014-10-26 05:54:11

标签: linux assembly x86 nasm x86-64

我刚开始学习装配。我在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个字来进行比较。

1 个答案:

答案 0 :(得分:2)

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位。