【问题标题】:NASM printf print 64 bit double segfaultsNASM printf 打印 64 位双段错误
【发布时间】:2020-06-07 12:58:00
【问题描述】:

我正试图在组装中打印双打,但我失败了。我在调用我自己的函数时遇到了段错误,我打算将其用作帮助器来打印双精度以进行调试。我正在关注这些printf 示例:https://www.csee.umbc.edu/portal/help/nasm/sample.shtml

我的代码目前如下所示:

section .data
    formatStrf: db `The number is %f\n`,0

section .text

extern printf

printfcallfloat:

    ;Pass in RDI
    PUSH RDI ;Preserve value of rdi
    PUSH RAX ;Preserve value of RAX

    PUSH RDI;The value we want to print
    PUSH DWORD formatStrf
    CALL printf ;Segfault

    POP RAX;Pop the stack back (too lazy to manually change the RSP value)
    POP RAX

    POP RAX;Restore the RAX and RDI
    POP RDI
    RET

我将浮点值传递给RDI reg,如下所示:

MOVSD QWORD [RSP], XMM0 ;Copy to stack
MOV RDI, QWORD [RSP]
CALL printfcallfloat

编辑:我在 linux 上运行它。

【问题讨论】:

  • @prl 是的,我确实在 linux 上运行它。也将该信息添加到问题中。
  • 您链接的页面有 32 位示例,您似乎已经通过简单的方式将其转换为 64 位,但这不起作用,因为调用约定完全不同。该页面上有 64 位示例的链接;你应该关注那些。

标签: assembly segmentation-fault printf x86-64


【解决方案1】:

在 x86_64 上,参数在寄存器中传递,而不是在堆栈中(仅当参数的大小太大而无法放入寄存器时才使用堆栈)。所有血淋淋的细节1都在SYSV ABI for x86_64

中列出

其基础是前 6 个整数/指针参数在 RDI/RSI/RDX/RCX/R8/R9 中传递,而前 8 个浮点/双精度参数在 XMM0..XMM7 中传递。此外,您需要指定用于 AL2 参数的 XMM 寄存器的数量。因此,在您的情况下,您需要 RDI 中的格式,XMM0 中的双精度值和 AL 中的 1

wikipedia page 也有很多关于此的好(简明)信息。


1对于非 Microsoft 系统——MS 是 MS,它们以自己不兼容的方式做事

2您实际上只需要为使用至少一个 XMM 寄存器的可变参数函数设置此项。对于非 varargs 函数,它将被忽略,如果对于 varargs 函数它设置得太大,结果将是一些浪费的周期(保存不需要的 XMM regs),但实际上不会破坏任何东西。

【讨论】:

  • OP 似乎也不知道 ABI 要求 RSP 在 call 之前是 16 字节对齐的。 (私有辅助函数除外。)
【解决方案2】:

编辑:正如 cmets 中所指出的,这仅适用于 Windows 架构。请参阅 Chris 对 Linux 系统约定的回答。


您链接到的页面包含x86 的示例,32 位架构。 x86_64 架构的不同之处在于参数传递给函数的方式。

前四个整数参数在寄存器中传递。整数值分别在 RCX、RDX、R8 和 R9 中以从左到右的顺序传递。参数 5 和更高的参数在堆栈上传递。

source

任何浮动参数通常会在 XMM0...3 中传递,但对于可变参数,情况不同:

如果参数通过可变参数(例如,省略号参数)传递,则适用正常的寄存器参数传递约定,包括将第五个和后续参数溢出到堆栈。被调用者有责任转储已获取地址的参数。仅对于浮点值,整数寄存器和浮点寄存器都必须包含该值,以防被调用者期望整数寄存器中的值。

因此,换句话说,在调用printf 之前,您应该将RCX 设置为格式字符串,并将RDXXMM1 设置为数字。

【讨论】:

  • 您的引述来自微软文档,它使用与其他所有人(微软)不同的寄存器。对于任何非 MS 你想要SYSV ABI for x86_64
  • Microsoft ABI 还需要在堆栈顶部有额外的 32 字节未使用空间,然后调用并将堆栈对齐为 16 字节对齐。
  • 好吧,这显然不适合我,因为我在 linux 上运行它。
猜你喜欢
  • 2023-01-11
  • 2016-09-10
  • 1970-01-01
  • 2014-12-27
  • 2015-06-25
  • 2013-12-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多