汇编阶乘程序输出头部出现异常字符问题求助
问题分析与修复
你的阶乘程序头部出现异常字符,核心问题出在ASCII转换阶段的寄存器滥用和错误内存写入,具体问题点如下:
关键错误点
寄存器ecx被重复误用
你一开始把ecx作为转换循环的计数器并清零,但在循环内部又将其赋值为10(除数),之后还执行inc ecx——这完全破坏了计数器的功能,最后用ecx作为输出长度自然也是错误的。错误的内存写入操作
转换循环里的mov [fac],bl是致命错误:bl是当前指向fac缓冲区的指针(比如fac+11的低8位),你把这个地址值直接写入fac的第一个字节,这就把随机的非数字ASCII字符(比如地址的低8位对应的ASCII)放到了结果的开头,这就是你看到的-、,、+等异常字符的来源。长度计算逻辑混乱
由于ecx被滥用,最后传递给sys_write的edx(输出长度)完全不正确,导致输出内容包含多余字节。
修复后的代码
section .data msg db 'Enter a number: ',0 ; 用户提示内容 lenmsg equ $ - msg ; 提示长度 disp db 'Factorial: ',0 ; 输出提示内容 lendisp equ $ - disp ; 输出提示长度 newline db 0xa ; 换行符 section .bss num resb 3 ; 2字节存数字,1字节存换行 fac resb 12 ; 12字节存阶乘结果 section .text global _start _start: ; 显示用户提示 mov edx,lenmsg ; 写入字节数 mov ecx,msg ; 写入内容 mov ebx,1 ; 文件描述符:stdout mov eax,4 ; 系统调用:sys_write int 0x80 ; 调用内核 ; 读取用户输入 mov edx,2 ; 读取字节数 mov ecx,num ; 输入存储位置 mov ebx,0 ; 文件描述符:stdin mov eax,3 ; 系统调用:sys_read int 0x80 ; 调用内核 mov byte [num+eax-1],0 ; 替换换行符为null ; 计算阶乘 movzx eax, byte [num] ; 将num移入eax,高位补零 sub eax,'0' ; ASCII转整数 mov ecx,eax ; 移入ecx作为计数器 mov eax,1 ; eax初始化为1,存储阶乘结果 cmp ecx,0 ; 判断输入是否为0 jz output ; 输入为0直接跳转到输出 loop_calc: mul ecx ; 阶乘乘法 dec ecx ; 计数器减1 jnz loop_calc ; 计数器>0则循环 output: ; 整数转ASCII mov ebx,fac+11 ; 指向fac缓冲区末尾 mov byte [ebx],0 ; 添加结束符 xor edi,edi ; 用edi作为计数器,避免和ecx冲突 convert: xor edx,edx ; 清零edx(除法余数寄存器) mov ecx,10 ; 除数为10 div ecx ; eax = eax/10,edx=余数 add dl,'0' ; 余数转ASCII dec ebx ; 缓冲区指针左移 mov [ebx],dl ; 存储当前数字 inc edi ; 计数器加1 test eax,eax ; 判断eax是否为0 jnz convert ; eax不为0则继续循环 ; 显示输出提示 mov edx,lendisp ; 输出提示长度 mov ecx,disp ; 输出提示内容 mov ebx,1 ; 文件描述符:stdout mov eax,4 ; 系统调用:sys_write int 0x80 ; 调用内核 ; 显示阶乘结果 mov edx,edi ; 结果长度(计数器edi的值) mov ecx,ebx ; 结果起始地址(ebx指向第一个有效数字) mov ebx,1 ; 文件描述符:stdout mov eax,4 ; 系统调用:sys_write int 0x80 ; 调用内核 ; 显示换行 mov edx,1 ; 换行符长度 mov ecx,newline ; 换行符内容 mov ebx,1 ; 文件描述符:stdout mov eax,4 ; 系统调用:sys_write int 0x80 ; 调用内核 ; 退出程序 mov eax,1 ; 系统调用:sys_exit int 0x80 ; 调用内核
修复说明
- 寄存器分离使用:用edi作为转换循环的计数器,避免和用作除数的ecx冲突,保证长度计算准确。
- 移除错误写入:删掉
mov [fac],bl这一行,不再向结果开头写入垃圾地址值。 - 正确传递输出参数:输出阶乘时,用edi作为长度,ebx作为结果的起始地址(因为转换后ebx指向第一个有效数字),确保只输出有效数字部分。
测试修复后的代码,输入2-9的阶乘都会正常显示,比如输入9会输出Factorial: 362880,无异常字符。
内容的提问来源于stack exchange,提问作者nkminion
相关产品推荐
相关产品推荐

