11

Starting to teach myself assembly (NASM) I wanted to know how to divide 2 numbers (For instance on Windows).

My code looks like this but it crashes.

global _main
extern _printf

section .text

_main:

mov eax, 250
mov ebx, 25
div ebx
push ebx
push message 

call _printf
add esp , 8
ret

message db "Value is = %d", 10 , 0

I wonder what's really wrong? It doesn't even display the value after the division.

Fifoernik
  • 9,779
  • 1
  • 21
  • 27
Karen
  • 111
  • 1
  • 1
  • 3
  • 5
    Consult an instruction set reference about how `div` works. Hint: the dividend is a 64 bit value, you need to zero `edx`. Also, calling convention mandates `ebx` to be preserved and the result won't be in `ebx` anyway. – Jester Aug 04 '17 at 12:11
  • The assembly instructions don't follow wishes or logic, i.e. just because some instruction is called "DIV", it doesn't mean it works as you expect. But your code looks like you didn't check the instruction manual. You need the instruction reference guide [(simplified web version here)](http://www.felixcloutier.com/x86/) (but in rare cases don't hesitate to use official Intel docs) for ASM programming, to check it often for all kinds of instructions (especially when flags are involved, or other tricky subtle details, like `DIV` behaviour). – Ped7g Aug 04 '17 at 12:47

2 Answers2

12

Your instruction div ebx divides the register pair edx:eax (which is an implicit operand for this instruction) by the provided source operand (i.e.: the divisor).


mov edx, 0
mov eax, 250
mov ecx, 25
div ecx

In the code above edx:eax is the dividend and ecx is the divisor. After executing the div instruction the register eax contains the quotient and edx contains the remainder.


I am using the register ecx instead of ebx for holding the divisor because, as stated in the comments, the register ebx has to be preserved between calls. Otherwise it has to be properly saved before being modified and restored before returning from the corresponding subroutine.


Divide by zero error may occur

As stated in one comment, if the quotient does not fit within the rage of the quotient register (eax in this case), a divide by zero error does occur.

This may explain why your program is crashing: since the register edx is not being set prior to executing the div instruction, it might contain a value so large, that the resulting quotient doesn't fit in the eax register.

Community
  • 1
  • 1
JFMR
  • 23,265
  • 4
  • 52
  • 76
  • I'm already aware of the fact that either `cdq` after setting `eax` or `xor edx, edx` would perform better than `mov edx, 0`. I just used the latter to keep the code simpler to understand. – JFMR Aug 04 '17 at 13:52
  • 1
    `cdq` sign extends eax into edx, it doesn't zero extend it. – Michael Petch Aug 04 '17 at 23:01
  • @MichaelPetch you are right, `cdq` sign extends `eax` into `edx` and it is therefore suited for `idiv` and not `div`. – JFMR Aug 05 '17 at 06:11
  • This explains about using div correctly, but doesn't explain why the code crashes rather than printing the value is 25. In most assemblers, "push message" pushes the first 4 bytes of message rather than the address of message. But in NASM, that syntax does push the address. So the crash is still unexplained. – prl Aug 07 '17 at 00:07
-2

The other comments and answer explain about using div correctly, but they don't explain why your code crashes rather than printing the wrong result. In most assemblers, "push message" pushes the first 4 bytes of message rather than the address of message, which is what printf expects. In NASM, as far as I can tell, it pushes the address. But you should double check that, since I don't use NASM.

prl
  • 11,716
  • 2
  • 13
  • 31
  • 2
    In NASM syntax, it pushes the address. You always need `[]` around something to make it a memory reference. – Peter Cordes Aug 07 '17 at 00:14
  • 2
    Also, it may be crashing with SIGFPE (or the windows equivalent) if the quotient doesn't fit in a 32-bit register. (Same error as division by zero.) – Peter Cordes Aug 07 '17 at 00:15