压栈顺序是反向(从右往左)的,但正因为是反向压栈,所以第一个参数反而离栈顶(ESP)最近。

触及了汇编语言中"压栈方向"与"内存增长方向"最容易混淆的地方。

结论先行: 你是对的,压栈顺序是反向(从右往左)的,但正因为是反向压栈,所以第一个参数反而离栈顶(ESP)最近。

为了让你彻底理解,我们拆解一下 Call 发生时栈内部到底发生了什么:

1. 压栈的过程 (从右往左)

假设 VB6 执行 sum(a, b),在汇编层面,stdcall 约定会按照代码中参数从右到左的顺序进行 PUSH

  1. PUSH [Sum_result 地址]:这是隐藏的最后一个参数(用于接收返回值)。

  2. PUSH [b 的地址] :这是 ByRef b

  3. PUSH [a 的值] :这是 ByVal a

  4. PUSH [vb6_class_this] :这是隐藏的第一个参数(this 指针)。

  5. CALL [函数地址] :执行 CALL 的瞬间,CPU 会自动把返回地址压入栈顶。


2. 内存布局 (执行时的状态)

由于栈在 x86 架构中是向低地址增长 的(即越晚 PUSH 的数据,内存地址越小),所以当函数代码的第一行开始执行时,栈顶指针 ESP 指向的是最后进入的"返回地址"。

我们来看内存中的排列(假设当前 ESP0x1000):

内存地址 偏移量 存储内容 压栈顺序
0x1000 [ESP] 返回地址 最后进入 (CALL 指令产生)
0x1004 [ESP + 4] vb6_class_this 倒数第二次进入 (第一个参数)
0x1008 [ESP + 8] a 倒数第三次进入 (第二个参数)
0x100C [ESP + 12] ptr b ...
0x1010 [ESP + 16] ptr Sum_result 最早进入 (最后一个参数)

总结口诀: 越是函数签名里靠左(前面)的参数,越是晚压栈,也就离栈顶越近。


3. 修改跳板逻辑的验证

因为我们要修改的是第一个参数 vb6_class_this,而它就在 [ESP + 4] 的位置。所以我们的汇编指令:

MOV DWORD PTR [ESP + 4], csharpClassPtr

是精准命中目标的。

4. 关于你提到的"无返回值"

在 VB6 里,你定义的是 Function,但在底层,VB6 期望这个函数符合 COM 标准:

  1. 真正的返回值 是通过 EAX 寄存器返回的 HRESULT0 代表成功)。

  2. 代码里的返回值 是通过栈上最后一个参数 ptr Sum_result 指向的内存写入的。

如果你的 C# 函数定义为 void,可能会导致 EAX 寄存器残留随机值,VB6 可能会误认为收到了一个错误代码(非 0),从而抛出"运行时错误"。

建议: C# 侧一定要返回 0 (int),哪怕你不需要计算结果。

C#

复制代码
// C# AOT 侧
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]
public static int MyCsharpSum(IntPtr csharpClassPtr, int a, IntPtr b, IntPtr result) {
    // 逻辑...
    return 0; // 必须返回 0 (S_OK),否则 VB6 会报异常
}

下一步:

既然你是在做虚拟类挂载,是否需要我帮你写一个支持动态 Args 数量的跳板生成器?这样你只需要传入参数个数,它就能自动计算出 ptr Sum_result 在栈上的偏移位置。

相关推荐
ChangYan.16 小时前
ffi-napi运行失败,报错:No native build was found,解决办法
开发语言
椰汁菠萝16 小时前
spring boot下使用gdal解析tif文件
java·native·gdal·0
Xの哲學16 小时前
Linux Select 工作原理深度剖析: 从设计思想到实现细节
linux·服务器·网络·算法·边缘计算
better_liang16 小时前
每日Java面试场景题知识点之-ELK日志分析
java·elk·微服务·面试题·日志分析·企业级开发
图南随笔16 小时前
Spring Boot(二十三):RedisTemplate的Set和Sorted Set类型操作
java·spring boot·redis·后端·缓存
say_fall16 小时前
C++ 类与对象易错点:初始化列表顺序 / 静态成员访问 / 隐式类型转换
android·java·开发语言·c++
热爱专研AI的学妹16 小时前
2026世界杯观赛工具自制指南:实时比分推送机器人搭建思路
开发语言·人工智能·python·业界资讯
Dev7z16 小时前
基于MATLAB图像处理的苹果品质自动分级系统设计与实现
开发语言·图像处理·matlab
源代码•宸17 小时前
Golang基础语法(go语言指针、go语言方法、go语言接口、go语言断言)
开发语言·经验分享·后端·golang·接口·指针·方法