Неожиданное поведение встроенного 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: Даже если встроенная сборка, похоже, работает, у нее могут быть скрытые проблемы, которые укусят вас в другой день, когда компилятор сделает другие варианты. Вы должны действительно избежать этого.