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