编写x86汇编my_pow函数运行出现Segmentation Fault,请求排查
汇编函数
my_pow段错误排查与修复 问题概述
编写x86-64汇编函数my_pow搭配C主函数运行后,能输出预期数值序列,但最终触发Segmentation Fault。已在quit段执行pop指令释放栈空间,仍无法解决错误。
代码展示
汇编函数my_pow.s
.global my_pow .type my_pow, @function .data format: .asciz "%d\n" .text my_pow: // Variable pushq %rbp # value to print pushq %rbx # i movq $0x01, %rbp # value = 1 movl %edi, %ebx # i = number of iteration (1st arg) loop: movq $format, %rdi # 1st arg of printf is the format : "%d\n" movq %rbp, %rsi # 2nd arg of printf is the value xor %eax, %eax call printf cmp $0, %ebx # break if (i == 0) je quit addq %rbp, %rbp # value += value subq $0x1, %rbx # i -= 1 jmp loop quit: // Deallocate stack popq %rbp popq %rbx nop ret
C主函数main.c
#include <stdio.h> extern int my_pow(int n); int main(void) { int n = 5; my_pow(n); return 0; }
运行输出
1 2 4 8 16 32 zsh: segmentation fault (core dumped) ./a.out
错误原因分析
段错误的核心是栈中寄存器弹出顺序与压入顺序颠倒,破坏了被调用者保存寄存器的状态:
- 进入
my_pow时,压栈顺序为pushq %rbp→pushq %rbx,栈内从栈底到栈顶的存储结构为:[原rbp值, 原rbx值](栈顶上方还有调用my_pow时的返回地址)。 - 当前quit段先执行
popq %rbp,再执行popq %rbx,会把栈顶的原rbx值恢复到%rbp,把原rbp值恢复到%rbx,完全颠倒了两个寄存器的原始值。 - 根据x86-64 System V调用约定,
%rbp和%rbx属于被调用者保存寄存器,函数必须完整恢复其初始值才能返回。%rbp被错误赋值后,会破坏调用者(main函数)的栈帧结构,导致main执行return 0时触发栈操作错误,最终引发段错误。
修复方案
调整quit段的pop顺序,遵循栈后进先出的规则:先弹出最后压入的%rbx,再弹出最先压入的%rbp。修改后的quit段代码如下:
quit: // Deallocate stack popq %rbx popq %rbp nop ret
修改后重新编译运行,程序会正常输出数值序列并退出,不会触发段错误。
内容的提问来源于stack exchange,提问作者Nicolas
相关产品推荐
相关产品推荐

