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,有两种合法处理方式:
- 改用
call指令:把je print_juhu改成je call_print,新增代码段实现调用逻辑:
这样call_print: call print_juhu jmp exit_code exit_code: mov rax, 60 mov rdi, 0 syscallret能正确回到exit_code继续执行退出流程。 - 修改函数结尾,去掉
ret:如果坚持用跳转指令,把print_juhu的ret替换成退出逻辑,比如直接执行exit系统调用:
这样函数执行完直接退出程序,不需要依赖栈中的返回地址。print_juhu: ; ... 原有寄存器保存和打印代码 ... pop rsi ; 替换ret为退出逻辑 mov rax, 60 mov rdi, 0 syscall
内容的提问来源于stack exchange,提问作者green tea
相关产品推荐
相关产品推荐

