-2

私はこのプログラムの下にあり、何らかの理由でアセンブリルーチンがスタックしているのを見つけることができません。

私はすでにチェックSPしており、コードが正しい場所に戻ること、およびスタックが常にあるべき場所にあることを確認しました。

ルーチンがスタックしないようにするために私が行ったことが 1 つだけあります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

FCOMPPFPU の条件コード ビットのみを設定します。条件分岐命令を使用できるようにするために、おそらくFCOMIP(必要に応じて別の pop が続く) ことを意味していました。

また、チェックしたと言ったとしてもSP、典型的な C 呼び出し規則では変更が許可されDXているため、変更されていないと仮定するのは安全ではありません。の前に要素数をリロードする必要がありADD SP,DXます。


更新: わかりました、動作するようになりました (ただし、結果が正しいかどうかはわかりません: x=0.9516 および y=0.3072)。結果に応じてによって設定された FPU フラグ ビットおよびがそれぞれおよびに転送されるため、 JBnotを使用する必要がありますが、チェックおよびはここでは意味がありません。JLC0C3FCOMPPCFZFJLSFOF

補足:DWORD PTRコードを使用する場合、純粋な 16 ビットではなく、32 ビット プロセッサでのみ実行されます。

もちろん、プログラムは大幅に簡素化できます。

于 2013-01-18T18:31:30.040 に答える