注册 登录
编程论坛 汇编论坛

请教罗云彬汇编中的一段程序

Hallelujah 发布于 2008-09-18 17:20, 4774 次点击
罗云彬win32汇编第7章Clock.asm,也就是第203页 程序段  _CalcX
_CalcX        proc    _dwDegree,_dwRadius
        local    @dwReturn

        fild    dwCenterX
        fild    _dwDegree
        fldpi
        fmul            ;角度*Pi
        fild    _dwPara180
        fdivp    st(1),st    ;角度*Pi/180
        fsin            ;Sin(角度*Pi/180)
        fild    _dwRadius
        fmul            ;半径*Sin(角度*Pi/180)
        fadd            ;X+半径*Sin(角度*Pi/180)
        fistp    @dwReturn
        mov    eax,@dwReturn
        ret

_CalcX        endp
用的是浮点指令,用到了浮点数据寄存器,FPU共有8个浮点数据寄存器,FPR0---FPR7相连并组成一个循环。fild是入栈指令,如果一个整数压入了浮点数据寄存器中就自动被转换成了浮点数,一st0至st7动态表示8个寄存器,并不一定是st0表示FPR0、st7表示FPR7,
现在看一下操作数的载入过程。当第一次载入时候,数据被存放在ST,以后每次操作,堆栈上升,开始被载入的操作数也随之上移,
直到ST(7)。比如:
load a : ST(0) = a; ST(1) = 0; ST(2) = 0.....
load b : ST(0) = b; ST(1) = a; ST(2) = 0.....
load c : ST(0) = c; ST(1) = b; ST(2) = a.....
而这段程序的入栈时
fild dwCenterX   ;st(0)=dwCenterX
fild _dwDegree   ;st(0)=_dwDegree,st(1)=dwCenterX
fldpi            ;st(0)=PI,st(1)=_dwDegree,st(2)=dwCenterX
fmul             ;st(0)=PI*_dwDegree,st(1)=_dwDegree,st(2)=dwCenterX;fmul指的是st(0)<-st(0)*st(1)
fild _dwPara180  ;st(0)=180,st(1)=PI*_dwDegree,st(2)=_dwDegree,st(3)=dwCenterX
fdivp st(1),st   ;st(1)=st(0)/st(1);也就是说 st(1)=180/(PI*_dwDegree),而不是书上说的 角度*PI/180,是不是哪里不对呢,请大家帮忙。
28 回复
#2
Hallelujah2008-09-18 17:22
_dwPara180  dw   180;也就是说_dwPara180值为180。
fdivp st(i),st的意思是st(i)<-st(0)/st(i)然后执行一次出栈。
得出以上结论是根据看雪网站的汇编浮点指令集:
http://www.,不知是不是看雪网站写错了,请大家指证。

[[it] 本帖最后由 Hallelujah 于 2008-9-18 18:03 编辑 [/it]]
#3
ONEPROBLEM2008-09-18 23:37
LZ,你真够细心的,我也看了,觉得不得其解~~
#4
ONEPROBLEM2008-09-18 23:40
这种指令不常用,不怎么熟.编个小程序试试看先~~~
#5
Hallelujah2008-09-19 11:03
我在一本国外下载的汇编上看到浮点除的如下解释:
With two register operands, these instructions compute the following quotients:
fdiv st(0), st(i) ;st(0) := st(0)/st(i)
fdiv st(i), st(0) ;st(i) := st(i)/st(0)
fdivp st(i), st(0) ;st(i) := st(i)/st(0)
fdivr st(i), st(i) ;st(0) := st(0)/st(i)
fdivrp st(i), st(0) ;st(i) := st(0)/st(i)
The fdivp and fdivrp instructions also pop st(0) after performing the division operation. The
value for i in this two instructions is computed before popping st(0).
再看《The Art Of Assembly Language》第六章 Floating Point Arithmetic
这样写:
With no operands, the fdiv and fdivp instructions pop ST0 and ST1, compute ST1/ST0, and push the result back onto the stack. The fdivr and fdivrp instructions also pop ST0 and ST1 but compute ST0/ST1 before pushing the quotient onto the stack.

With two register operands, these instructions compute the following quotients:

     fdiv( sti, st0 );      // ST0 := ST0/STi
     fdiv( st0, sti );      // STi := STi/ST0
     fdivp( st0, sti );     // STi := STi/ST0 then pop ST0
     fdivr( st0, sti );     // ST0 := ST0/STi
     fdivrp( st0, sti );    // STi := ST0/STi then pop ST0

这两者明显是矛盾的,到底 fdivp st(i),st 表示 st(i)<-st(i)/st(0)还是
st(i)<-st(0)/st(i)?
这个问题有没有高手来回答一下。
#6
ONEPROBLEM2008-09-19 12:08
从程序的运行结果来看,明显应该是"fdivp st(i),st 表示 st(i)<-st(i)/st(0)"
我在Intel手册上没查到fdivp 这个指令,却查到fdivrp 这条指令,Intel是这样说的: FDIVRP ST(i), ST(0)
      Divide ST(0) by ST(i), store result in ST(i), and pop the register stack.
#7
ONEPROBLEM2008-09-19 12:16
我推测:被除数应该首先入栈,因为可能被除数要先参加其它的运算,或通过其它的运算得出;而除数要相对后入栈,再处理比较方便些.所以在"fdivp st(i),st "中,st 是后入栈的除数,而st(i)是先入栈的被除数,最终的表示就是 st(i)<-st(i)/st(0).
#8
ONEPROBLEM2008-09-19 12:18
期待高人一锤定音中... ...
#9
Hallelujah2008-09-19 17:45
回复 8# ONEPROBLEM 的帖子
解决了,编了一段程序:
            .386
            .model flat,stdcall
            option casemap:none

include        windows.inc
include        user32.inc
includelib    user32.lib
include        kernel32.inc
includelib    kernel32.lib

            .const
szCaption    db    'This is caption.',0
szStart        db    'the final value %x',0
            .data
szBuffer    db    32 dup(?)
            .data?
szValue        dd    ?
vFirst        dd    ?
vSecond        dd    ?
vThird        dd    ?

            .code
start:
    mov    vFirst,1000
    mov    vSecond,100
    mov    vThird,10
    mov    szValue,0
    finit
    fild    vFirst
    fild    vSecond
    fild    vThird
    fdivp    st(1),st
    fistp    szValue
    invoke    wsprintf,addr szBuffer,addr szStart,szValue
    invoke    MessageBox,NULL,offset szBuffer,offset szCaption,MB_OK
    invoke    ExitProcess,NULL
end    start
是三个值逐个压栈。1000,100,10
最后出来应该是10
表示 fdiv st(i),st 表示的是 st(i)<-st(i)/st(0),看雪网站上写错了。

[[it] 本帖最后由 Hallelujah 于 2008-9-19 17:47 编辑 [/it]]
#10
Hallelujah2008-09-19 17:49
还有一个问题,怎样把硬盘上的图片上传到论坛上。
#11
ONEPROBLEM2008-09-19 17:56
[bo][un]Hallelujah[/un] 在 2008-9-19 17:49 的发言:[/bo]

还有一个问题,怎样把硬盘上的图片上传到论坛上。

要用程序来实现?
#12
Hallelujah2008-09-19 19:54
不是,我指我回帖时怎么发不上图片,我写的程序有载图大家看得更直观点。
#13
ONEPROBLEM2008-09-19 22:25
发帖或回帖的时候,请注意观察页面的下方"上传附件",并且注意自己的文件格式是否符合要求就可以了.
#14
ONEPROBLEM2008-09-19 22:33
示例:
#15
ONEPROBLEM2008-09-19 22:34
示例:
#16
Hallelujah2008-09-20 08:34
谢了,这是程序运行后的效果:a就是十六进制10,证明了我的运算。
#17
zklhp2008-09-20 11:53
偶一直搞不懂这些浮点之类的东西…
#18
arsionbc2008-09-21 20:31
_CalcX        proc    _dwDegree,_dwRadius
        local    @dwReturn

        fild    dwCenterX              ;st(0)=dwCenterX
        fild    _dwDegree              ;st(0)=_dwDegree,st(1)=dwCenterX
        fldpi                          ;st(0)=pi,st(1)=_dwDegree,st(2)=dwCenterX
        fmul            ;角度*Pi       ;st(1)=st(0)*s(1),然后s(0)出栈,于是s(0)=角度*pi,st(1)=_dwDegree,st(2)=dwCenterY
        fild    _dwPara180
        fdivp    st(1),st    ;角度*Pi/180
        fsin            ;Sin(角度*Pi/180)
        fild    _dwRadius
        fmul            ;半径*Sin(角度*Pi/180)
        fadd            ;X+半径*Sin(角度*Pi/180)
        fistp    @dwReturn
        mov    eax,@dwReturn
        ret

_CalcX        endp


以下我没时间帖了,用OD反编译一下,跟踪一下st的八个寄存器的用法,只是有两个指令特珠,就是fadd = faddp st(1),st(0)  即 st(1)=st(1)*st(0),算完后自动把st(0)出栈,fmul=fmulp st(1),st(0)和fadd一样
#19
ONEPROBLEM2008-09-22 17:29
以下我没时间帖了,用OD反编译一下,跟踪一下st的八个寄存器的用法,只是有两个指令特珠,就是fadd = faddp st(1),st(0)  即 st(1)=st(1)*st(0),算完后自动把st(0)出栈,fmul=fmulp st(1),st(0)和fadd一样
==========================================================
LS匆忙中打错了个地方~~上面的"即 st(1)=st(1)*st(0)",改一下"即 st(1)=st(1)+st(0)"
#20
asli332008-10-14 18:36
刚好也看到这里,发现有些问题不大懂,学习了下两位的帖子
用OD跟踪了一下,执行如下:
1 .fild     dwCenterX    st(0)<--dwCenterX
2 .fild     _dwDegree    st(0)<--_dwDegree,                st(1)<--dwCenterX
3 .fldpi        st(0)<--pi,                    st(1)<--_dwDegree,        st(2)<--dwCenterX
4 .fmulp st(1),st    st(0)<--pi*_dwDegree,                st(1)<--dwCenterX
5 .fild     _dwPara180    st(0)<--180,                    st(1)<--pi*_dwDegree,        st(2)<--dwCenterX
6 .fdivp st(1),st    st(0)<--pi*_dwDegree/180,            st(1)<--dwCenterX
7 .fsin            st(0)<--sin(pi*_dwDegree/180),            st(1)<--dwCenterX
8 .fild     _dwRadius    st(0)<--_dwRadius,                st(1)<--sin(pi*_dwDegree/180),    st(2)<--dwCenterX
9 .fmulp st(1),st    st(0)<--_dwRadius*sin(pi*_dwDegree/180),    st(1)<--dwCenterX
10.faddp st(1),st    st(0)<--dwCenterX+_dwRadius*sin(pi*_dwDegree/180)
11.fistp @dwReturn    @dwReturn=dwCenterX+_dwRadius*sin(pi*_dwDegree/180)

其中第4、9、10三行变化如下:
4 .
fmul             原文件
fmulp st(1),st   反汇编结果
9 .
fmul             原文件
fmulp st(1),st   反汇编结果
10.
fadd             原文件
faddp st(1),st   反汇编结果
不明白为什么会变成这样,
源文件中并未包含对出栈操作的考虑,程序为何会这样变动达到堆栈平衡的?
#21
ONEPROBLEM2008-10-14 21:40
这个问题,我查阅了相关的书籍,现在有点眉目了.
我复制一点过来,你就清楚了:

1、加法指令
 指令格式: FADD [STReg1, STReg2](*)
FADD MemReal
FADDP STReg, ST
FIADD MemInt

(*) 在此指令格式下,如果同时指定了二个堆栈寄存器,那么,其中一个寄存器必须是ST。其它指令的同类格式与此同理。

指令FADD含有二个隐含操作数ST(1)和ST,其运算功能是:从堆栈中弹出这二个操作数,然后把计算的“和”压入堆栈,即:ST=ST(1)+ST。
#22
asli332008-10-14 22:08
哦,如果这个指令这样理解就明白了,前面在网上搜了一些浮点指令的解释跟这不一样,被搞懵了,多谢了
不知你查的是什么书啊?
#23
ONEPROBLEM2008-10-14 22:34
[bo][un]asli33[/un] 在 2008-10-14 22:08 的发言:[/bo]

哦,如果这个指令这样理解就明白了,前面在网上搜了一些浮点指令的解释跟这不一样,被搞懵了,多谢了
不知你查的是什么书啊?

你留个邮箱,我发给你,你仔细看看,也许就都明白了~~
#24
asli332008-10-14 22:39
asli.asli33@,多谢
#25
asli332008-10-14 22:53
搞明白了,查到这个网页,是对这个问题的解释
http://software.
#26
ONEPROBLEM2008-10-14 23:01
[bo][un]asli33[/un] 在 2008-10-14 22:53 的发言:[/bo]

搞明白了,查到这个网页,是对这个问题的解释
http://software.

嗯,看到了~~
#27
Hallelujah2008-10-15 14:42
请看我的博客吧。
http://blog.
我把这些都搞清楚了。
#28
ONEPROBLEM2008-10-15 17:37
[bo][un]Hallelujah[/un] 在 2008-10-15 14:42 的发言:[/bo]

请看我的博客吧。
http://blog.
我把这些都搞清楚了。

嗯,我去看了.由于没在那注册,所以在那无法回帖~~那么认真,你行啊,我向你学习了.
#29
cnhanxiao2008-10-17 08:20
fdivp ST(i),ST——除实数并弹栈。用ST去除ST(i),弹出栈顶元素,结果放入ST(i)中,两个操作数都被破坏。

实际老罗的结果是正确的,呵呵,那个表走得不错嘛。
1