Search code examples
assemblynasminteger-division

Unsigned division in nasm


I have been trying to debug a little assembly program where I ask for a dividend and a divisor and have to output the quotient and the remainder. For some reason however, my quotient and remainder are not output to the screen. Here is my code:

segment .data

prompt db "Please enter a number: ", 10
promptLen equ $-prompt
prompt2 db "Please enter the divisor: ", 10
prompt2Len equ $-prompt2
prompt3 db "Your quotient is: ", 10
prompt3Len equ $-prompt3
prompt4 db "Your remainder is: ", 10
prompt4Len equ $-prompt4

segment .bss

inputNum resb 2
inputDiv resb 2
quotient resb 2
remainder resb 2

segment .text

global _start

_start:

mov eax, 4
mov ebx, 1
mov ecx, prompt
mov edx, promptLen
int 80h

mov eax, 3
mov ebx, 0
mov ecx, inputNum
mov edx, 2
int 80h

mov eax, 4
mov ebx, 1
mov ecx, prompt2
mov edx, prompt2Len
int 80h

mov eax, 3
mov ebx, 0
mov ecx, inputDiv
mov edx, 2
int 80h

xor edx, edx
mov ax, [inputNum]
mov bx, [inputDiv]
sub ax, '0'
sub bx, '0'

div bx

add ax, '0'
add dx, '0'
mov [quotient], ax
mov [remainder], dx

mov eax, 4
mov ebx, 1
mov ecx, prompt3
mov edx, prompt3Len
int 80h

mov eax, 4
mov ebx, 1
mov ecx, [quotient]
mov edx, 2
int 80h

mov eax, 4
mov ebx, 1
mov ecx, prompt4
mov edx, prompt4Len
int 80h

mov eax, 4
mov ebx, 1
mov ecx, [remainder]
mov edx, 2
int 80h
jmp exit

exit:

mov eax, 1
xor ebx, ebx
int 80h

I would appreciate if someone could help me understand what I am doing wrong.


Solution

  • System call 4 (write) requires a char * for its buffer address in ecx. With your code:

    mov eax, 4          ; sys_write
    mov ebx, 1          ; standard output
    mov ecx, [quotient] ; here, ecx <- your character code
    mov edx, 2          ; two bytes (hmmm)
    int 80h
    

    you are loading ecx with the actual data that was input, rather than the address of it.

    What you need to do is to load ecx with the address of the character, which will probably just be something like:

    mov ecx, quotient ; here, ecx <- your character address
    

    You may also want to reduce your byte count to one rather than two. The way you're turning integers into characters (adding '0') will only work for one-character numbers anyway so you only want the least significant byte (the one at the lowest memory address for x86).

    Ditto for the remainder.


    As an aside, when you do fix that, you still get a funny result. Dividing 5 by 2 gives you a quotient of 1 and a remainder of 3, clearly wrong.

    This has to do with how you input the data and load the values into ax and bx.

    Since you're reading two bytes for each number, the memory is loaded up with the digit itself '5', or 0x35, followed by a newline character 0x0a.

    Then, when you load the two-byte word into ax, it ends up with 0x0a35.

    After subtracting 0x0030 ('0') from each, you end up with 0x0a05 and 0x0a02 which is, in decimal, 2565 and 2562. When you divide those numbers, you do indeed get a quotient of 1 and remainder of 3.

    To fix that, you can simply throw away the 0x0a00 but when loading the value, by changing:

    xor edx, edx
    mov ax, [inputNum]
    mov bx, [inputDiv]
    sub ax, '0'
    sub bx, '0'
    

    into:

    xor edx, edx
    mov ax, [inputNum]
    mov bx, [inputDiv]
    and ax, 0xff          ; add these
    and bx, 0xff          ;   two lines.
    sub ax, '0'
    sub bx, '0'