Непредвиденное поведение встроенного ASM в GCC (перезаписанная переменная)
На моем компьютере скомпилированный исполняемый файл не выполняет "mov %2, %%ax" в верхней части цикла
когда "добавить%1, %%ax" не закомментировано.
Кто-нибудь, чтобы проверить или прокомментировать?
#include <stdio.h>
int main() {
short unsigned result, low ,high;
low = 0;
high = 1;
__asm__ (
"movl $10, %%ecx \n\t"
"loop: mov %2, %%ax \n\t"
// "add %1, %%ax \n\t" // uncomment and result = 10
"mov %%ax, %0 \n\t"
"subl $1, %%ecx \n\t"
"jnz loop"
: "=r" (result)
: "r" (low) , "r" (high)
: "%ecx" ,"%eax" );
printf("%d\n", result);
return 0;
}
Следует за созданной сборкой
movl $1, %esi
xorl %edx, %edx
/APP
movl $10 ,%ecx
loop: mov %si, %ax
mov %dx, %bx
add %bx, %ax
mov %ax, %dx
subl $1, %ecx
jnz loop
/NO_APP
Благодаря Jester решение:
: "=&r" (result) // early clober modifier
1 ответ
Встроенная сборка GCC - это сложное программирование с множеством подводных камней. Убедитесь, что он вам действительно нужен, и не можете заменить его автономным модулем сборки или кодом C с использованием встроенных функций. или векторная поддержка.
Если вы настаиваете на встроенной сборке, вы должны быть готовы хотя бы взглянуть на сгенерированный ассемблерный код и попытаться выяснить возможные ошибки. Очевидно, что компилятор не пропускает ничего, что вы пишете в блок asm, он просто подставляет аргументы. Если вы посмотрите на сгенерированный код, вы можете увидеть что-то вроде этого:
add %dx, %ax
mov %ax, %dx
Видимо компилятор подобрал dx
для обоих аргументов 0
а также 1
, Это разрешено делать, потому что по умолчанию предполагается, что входные аргументы используются перед записью любых выходных данных. Чтобы показать, что это не так, вы должны использовать ранний модификатор clobber для выходного операнда, чтобы он выглядел следующим образом "=&r"
,
PS: даже когда встроенная сборка кажется работающей, у нее могут быть скрытые проблемы, которые укусят вас в другой день, когда компилятор сделает другой выбор. Вы должны действительно избегать этого.