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

x86_64汇编中跳转后执行ret触发段错误的原因咨询

x86_64汇编跳转指令导致段错误的问题

问题描述

刚接触x86_64汇编,正在学习跳转指令的使用规则。我的代码中,使用je(相等则跳转)指令跳转到print_juhu函数后会触发段错误,但直接调用该函数并执行ret却无异常。我确认栈的入栈和出栈操作数量一致,想请教这一问题的原因,另外是否只有调用exit这类函数才能正常退出跳转分支?

相关代码

section .data
    success db "yeah"

section .text
    global _start

print_juhu:
    push rsi
    push rdx
    push rax
    push rdi

    mov rax,1
    mov rsi,success
    mov rdx,4
    syscall

    pop rdi
    pop rax
    pop rdx
    pop rsi

    ret

_start:
    mov r12,3
    mov r14,3
    cmp r12,r14
    je print_juhu

    ; Exit the program
    mov rax, 60
    mov rdi, 0
    syscall

问题解答

段错误的原因

核心问题是跳转指令和调用指令对栈的处理逻辑完全不同:

  • 用call调用函数时,CPU会自动将当前指令的下一条地址压入栈,函数末尾的ret会弹出这个地址,让程序回到调用点继续执行。
  • 但je是直接修改指令指针跳转到目标地址,不会在栈中压入任何返回地址。当print_juhu执行到ret时,只能从栈顶取出一个随机值作为返回地址,跳转到非法内存区域,触发段错误。

你确认的内部push/pop数量平衡,只是保证了函数执行前后寄存器状态不受影响,但ret依赖的返回地址根本不存在,这才是崩溃的根源。

跳转分支的合法退出方式

不是必须调用exit,有两种合法处理方式:

  1. 改用call指令:把je print_juhu改成je call_print,新增代码段实现调用逻辑:
    call_print:
        call print_juhu
        jmp exit_code
    exit_code:
        mov rax, 60
        mov rdi, 0
        syscall
    
    这样ret能正确回到exit_code继续执行退出流程。
  2. 修改函数结尾,去掉ret:如果坚持用跳转指令,把print_juhu的ret替换成退出逻辑,比如直接执行exit系统调用:
    print_juhu:
        ; ... 原有寄存器保存和打印代码 ...
        pop rsi
        ; 替换ret为退出逻辑
        mov rax, 60
        mov rdi, 0
        syscall
    
    这样函数执行完直接退出程序,不需要依赖栈中的返回地址。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 04:44:59