2017-12-16 42 views
1

이 프로그램은 사용자가 제공 한 정확도로 pi를 계산해야합니다. calculate_pi() 함수는 NASM으로 작성됩니다. 이 라인은 주석 경우 왜 는 누군가가 나에게 설명 할 수 :asm 함수를 호출하기 전에 C에서 printf를 호출했는지 여부를 알 수없는 부작용이 있습니까?

//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 

샘플 출력 :

enter image description here

내가 사용 :

  • NASM 버전 2.11.06에 컴파일 2014 년 10 월 20 일
  • GCC (MinGW.org GCC-6.3.0-1) 6.3.0

컴파일과 어셈블러 명령 :

nasm -o pi.o -f coff pi.asm 
gcc pi.o pi_interface.c -o projekt.exe -Wall -Wextra 
+0

정확도를 지정하는 것은 사용자에게 친숙하지 않습니다. 올바른 자릿수가 더 많이 기대됩니다. – molbdnilo

+0

어떤 방식으로 올바르게 작동하지 않는지 설명하십시오. – molbdnilo

+0

다음과 같은 경우 프로그램이 올바르게 작동하지 않습니다. calculate_pi() 함수는 arctg (1)에 대한 테일러 공식으로 pi를 계산합니다. 이 행이 주석을하면 함수에 아주 작은 값이 전송되고 프로그램이 무한히 실행됩니다. – LeoProXXX

답변

3

나는 당신이 상쇄 잘못 함수 인수를 액세스하는 생각 4 바이트. 스택 프레임을 만들 때 첫 번째 인수는 [ebp+8]이지만, [ebp+12]에서로드됩니다.

이 당신이 precision로 사용하고있는 double 값이 높은 4 바이트를 가지고 의미한다 (이것은 스택에 인수를 전달하는 모든 호출 규칙을 적용한다. 나는 32 비트와 Mingw는 기본적으로 double.에 대한 것을하지 생각하는) 어떤에서 호출자는 8 바이트 arg 슬롯 위로 스택을 떠났다. 이것은 호출자의 변경이 함수의 동작에 영향을 미치는 이유와 무한 루프를 얻을 수있는 이유를 설명합니다.로드하는 바이트가 매우 작아서 double을 나타내는 경우 루프가 종료되지 않습니다.

낮은 4 바이트 (가수의 최하위 32 비트)는 호출자가 통과 한 상위 4 바이트에서 비롯됩니다.

레지스터를보고 디버거에서 쉽게 찾을 수 있고로드 한 값이 호출자가 전달한 값이 아니라는 것을 알 수 있습니다. 또한, @ Ped7g의 제안은 단지 asm 함수에서 precision을 반환하려고 시도했을 때도 문제를 발견했을 것입니다.

+0

도움 주셔서 감사합니다. 그것은 문제를 해결했습니다. – LeoProXXX