2015-04-04 83 views
0

我试图使用NASM风格的x86汇编打印出一些32位浮点数。这是我想要做的最小工作示例:使用printf在x86 nasm中打印浮点数32位

global main 
extern printf, scanf 

section .data 
    scan_format: db "%f",0 
    print_format: db "%f",0xA,0 

section .bss 
    result_num: resb 4 

section .text 
main: 
    push result_num 
    push scan_format 
    call scanf 
    add esp, 8 

    push dword [result_num] 
    push print_format 
    call printf 
    add esp, 8 
    ret 

当我运行它,我得到一些奇怪的输出:

$ nasm -felf32 -g printf_test.asm 
$ gcc printf_test.o -o printf_test.out 
$ ./printf_test.out <<< 1234 
-0.000000 

如果我尝试检查,而该计划的价值它似乎是正确的:

$ gdb ./printf_test.out 
(gdb) disassemble *main 
Dump of assembler code for function main: 
    0x08048420 <+0>:  push 0x804a028 
    0x08048425 <+5>:  push 0x804a018 
    0x0804842a <+10>: call 0x8048330 <[email protected]> 
    0x0804842f <+15>: add esp,0x8 
    0x08048432 <+18>: push DWORD PTR ds:0x804a028 
    0x08048438 <+24>: push 0x804a01b 
    0x0804843d <+29>: call 0x8048320 <[email protected]> 
    0x08048442 <+34>: add esp,0x8 
    0x08048445 <+37>: ret 
    0x08048446 <+38>: nop 
    0x08048447 <+39>: nop 
    0x08048448 <+40>: nop 
    0x08048449 <+41>: nop 
    0x0804844a <+42>: nop 
    0x0804844b <+43>: nop 
    0x0804844c <+44>: nop 
    0x0804844d <+45>: nop 
    0x0804844e <+46>: nop 
    0x0804844f <+47>: nop 
End of assembler dump. 
(gdb) break *main+34 
Breakpoint 1 at 0x8048442 
(gdb) r 
Starting program: /vagrant/project_03/printf_test.out 
1234 
-0.000000 

Breakpoint 1, 0x08048442 in main() 
(gdb) p /f result_num 
$1 = 1234 

我在做什么错在这里?

编辑

如果我尝试使用双打,它甚至不会安装,该程序:

global main 
extern printf, scanf 

section .data 
    scan_format: db "%f",0 
    print_format: db "%f",0xA,0 

section .bss 
    result_num: resb 4 
    result_num_dub: resb 8 

section .text 
main: 
    push result_num 
    push scan_format 
    call scanf 
    add esp, 8 

    fld dword [result_num] 
    fstp qword [result_num_dub] 

    push qword [result_num_dub] ;ASSEMBLER ERROR HERE 
    push print_format 
    call printf 
    add esp, 8 
    ret 

生成的输出:

$ nasm -felf32 -g printf_test.asm 
printf_test.asm:22: error: instruction not supported in 32-bit mode 

如果我尝试去直接从浮动堆栈到内存堆栈,我得到一个段错误,即使正确的东西似乎存储在内存中。

fld dword [result_num] 
fstp qword [esp] 
push format 

call printf 

它看起来就在GDB:

(gdb) p *((double*)($esp)) 
$9 = 2.5 

但它产生的printf的调用的中间段错误。我不得不丢失一些东西。

+1

不''printf'希望'%f'说明符有'double'参数吗? (请参阅“说明符”表[这里](http://www.cplusplus.com/reference/cstdio/printf/)) – Michael 2015-04-04 08:59:40

+0

@迈克尔刚刚编辑以反映尝试使用双打时的错误 – 2015-04-04 16:13:19

+0

有关无法使用的更多详细信息要将'float'直接传递给'printf',请参阅https://stackoverflow.com/questions/37082784/how-to-print-a-single-precision-float-with-printf获取C默认参数提升规则。 – 2017-12-23 16:50:19

回答

2

正如迈克尔指出,%fprintf需要一个double,所以你的电话号码必须转换成一个double只是推动它的堆栈上printf前:

global main 
extern printf, scanf 

section .data 
    scan_format: db "%f",0 
    print_format: db "Result: %f",0xA,0 

section .bss 
    result_num: resb 4 

section .text 
main: 
    push result_num 
    push scan_format 
    call scanf 
    add esp, 8 

    sub esp,8 ;reserve stack for a double in stack 
    mov ebx,result_num 
    fld dword [ebx] ;load float 
    fstp qword [esp] ;store double (8087 does the conversion internally) 
    push print_format 
    call printf 
    add esp, 12 
    ret 

推四字[result_num_dub];汇编错误在这里

你不能做64位操作,就像在32位模式下一次按64位一样。这就是我使用sub esp方法保留堆栈空间的原因。你的第二个程序只是需要这个:

section .text 
main: 
    push result_num 
    push scan_format 
    call scanf 
    add esp, 8 

    fld dword [result_num] 
    fstp qword [result_num_dub] 
    push dword [result_num_dub+4] ;pushes 32 bits (MSB) 
    push dword [result_num_dub] ;pushes 32 bits (LSB) 
    push print_format 
    call printf 
    add esp, 12 ;<-- 12 bytes, not 8. 
    ret