内联汇编中传递float参数、外部调用传参并返回float的问题(附崩溃示例)
内联汇编里float参数传递与外部函数调用问题详解
嘿,针对你提出的两个问题,结合你那段崩溃的代码,我给你捋清楚怎么搞定——毕竟x86的浮点栈和调用约定确实容易踩坑!
1. 内联汇编里怎么传递float类型参数?
得分两种场景说:
- 汇编内部自己用:直接用x87的浮点栈寄存器(
st(0)、st(1)这些)就行,就像你代码里的fld a、fld b,把float加载到浮点栈后,后续的汇编指令直接操作这些寄存器里的值就ok。要是需要临时存起来,用fst dword ptr [temp_var]把值写到内存变量里,之后要用再fld加载回来。 - 给C函数传参数:得严格遵循平台的调用约定(比如x86常用的cdecl/stdcall)。C里的float参数在栈上是按32位dword存的,所以你得把浮点栈里的float值写到函数调用的栈帧对应位置,比如用
fstp dword ptr [esp + 4]这种指令把值压到栈的正确偏移处。
2. 调用外部函数时传float参数并获取float返回值(顺便修复你的崩溃代码)
你的代码崩溃大概率是栈没平衡或者调用约定没搞对!结合你说的st(0)和st(1)已经有两个float值的场景,我给你写个能跑的版本,再给你讲关键点:
假设我们要调用的外部C函数原型是这样的:
float add_float(float x, float y);
修正后的内联汇编代码(以GCC为例)
// 前提:st(0)存的是b,st(1)存的是a,和你说的已有值场景一致 sub esp, 8 ; 给两个float参数分配栈空间(每个占4字节) fstp dword ptr [esp+4] ; 先把st(0)的b存入第二个参数的位置(因为cdecl是从右往左压栈) fstp dword ptr [esp] ; 再把st(1)的a存入第一个参数的位置,此时浮点栈清空 call add_float ; 调用外部函数,返回的float会存在st(0)里 add esp, 8 ; 恢复栈平衡,把刚才分配的参数空间释放掉 // 现在st(0)就是函数返回的结果,要存到变量里就用这个 fstp dword ptr [result]
必须注意的几个点(这就是你代码崩溃的原因!)
- 调用约定要匹配:x86的cdecl约定要求参数从右往左压栈,所以得先存第二个参数(y)再存第一个(x)。要是用的是stdcall,函数自己会清理栈,那最后就不用写
add esp,8了。 - 栈一定要平衡:你原来只分配了4字节空间,但函数需要两个参数的话,栈空间不够直接就栈溢出崩溃;调用完函数不恢复栈,会破坏整个栈帧结构,程序肯定崩。
- 返回值的位置:x86平台下,float类型的返回值默认存在
st(0)寄存器里,调用完函数直接读这个寄存器的值就行。 - 浮点栈状态:调用外部函数前,尽量保证浮点栈的状态符合约定(比如有些函数要求调用前浮点栈是空的),不然函数内部操作浮点栈的时候容易冲突出问题。
要是你用的是MSVC的内联汇编,写法稍微有点不一样,直接在__asm块里引用C变量就行:
float a = 1.5f, b = 2.5f, result; __asm { fld a ; st(0)=a fld b ; st(0)=b, st(1)=a sub esp, 8 fstp dword ptr [esp+4] fstp dword ptr [esp] call add_float add esp, 8 fstp result }
内容的提问来源于stack exchange,提问作者Zax Ftw
相关产品推荐
相关产品推荐

