我想用 printf 打印一个浮点值
global main
extern printf
section .data
string: db `%f\n`, 0
section .bss
rs: resq 1
[...]
movq xmm0, [rs]
mov rdi, string
mov rax, 0
call printf
rs 包含浮动值 1.6
(gdb) x/fg &rs
0x600ad8 <rs>: 1.6000000000000001
但是程序打印
[username@localhost folder]$ ./programname
0.000000
我可以得到打印 1.6 的程序吗?我做错了什么?
我怀疑问题与您的代码设置有关
rax
到 0
而它必须是 1
因为您传递了一个浮点参数(有关详细信息,请参见 here)。基本上rax
应该包含在xmmN
寄存器中传递的变量参数的数量。
编辑:
printf
中的崩溃似乎是由堆栈错位引起的,因为程序在 movaps
指令处崩溃(它期望内存操作数在 16 字节边界上对齐):
=> 0x7ffff7a65f84 <__printf+36>: movaps %xmm0,0x50(%rsp)
0x7ffff7a65f89 <__printf+41>: movaps %xmm1,0x60(%rsp)
0x7ffff7a65f8e <__printf+46>: movaps %xmm2,0x70(%rsp)
0x7ffff7a65f93 <__printf+51>: movaps %xmm3,0x80(%rsp)
0x7ffff7a65f9b <__printf+59>: movaps %xmm4,0x90(%rsp)
0x7ffff7a65fa3 <__printf+67>: movaps %xmm5,0xa0(%rsp)
0x7ffff7a65fab <__printf+75>: movaps %xmm6,0xb0(%rsp)
0x7ffff7a65fb3 <__printf+83>: movaps %xmm7,0xc0(%rsp)
当输入
main
时,堆栈不是 16 字节对齐的,但如果你修复这个问题,程序就可以正常工作。下面是我的测试程序(注意开头的sub rsp, 8
):
global main
extern printf
section .data
string db `%f\n`, 0
rs dq 1.6
section .text
main:
sub rsp, 8
movq xmm0, qword [rs]
mov rdi, string
mov rax, 1
call printf
add rsp, 8
mov eax, 0x60
xor edi, edi
syscall
我做错了什么?
第一:确保您使用正确的调用约定(堆栈、寄存器、从左到右、从右到左等)。如果你的程序确实打印了一个浮点数,尽管它不是你需要的,那么至少格式字符串被正确传递了(或者你很幸运,
printf
找到格式字符串的地址在正确的地方,即使你没有把它的地址放在那里)。
第二个:您要打印的数字...是浮点数还是双数?
rs
被定义为保存四字值(64 位),但浮点数是 32 位。所以,如果第一点已经检查过了,没问题,我建议你使用"%lf"
作为格式,而不是"%f"
。
顺便说一句:你为什么放
RAX = 0
? printf
的调用是什么意思?
更新:这可能对您有所帮助。一个傻程序的反汇编(
f.c
):
#include <stdio.h>
main()
{
float x;
x = 1.6;
printf ("%f\n", x);
}
$ gcc -c -S f.c
$ less f.s
.file "f.c"
.section .rodata
.LC1:
.string "%f\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
subq $16, %rsp
movl $0x3fcccccd, %eax
movl %eax, -4(%rbp)
movss -4(%rbp), %xmm0
cvtps2pd %xmm0, %xmm0
movl $.LC1, %eax
movq %rax, %rdi
movl $1, %eax
call printf
leave
; file: pf.asm
; assemble with: nasm -f elf64 pf.asm -o pf.o
; link with: ld -pie -z noexecstack -e _start -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o test test.o -lc
default rel ; Use PC relative offsets (for PIE executable)
global _start ; Execute at _start (don't use any provided startup code)
extern printf ; printf is our only external function
section .rodata ; The format string in printf should be read only
string: db "Your number is %f", 0xa, 0
section .data ; We could make this read only, but if we want to change it
rs dq 1.6 ; through a scanf or something we can
section .text ; Program code
_start:
; Uncomment stack frame stuff if stack space needed, not needed for this example
; push rbp ; Setup our stack frame
; mov rbp, rsp
; sub rsp, 8 ; Create space on the stack
movq xmm0, qword [rs] ; Put float in xmm0
lea rdi, [string] ; Load address of string, lea is needed for PC relative
mov eax, 1 ; One floating point value, 0 extend into rax
call printf wrt ..plt ; PC relative function call
; add rsp, 8 ; Remove allocated space on the stack
; pop rbp ; Undo our stack frame
mov eax, 60 ; Exit syscall
xor edi, edi ; No error, 0 extend into rdi
syscall