【问题标题】:Printing floats with printf in x86 nasm 32-bit在 x86 nasm 32 位中使用 printf 打印浮点数
【发布时间】:2015-06-09 03:09:58
【问题描述】:

我正在尝试使用 NASM 风格的 x86 程序集打印出一些 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 <scanf@plt>
   0x0804842f <+15>:    add    esp,0x8
   0x08048432 <+18>:    push   DWORD PTR ds:0x804a028
   0x08048438 <+24>:    push   0x804a01b
   0x0804843d <+29>:    call   0x8048320 <printf@plt>
   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 调用的中间产生一个段错误。

我必须错过一些东西。

【问题讨论】:

  • printf 期望 double 参数用于 %f 说明符? (参见“说明符”表here
  • @Michael 刚刚编辑以反映尝试使用双打时的错误
  • 有关无法将float 直接传递给printf 的更多详细信息,请参阅stackoverflow.com/questions/37082784/… 了解C 默认参数提升规则。

标签: assembly x86 printf nasm


【解决方案1】:

正如 Michael 指出的那样,printf 中的 %f 需要 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

push qword [result_num_dub] ;这里出现汇编错误

您不能在 32 位模式下执行 64 位操作,例如一次推送 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-06
    • 2015-06-25
    • 1970-01-01
    • 2013-12-14
    • 1970-01-01
    • 2014-01-02
    • 2015-01-12
    • 2015-06-29
    相关资源
    最近更新 更多