【发布时间】:2013-04-12 09:46:30
【问题描述】:
当我在 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。那么问题一定出在其他地方?
【问题讨论】:
-
出于兴趣,将
mov转为%rax的目的是什么? -
浮点参数计数,IIRC。
-
相关:您不能直接打印带有
printf的float,只能打印double(带有"%f")或long double,因为可变参数函数的C 提升规则:@987654321 @. -
也相关; glibc
printf仅在%al != 0时关心堆栈对齐,因为这就是 gcc 编译可能接受 FP args 的可变参数函数的方式。 printf float in nasm assembly 64-bit 表明printf在使用未对齐的堆栈和 RAX=0 调用时不会崩溃,答案显示 gcc 的代码(仅对非零 AL 运行)将 xmm0..7 转储到带有 @ 的堆栈987654342@(可变参数函数也可以接受__m128args,而不仅仅是double。)
标签: assembly floating-point x86-64