x86装配程序无缘无故地卡住了

时间:2013-01-18 17:01:53

标签: c assembly x86

我已经低于这个程序了,由于某些原因我无法找到我的程序集常常卡住。

我已经检查了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 CODE:

;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);
}

1 个答案:

答案 0 :(得分:2)

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

即使你说你检查了SP,也要注意典型的C调用约定允许修改DX,所以假设它没有改变它是不安全的。您应该在ADD SP,DX之前重新加载元素计数。


更新:好的,我已经开始工作了(虽然我不知道结果是否正确:x = 0.9516和y = 0.3072)。您应该使用JB而不是JL,因为根据结果由C0设置的FPU标志位C3FCOMPP - 将被转移到分别是CFZF,但JL检查SFOF这些没有意义。

附注:如果使用DWORD PTR,则代码不是纯16位,只能在32位处理器上运行。

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