You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

非递归NASM阶乘程序问题:仅输出提示语未显示结果120

NASM非递归阶乘程序的错误排查

我编写了一段非递归的NASM汇编程序用于计算数字阶乘,代码如下:

section .data
    result_msg db 'Factorial: ', 0
    newline db 10

section .text
    global _start

_start:
    ; Constants
    mov eax, 5      ; Number for which factorial is to be calculated

    ; Initialize result to 1
    mov ebx, 1      ; Result

    ; Loop to calculate factorial
    fact_loop:
        cmp eax, 1
        jle print_result

        ; Multiply current result by the current number
        imul ebx, eax

        ; Decrement the number
        dec eax

        jmp fact_loop

    print_result:
        ; Print "Factorial: "
        mov eax, 4
        mov ebx, 1
        mov ecx, result_msg
        mov edx, 10      ; Updated to the correct length of the message
        int 0x80

        ; Convert the result to ASCII and display it
        add ebx, '0'    ; Convert the result to ASCII
        mov eax, 4
        mov ecx, ebx    ; Use ebx directly as the result
        mov edx, 1
        int 0x80

        ; Print newline
        mov eax, 4
        mov ebx, 1
        lea ecx, [newline]
        mov edx, 1
        int 0x80

        ; Exit program
        mov eax, 1
        xor ebx, ebx
        int 0x80

运行该程序时,仅能打印出提示语“Factorial: ”,无法输出正确的阶乘结果120。请问程序中存在哪些缺失或错误?


核心错误点

  • 多位数ASCII转换逻辑缺失:add ebx, '0'仅适用于0-9的单个数字,120是三位数,直接加'0'会得到120+48=168,这是超出可打印数字范围的ASCII值,无法正确显示。必须实现多位数转ASCII字符串的逻辑(比如通过循环取余、逆序存储字符)。
  • Write系统调用参数错误:Linux的int 0x80 write调用(eax=4)要求ecx指向内存中的字符串地址,但代码中直接将寄存器ebx的值传给ecx,系统调用会读取错误的内存区域,导致无法输出有效内容。
  • 提示语长度错误:result_msg的实际长度是11('Factorial: '包含11个字符),但代码中mov edx,10设置的长度不对,虽然不影响提示语显示,但属于细节错误。

修正思路示例

  1. 在.data段添加缓冲区用于存储转换后的ASCII字符串:
    section .data
        result_msg db 'Factorial: ', 0
        newline db 10
        buffer resb 10  ; 预留足够空间存储多位数ASCII
    
  2. 重写print_result部分,实现多位数转ASCII并正确输出:
    print_result:
        ; 打印提示语,修正长度为11
        mov eax, 4
        mov ebx, 1
        mov ecx, result_msg
        mov edx, 11
        int 0x80
    
        ; 保存阶乘结果,准备转换
        mov ecx, ebx    ; ecx = 120
        mov ebx, buffer ; ebx指向缓冲区起始地址
        mov edi, 0      ; 记录数字位数
    
    ; 循环取余,将数字转为逆序ASCII字符
    convert_loop:
        xor edx, edx    ; 清空edx,div指令会使用edx:eax
        mov eax, ecx
        mov esi, 10
        div esi         ; eax=商,edx=余数
        add dl, '0'     ; 余数转ASCII
        mov [ebx+edi], dl ; 存入缓冲区
        inc edi
        cmp eax, 0
        jne convert_loop
    
        ; 调整指针到最后一个有效字符,准备逆序输出
        dec edi
        add ebx, edi
    
        ; 逐个打印数字字符
        mov eax, 4
        mov edx, 1
    print_digit:
        int 0x80
        dec ebx
        dec edi
        jns print_digit ; 直到所有字符打印完毕
    
        ; 打印换行
        mov eax, 4
        mov ebx, 1
        mov ecx, newline
        mov edx, 1
        int 0x80
    
        ; 退出程序
        mov eax, 1
        xor ebx, ebx
        int 0x80
    

内容的提问来源于stack exchange,提问作者Little

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 14:15:13