【发布时间】:2017-08-24 00:56:46
【问题描述】:
Assembly 是我正在学习的第一门编程语言,并且 我已经阅读了 Intel IA-32 手册和与 FPU 相关的http://www.ray.masmcode.com/tutorial/fpuchap3.htm#fstenv 部分。我找到了 32 位的内存布局:
根据上面的这张图表,标签字在地址 8 上占用 16 位。 不幸的是,英特尔指南和 ray 指南都使用了语法示例。
我的问题是,当我在第二个循环期间将fld $Tvalueinc[ecx] 加载到 st(0) 时,我 WAS 得到 1#IND。
为了弄清楚我为什么会得到 #1INF,我四处寻找,发现您可以使用 TAG WORD 寄存器 (http://www.ray.masmcode.com/tutorial/fpuchap1.htm) 查看 FPU 状态。
使用这部分代码:
fstenv [ebx-16]
fwait
fldenv [ebx-16]
mov eax, [ebx-16]
如果代码有效,则数据应更改每个循环,但保持不变。
我在尝试访问 FPU 时做错了什么? 您不必担心我的代码的意义,以及为什么我无法访问 TAG WORD。
.386
.model flat, stdcall
option casemap :none
includelib \masm32\lib\msvcrt.lib
sprintf proto C :vararg
includelib \masm32\lib\user32.lib
MessageBoxA proto :ptr,:ptr,:ptr,:DWORD
includelib \masm32\lib\kernel32.lib
ExitProcess proto :dword
.data
_title db "Result",13,10,0
$interm db "%0.4f","+","%0.5f",13,10,0
Aval REAL8 1.000
Bval REAL8 -2.000
Cval REAL8 19.000
_fourval REAL8 4.000
$Tvalueinc REAL4 1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0
$sampleval real10 4478784.0
squareroot dq ?
$prevCW dw ?
$Tagword dd ?
.code
main PROC
LOCAL szBuf[9]:byte
fstcw $prevCW
fwait
fld Bval ; [loads first instance of b]]
fmul Bval ; [b*b = b^2]
fld Aval ;[Load a (a*c)]
fmul Cval ;(a*c)
fmul _fourval ;[4*a*c]
fsubp;[b^2-4*a*c]
ffree st(7)
ftst ;compare ST(0) with 0.0
fstsw ax ;[store camparison results in ax]
fwait;wait
sahf ;transfer flags from AH register
mov ecx, 04h
fld $sampleval
jb _negative ;jump if <0
fsqrt ;sqrt(b^2-4*a*c)
jmp Finished
_negative:
$repeat:
mov ax, $prevCW
push eax
fld $Tvalueinc[ecx]
fstenv [ebx-16]
fwait
fldenv [ebx-16]
mov eax,[ebx-16]
fdiv
fldcw [esp]
fstsw ax
FRNDINT
fldcw $prevCW
pop eax
jne $repeat
Finished:
fstp squareroot
mov eax, dword ptr squareroot
mov edx, dword ptr squareroot[4h]
invoke sprintf, addr szBuf, offset $interm, eax, edx
invoke MessageBoxA, 0, addr szBuf, offset _title, 0
invoke ExitProcess, 0
main ENDP
END main
注意:我使用 Visual Studio 2017,调试器出于某种原因一直显示弹出的值。
【问题讨论】:
-
如果您刚开始学习 asm,您可能不知道这一点,但是 x87 浮点已经过时了。 64 位代码和大多数 32 位代码使用 xmm 寄存器中的 SSE/SSE2 指令进行数学运算。例如,
movss xmm0, [var1]/mulss xmm0, [var2]/movss [result], xmm0。或者更好的是,将所有内容保存在 xmm 寄存器中,因为它是一个平面寄存器集,而不是 x87 之类的堆栈。有关更多信息,请参阅x86 tag wiki。这并不是一个坏问题,但值得指出。 -
AFAIK,在现代 CPU 上你永远不需要
fwait(至少从最初的 Pentium 开始)。所以你可以只使用fnstenv而不是fstenv(实际上是fwait+fnstenv)。
标签: assembly x86 masm masm32 x87