Нужно ли инициализировать все используемые регистры во встроенной сборке? - PullRequest
0 голосов
/ 12 октября 2018

Я тестирую простой встроенный код ассемблера, используя gcc.И я нахожу результат следующего кода неожиданным:

#include <stdio.h>
int main(void) {
    unsigned x0 = 0, x1 = 1, x2 = 2;
    __asm__ volatile("movl %1, %0;\n\t"
                     "movl %2, %1"
                     :"=r"(x0), "+r"(x1)
                     :"r"(x2)
                     :);
    printf("%u, %u\n", x0, x1);
    return 0;
}

Напечатанный результат - 1, 1, а не ожидаемый 1, 2.Затем я скомпилировал код с параметром -S и обнаружил, что gcc сгенерировал код, поскольку

movl %eax, %edx;
movl %edx, %eax;

%0 и %2 используют один и тот же регистр, почему?

Я хочуgcc для генерации, скажем,

movl %eax, %edx;
movl %ecx, %eax;

Если я добавлю "0"(x1) к ограничениям ввода, gcc сгенерирует приведенный выше код.Означает ли это, что все регистры должны быть инициализированы перед использованием во встроенной сборке?

1 Ответ

0 голосов
/ 13 октября 2018

Перемещение моего комментария в 'Ответ', чтобы этот вопрос можно было закрыть.

Чтобы запретить компилятору повторно использовать регистр для ввода и вывода, вы можетеиспользуйте ограничение early clobber (например, =&r (x)), которое информирует компилятор о том, что регистр, связанный с параметром,

, записанный до завершения инструкции с использованием входных операндов.

Хотя это может быть полезно (так как уменьшает количество регистров, которые должны быть доступны до вызова вашего asm), это также может вызвать проблемы (как вы уже видели).Итак, либо убедитесь, что вы закончили использовать все входные данные перед записью в выходные данные, либо используйте &, чтобы сообщить компилятору не выполнять эту оптимизацию.

Для полноты позвольте мне также указать, что использование встроенногоasm - это обычно плохая идея .

...