2012-05-18 5 views
1

C 코드에 대한 Prime.Asm 예 도움말 :PC 어셈블리 언어 (폴 카터) - JO 그리고 JE

#include <stdio.h> 

int main() 
{ 
    unsigned guess;   /* current guess for prime  */ 
    unsigned factor;   /* possible factor of guess  */ 
    unsigned limit;   /* find primes up to this value */ 

    printf("Find primes up to: "); 
    scanf("%u", &limit); 

    printf("2\n"); /* treat first two primes as special case */ 
    printf("3\n"); 

    guess = 5;  /* initial guess */ 
    while (guess <= limit) { 
    /* look for a factor of guess */ 
    factor = 3; 
    while (factor*factor < guess && guess % factor != 0) 
     factor += 2; 
    if (guess % factor != 0) 
     printf("%d\n", guess); 
    guess += 2; /* only look at odd numbers */ 
    } 
    return 0; 
} 

어셈블리 코드 (NASM) :

%include "asm_io.inc" 

segment .data 
Message   db  "Find primes up to: ", 0 


segment .bss 
Limit   resd 1    ; find primes up to this limit 
Guess   resd 1    ; the current guess for prime 



segment .text 
     global _asm_main 
_asm_main: 
     enter 0,0    ; setup routine 
     pusha 

     mov  eax, Message 
     call print_string 

     call read_int    ; scanf("%u", & limit); 
     mov  [Limit], eax 

     mov  eax, 2    ; printf("2\n"); 
     call print_int 
     call print_nl 
     mov  eax, 3    ; printf("3\n"); 
     call print_int 
     call print_nl 

     mov  dword [Guess], 5  ; Guess = 5; 

while_limit:       ; while (Guess <= Limit) 
     mov  eax,[Guess] 
     cmp  eax, [Limit] 
     jnbe end_while_limit  ; use jnbe since numbers are unsigned 

     mov  ebx, 3    ; ebx is factor = 3; 
while_factor: 
     mov  eax,ebx 
     mul  eax     ; edx:eax = eax*eax 
     **jo  end_while_factor  ; if answer won't fit in eax alone** 
     cmp  eax, [Guess] 
     jnb  end_while_factor  ; if !(factor*factor < guess) 
     mov  eax,[Guess] 
     mov  edx,0 
     div  ebx     ; edx = edx:eax % ebx 
     cmp  edx, 0 
     je  end_while_factor  ; if !(guess % factor != 0) 

     add  ebx,2    ; factor += 2; 
     jmp  while_factor 
end_while_factor: 
     **je  end_if    ; if !(guess % factor != 0)** 
     mov  eax,[Guess]   ; printf("%u\n") 
     call print_int 
     call print_nl 
end_if: 
     mov  eax,[Guess] 
     add  eax, 2 
     mov  [Guess], eax   ; guess += 2 
     jmp  while_limit 
end_while_limit: 

     popa 
     mov  eax, 0   ; return back to C 
     leave      
     ret 

당신이 볼 수 있듯이, 내가 가진 ** 두 가지 지침이 표시되어 있습니다.

우선, MUL 명령어는 EAX * EAX를 곱하고 그 값을 EAX에 맞게 너무 큰 경우 EDX : EAX에 저장합니다. 맞습니까? 그런 다음 프로그램이 오버플로를 확인합니다. 값이 너무 커서 EAX에 맞지 않으면 시스템은 오버플로를 감지하고 OF = 1로 설정합니까? 왜? 필요한 경우 EAX & EDX에 값을 저장하지 않으시겠습니까?

둘째, JE 명령입니다. 설명문은 if! (추측 % factor! = 0)입니다. ! (요인 * 요소 < 0) 경우 점프가 있기 때문에 오버 플로우 검사 만들어진, 또는 어떤 경우

cmp edx,0 
je end_while_factor 

그러나 다음 프로그램에서이 점프 할 때

그게 좋아? 괜찮습니까? 비교할 값은 무엇입니까? 그냥 ZF를 확인합니까? 그러나 이전에 다른 이유로 변경되지 않았습니다 (다른 명령).

미리 도움을 주셔서 감사합니다.

답변

2

예, MUL 명령어는 EDX 레지스터가 0이 아닌 경우 OF 플래그를 설정합니다. 즉 곱셈이 더 이상 32 비트 부호없는 int에 들어 가지 않는 결과를 생성 할 때입니다. 테스트중인 표현식은 factor*factor < guess입니다. 여기서 guess은 32 비트 부호없는 int입니다. 따라서 코드 생성기가 멋진 코드를 생성합니다. 오버플로 플래그가 설정되어 있으면 추측 값에 관계없이 항상 표현식이 false가됩니다. 대안은 더 심각합니다. 오버플로가 있으면 표현식의 결과가 참일 수 있습니다.

불행하게도 점프 대상을 찾지 못한 인텔 설명서는 MUL이 ZF 플래그를 정의되지 않은 것으로 지정합니다. 코드 생성기 버그처럼 보입니다. 어떤 컴파일러가이 코드를 생성했는지 또는이 코드가 C 코드의 손 유형의 대체 코드인지는 분명하지 않습니다. 코드 생성기는 일반적으로 이와 같은 코드를 생성하지 않으므로 손으로 입력 한 코드의 버그 일뿐입니다.

+0

답변 해 주셔서 감사합니다. OF의 현재 상황은 명확합니다. JE 정보 ... 이전에는 명령 : cmp eax, [Limit]가 실행되었습니다. eax = [Limit]이면 JMP가 작성되지 않고 while 루프가 시작되므로 cmp 때문에 ZF = 1입니다. 오버 플로우가 발생하여 프로그램이 end_while_factor로 점프하면 ZF가 1로 남아 있기 때문에 번호가 인쇄되지 않습니다. –

+0

Erm, 아니요, 그 비교는 end_while_limit로 점프합니다. end_while_factor로 점프하는 장소가 여러 곳 있습니다. 이것은 단지 버그 코드입니다. –

+0

좋습니다! 도와 줘서 고마워! –