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
相关产品推荐
相关产品推荐

