印刷用的printf漂浮在NASM x86的32位 [英] Printing floats with printf in x86 nasm 32-bit

查看:365
本文介绍了印刷用的printf漂浮在NASM x86的32位的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想打印出一些32位彩车使用NASM味x86汇编。这是我想要做一个最低工作例如:

 全球主要
EXTERN具有printf,scanf段.data
    scan_format:DB%F,0
    print_format:DB%F,为0xA,0.bss段
    result_num:4 RESB.text段
主要:
    推result_num
    推scan_format
    调用scanf函数
    ADD ESP,8    推DWORD [result_num]
    推print_format
    调用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)拆卸主*
汇编code的转储为主要功能:
   0x08048420 1 + 0计算值:推0x804a028
   0x08048425 1 + 5计算值:推0x804a018
   0x0804842a 1 + 10 -10 ;:调用0x8048330&下; scanf的@ PLT>
   0x0804842f 1 + 15计算值:ADD ESP,0x8中
   0x08048432 1 + 18计算值:推DWORD PTR DS:0x804a028
   0x08048438 1 + 24计算值:推0x804a01b
   0x0804843d 1 + 29计算值:调用0x8048320< printf的PLT @>
   0x08048442 1 + 34计算值:ADD ESP,0x8中
   0x08048445 1 + 37计算值:保留
   0x08048446 1 + 38计算值:NOP
   0x08048447 1 + 39计算值:NOP
   0x08048448 1 + 40计算值:NOP
   0x08048449 1 + 41计算值:NOP
   0x0804844a 1 + 42计算值:NOP
   0x0804844b 1 + 43计算值:NOP
   0x0804844c 1 + 44计算值:NOP
   0x0804844d 1 + 45计算值:NOP
   0x0804844e 1 + 46计算值:NOP
   0x0804844f 1 + 47计算值:NOP
汇编转储结束。
(GDB)打破主* + 34
在0x8048442断点1
(GDB)R
启动程序:/vagrant/project_03/printf_test.out
1234
-0.000000断点1,0x08048442在main()
(GDB)P / F result_num
$ 1 = 1234

我在做什么错在这里?

修改

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

 全球主要
EXTERN具有printf,scanf段.data
    scan_format:DB%F,0
    print_format:DB%F,为0xA,0.bss段
    result_num:4 RESB
    result_num_dub:8 RESB.text段
主要:
    推result_num
    推scan_format
    调用scanf函数
    ADD ESP,8    FLD DWORD [result_num]
    FSTP四字[result_num_dub]    推四字[result_num_dub];汇编ERROR HERE
    推print_format
    调用printf
    ADD ESP,8
    RET

生成的输出:

  $ NASM -felf32 -g printf_test.asm
printf_test.asm:22:错误:指令32位模式下不支持

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

  FLD DWORD [result_num]
FSTP四字[ESP]
推格式调用printf

看起来就在GDB:

 (GDB)P *((双*)($ ESP))
$ 9 = 2.5

但它产生的printf的调用中间段错误。

我必须失去了一些东西。


解决方案

正如迈克尔指出,%F 的printf 需要一个双击,所以你的电话号码必须转换成双击只需按下它在堆栈上的前的printf

 全球主要
EXTERN具有printf,scanf段.data
    scan_format:DB%F,0
    print_format:DB结果:%F,为0xA,0.bss段
    result_num:4 RESB.text段
主要:
    推result_num
    推scan_format
    调用scanf函数
    ADD ESP,8    子ESP,8;在堆栈双堆栈储备
    MOV EBX,result_num
    FLD DWORD [EBX];负载浮动
    FSTP四字[ESP];存储双(8087确实在内部转换)
    推print_format
    调用printf
    ADD ESP,12
    RET


  

推四字[result_num_dub];汇编ERROR HERE


您不能做的64位运算,就像推64位的时间,在32位模式。这就是为什么我使用了子ESP 方法来保留堆栈空间。你的第二个计划只需要这样的:

  .text段
主要:
    推result_num
    推scan_format
    调用scanf函数
    ADD ESP,8    FLD DWORD [result_num]
    FSTP四字[result_num_dub]
    推双字[result_num_dub + 4];推32位(MSB)
    推DWORD [result_num_dub];推动32位(LSB)
    推print_format
    调用printf
    ADD ESP,12;< - 12字节,而不是8。
    RET

I'm trying to print out some 32-bit floats using NASM flavored x86 assembly. This is a minimum working example of what I'm trying to do:

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

When I run this, I get some strange output:

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

If I try to examine the value while the program is running, it seems to be correct:

$ 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

What am I doing wrong here?

EDIT

If I try to use doubles, it won't even assemble, this program:

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

Generates this output:

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

And if I try to go directly from the float stack to the memory stack, I get a segfault, even though the right thing appears to be stored in memory.

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

call printf

It looks right in gdb:

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

But it generates a segfault in the middle of the printf call.

I have to be missing something.

解决方案

As Michael pointed, %f in printf expects a double, so your number must be converted into a double just before pushing it on the stack for 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] ;ASSEMBLER ERROR HERE

You cannot do 64 bit operations, like pushing 64 bits at a time, in 32 bit mode. This is why I used the sub esp method to reserve stack space. Your second program just needs this:

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

这篇关于印刷用的printf漂浮在NASM x86的32位的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆