PC汇编语言(Paul Carter) - Prime.Asm示例帮助关于JO和JE

时间:2012-05-18 09:43:55

标签: assembly x86 overflow instructions

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

如您所见,我已经标记了**两条指令。

首先,MUL指令将EAX * EAX与EX * EAX相乘并存储在EDX:EAX中,如果它太大而不适合EAX,对吧? 然后程序检查溢出。 因此,当该值太大而不适合EAX时,系统会检测到溢出并设置OF = 1? 为什么?该值不应存储在EAX和EAX中。 EDX,如果需要?

其次,JE指令。评论解释说:if!(猜测%factor!= 0)。

当程序从那里跳过时,这很好:

cmp edx,0
je end_while_factor

但是如果跳转是因为溢出检查,或者是!(因素*因素&lt; 0)? 会没事吗?正在比较哪些值?它只是检查ZF? 但是之前是否因为其他原因(另一条指令)而修改了它。

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

是,当EDX寄存器变为非零时,MUL指令设置OF标志。换句话说,当乘法产生的结果不再适合32位无符号整数时。正在测试的表达式是factor*factor < guess,其中guess是32位无符号整数。所以代码生成器生成了很好的代码,如果设置了溢出标志,那么无论guess的值如何,表达式都将始终为false。替代方案更糟糕,如果存在溢出,则表达式的结果可能为真。

不幸的是它然后摸索了跳转目标,英特尔手册指定MUL保留未定义的ZF标志。所以这看起来像是一个代码生成器错误。目前尚不清楚编译器生成此代码的是什么,或者这只是C代码的手工替代方案。代码生成器通常不会生成这样的代码,所以我很容易认为它只是手动类型代码中的一个错误。