-2

我在这个程序下面,由于某种原因,我找不到我的汇编程序卡住了。

我已经检查SP过代码是否返回到它应该返回的正确位置,并且堆栈始终是它应该的。

为了使例程没有卡住,我只做了一件事就是将跳转更改为JNL,而任何其他跳转都会卡住。

这是我在 C 和汇编中的代码。最后有一个 C 代码显示了汇编程序应该做什么。

#include <stdio.h>
#include <math.h>
#include <conio.h>
extern void two_point (double (*f1)(double, double), double (*f2)(double, double), double x, double y, double *ptr1, double *ptr2);
extern void fixed2 (double (*f1)(double, double), double (*f2)(double, double), double x0, double y0, double *ptr1, double *ptr2, double eps);
double f1 (double x, double y);
double f2 (double x, double y);
int main()
{
    double x, y;

    fixed2 (f1, f2, 1.4, 1.4, &x, &y, 0.001);
    printf ("x= %lf, y= %lf\n", x, y);
    return 0;
}

double f1 (double x, double y)
{
    return sin (x+y);
}

double f2 (double x, double y)
{
    return cos (x+y);
}

ASM 代码:

;HW4a.asm
.MODEL SMALL
.DATA
x0 DQ ?
x1 DQ ?
y0 DQ ?
y1 DQ ?
x2 DQ ?
y2 DQ ?
element DW 16;double*2
.CODE
.386
.387
;two_point (double (*f1)(double, double), double (*f2)(double, double), double x, double y, double *ptr1, double *ptr2)
;f1=BP+4, f2=BP+6, x=BP+8, y=BP+16, ptr1=BP+24, ptr2=BP+26  
_two_point PROC NEAR
PUSH BP
MOV BP,SP
PUSH SI
PUSH DI
MOV SI,WORD PTR[BP+24]
MOV DI,WORD PTR[BP+26]
FLD QWORD PTR [BP+16];ST0=Y
FSTP y2
FLD QWORD PTR [BP+8];ST0=X
FSTP x2
PUSH DWORD PTR y2+4
PUSH DWORD PTR y2
PUSH DWORD PTR x2+4
PUSH DWORD PTR x2
;f1:    
CALL [BP+4];CALL F1
FSTP QWORD PTR [SI];SI GET RETURNED VALUE FROM F1
MOV [BP+24],SI;PTR1=F1(X,Y)
;f2:    
CALL [BP+6];CALL F2
FSTP QWORD PTR [DI];DI GET RETURNED VALUE FROM F2
MOV [BP+26],DI;PTR2=F2(X,Y)
;end:   
ADD SP,element
POP DI
POP SI
POP BP
RET
_two_point ENDP

;fixed2 (double (*f1)(double, double), double (*f2)(double, double), double x0, double y0, double *ptr1, double *ptr2, double eps)
;f1=BP+4, f2=BP+6, x0=BP+8, y0=BP+16, ptr1=BP+24, ptr2=BP+26, eps=BP+28
PUBLIC _fixed2
_fixed2 PROC NEAR
PUSH BP
MOV BP,SP
;pre loop:
PUSH SI
PUSH DI
MOV SI,WORD PTR[BP+24];SI=&ptr1
MOV DI,WORD PTR[BP+26];DI=&ptr2 
FLD QWORD PTR [BP+16];ST0=Y
FST y0
FSTP y1
FLD QWORD PTR [BP+8];ST0=X
FST x0
FSTP x1
LOOPER:
FLD y1
FST y0;y0=y1
FSTP QWORD PTR [DI];SI=&y1
PUSH WORD PTR DI;push &y1
FLD x1
FST x0;x0=x1
FSTP QWORD PTR [SI];SI=&x1
PUSH WORD PTR SI;push &x1
PUSH DWORD PTR y0+4
PUSH DWORD PTR y0
PUSH DWORD PTR x0+4
PUSH DWORD PTR x0
PUSH WORD PTR [BP+6];push f2
PUSH WORD PTR [BP+4];push f1
CALL _two_point
MOV DI,WORD PTR [BP-6];DI=&y0
MOV SI,WORD PTR [BP-8];SI=&x0
ADD SP,8;sizeof(f1+f2)+sizeof(*ptr1+*ptr2)
ADD SP,element
FLD QWORD PTR [SI];load x1
FST x1
FLD x0
FSUB
FABS;|x1-x0|
FLD QWORD PTR [DI];load y1
FST y1
FLD y0
FSUB
FABS;|y1-y0|
FADD;ST[0]=|y1-y0|+|x1-x0|
FLD QWORD PTR [BP+28];ST[0]=eps
FCOMPP;ST[0]-ST[1]
FSTSW AX
SAHF
JBE LOOPER;while ((fabs(x1-x0) + fabs(y1-y0))>=eps)
;end:   
FLD x1
FSTP QWORD PTR [SI]
MOV WORD PTR [BP+24],SI;update *ptr1=x1
FLD y1
FSTP QWORD PTR [DI]
MOV WORD PTR [BP+26],DI;update *ptr2=y1
POP DI
POP SI
POP BP
RET
_fixed2 ENDP
END  

这就是 ASM 应该做的:

void fixed2 (double (*f1)(double, double), double (*f2)(double, double), double x0, double y0, double *ptr1, double *ptr2, double eps)
{
double x1= x0, y1= y0;

do
{
    x0= x1;
    y0= y1;
    two_point (f1, f2, x0, y0, &x1, &y1);
} while ((fabs(x1-x0) + fabs(y1-y0))>=eps);

*ptr1 = x1;
*ptr2 = y1;
}

F1 和 F2:

double f1 (double x, double y)
{
    return sin (x+y);
}

double f2 (double x, double y)
{
return cos (x+y);
}
4

1 回答 1

2

FCOMPP仅设置 FPU 中的条件代码位。您可能的意思是FCOMIP(如果需要,后跟另一个弹出),以便您可以使用条件分支指令。

此外,即使您说您检查过,请SP注意典型的 C 调用约定允许DX修改,因此假设它没有更改是不安全的。您应该在ADD SP,DX.


更新:好的,我已经让它工作了(虽然我不知道结果是否正确:x=0.9516 和 y=0.3072)。JB您不应该使用,因为根据结果设置JL的 FPU 标志位C0和- 将分别传输到和,但检查和在这里没有意义。C3FCOMPPCFZFJLSFOF

旁注:如果您使用DWORD PTR的代码不是纯 16 位的,它只会在 32 位处理器上运行。

当然你的程序可以简化很多。

于 2013-01-18T18:31:30.040 回答