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

X86汇编编写的阶乘函数运行触发段错误的原因是什么?

段错误触发原因
  • 编译命令缺失格式参数:当前nasm命令没有指定-f elf64输出格式,生成的不是64位ELF目标文件,ld链接后生成的程序结构异常,直接触发段错误。
  • sys_write系统调用参数错误:系统调用号为1的sys_write的第二个参数rsi要求传入待输出字符串的内存地址,直接把阶乘计算结果的数值赋值给rsi时,内核会尝试访问该数值对应的低地址内存,该区域属于用户态不可访问范围,直接触发段错误。
  • 阶乘函数逻辑缺失返回指令:.return1分支执行mov rbx, 1后没有加ret指令,会直接顺序执行后续的.print代码,此时栈上还残留递归调用的返回地址,执行流完全混乱。
  • 代码段命名不规范:NASM + ld组合下64位Linux程序的代码段默认命名为.text,你写的.code不会被ld识别为可执行代码段,可能导致执行权限缺失触发段错误。
  • 冗余指令问题:.print中调用sys_exit(系统调用号60)后进程会直接终止,后续的ret指令永远不会执行,属于冗余代码。
修复方案

1. 修正编译命令

正确的64位NASM编译、链接、执行命令如下:

nasm -f elf64 program.asm -o program.o
ld -o program program.o
./program

2. 修正代码逻辑

新增数字转ASCII字符串的逻辑,修正段名、返回指令、阶乘计算逻辑后的完整代码如下:

global _start

section .text
    _start:
        mov rax, 4
        call .factorial
        call .print

    .factorial:
        cmp rax, 1
        je .return1
        cmp rax, 0
        je .return1
        push rax        ; 保存当前n值到栈
        dec rax
        call .factorial
        pop rcx         ; 取出之前保存的n值
        imul rbx, rcx   ; 计算n * 上一层结果
        ret
        
    .return1:
        mov rbx, 1
        ret             ; 新增返回指令

    .print:
        ; 把rbx中的数字转成ASCII字符串存到缓冲区
        mov rax, rbx
        mov rdi, num_buf + 7  ; 从缓冲区末尾开始存
        mov rcx, 10
    .convert_loop:
        xor rdx, rdx
        div rcx
        add dl, '0'       ; 余数转ASCII
        dec rdi
        mov [rdi], dl
        test rax, rax
        jnz .convert_loop

        ; 调用sys_write输出结果
        mov rax, 1
        mov rdi, 1
        mov rsi, rdi
        mov rdx, num_buf + 7
        sub rdx, rsi      ; 计算输出长度
        syscall

        ; 正常退出进程
        mov rax, 60
        mov rdi, 0
        syscall

section .bss
    num_buf resb 8        ; 预留8字节缓冲区存储数字字符串

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 15:54:00