gpt4 book ai didi

assembly - 从x86-64打印 float 似乎需要保存%rbp

转载 作者:行者123 更新时间:2023-12-04 03:52:34 26 4
gpt4 key购买 nike

当我在Ubuntu上使用gcc 4.6.1编写一个与C库链接的简单汇编语言程序时,我尝试打印一个整数,它可以正常工作:

        .global main
.text
main:
mov $format, %rdi
mov $5, %rsi
mov $0, %rax
call printf
ret
format:
.asciz "%10d\n"

如预期,这将打印5。

但是现在,如果我做了一些小的更改,并尝试打印浮点值:
        .global main
.text
main:
mov $format, %rdi
movsd x, %xmm0
mov $1, %rax
call printf
ret
format:
.asciz "%10.4f\n"
x:
.double 15.5

此程序无法打印任何内容而出现故障。只是一个悲伤的段。

但是我可以通过推送并弹出 %rbp来解决此问题。
        .global main
.text
main:
push %rbp
mov $format, %rdi
movsd x, %xmm0
mov $1, %rax
call printf
pop %rbp
ret
format:
.asciz "%10.4f\n"
x:
.double 15.5

现在,它可以工作并打印15.5000。

我的问题是:为什么推送和弹出 %rbp会使应用程序正常工作?根据ABI的说法, %rbp是被调用者必须保留的寄存器之一,因此 printf不能将其弄乱。实际上,当仅将一个整数传递给 printf时, printf在第一个程序中起作用。那么问题一定在其他地方吗?

最佳答案

我怀疑该问题与%rbp没有任何关系,而是与堆栈对齐有关。引用ABI:

The ABI requires that stack frames be aligned on 16-byte boundaries. Specifically, the end of the argument area (%rbp+16) must be a multiple of 16. This requirement means that the frame size should be padded out to a multiple of 16 bytes.



输入 main()时,堆栈已对齐。调用 printf()将返回地址压入堆栈,将堆栈指针移动8个字节。您可以通过将另外八个字节压入堆栈来恢复对齐状态(碰巧是 %rbp,但也很可能是其他字节)。

这是 gcc生成的代码(也是 on the Godbolt compiler explorer):
.LC1:
.ascii "%10.4f\12\0"
main:
leaq .LC1(%rip), %rdi # format string address
subq $8, %rsp ### align the stack by 16 before a CALL
movl $1, %eax ### 1 FP arg being passed in a register to a variadic function
movsd .LC0(%rip), %xmm0 # load the double itself
call printf
xorl %eax, %eax # return 0 from main
addq $8, %rsp
ret

如您所见,它通过从 %rsp的开头减去8,然后在结尾将其重新添加,来满足对齐要求。

相反,您可以对所需的任何寄存器执行虚拟插入/弹出操作,而不是直接操作 %rspsome compilers do use a dummy push to align the stack,因为 this can actually be cheaper在现代CPU上,并节省了代码大小。

关于assembly - 从x86-64打印 float 似乎需要保存%rbp,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16097173/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com