简体   繁体   中英

printf float in nasm assembly 64-bit

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 ( fc ):

#include <stdio.h>

main()
{
  float x;

  x = 1.6;
  printf ("%f\n", x);
}

$ gcc -c -S fc

$ less fs

        .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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM