Добавление двух чисел - PullRequest
11 голосов
/ 12 декабря 2011

Я пытаюсь ознакомиться со сборкой x86, используя встроенный ассемблер GCC. Я пытаюсь добавить два числа (a и b) и сохранить результат в c. У меня есть четыре слегка отличающиеся попытки, три из которых работают; последнее не дает ожидаемого результата.

Первые два примера используют промежуточный регистр, и оба работают нормально. Третий и четвертый примеры пытаются добавить два значения напрямую без промежуточного регистра, но результаты варьируются в зависимости от уровня оптимизации и порядка, в котором я добавляю входные значения. Что я не так делаю?

Окружающая среда:

i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3)

Сначала переменные объявляются следующим образом:

int a = 4;
int b = 7;
int c;

Пример 1:

asm("   movl    %1,%%eax;"
    "   addl    %2,%%eax;"
    "   movl    %%eax,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
    : "%eax"
   );
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output: a=4, b=7, c=11

Пример 2:

asm("   movl    %2,%%eax;"
    "   addl    %1,%%eax;"
    "   movl    %%eax,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
    : "%eax"
   );
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output: a=4, b=7, c=11

Пример 3:

asm("   movl    %2,%0;"
    "   addl    %1,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
   );
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output with -O0: a=4, b=7, c=11
// output with -O3: a=4, b=7, c=14

Пример 4:

// this one appears to calculate a+a instead of a+b
asm("   movl    %1,%0;"
    "   addl    %2,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
   );
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output with -O0: a=4, b=7, c=8
// output with -O3: a=4, b=7, c=11

решено. ответ Мэтью Слэттери правильный. Раньше он пытался повторно использовать eax для b и c:

movl    -4(%rbp), %edx
movl    -8(%rbp), %eax
movl    %edx, %eax
addl    %eax, %eax

С предложенным Мэтью исправлением теперь он использует ecx для удержания c отдельно.

movl    -4(%rbp), %edx
movl    -8(%rbp), %eax
movl    %edx, %ecx
addl    %eax, %ecx

Ответы [ 2 ]

8 голосов
/ 12 декабря 2011

По умолчанию gcc будет предполагать, что встроенный блок asm завершит использование входных операндов перед обновлением выходных операндов.Это означает, что и вход, и выход могут быть назначены одному и тому же регистру.

Но это не обязательно так в ваших примерах 3 и 4.

, например, в примере 3:

asm("   movl    %2,%0;"
    "   addl    %1,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
   );

... вы обновили c (%0) перед чтением a (%1).Если gcc случится присвоить один и тот же регистр как %0, так и %1, то он вычислит c = b; c += c и, следовательно, потерпит неудачу именно так, как вы наблюдаете:

printf("a=%d, b=%d, c=%d\n", a, b, c);
// output with -O0: a=4, b=7, c=11
// output with -O3: a=4, b=7, c=14

Вы можетеисправьте это, сказав gcc, что выходной операнд может использоваться до использования входов, добавив модификатор "&" к операнду, например:

asm("   movl    %2,%0;"
    "   addl    %1,%0;"
    : "=&r" (c)
    : "r" (a), "r" (b)
   );

(см. «Символы модификатора ограничения» в gcc документах.)

0 голосов
/ 12 декабря 2011

Хой, я не вижу проблемы там, и она компилируется и работает здесь хорошо.Однако небольшая подсказка: я очень скоро запутался с неназванными переменными / регистрами, поэтому решил использовать именованные.Например, добавление, которое вы могли бы реализовать следующим образом:

static inline void atomicAdd32(volInt32 *dest, int32_t source) {
// IMPLEMENTS:  add m32, r32
__asm__ __volatile__(
        "lock; addl %[in], %[out]"
        : [out] "+m"(*dest)
        : [in] "ir"(source)//, "[out]" "m"(*dest)
        );
return;
  }

(вы можете пока просто игнорировать атомарные / блокирующие вещи), которое проясняет, что происходит:

1) что регистрируетдоступны для записи, чтения или и того, и другого

2) того, что используется (память, регистры), что может быть важно, когда речь идет о производительности и тактах, поскольку операции с регистрами выполняются быстрее, чем те, которые обращаются к памяти.

Cheers, G.

PS: Вы проверяли, переставляет ли ваш компилятор код?

...