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

编写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

错误原因分析

段错误的核心是栈中寄存器弹出顺序与压入顺序颠倒,破坏了被调用者保存寄存器的状态:

  1. 进入my_pow时,压栈顺序为pushq %rbp → pushq %rbx,栈内从栈底到栈顶的存储结构为:[原rbp值, 原rbx值](栈顶上方还有调用my_pow时的返回地址)。
  2. 当前quit段先执行popq %rbp,再执行popq %rbx,会把栈顶的原rbx值恢复到%rbp,把原rbp值恢复到%rbx,完全颠倒了两个寄存器的原始值。
  3. 根据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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 01:25:25