Язык ассемблера ПК (Пол Картер) - Пример справки Prime.Asm по JO и JE

Код 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 и сохраняет значение в EDX: EAX, если оно слишком велико для EAX, верно? Затем программа проверяет наличие переполнения. Итак, когда значение слишком велико для EAX, система обнаруживает переполнение и устанавливает OF = 1? Почему? При необходимости значение не должно храниться как в EAX, так и в EDX?

Во-вторых, инструкция JE. Комментарий объясняет: если! (Угадайте,% фактор! = 0).

Нормально, когда программы прыгают оттуда:

cmp edx,0
je end_while_factor

Но что, если скачок сделан из-за проверки переполнения, или если! (Factor * factor ‹0)? Все будет нормально? Какие значения сравниваются? Это просто ZF проверяет? Но разве он не модифицировался ранее по другой причине (другая инструкция).

Заранее спасибо за помощь.


person Nic Marioc Katritcic    schedule 18.05.2012    source источник


Ответы (1)


Да, инструкция MUL устанавливает флаг OF, когда регистр EDX становится ненулевым. Другими словами, когда умножение дает результат, который больше не умещается в 32-битном беззнаковом int. Проверяется выражение factor*factor < guess, где guess - 32-разрядное целое число без знака. Таким образом, генератор кода генерирует хороший код, если установлен флаг переполнения, выражение всегда будет ложным, независимо от значения предположения. Альтернатива хуже, если есть переполнение, тогда результат выражения может быть истинным.

К сожалению, затем он теряет цель перехода, руководство Intel указывает, что MUL оставляет флаг ZF неопределенным. Мне кажется, что это ошибка генератора кода. Неясно, какой компилятор сгенерировал этот код или это просто набранная вручную альтернатива кода C. Генераторы кода обычно не генерируют такой код, поэтому я с готовностью предполагаю, что это просто ошибка в коде, набранном вручную.

person Hans Passant    schedule 18.05.2012
comment
Спасибо за Ваш ответ! Что происходит с OF, теперь ясно. О JE ... Раньше выполнялась инструкция: cmp eax, [Limit]. Если eax = [Limit], JMP не создается и запускается цикл while, поэтому ZF = 1 из-за cmp. Если теперь произойдет переполнение и программа перейдет к end_ while_factor, число не будет напечатано, так как ZF остаётся равным 1? - person Nic Marioc Katritcic; 18.05.2012
comment
Эээ, нет, это сравнение переходит к end_ while_limit. Есть несколько мест, где он переходит к end_ while_factor. Это просто ошибочный код. - person Hans Passant; 18.05.2012
comment
Оригинальный автор здесь. Я только что наткнулся на это. Я был генератором кода, так что это просто ошибка, которую я сделал. Хороший анализ! - person pcarter; 16.07.2016