Что происходит в выводе сборки, когда мы добавляем «cc» в список дубликатов - PullRequest
2 голосов
/ 09 января 2020

Я прочитал, что если мы указываем "cc" в списке clobber, это означает, что код ассемблера изменяет регистр флагов

Написал пример программы, чтобы проверить разницу между добавлением "cc" и не добавление. Сравнение сборки не меняется, когда мы добавляем «cc».

#include <stdio.h>

int main(void)
{
        unsigned long sum;

        asm("incq %0" 
        : "=r"(sum)//output operand
        : "r" (sum) //input operand
    );
        printf("sum= %lu\n", sum);
        return 0;
}

Когда мы должны использовать «cc», и как это повлияет на вывод сборки

1 Ответ

4 голосов
/ 09 января 2020

Для x86 абсолютно ничего. Для x86 и x86-64, cc clobber подразумевается в каждом asm() выражении. Это конструктивное решение имеет некоторый смысл, потому что большинство инструкций x86 написали FLAGS. И потому что это легко пропустить и может быть трудно поймать с тестированием. (Хотя нет недостатка в вещах, которые легко ошибиться с помощью встроенного ассемблера GNU C. Обычно его не нужно использовать.)

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

Если вы хотите быть pedanti c, вы можете использовать "cc" clobber в каждом операторе asm, который изменяет FLAGS.


Для не x86, вы должны использовать cc clobber в каждом операторе asm, который изменяет флаги / коды условий (на ISA, у которых они есть). например, ARM . В ARM установка флагов не обязательна; инструкции с суффиксом S устанавливают флаги. Таким образом, adds r0, r1, r2 устанавливает флаги в соответствии с r0 = r1+r2, но add r0, r1, r2 оставляет флаги нетронутыми.

Если вы не указали "cc" clobber (на не-x86), компилятор может выдавать asm, который устанавливает флаги перед asm-оператором и прочитайте их позже, как часть реализации некоторого другого не-asm-оператора. По сути, это может быть то же самое, что уничтожение регистра: бессмысленное поведение, которое зависит от деталей того, для чего компилятор использовал регистр или флаги, и которое зависит от уровня оптимизации и / или версии компилятора.

Вот почему тестирование не является достаточным, чтобы доказать, что встроенный asm безопасен. С одной версией компилятора вы можете легко повезти, и компилятор сгенерирует код, который не содержит ничего в регистре состояния / кодах условий в операторе asm, но имеет другую версию компилятора или другой окружающий код в функции, где это может быть встроено быть уязвимым для ошибочного оператора asm.

...