【问题标题】:Using nasm with __vectorcall convention将 nasm 与 __vectorcall 约定一起使用
【发布时间】: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/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

【问题讨论】:

  • 旁注: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


【解决方案1】:

所以主要问题是使用@@4 作为字节大小。出于某种原因,它必须是@@8。也许是因为返回值?

另外,我搞砸了 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

【讨论】:

  • 这是与您的问题相同的代码,您声称该代码不起作用。我认为您需要回滚您的问题,以便它实际上具有此答案声称要修复的错误。否则就不是问题了。
  • @PeterCordes 我将样本还原为原始版本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-20
  • 2017-08-05
  • 2023-03-08
  • 2017-05-03
相关资源
最近更新 更多