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

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值而非输入的字符,和需求不符。

修复方案

你可以选择两种方案规避栈结构冲突:

  1. 优先推荐:单独开辟存储区存输入字符
    不要用系统分配的调用栈存储业务数据,在.bss段额外开一块缓冲区,按顺序写入输入的字符,后续从尾部倒序读取打印即可,完全不会干扰调用栈的返回地址逻辑。
  2. 如果要沿用调用栈存字符的逻辑
    在进入字符压栈逻辑前,先把返回地址弹出存到寄存器或预留内存中,等所有字符压栈完成后,再把返回地址压回栈顶再执行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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 22:45:03