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

64位Linux下C调用x86汇编斐波那契函数printf报错求助

问题场景

在64位Linux环境下尝试在C代码中调用自行编写的x86汇编fibonacci函数,使用如下编译命令:

nasm -f elf32 asmcode.asm -o a.o
gcc -ggdb -no-pie -m32 a.o ccode.c -o a.out

调试时发现C代码中存储返回值的变量x数值正确,但执行printf函数时会出现错误,对应代码如下:

C代码

#include <stdio.h>

int fibonacci(int);

int main()
{
    int x = fibonacci(3);
    printf("Fibonacci is : %d",x);
    return 0;
}

汇编代码

section .text
global fibonacci

fibonacci:
    push ebp
    mov ebp, esp
    ; 初始化变量
    mov dword [prev], 0x00000000
    mov dword [cur], 0x00000001
    mov byte [it], 0x01
    mov eax, dword [ebp + 8] ; 取输入参数n=3
    mov byte [n], al

getfib:
    xor edx,edx
    mov dl, byte [n]
    cmp byte [it] , dl
    jg loopend
    mov eax,dword [prev]
    add eax, dword [cur]
    mov ebx, dword [cur]
    mov dword [prev], ebx
    mov dword [cur] , eax
    inc byte [it]
    jmp getfib

loopend:
    mov eax, dword [cur]
    pop ebp
    ret

section .bss
    it resb 1
    prev resd 1
    cur resd 1
    n resb 1
问题排查与修复

核心问题1:违反C调用约定的寄存器保护规则

x86 32位环境下C语言默认使用cdecl调用约定,约定明确要求ebx、esi、edi、ebp属于被调用者保存寄存器:如果被调用的函数内部需要使用这些寄存器,必须在函数入口处压栈保存,函数返回前弹出恢复,不能直接修改原值。
你的汇编代码中直接修改了ebx寄存器的值,没有做任何保存恢复操作,当fibonacci函数返回main函数后,ebx已经被篡改,而后续调用printf时依赖ebx的原有值,直接导致执行异常。

核心问题2:使用全局变量存储临时计算值

你把计算过程用到的it、prev、cur、n都定义在了.bss段的全局变量中,这些全局内存区域是可被所有函数修改的,printf执行过程中完全可能覆盖这些位置的内容,同时这种写法也不支持函数重入、多线程调用场景。
临时变量应该分配在函数栈帧中,不要使用全局变量存储。

修复后的汇编代码

section .text
global fibonacci

fibonacci:
    push ebp
    mov ebp, esp
    push ebx ; 保存ebx寄存器,符合调用约定
    ; 栈上分配临时变量空间:prev(-4)、cur(-8)、it(-12)、n(-16),4字节对齐方便操作
    sub esp, 16
    ; 初始化临时变量
    mov dword [ebp-4], 0x00000000 ; prev
    mov dword [ebp-8], 0x00000001 ; cur
    mov dword [ebp-12], 0x00000001 ; it
    mov eax, dword [ebp + 8]
    mov dword [ebp-16], eax ; n

getfib:
    mov edx, dword [ebp-16]
    cmp dword [ebp-12], edx
    jg loopend
    mov eax, dword [ebp-4]
    add eax, dword [ebp-8]
    mov ebx, dword [ebp-8]
    mov dword [ebp-4], ebx
    mov dword [ebp-8], eax
    inc dword [ebp-12]
    jmp getfib

loopend:
    mov eax, dword [ebp-8] ; 取返回值
    add esp, 16 ; 回收栈上临时变量空间
    pop ebx ; 恢复ebx寄存器原值
    pop ebp
    ret

使用上述汇编代码重新编译即可正常运行。


内容的提问来源于stack exchange,提问作者Bhavya Kapoor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 19:12:01