在链接的程序集文件中,我想从 C++ 调用代码中访问一个变量。可以在不触发访问冲突的情况下执行此操作吗?

Posted

技术标签:

【中文标题】在链接的程序集文件中,我想从 C++ 调用代码中访问一个变量。可以在不触发访问冲突的情况下执行此操作吗?【英文标题】:In a linked assembly file, I want to access a variable from the c++ calling code. Can do this without triggering an Access Violation? 【发布时间】:2019-08-30 01:05:27 【问题描述】:

假设在我的 c++ 文件中,我有以下内容:

extern "C" void __stdcall AsmTest(
    __m128i& chain0);

通过检查周围 c++ 代码中的反汇编,我看到 chain0 是用 with 写入和读取的

(1)

movdqa xmmword ptr [rsp+60h], xmm0

(2)

movdqa xmm0, xmmword ptr [rsp+60h]

分别。在我的 .asm 文件中,我有

OPTION CASEMAP:NONE

PUBLIC AsmTest

.CODE

AsmTest:
    movdqa xmm0, xmmword ptr [rsp+60h]
    ret
END

在我的 c++ 代码中调用 AsmTest(chain0) 会导致访问冲突。我可以避免这个问题吗?

【问题讨论】:

为什么需要这样做?将必要的参数传递给被调用的函数不是更简单吗? 还有为什么你需要使用汇编函数而不是内联汇编? (调用函数将返回地址压栈) 对于第二个问题,我想知道如何处理这样的事情,因为如果我必须为 x86 和 x64 单独组装,我可能会发现将它们放在单独的文件中更优雅.首先,我对这个 x86 组装业务还是个新手,我不确定我是否理解你在这种情况下的意思,或者如果我理解了,那么我不知道正确的语法。可以举个例子吗? 使用vectorcall 让MSVC 在XMM 寄存器中传递__m128i 值。 Windows x64 的默认fastcall 约定不适合小功能。 (小函数通常不好,因为优化调用站点周围代码的函数调用开销,以及call/ret 开销。) @user202729 - 如果这是 64 位代码,则 Visual Studio 不支持内联汇编。 【参考方案1】:

使用vectorcall 让MSVC 在XMM 寄存器中传递__m128i 值,前提是您按值传递而不是通过使用引用将其强制到内存中。

Windows x64 的默认fastcall 约定不适合小功能。 (小函数通常不好,因为优化调用站点周围代码的函数调用开销,以及call/ret 开销。)


您的测试函数已损坏,因为被调用者中的[rsp+60h] 与调用者中的[rsp+60h] 的地址不同。调用指令本身压入一个 8 字节的返回地址。

movdqa 需要 16 字节对齐,因此您的加载错误。 (ABI 要求堆栈在 call 之前 对齐 16。)


但您实际上根本不应该相对于rsp 访问它:它本身并不是作为堆栈参数传递的,而是通过使用指针的引用来传递的。当第一个参数是整数/指针时,它进入 RCX。这就是为什么您会看到调用者设置 RCX 来保存指向该堆栈空间的指针。

让 MSVC 在启用优化的情况下编译 __m128i AsmTest(__m128i x) return x; 并查看它从哪里加载。 https://godbolt.org/z/7pvWqa

        movdqu  xmm0, XMMWORD PTR [rcx]
        ret

它使用movdqu 而不是movdqa,因为MSVC 宁愿让您的代码在Core 2 和K8/K10 等旧CPU 上运行缓慢,也不愿在您未对齐__m128i 时出错。显然。


顺便说一句,从编译器输出中学习是很有帮助的,当您了解编译器为什么会做它正在做的事情,并且只需要检查细节时。

您还应该查找有关调用约定的文档。请参阅https://***.com/tags/x86/info 中的链接。

【讨论】:

这似乎可以很好地回答我的问题,但我仍然遇到了一些麻烦。对此如此陌生,我仍然遇到语法问题,并且无法使用 vectorcall 进行编译 - 还没有找到我想的正确示例。忽略 movdqa xmm0, xmmword ptr [rsp+60h] 行,您能否发布如何更改我发布的 .asm 以使其与相应的 extern "C" void __vectorcall AsmTest(__m128i& chain0); 一起编译?我真的很感激。 你从来没有真正说出“仍然有麻烦”是什么意思。有错误信息吗?猜测一下,您没有正确decorate asm 文件中的函数名称。我期望像AsmTest@@8 这样的东西,其中@@ 表示一个vectorcall,而8 是参数列表中的十进制字节数。 64 位指针有8 个字节长。 @david @@8 仅适用于 32 位被调用者弹出堆栈参数 @DavidWohlferd 你的猜测绝对正确!现在它正在工作,我可以继续我的玩弄和摆弄。

以上是关于在链接的程序集文件中,我想从 C++ 调用代码中访问一个变量。可以在不触发访问冲突的情况下执行此操作吗?的主要内容,如果未能解决你的问题,请参考以下文章

我想从 C++ 非托管代码调用 C# 委托。无参数委托工作正常,但有参数委托使我的程序崩溃

如何从 C++ 执行 Matlab 脚本

在程序集文件中调用 C++ 函数

从 C# 调用 C++ 代码而不创建 dll?

从 C++ 调用 C#

C++ 函数挂钩