1

C コード:

 #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

ご覧のとおり、** の 2 つの指示をマークしました。

まず、MUL 命令は EAX*EAX を乗算し、値が大きすぎて EAX に収まらない場合は EDX:EAX に値を格納しますよね? 次に、プログラムはオーバーフローをチェックします。値が大きすぎて EAX に収まらない場合、システムはオーバーフローを検出し、OF=1 を設定しますか? なんで?値は、必要に応じて EAX と EDX の両方に保存されませんか?

2 つ目は JE 命令です。コメントの説明: if !(guess% factor !=0)。

プログラムがそこからジャンプするときは問題ありません:

cmp edx,0
je end_while_factor

しかし、オーバーフロー チェックのためにジャンプが行われた場合、または !(factor*factor < 0) の場合はどうなるでしょうか? 大丈夫ですか?どの値が比較されていますか? ZFをチェックするだけですか?しかし、別の理由(別の指示)で以前に変更されていませんか。

よろしくお願いします。

4

1 に答える 1

2

はい、EDX レジスタが非ゼロになると、MUL 命令は OF フラグを設定します。つまり、乗算の結果が 32 ビットの unsigned int に収まらなくなった場合です。テストされている式はfactor*factor < guesswhere guessis a 32-bit unsigned int です。したがって、コード ジェネレーターは優れたコードを生成します。オーバーフロー フラグが設定されている場合、その式は、guess の値に関係なく、常に false になります。別の方法はさらに悪く、オーバーフローが発生した場合、式の結果が true になる可能性があります。

残念ながら、それはジャンプ ターゲットを混乱させます。Intel のマニュアルでは、MUL が ZF フラグを未定義のままにすることを指定しています。これは、コード ジェネレーターのバグのように見えます。どのコンパイラがこのコードを生成したのか、またはこれが C コードの単なる手書きの代替物なのかは明らかではありません。通常、コード ジェネレーターはこのようなコードを生成しないため、手で入力したコードの単なるバグであるとすぐに推測できます。

于 2012-05-18T12:31:17.623 に答える