Chinaunix首页 | 论坛 | 博客
  • 博客访问: 999686
  • 博文数量: 633
  • 博客积分: 30780
  • 博客等级: 大将
  • 技术积分: 7532
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-12 21:07
文章分类

全部博文(633)

文章存档

2011年(10)

2010年(500)

2009年(47)

2008年(76)

我的朋友

分类:

2011-03-08 18:36:37

1. X86浮点环境

包括FPU寄存器堆栈,控制字,状态字,标记字

1) FPU寄存器堆栈:
FPU寄存器包括8个80位数据寄存器和3个16位寄存器(控制,状态,标记)
8个80位数据寄存器成为R0到R7(在汇编代码中,称为ST(0)到ST(7))

状态寄存器:
状态寄存器表明FPU的操作情况,它包含在一个16位的寄存器中,不同的位作为不同的标志,入下图:

使用FSTSW指令,可以把状态寄存器的值读取到一个4字节的内存中或者AX寄存器,见下面的代码:

[root@higtest lzhou1]# cat getstatus.s
.section .bss
        .lcomm status, 2
.section .text
.global _start
_start:
        nop
        fstsw %ax
        fstsw status

        movl $1, %eax
        movl $0, %ebx
        int $0x80
[root@higtest lzhou1]#


再GDB一把:

[root@higtest lzhou1]# gdb getstatus
GNU gdb Fedora (6.8-37.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb) break *_start+1
Breakpoint 1 at 0x8048075: file getstatus.s, line 7.
(gdb) run
Starting program: /home/lzhou1/getstatus

Breakpoint 1, _start () at getstatus.s:7
7 fstsw %ax
Current language: auto; currently asm
(gdb) l
2 .lcomm status, 2
3 .section .text
4 .global _start
5 _start:
6 nop
7 fstsw %ax
8 fstsw status
9
10 movl $1, %eax
11 movl $0, %ebx
(gdb) l
12 int $0x80
(gdb) print/x $eax
$1 = 0x0
(gdb) s
_start () at getstatus.s:8
8 fstsw status
(gdb) print/x $eax
$2 = 0x0
(gdb) s
_start () at getstatus.s:10
10 movl $1, %eax
(gdb) print &status
$3 = (<data variable, no debug info> *) 0x804908c
(gdb) print/x &status
$4 = 0x804908c
(gdb) info all
eax 0x0 0
ecx 0x0 0
edx 0x0 0
ebx 0x0 0
esp 0xbf913120 0xbf913120
ebp 0x0 0x0
esi 0x0 0
edi 0x0 0
eip 0x804807f 0x804807f <_start+11>
eflags 0x212 [ AF IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x0 0
st0 0 (raw 0x00000000000000000000)
st1 0 (raw 0x00000000000000000000)
st2 0 (raw 0x00000000000000000000)
st3 0 (raw 0x00000000000000000000)
st4 0 (raw 0x00000000000000000000)
st5 0 (raw 0x00000000000000000000)
st6 0 (raw 0x00000000000000000000)
st7 0 (raw 0x00000000000000000000)
fctrl 0x37f 895
fstat 0x0 0
ftag 0xffff 65535
fiseg 0x0 0
fioff 0x0 0
foseg 0x0 0
fooff 0x0 0
fop 0x0 0
xmm0 {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0},
  v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0},
  uint128 = 0x00000000000000000000000000000000}
xmm1 {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0},
  v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0},
  uint128 = 0x00000000000000000000000000000000}
xmm2 {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0},
  v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0},
  uint128 = 0x00000000000000000000000000000000}
xmm3 {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0},
  v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0},
  uint128 = 0x00000000000000000000000000000000}
xmm4 {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0},
  v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0},
  uint128 = 0x00000000000000000000000000000000}
xmm5 {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0},
  v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0},
  uint128 = 0x00000000000000000000000000000000}
xmm6 {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0},
  v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0, 0x0, 0x0,
---Type <return> to continue, or q <return> to quit---
    0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0},
  uint128 = 0x00000000000000000000000000000000}
xmm7 {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0},
  v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0},
  uint128 = 0x00000000000000000000000000000000}
mxcsr 0x1f80 [ IM DM ZM OM UM PM ]
mm0 {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0,
    0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm1 {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0,
    0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm2 {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0,
    0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm3 {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0,
    0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm4 {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0,
    0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm5 {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0,
    0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm6 {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0,
    0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm7 {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0,
    0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
(gdb)
(gdb)
(gdb) x/x &status
0x804908c <status>: 0x00000000
(gdb) quit
The program is running. Exit anyway? (y or n) y
[root@higtest lzhou1]#



控制寄存器

控制寄存器的默认值是0X037F.
可以使用FSTCW指令把控制寄存器的值加载到4字节内容中查看设置的内容,也可以使用FLDCW指令改变设置,这条指令把四字节内存值加载到控制寄存器内。
见如下例子:



1. 1 .section .data
   2. 2 newvalue:
   3. 3 .byte 0x7f, 0x00
   4. 4 output:
   5. 5 .asciz "The control register is 0x%x\n"
   6. 6 .section .bss
   7. 7
   8. 8 .lcomm control, 2
   9. 9
  10. 10 .section .text
  11. 11 .global _start
  12. 12 _start:
  13. 13 nop
  14. 14 fstcw control
  15. 15 movl control, %eax
  16. 16 pushl %eax
  17. 17 pushl $output
  18. 18 call printf
  19. 19 addl $8, %esp
  20. 20
  21. 21 fldcw newvalue
  22. 22 fstcw control
  23. 23 movl control, %eax
  24. 24 pushl %eax
  25. 25 pushl $output
  26. 26 call printf
  27. 27 addl $8, %esp
  28. 28
  29. 29 movl $1, %eax
  30. 30 movl $0, %ebx
  31. 31 int $0x80
  32. 32


这里出了点小问题,我发了个帖子在CU上:
%3D1



标记寄存器
标记寄存器用于标示8个80位FPU数据寄存器中的值。标记寄存器使用16位(每个寄存器2位)标示每个FPU数据寄存器的内容,见下图:


每个标记值对应一个屋里的FPU寄存器。每个寄存器对应的2位值可以包含表明寄存器内容的4个特殊代码之一。在任何给定的时刻,FPU数据寄存器可以包含下面的内容:
  • 一个合法的扩展双精度值(代码00)
  • 零值(代码01)
  • 特殊的浮点值(代码10)
  • 无内容(空)(代码11)
这使程序员可以快速检查标记寄存器以便确定FPU寄存器中是否包含合法数据,而不必读取和分析寄存器的内容。虽然在实际操作中,因为是程序员把值压入到寄存器堆栈中的,所以程序员应该知道其中的内容是什么。


下面看一个综合例子,对FPU stack进行各种操作

[root@higtest lzhou1]# cat stacktest.s
.section .data
value1:
        .int 40
value2:
        .float 92.4405
value3:
        .double 221.440321

.section .bss
        .lcomm int1, 4
        .lcomm control, 2
        .lcomm status, 2
        .lcomm result, 4

.section .text
.global _start
_start:
        nop
        finit
        fstcw control
        fstsw status
        filds value1
        fists int1
        flds value2
        fldl value3
        fst %st(4)
        fxch %st(1)
        fstps result
        movl $1, %eax
        movl $0, %ebx
        int $0x80

在GDB单步调试一下,通过命令info all观察st0到st7的值的变化,就很清楚具体的stack操作是怎样运行的了。

2. 基本的浮点运算


上图表明了FPU的基本浮点指令.


阅读(1664) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~