Search code examples
assemblyx86nasmdivision

Issue with div in NASM


I am learning basic assembly using NASM and stumbled on an issue in the div of two numbers.
Here is the code I wrote:

section .data 
   msg1 db "Enter first digit  (a): ", 0
   len1 equ $- msg1 

   msg2 db "Enter second digit (b): ", 0 
   len2 equ $- msg2 

   newLine db "",0xA

   msg3 db "The division (a/b) is: ",0
   len3 equ $- msg3

section .bss
   num1 resb 2 
   num2 resb 2 
   res resb 1   

section .text
   global _start
    
_start:
    mov eax, 4         
    mov ebx, 1         
    mov ecx, msg1         
    mov edx, len1 
    int 0x80                

    mov eax, 3 
    mov ebx, 0  
    mov ecx, num1 
    mov edx, 2
    int 0x80            

    mov eax, 4        
    mov ebx, 1         
    mov ecx, msg2          
    mov edx, len2         
    int 0x80

    mov eax, 3  
    mov ebx, 0  
    mov ecx, num2 
    mov edx, 2
    int 0x80        

    mov eax, 4         
    mov ebx, 1         
    mov ecx, msg3          
    mov edx, len3         
    int 0x80
    
    mov ax, [num1]     ; Load the 16-bit value from num1
    sub ax, '0'

    mov eax, 0         ; Clear the upper 16 bits of eax
    mov [num1], ax     ; Store the result back in num1

    mov bx, [num2]     ; Load the 16-bit value from num2
    sub bx, '0'

    mov ebx, 0         ; Clear the upper 16 bits of eax
    mov [num2], bx     ; Store the result back in num2

    mov eax, [num1]
    sub eax, '0'

    mov ebx, [num2]
    sub ebx, '0'

    mov edx, 0
    div bx     ; eax = quotient, edx = remainder
    add ax, '0'

    mov [res], ax

    mov eax, 4        
    mov ebx, 1
    mov ecx, res         
    mov edx, 1
    int 0x80

    mov eax, 4
    mov ebx, 1  
    mov ecx, newLine 
    mov edx, 1
    int 0x80   

    mov eax, 1
    int 0x80

And the output generated is

output

I did some research on the previous similar questions on div on stack overflow but to no avail and also did the reading on google but couldn't solve the issue.

please help, I am stuck on this since last night


Solution

  • mov ax, [num1]     ; Load the 16-bit value from num1
    sub ax, '0'
    mov eax, 0         ; Clear the upper 16 bits of eax
    mov [num1], ax     ; Store the result back in num1
    

    Although num1 had 2 bytes reserved, only the first byte is important for your calculation. Remember you were asking the user for a single digit number? Subtracting '0' will correctly convert from the character ["0","9"] into the value [0,9], but if you move zero into EAX you will lose that value immediately. The solution is to write the following and with no need to store it back in num1:

    movzx eax, byte [num1]
    sub   eax, '0'
    

    mov bx, [num2]     ; Load the 16-bit value from num2
    sub bx, '0'
    mov ebx, 0         ; Clear the upper 16 bits of eax
    mov [num2], bx     ; Store the result back in num2
    

    Same as above, but keep the result in EBX


    mov eax, [num1]
    sub eax, '0'
    

    Here you are reading 4 bytes where you had only 2 bytes stored. Plus you are erroneously subtracting '0', again. The conversion had already been done before! This part can be removed.


    mov ebx, [num2]
    sub ebx, '0'
    

    Similar to the first number, you can remove this part too.


    mov edx, 0
    div bx     ; eax = quotient, edx = remainder
    add ax, '0'
    mov [res], ax
    

    From your comment, it seems like you want dword-sized division, but then you need to write div ebx. And since the res variable had only 1 byte reserved, you should never try to store 2 bytes in it.

    All together:

        ...
        
        movzx eax, byte [num1]
        sub   eax, '0'
        movzx ebx, byte [num2]
        sub   ebx, '0'
        jz    Quit            ; You should not divide by zero!
        xor   edx, edx
        div   ebx             ; -> EAX = quotient, EDX = remainder
        add   eax, '0'        ; Convert to character
        mov   [res], al
        
        ...
        
    Quit:
        mov   eax, 1
        int   0x80