请求修复x86(32位)汇编程序:输出1-100000的质数
我帮你排查了这段x86 32位汇编代码里的问题,主要涉及语法错误、质数判断逻辑漏洞和系统调用误用几个方面,下面是修正后的代码和详细的错误说明:
原代码的核心错误点
div指令语法错误:x86的div是单操作数指令,原代码里的div edx, edx是无效写法,正确用法是用EDX:EAX作为被除数,操作数作为除数,余数会存在EDX中。- 质数判断逻辑混乱:
- 从
eax=1开始,但1不是质数,应该从2起步; - 检查新数字时没有重置除数
edx,导致后续判断复用旧的除数,逻辑错误; - 没有优化判断终止条件(可以在除数平方超过当前数时停止,提升效率)。
- 从
- 打印功能完全错误:
- 用了
eax=3(read系统调用)而不是eax=4(write)来打印; - 直接把数字传入
ecx,但write要求ecx指向内存中的ASCII字符串,数字必须先转换为字符串才能打印; - 打印完一个数后直接退出,没有继续查找后续质数。
- 用了
修正后的代码
section .data msg db 'The next prime number is: ', 0xA ; 添加换行符,输出更清晰 len equ $-msg num_buf db '00000', 0xA ; 存储转换后的数字字符串(最多5位,加换行) buf_len equ $-num_buf section .text global _start _start: mov eax, 2 ; 从第一个质数2开始 mov ecx, 100000 ; 上限值100000 find_next_prime: cmp eax, ecx jg exit_program ; 超过上限则退出程序 ; 保存当前数字到栈上(因为mul/div会覆盖eax) push eax mov edx, 2 ; 除数从2开始试除 check_divisor: mov ebx, edx mul ebx ; edx:eax = edx * edx(除数的平方) cmp eax, [esp] ; 比较除数平方和原数字 jg is_prime ; 除数平方>原数字,说明是质数 mov eax, [esp] ; 恢复原数字 xor edx, edx div ebx ; 原数字除以除数,余数存edx cmp edx, 0 je next_number ; 余数为0,不是质数,跳去下一个数 inc edx ; 除数加1,继续试除 jmp check_divisor is_prime: mov eax, [esp] ; 恢复原质数 ; 打印提示信息 mov eax, 4 mov ebx, 1 mov ecx, msg mov edx, len int 0x80 ; 转换质数为ASCII字符串并打印 push eax call num_to_str add esp, 4 mov eax, 4 mov ebx, 1 mov ecx, num_buf mov edx, buf_len int 0x80 next_number: pop eax ; 弹出栈中保存的数字 inc eax ; 检查下一个数 jmp find_next_prime exit_program: mov eax, 1 xor ebx, ebx int 0x80 ; 辅助函数:将整数转换为ASCII字符串 ; 输入:eax = 待转换的整数 ; 输出:num_buf中存储对应的ASCII字符串(带换行) num_to_str: mov ebx, num_buf + buf_len - 2 ; 从字符串末尾(换行前)开始填充 mov ecx, 10 ; 十进制除数 convert_loop: xor edx, edx div ecx ; eax = 商,edx = 余数 add dl, '0' ; 余数转换为ASCII字符 mov [ebx], dl dec ebx cmp eax, 0 jne convert_loop ; 直到商为0,转换完成 ret
关键修改说明
- 质数判断优化:新增了栈存储原数字的逻辑,避免
mul/div覆盖寄存器值;当除数的平方超过当前数字时,直接判定为质数,大幅提升效率。 - 数字转换功能:新增
num_to_str函数,通过逐位取余的方式将整数转换为ASCII字符串,解决了直接打印数字的错误。 - 流程控制修复:打印完一个质数后,回到循环继续查找下一个数,直到超过100000才退出。
内容的提问来源于stack exchange,提问作者wiktor
相关产品推荐
相关产品推荐

