使用 nasm 和 __vectorcall 约定
Using nasm with __vectorcall convention
我刚刚开始使用 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 dissassembly,我看到它们 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
所以主要问题是使用 @@4
作为字节大小。由于某种原因,它需要 @@8
。可能是因为 return 值?
此外,我搞砸了 64/32 位调用。这是最终的工作版本:
; float sin_f(float)
global sin_f@@8
section .text
sin_f@@8:
sub rsp, 24 ; red-zone
movss [rsp], xmm0 ; mov float arg onto stack
fld dword [rsp] ; push argument on float stack
fsin ; do sin in radians
fstp dword [rsp] ; pop float stack
movss xmm0, [rsp] ; move back to xmm0
add rsp, 24 ; red-zone
ret
我刚刚开始使用 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 dissassembly,我看到它们 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
所以主要问题是使用 @@4
作为字节大小。由于某种原因,它需要 @@8
。可能是因为 return 值?
此外,我搞砸了 64/32 位调用。这是最终的工作版本:
; float sin_f(float)
global sin_f@@8
section .text
sin_f@@8:
sub rsp, 24 ; red-zone
movss [rsp], xmm0 ; mov float arg onto stack
fld dword [rsp] ; push argument on float stack
fsin ; do sin in radians
fstp dword [rsp] ; pop float stack
movss xmm0, [rsp] ; move back to xmm0
add rsp, 24 ; red-zone
ret