【发布时间】:2018-06-16 21:40:44
【问题描述】:
我刚刚开始使用 nasm,但我在使用 __vectorcall 约定时遇到了一些问题。调用我的测试函数 (sinf) 时,我从被调用方返回访问冲突。
; float sin_f(float)
global sin_f@@4
section .text
sin_f@@4:
push rdi
; sub rsp, 16 ; make room for xmm
movss [rsp - 16], xmm0 ; mov float arg onto stack
fld qword [rsp - 16] ; push argument on float stack
fsin ; do sin in radians
fstp qword [rsp - 16] ; pop float stack
movss xmm0, [rsp - 16] ; move back to xmm0
movq rax, xmm0
; add rsp, 16 ; reset stack
pop rdi
ret
我显然没有正确地进行清理,但到目前为止我所有的尝试都失败了。看着一些 MSVC 拆解我已经看到他们push/pop rdi,所以我已经添加了。而不是sub/add 到rsp(这导致了无人区的崩溃),我只是直接减去rsp。
这个article 涵盖了流行的调用约定,并提到__vectorcall 类似于__fastcall。但是,使用 ret 4 不会改变任何东西。另外,MSVC 本身并不这样做。哦,我也搬到rax 只是因为。
对于这些概念的任何帮助将不胜感激。谢谢!
编辑:错误是
Exception thrown at 0x00007FF6198B2C5A in demo1.exe:
0xC0000005: Access violation reading location 0x00000000B817FA20
调用者反汇编:
; 13 : T sin(T angle) {
$LN3:
movss DWORD PTR [rsp+8], xmm0
push rdi
sub rsp, 48 ; 00000030H
mov rdi, rsp
mov ecx, 12
mov eax, -858993460 ; ccccccccH
rep stosd
; 14 : static_assert(std::is_floating_point_v<T>, "requires floating point");
; 15 : if constexpr (std::is_same_v<float, T>) {
; 16 : return detail::sin_f(angle);
movss xmm0, DWORD PTR angle$[rsp]
call sin_f@@8
; 17 : } else {
; 18 : return detail::sin_d(angle);
; 19 : }
; 20 :
; 26 : }
add rsp, 48 ; 00000030H
pop rdi
ret 0
【问题讨论】:
-
旁注:
movss是浮点数而不是双精度数。您必须取消注释sub rsp, 16和add rsp, 16,因为 windows 不提供红色区域(我假设您在 windows 上,因为您提到了 MSVC)。在这种情况下,您当然应该使用[rsp]而不是[rsp-16]。 -
感谢您的提示。我正在使用花车 (
float sin_f(float))。我刚刚读到关于红色区域的信息。根据 nasm 文档,我正在尝试使用sub rsp, 24。会不会是对齐问题?该程序正在使用自定义对齐方式进行编译。 -
对齐在这里并不重要。使用当前版本的代码更新您的问题。 PS:如果您确实有浮点数,那么 FPU 指令中的
qword当然是错误的,因为那是双精度数。ret 4肯定坏了,你想要简单的ret。 -
@Jester 好的,我尝试使用 dword(并删除 ret 值)仍然没有。将再次更新。
-
Windows x64
__vectorcall(和“普通”x64__fastcall)具有阴影空间高于 RSP,您可以将其用作暂存空间。红色区域是 RSP 下方的空间,您可以在没有信号处理程序或其他任何破坏它的情况下使用,所以这是错误的术语。 (scx:如果您确实阅读了有关红色区域的信息,请再次搜索阴影空间。或者在 stackoverflow.com/tags/x86/info 中查看 ABI 文档的链接。
标签: assembly nasm calling-convention