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
相关产品推荐
相关产品推荐

