I want to print a float value with 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 contains the floating value 1.6
(gdb) x/fg &rs
0x600ad8 <rs>: 1.6000000000000001
but the program prints
[username@localhost folder]$ ./programname
0.000000
who can I get the program to print 1.6? what am I doing wrong?
I suspect the problem has something to do with your code setting rax
to 0
whereas it must be 1
because you pass a floating point argument (see here for details). Basically rax
should contain the number of variable arguments passed in xmmN
registers.
Edit:
The crash in printf
seems to be caused by stack miaslignment as the program crashes at a movaps
instruction (which expects the memory operand to be aligned on 16-byte boundary):
=> 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)
When entering main
the stack is not 16-byte aligned but if you fix this the program works fine. Below is my test program (notice the sub rsp, 8
in the beginning):
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
what am I doing wrong?
First: make sure you are using the right calling convention (stack, registers, left to right, right to left, etc.). If your program indeed prints a floating point number, although it is not the one you required, then at least the format string is being passed correctly (or you are having a lot of luck and printf
found the address of the format string at the right place even if you didn't put its address there).
Second: the number you are trying to print... is it a float or a double? rs
is defined to hold a quadword value (64 bits), but floats are 32 bits. So, if the first point has been checked and it's ok, I suggest you to use "%lf"
as format, instead of "%f"
.
BTW: why do you put RAX = 0
? What does it mean regarding the call to printf
?
UPDATE: This may help you. A disassembly of a silly program (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