Comparing 16 bit numbers in nasm produces wrong re

2020-05-01 09:12发布

问题:

I have just started learning assembly. I am coding nasm in 32 bit mode. I am trying to compare 3 numbers inputted by the user and print the largest number. However, I cannot seem to correctly compare the numbers if I only reserve 16 bits for each number using resb 2. I do, however, get correct results when I reserved 32 bits for the numbers using resw 2. I cannot understand why this is the case. Here is my code:

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

Sorry if it has a lot of repeating code. I understand why I need 2 bytes to store keyboard input when supposedly ascii characters are only 8 bits in length (Since the standard input will also read the new line character aside from the digit). However, I do not know a lot of things about how nasm works such as how it reacts when I move 16 bits of memory to a 32 bit register, how it compares 32 bit and 16 bit values (will it do signed expansion or just pad 0 before binary subtraction). I would truly appreciate it if someone can recommend me resources on the technicalities of nasm aside from explaining why I need to reserve 2 words to do the comparison.

回答1:

Nasm does not keep record of the size of the data at label like some other assemblers. Suppose you enter 1, 2 and 3. Bytes stored at your labels will then be:

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

When you move 32 bits of data from label num1, you are actually also moving data from num2. Because little endian machines store least significant bytes first, you get something like:

    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 (or resd 1) would work because reserved memory is initialized to zeros. As Frank stated in the comment, you should use cl instead of ecx because 8 bits is all you need to handle in this case.