NASM汇编函数内使用push/pop指令触发SIGSEGV错误如何解决?
问题解答
基础问题答复
函数内部完全可以正常使用push/pop指令,这是汇编开发中栈操作的标准用法,你遇到的SIGSEGV错误和在函数内用栈操作无关,是栈结构被破坏、内存操作不匹配等逻辑错误导致的。
具体错误原因
- 调用栈的返回地址被业务数据覆盖:执行
call read_data时,CPU会自动把下一条指令的地址(返回地址)压入栈顶,作为后续ret的跳转依据。但你在循环读取字符的过程中,不断把字符通过push ax压入栈,没有做栈平衡处理,等读到.触发ret时,栈顶已经是你最后压入的字符数据,CPU会把这个字符值当成指令地址跳转,自然触发无效内存引用错误。 - 内存操作长度不匹配:你在.bss段定义
counter resb 1,只给counter分配了1字节内存,但_start中mov [counter], word 1是写入2字节的word类型数据,出现内存越界写入,会破坏相邻内存变量的值。 - 翻转输出逻辑也存在栈错误:如果你启用
call FlipString,call指令同样会先把返回地址压入栈,你第一行pop ax会直接把返回地址读走,等FlipString执行ret时,栈顶是字符数据,也会触发非法跳转。 - 其他细节错误:read系统调用的注释误写为标准输出,打印逻辑中输出的是counter值而非输入的字符,和需求不符。
修复方案
你可以选择两种方案规避栈结构冲突:
- 优先推荐:单独开辟存储区存输入字符
不要用系统分配的调用栈存储业务数据,在.bss段额外开一块缓冲区,按顺序写入输入的字符,后续从尾部倒序读取打印即可,完全不会干扰调用栈的返回地址逻辑。 - 如果要沿用调用栈存字符的逻辑
在进入字符压栈逻辑前,先把返回地址弹出存到寄存器或预留内存中,等所有字符压栈完成后,再把返回地址压回栈顶再执行ret即可,核心参考代码如下:
read_data: pop ebx ; 先把返回地址存到ebx寄存器 read_loop: mov eax,3 mov ebx,0 mov ecx,myData mov edx,1 int 80h mov bl, [myData] cmp bl, '.' je read_finish mov ax, [myData] push ax add byte [counter], 1 jmp read_loop read_finish: push ebx ; 把返回地址压回栈顶,保证ret正常跳转 ret
同时要把_start中的mov [counter], word 1修改为mov byte [counter], 0,匹配counter的1字节长度。FlipString也需要做相同的返回地址保存/恢复处理,同时把打印的数据源从counter改为temp即可。
内容的提问来源于stack exchange,提问作者A Z I N E Z
相关产品推荐
相关产品推荐

