idiv overflow exception asm

2019-09-20 05:20发布

问题:

I'm very new to assembly, before only C C++
I was trying to create a simple application that print all the prime number from 2 to given input
When I run, it crashes, and that's normal. Looking at OllyDbg, the guilty piece is this:

move eax, ebx
idiv ecx ; !!! here

It is strange because ecx is not 0
Values are EAX = 0000 0004, ECX = 0000 0002, and it says me that's an Integer_Overflow (exception C000 0095)
How it's possible to have an overflow during a division? Both operands are 32bit

Floowing the code and a screenshot of ollydbg

%include "asm_io.inc"

segment .data
input_msg   db  "Insert a number: ", 0
output_msg  db  "This is prime: ", 0

segment .bss
input       resd    1

segment .text
global _asm_main

; input => input number
; ebx => current number to execute [2 .. input]
; ecx => counter from 2 to current [2 .. current]

_asm_main:
    mov eax, input_msg
    call print_string

    call read_int
    inc eax
    mov [input], eax
    call print_nl

    mov ebx, 2h

    _start_main_loop:
        mov eax, [input] ; if current > input
        cmp eax, ebx
        jz _end_main_loop       

        mov ecx, 2h

        _iteration:
            cmp ebx, ecx
            je _print_number

            mov eax, ebx
            idiv ecx ; unsigned division?

            cmp edx, 0 ; if rem != 0 jmp
            jne _end_iteration
            inc ecx ; else inc ecx and re-divide
            jmp _iteration

        _print_number:
            mov eax, output_msg
            call print_string
            mov eax, ebx
            call print_int
            call print_nl

        _end_iteration:
            inc ebx

            jmp _start_main_loop

    _end_main_loop:

    popa
    mov     eax, 0
    leave
    ret

回答1:

Integer overflow exception on idiv instruction occurs when result of n-bit division can not fit into n-bit register. That is possible because idiv and div divide the whole register pair EDX:EAX. Your EDX value is 1 and you divide EDX:EAX by 2, which results into a bit shift to right. This shift moves 1 on EAX´s MSB, and you have a positive result 0x80000000 greather than 0x7FFFFFFF, what is illegal according to the documentation.

You may be asking yourself "why is there such restriction?". It's there, because a negative value (MSB set) in EAX wouldn't be a valid result of division of two positive integers.

A general solution for this problem is either to zero contents of EDX before unsigned division

mov eax, ebx
xor edx, edx
div ecx ;unsigned division

...or to sign-extend EAX (if you expect negative input, which you shouldn't beacuse no negative integer can be a prime number).

mov eax, ebx
cdq 
idiv ecx ;signed division