FPU中fcompp与fstsw ax结果异常:AX值随ST栈元素数变化求助
问题原因分析
你观察到的现象是FPU的正常行为,核心原因是fstsw ax返回的AX寄存器存储的是完整的FPU状态字,而非仅比较结果。状态字中包含了随栈元素数量变化的**栈指针(TOP)**字段,导致AX整体值随栈元素数量改变。
关键细节拆解
1. FPU状态字结构
16位的FPU状态字包含多个控制/状态字段,和你问题相关的两个核心部分:
- TOP字段(位15-12):4位无符号数,表示当前逻辑ST0对应的物理寄存器编号(ST0-ST7)。FPU栈是向下生长的循环栈,每压入一个元素,TOP值减1(模8)。因此栈元素数量越多,TOP值越小:
- 栈有2个元素 → TOP=6
- 栈有3个元素 → TOP=5
- ...
- 栈有8个元素 → TOP=0
- 比较条件码(C0、C2、C3):分别对应状态字的位11、位9、位8,用于表示
fcompp的比较结果:比较结果 C0 C2 C3 ST0 > ST1 0 0 0 ST0 == ST1 1 0 1 ST0 < ST1 0 0 1
2. 测试结果对应逻辑
你看到的AX值变化,是TOP字段和条件码字段的组合结果:
- TOP字段占据状态字的高4位,直接决定了AX的高字节部分,因此栈元素数量变化时,AX的高位会呈现规律性改变(如你给出的数值中,高字节每次递减0x08)。
- 条件码字段占据状态字的低几位,决定了AX低位的固定差异(如ST0<ST1时低位为0x01,ST0>ST1时为0x00)。
正确的比较结果判断方式
不要直接使用AX的整数值判断比较结果,应该提取状态字中的条件码位,常用两种方式:
方式1:利用sahf映射到标志位
fcompp ; 比较ST0和ST1,弹出两个元素 fstsw ax ; 将FPU状态字存入AX sahf ; 将AH的位映射到EFLAGS的SF、ZF、AF、PF、CF ; 直接用跳转指令判断 ja st0_gt_st1 ; ST0 > ST1 je st0_eq_st1 ; ST0 == ST1 jb st0_lt_st1 ; ST0 < ST1 st0_gt_st1: ; 处理ST0大于ST1的逻辑 st0_eq_st1: ; 处理相等的逻辑 st0_lt_st1: ; 处理ST0小于ST1的逻辑
方式2:手动提取条件码位
fcompp fstsw ax ; 提取C0(位11)和C3(位8) test ax, 0x400 ; 检查C0位 jnz st0_eq ; C0=1表示相等 test ax, 0x100 ; 检查C3位 jnz st0_lt ; C3=1表示ST0<ST1 jmp st0_gt ; 否则ST0>ST1 st0_eq: ; 相等逻辑 st0_lt: ; 小于逻辑 st0_gt: ; 大于逻辑
内容的提问来源于stack exchange,提问作者Vitaly
相关产品推荐
相关产品推荐

