使用 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/addrsp (这导致了无人区内的崩溃),我只是直接减去 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