该程序必须以用户提供的准确度计算pi。 calculate_pi()函数是用NASM编写的。 有人可以向我解释为什么这条线被评论:
//printf("accuracy: %.15f\n", precision); //<- This line
程序无法正常运行。将奇怪的数字发送到calcuta_pi()函数?如果注释了这一行,则会向函数发送一个非常小的值,程序将无限运行。
但如果不是评论的程序可以正常工作。
#include <stdio.h>
#include <math.h>
extern double calculate_pi(double precision); /* external function declaration */
double calculate_pi(double precision); /* function prototype */
int main()
{
double precision = 1;
printf("A program that calculates pi, with accuracy provided by the user\n");
printf("Give me accuracy\n");
while(1)
{
if (scanf("%lf", &precision) != 1)
{
printf("reading error\n");
fseek(stdin,0,SEEK_END);
continue;
}
if(precision<0)
precision = fabs(precision);
//printf("accuracy: %.15f\n", precision); //<- This line
printf("pi: %.15f\n", calculate_pi(precision));
}
return 0;
}
这是我的汇编代码:
; arctg(1)=a
; tg(arctg(1))=tg(a)
; atan(x) = x - x^3/3 + x^5/5 - x^7/7 + x^9/9..
; PI/4 = atan(1) = 1 - 1/3 + 1/5 - 1/7 + 1/9...
; PI = (4/1) - (4/3) + (4/5) - (4/7) + (4/9) - (4/11) + (4/13) - (4/15) ...
section .text use32
global _calculate_pi
_calculate_pi:
%idefine a [ebp+12]
;ramka stosu
push ebp
mov ebp, esp
;ustawianie zmiennych
fld qword [const_wynik]
fstp qword [wynik]
fld qword [const_licznik]
fstp qword [licznik]
fld qword [const_mianownik]
fstp qword [mianownik]
.loop:
finit ; inicjalizacja stosu FPU
fld qword [licznik] ;licznik na stos
fld qword [mianownik] ;mianownik na stos
fdiv ;wynik dzielenia st1/st0
fadd qword [wynik] ;st0 = wynik dzielenia + [wynik]
fstp qword [wynik] ;wywalamy z st0 do [wynik]
;zmieniamy mianownik + 2
fld qword [mianownik] ;mianownik na stos
fadd qword [zwiekszmian] ;st0 = mianownik + 2
fstp qword [mianownik] ;wywalamy z st0 do [mianownik]
;zmieniamy licznik *(-1)
fld qword [licznik] ;licznik na stos
fchs ;st0 = -st0 = -licznik
fstp qword [licznik] ;wywalamy z st0 do [licznik]
;sprawdzanie dokladnosci
fld qword[wynik] ;wynik na stos
fldpi ;pi na stos
fsub ;st0 = wynik-pi = st1 - st0
fabs ;st0 = |wynik-pi|
fld qword a ;st0 = zadana dokladnosc
;(Unordered Compare ST(0) to ST(i) and set CPU flags and Pop ST(0))
;Przyrostek p oznacza obniżenie stosu rejestrów koprocesora, przyrostek i oznacza zapisywanie wyników bezpośrednio do flag procesora a nie flag koprocesora
fucomip st0, st1 ;porownanie z dokladnoscia if(zadana dokladnosc > uzyskana)
jb .loop ;only the C0 bit (CF flag) would be set if no error
fld qword [wynik]
;zwraca to co w st0
leave ; LEAVE = mov esp, ebp / pop ebp
ret
section .data:
wynik dq 4.0
licznik dq -4.0
mianownik dq 3.0
zwiekszmian dq 2.0
const_wynik dq 4.0
const_licznik dq -4.0
const_mianownik dq 3.0
示例输出:
我正在使用:
编译和汇编程序命令:
nasm -o pi.o -f coff pi.asm
gcc pi.o pi_interface.c -o projekt.exe -Wall -Wextra
答案 0 :(得分:3)
我认为你正确地访问了arg函数,偏移了4个字节。当您创建堆栈框架时,第一个arg位于[ebp+8]
,但您从[ebp+12]
重新加载。 (这适用于在堆栈上传递args的所有调用约定。我认为32位mingw默认为double
执行此操作。)
这意味着您double
使用的precision
值与来自8字节arg插槽上方的堆栈上的调用者所留下的高4字节相同。这解释了为什么调用者的更改会影响函数的行为,以及为什么可以获得无限循环:如果加载的字节恰好代表一个非常小的double
,则循环永远不会退出。
低4字节(尾数的32个最低有效位)来自调用者传递的前4个字节。
通过查看寄存器并注意到您加载的值不是调用者传递的值,您可以通过调试器轻松找到它。另外,@ Ped7g的建议只是尝试在一个简单的asm函数中返回precision
也会发现问题。