印刷用的printf漂浮在NASM x86的32位 [英] Printing floats with printf in x86 nasm 32-bit
问题描述
我想打印出一些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。
RETI'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
inprintf
expects adouble
, so your number must be converted into adouble
just before pushing it on the stack forprintf
: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屋!