NASM汇编冒泡排序程序出现段错误,求定位与修复方案
汇编冒泡排序程序段错误问题分析
问题背景
在Linux平台使用NASM编写了一个冒泡排序汇编程序,目标是生成1000个8字节随机值,从小到大排序后打印。编译运行命令如下:
nasm test.asm -f elf64 ld test.o ./a.out
运行时出现Segmentation Fault(段错误),程序代码如下:
section .text global _start _start: mov rbp,rsp ;save stack pointer sub rsp,8000 ;reserve 1000 times 64bit value mov rbx,rbp ;save base pointer into rbx for Effective Address mov cx,1001 ;equal to for(int i=0; i<1000; ++i) load: sub cx,1 jz .exit rdrand eax ;get random 64bit value in eax sub rbx,8 mov [rbx],eax ;save the random value in stack jmp load .exit: mov rbx,rbp mov cx,1000 ;equal to for(int i=0; i<999; ++i) sort: ;Bubble Sort start here sub cx,1 jz .exit sub rbx,8 mov rax,[rbx] ;last value in rax mov rcx,[rbx-8] ;last-1 value in rcx cmp rax,rcx jge .noOperation ;if rax >= rcx continue mov [rbx],rcx ;change mov [rbx-8],rax ;change .noOperation: jmp sort .exit: mov rbx,rbp mov cx,1001 ;equal to for(int i=0; i<1000; ++i) print: ;classic decimal print .init: sub cx,1 jz .exit sub rbx,8 mov rax,[rbx] .divinit: mov rsi,10 mov rdi,1 sub rsp,1 mov [rsp],byte 10 .div: mov rdx,0 div rsi add dl,48 add rdi,1 sub rsp,1 mov [rsp],byte dl cmp rax,0 jnz .div .syscall: mov rax,1 mov rdx,rdi mov rdi,1 mov rsi,rsp syscall add rsp,rdx jmp .init .exit: add rsp,8000 programexit: mov rax,60 mov rdi,0 syscall
错误原因分析
1. 寄存器滥用直接触发段错误
排序阶段的sort循环里,你同时把rcx寄存器用作循环计数器和数据存储:
- 先用
cx(rcx的低16位)控制循环次数 - 随后执行
mov rcx,[rbx-8],把栈中值加载到完整64位rcx寄存器,直接覆盖了循环计数cx
这会导致循环终止条件jz .exit完全失效,程序会无限制执行sub rbx,8,最终访问到栈空间以外的非法内存,触发段错误。
解决方法:换用其他寄存器存储比较值,比如rdx,避免破坏循环计数器。
2. RDRAND指令使用错误(潜在问题)
你用rdrand eax获取随机值,但要存储的是8字节(64位)数据,eax仅为32位寄存器,高位4字节会是未定义的垃圾值。正确做法是用rdrand rax生成完整64位随机数。
3. 冒泡排序逻辑不完整
当前排序代码只实现了一轮相邻元素比较交换,完全缺少冒泡排序需要的外层循环控制排序轮数、内层循环遍历未排序区间的逻辑,即使修复寄存器问题,也无法完成正确排序。
4. 打印阶段栈恢复的潜在风险
打印字符时通过sub rsp,1临时存储字符,虽然每次打印后用add rsp,rdx恢复了这部分栈空间,但打印循环的.exit标签处仅恢复了存储随机数的8000字节栈空间,若打印过程异常退出,会导致栈不平衡,引发其他错误。
修复关键片段示例
以修复排序阶段寄存器问题为例:
sort: ;Bubble Sort start here sub cx,1 jz .exit sub rbx,8 mov rax,[rbx] ;last value in rax mov rdx,[rbx-8] ;用rdx代替rcx存前一个值,避免破坏循环计数器 cmp rax,rdx jge .noOperation ;if rax >= rdx continue mov [rbx],rdx ;交换操作 mov [rbx-8],rax ;交换操作 .noOperation: jmp sort .exit:
内容的提问来源于stack exchange,提问作者rawI4
相关产品推荐
相关产品推荐

