在链接的程序集文件中,我想从 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?
假设在我的 c++ 文件中,我有以下内容:
extern "C" void __stdcall AsmTest(
__m128i& chain0);
并且通过检查周围 c++ 代码中的反汇编,我看到 chain0 是用
写入和读取的
(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) 导致访问冲突。我可以避免这个问题吗?
使用 vectorcall
让 MSVC 传递 XMM 寄存器中的 __m128i
值,如果你按值传递而不是使用引用强制它到内存。
Windows x64 的默认 fastcall
约定不适合小函数。 (小函数通常不好,因为优化调用站点代码的函数调用开销,以及 call
/ret
开销。)
您的测试函数已损坏,因为被调用方中的 [rsp+60h]
与调用方中的 [rsp+60h]
地址不同。调用指令本身压入一个 8 字节的 return 地址。
movdqa
需要 16 字节对齐,因此您的加载错误。 (ABI 要求堆栈对齐 16 before a call
。)
但实际上您根本不应该相对于 rsp
访问它:它本身并不是作为堆栈参数传递的,而是通过使用指针的引用传递的.当第一个 arg 是 integer/pointer 时,它进入 RCX。这就是为什么您会看到调用者设置 RCX 以保存指向该堆栈的指针 space.
让 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://whosebug.com/tags/x86/info.
中的链接
假设在我的 c++ 文件中,我有以下内容:
extern "C" void __stdcall AsmTest(
__m128i& chain0);
并且通过检查周围 c++ 代码中的反汇编,我看到 chain0 是用
写入和读取的(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) 导致访问冲突。我可以避免这个问题吗?
使用 vectorcall
让 MSVC 传递 XMM 寄存器中的 __m128i
值,如果你按值传递而不是使用引用强制它到内存。
Windows x64 的默认 fastcall
约定不适合小函数。 (小函数通常不好,因为优化调用站点代码的函数调用开销,以及 call
/ret
开销。)
您的测试函数已损坏,因为被调用方中的 [rsp+60h]
与调用方中的 [rsp+60h]
地址不同。调用指令本身压入一个 8 字节的 return 地址。
movdqa
需要 16 字节对齐,因此您的加载错误。 (ABI 要求堆栈对齐 16 before a call
。)
但实际上您根本不应该相对于 rsp
访问它:它本身并不是作为堆栈参数传递的,而是通过使用指针的引用传递的.当第一个 arg 是 integer/pointer 时,它进入 RCX。这就是为什么您会看到调用者设置 RCX 以保存指向该堆栈的指针 space.
让 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://whosebug.com/tags/x86/info.
中的链接