Бесконечный цикл в ассемблере x86-64

0
#include <stdio.h>
#include <math.h>

int main(int argc, const char *argv[])
{
  long i, max;
  long sum = 0;
  max = (long)pow(2,32);

  for (i = 0; i < max; i++) {
    sum += i; 
  }
  printf("%ld\n", sum);
  return 0;
}

$gcc -S main.c

Возникает вопрос: в коде .L2 ниже -8(%rbp) всегда равен нулю, а %rax всегда больше нуля. Итак, это бесконечный цикл? И если я компилирую с gcc -S -O1 main.c, это очень ясно. Я действительно обеспокоен!

Просто небольшая часть кода ассемблера:

main:   
    pushq   %rbp
    movq    %rsp, %rbp
    subq    $48, %rsp
    movl    %edi, -36(%rbp)
    movq    %rsi, -48(%rbp)
    movq    $0, -16(%rbp)
    movl    $0, -8(%rbp)
    movl    $2, -4(%rbp)
    movq    $0, -24(%rbp)
    jmp .L2

.L3:
    movq    -24(%rbp), %rax
    addq    %rax, -16(%rbp)
    addq    $1, -24(%rbp)

.L2:
    movq    -24(%rbp), %rax     
    cmpq    -8(%rbp), %rax       
    jl  .L3                      

.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
  • 6
    Какой размер long ? Если это 32 бита (4 байта), то pow(2, 32) будет переполнен. Если вы хотите получить максимальное значение long , то вам следует использовать std::numeric_limits в C ++ и LONG_MAX из заголовочного файла <limits.h> в C.
  • 0
    -8(%rbp) - значение max поэтому оно не должно быть нулевым. Может быть, вы могли бы показать больше ассемблера, где он установлен.
Показать ещё 3 комментария
Теги:
gcc
assembly
x86-64

2 ответа

2

Счетчик реального цикла (i) находится в -24(%rbp). На третьей линии он увеличился. На 4-й строке он загружается в rax. Таким образом, rax не является постоянным нулем, он пробегает значения вместе с i.

-8(%rbp), предполагается, что это max. Таким образом, значение i сравнивается с этим, и это условие выхода из цикла. -8(%rbp) не должно быть равно нулю. Если это так, я ощущаю 32-битную арифметику изгоев.

EDIT: Я думаю, я знаю, в чем дело. Константы 2 и 32 являются int, но не long, поэтому предполагается, что они 32-битные. Размер int зависит от платформы; даже конвенция GCC может отличаться. pow(int, int) реализуется как неотъемлемая. 2 ^ 32 равно 0, когда аргументы 32-битные.

замещать

max = (long)pow(2,32);

с

max = pow(2l, 32l);

Или лучше с константой:

max = 0x100000000l;

Как и я и другие подозреваемые, в миксе был кусок 32-бит.

  • 0
    извините, я добавил дополнительные коды. увидеть снова...
1

Нет, это не бесконечный цикл. Прежде всего% rax не всегда больше 0, в этой строке он получает значение из -24 (% rbp), который, очевидно, является переменной i. Когда он входит в цикл, он устанавливает -24 (% rbp) в ноль, а затем переходит к.L2. Это частично происходит, что вы не показывали. Если -8 (% rbp), который является значением переменной max, равен нулю (в случае переполнения) jl не будет переходить на.L3, и цикл будет завершен после первой проверки. Я не совсем понимаю, почему вам нужно прочитать сборку для этого, что довольно очевидно из C++ исходного кода.

  • 0
    Кроме того, после запуска кода мы видим, что он заканчивается. Даже несколько дополнительных операторов printf() должны помочь.
  • 0
    нет, -8(%rbx) инициализируется нулем, выше которого я добавил дополнительные коды. и в первый раз cmpq -8(%rbx), %rax имеет значение true, затем всегда true, если %rax не переполнится.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню