Добавление значений в C с использованием встроенной сборки
Я пытаюсь понять основы встроенной сборки в C (сборка ATT), поэтому я тренируюсь, добавляя 2 переменные.
Итак, это работает как задумано; переменная src копируется в переменную dst, а затем переменная dst добавляется на 5. Значения src и dst равны 1 и 6 соответственно.
int src = 1;
int dst = 0;
asm ("mov %[SRC], %[DEST]\n\t"
"add $5, %0"
: [DEST] "=r" (dst));
: [SRC] "r" (src));
Но когда я пытаюсь это сделать, значения src и dst по-прежнему равны 1 и 6. Я ожидал, что src будет иметь значение 1, а dst будет иметь значение 5 с момента добавления 5 к dst (который имеет значение 0, поскольку MOV операция была удалена) должна иметь выход 5.
int src = 1; int dst = 0;
asm ("add $5, %[DEST]"
: [DEST] "=r" (dst)
: [SRC] "r" (src));
Затем я пытаюсь удалить src в качестве входного операнда, используя следующий код, но теперь dst получает значение 11.
int dst = 0;
asm (
"add $5, %[DEST]"
: [DEST] "=r" (dst));
Теперь я немного запутался, как это работает. Что я недопонимаю?
1 ответ
Первая часть вашего кода работает как положено. Там
mov %[SRC], %[DEST] ; copies %[SRC] into %[DEST], which is now 1
add $5, %0 ; adds 5 to %0 (which is %[DEST]), so that's 6
Вторая часть не работает, потому что вы никогда не используете %[SRC]
, и потому что %[DEST]
не является входным операндом, поэтому его значение не входит в расчет. Вы просто получаете то, что происходит в реестре, который gcc решает использовать. Третья часть терпит неудачу по той же причине.
Чтобы это работало, нужно указать dst
как входной и выходной операнд, поскольку вы используете его значение и меняете его. Однако это не работает:
asm("add $5, %0" // This does not work!
: "=r" (dst)
: "r" (dst));
потому что теперь у вас есть входной операнд %1
со значением dst
и отличный выходной операнд %0
чье значение будет записано в dst
и вы никогда не используете %1
, Эта запись позволит вам написать
asm("mov %1, %0; add $5, %0" // needlessly inefficient!
: "=r" (dst)
: "r" (dst));
но это, конечно, излишне неэффективно. Чтобы сделать это с одним регистром, вам нужно использовать соответствующее ограничение:
asm("add $5, %0"
: "=r" (dst)
: "0" (dst));
Это говорит GCC, что %0
как входной операнд разрешен, и что он имеет значение dst
, Вот соответствующая часть руководства gcc.
Наконец, с именованными операндами это выглядит так:
asm ("add $5, %[DEST]"
: [DEST] "=r" (dst)
: "[DEST]" (dst));