在C C ++之前,我对装配很新
我试图创建一个简单的应用程序,将所有素数从2打印到给定的输入
当我跑步时,它会崩溃,这是正常的。看着OllyDbg,有罪的是:
move eax, ebx
idiv ecx ; !!! here
奇怪的是因为ecx不是0
值是EAX = 0000 0004,ECX = 0000 0002,它说我是Integer_Overflow(例外C000 0095)
如何在分裂期间有溢出?两个操作数均为32位
完成代码和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
答案 0 :(得分:2)
当n位除法的结果不能适合n位寄存器时,会发生idiv
指令的整数溢出异常。这是可能的,因为idiv
和div
划分了整个寄存器对EDX:EAX
。您的EDX
值为1,您将EDX:EAX
除以2,这会导致向右移位。此移位会在1
的MSB上移动EAX
,并且您的结果0x80000000
比0x7FFFFFFF
更强,根据documentation,这是非法的。
你可能会问自己“为什么会有这样的限制?”。它就在那里,因为EAX
中的负值(MSB集)不是两个正整数除法的有效结果。
此问题的一般解决方案是在无符号除法之前将EDX
的内容归零
mov eax, ebx
xor edx, edx
div ecx ;unsigned division
...或者签署扩展EAX(如果你期望负输入,你不应该没有负整数可以是素数)。
mov eax, ebx
cdq
idiv ecx ;signed division