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

Win32内联汇编调用带参函数问题解决与自定义FFI接口实现

基于汇编实现自定义FFI接口(修复__stdcall函数调用栈崩溃问题)

问题背景

需要调用a1.dll中导出的__declspec( dllexport ) int i32(int y)函数(调用约定为__stdcall),最初通过手动汇编压栈传递参数时程序崩溃,现已定位并修复问题,以下是完整实现方案。

错误原因分析

原汇编代码中在函数调用后执行了pop %%eax操作,而__stdcall约定要求被调用者负责清理栈(函数返回时会执行ret n指令,n为参数总字节数),手动弹出参数会破坏栈平衡,导致程序崩溃。

修正后的完整代码

#include <stdio.h>
#include <windows.h>

struct prot{
    void* retn;
    void* arg1;
    void* arg2;
    void* arg3;
    void* arg4;
    int arg_len;
};

typedef struct prot Prot;

void c_func(void* fun, Prot* p){
    __asm__(
        "mov %2, %%eax\n\t"
        "push %%eax\n\t"          // 按__stdcall约定压入参数(从右到左,此处仅一个参数)
        "mov %1, %%eax\n\t" 
        "call *%%eax\n\t"         // 调用目标函数
        "mov %%eax, %0\n\t"       // __stdcall约定返回值存于eax,保存到结构体的retn字段
        : "=r"(p->retn)
        : "r" (fun), "r"(p->arg1)
        : "%eax"
    );
}

typedef int(__stdcall *fp)(int);

int main(){
    HMODULE hDll = LoadLibrary("a1.dll");
    fp lpFunc = (fp)GetProcAddress(hDll, "i32");
    Prot p;
    p.arg1 = (void*)35;
    p.arg_len = 1;
    c_func(lpFunc, &p);
    printf("retorno: %d\n", (int)p.retn);
    FreeLibrary(hDll);
    return 0;
}

关键实现要点

  • 调用约定适配:严格遵循__stdcall规则,由被调用者清理栈,调用者无需手动弹出参数
  • 参数传递:x86架构下__stdcall要求参数从右到左压栈,单个参数直接压入即可,多参数场景需按逆序依次压栈
  • 返回值处理:__stdcall约定下整数返回值存储在eax寄存器,直接读取该寄存器值保存即可
  • 扩展性设计:Prot结构体支持最多4个参数存储,arg_len标记实际参数数量,便于后续扩展多参数函数调用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 16:25:01