简体   繁体   English

在链接的程序集文件中,我想从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?

Let's say that in my c++ file, I have the following: 假设在我的c ++文件中,我有以下内容:

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

and by examining the disassembly in the surrounding c++ code, I see that chain0 is written to and read from with 通过检查周围的c ++代码中的反汇编,我看到chain0被写入和读取

(1) (1)

movdqa xmmword ptr [rsp+60h], xmm0

and

(2) (2)

movdqa xmm0, xmmword ptr [rsp+60h]

respectively. 分别。 In my .asm file, I have 在我的.asm文件中,

OPTION CASEMAP:NONE

PUBLIC AsmTest

.CODE

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

calling AsmTest(chain0) in my c++ code causes an Access Violation. 在我的C ++代码中调用AsmTest(chain0)会导致访问冲突。 Can I avoid this problem? 我可以避免这个问题吗?

Use vectorcall to let MSVC pass __m128i values in XMM registers, if you pass by value instead of forcing it to memory by using a reference. 如果您按值传递而不是通过使用引用将其强制传递到内存,请使用vectorcall使MSVC传递XMM寄存器中的__m128i值。

Windows x64's default fastcall convention is bad for small function. 64位的Windows的默认fastcall约定是坏的小功能。 (Small functions are bad in general because of function call overhead on optimizing the code around the call-site, and call / ret overhead.) (小功能通常是不好的,因为优化调用站点周围代码的函数调用开销以及call / ret开销。)


Your test function is broken because [rsp+60h] in the callee is not the same address as [rsp+60h] in the caller. 您的测试功能已损坏,因为被调用[rsp+60h]与调用[rsp+60h]地址不同。 The call instruction itself pushes an 8-byte return address. 调用指令本身会推送一个8字节的返回地址。

movdqa requires 16-byte alignment so your load fault. movdqa需要16字节对齐,因此会导致加载错误。 (The ABI requires the stack to be aligned by 16 before a call .) (ABI要求在call 之前将堆栈对齐16。)


But you shouldn't actually be accessing it relative to rsp at all: it's not passed as a stack-arg per se, but rather by reference using a pointer . 但是您实际上根本不应该相对于rsp访问它: 本身并没有作为stack-arg传递,而是通过使用指针进行引用 When the first arg is an integer/pointer it goes in RCX. 当第一个arg是整数/指针时,它将进入RCX。 That's why you'll see the caller setting up RCX to hold a pointer to that stack space. 这就是为什么您会看到调用方设置RCX来保存指向该堆栈空间的指针的原因。

Let MSVC compile __m128i AsmTest(__m128i x){ return x; } 让MSVC编译__m128i AsmTest(__m128i x){ return x; } __m128i AsmTest(__m128i x){ return x; } with optimization enabled and see where it loads from. __m128i AsmTest(__m128i x){ return x; }启用了优化功能,然后查看它的加载位置。 https://godbolt.org/z/7pvWqa https://godbolt.org/z/7pvWqa

        movdqu  xmm0, XMMWORD PTR [rcx]
        ret

It uses movdqu instead of movdqa because MSVC would rather make your code run slow on old CPUs like Core 2 and K8/K10 than fault when you misalign a __m128i . 它使用movdqu而不是movdqa因为MSVC宁愿使您的代码在诸如Core 2和K8 / K10之类的旧CPU上运行缓慢,而不是使__m128i对齐时__m128i Apparently. 显然。


BTW, learning from compiler output is helpful when you know enough to understand why the compiler is doing what it's doing, and just need to check the details. 顺便说一句,当您足够了解编译器为什么要执行其工作并且仅需要检查详细信息时,从编译器输出中学习会很有帮助。

You should also look up documentation on the calling convention. 您还应该查找有关调用约定的文档。 See links in https://stackoverflow.com/tags/x86/info . 请参阅https://stackoverflow.com/tags/x86/info中的链接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM