Подтвердить что ты не робот

Что делает-или сделал... "volatile void function (...)" do?

Я видел Сколько использования использует "volatile" ключевое слово имеет в функции С++, с точки зрения грамматики? об использовании ключевого слова volatile по функциям, но не было четкого объяснения того, что сделал случай 1 из этого вопроса. Только выражение одного из респондентов о том, что оно кажется бессмысленным/бесполезным.

Однако я не могу полностью согласиться с этим утверждением, поскольку реализация программного обеспечения AES для GNUC использовалась буквально в течение нескольких лет, и у них есть ряд функций, подобных этому:

INLINE volatile void functionname( /* ... */ ) {
    /* ... */
    asm( /* ... */ ) // embedded assembly statements
    /* ... */
}

Должна быть причина такого использования. Может ли кто-нибудь:

А. скажите мне, какова первоначальная причина; и

В. как добиться желаемого эффекта сейчас?

Я использую Ubuntu и GCC 4.6.3.


Примечание. Ближайшим образом я пришел к объяснению, что до GCC 2.5 вы можете обмануть атрибут "noreturn", который был реализован в версии 2.5, следующим образом:
void fatal( /* ... */ ) { /* ... */ exit(1); }

typedef void voidfn ();

volatile voidfn fatal;

Это позволит компилятору признать, что "фатальный" не вернется.

Но этот сценарий, похоже, не применяется к коду AES. Прошло много времени с тех пор, как я сделал что-то в сборке, но я думаю, что узнаю прыжок или что-то в этом роде.

4b9b3361

Ответ 1

ЛИТЕРАТУРЫ

ДОКАЗАТЕЛЬСТВА

  • volatile void function(...) не строго соответствует C99. (Спасибо @Adam и @ouah. @Adam для копания в спецификации C99 и @ouah для указания на DR, перечисленные выше.)

  • GCC добавил __attribute__((noreturn)) в версии 2.5 в качестве замены для volatile void, но продолжал принимать volatile void еще в версии 4.6.3 для поддержки совместимости кода с компиляторами до версии 2.5. (Документация GCC.)

  • Код, упомянутый выше, действительно возвращает управление туда, откуда он был вызван, поскольку инструкции не работают, чтобы манипулировать регистрами адресов, и они не выполняют команду перехода. Вместо этого они загружают различные значения в 32-разрядные регистры. (Проверка кода.)

  • Команды в строках с 323 по 333 реализуют специальные коды операций в поддержку операций шифрования. (Проверка кода плюс код "замка".)

  • Код с использованием функций сборки, очевидно, ожидает их возврата. (Проверка кода.)

  • Атрибут noreturn сообщает компилятору, что функция не возвращается, поэтому компилятор может сделать оптимизацию на основе этого. (Документация GCC.)

  • Из документации GCC: Не предполагайте, что регистры, сохраненные вызывающей функцией, будут восстановлены до вызова функции noreturn.

РЕШЕНИЕ

Это была дискуссия с коллегой, которая, наконец, привлекла меня. Компилятор должен делать что-то другое, когда функция заявляет, что она не вернется. Об этом свидетельствует проверка документации GCC.

A. Исходная причина

Вам нужно задать себе следующий вопрос.

Вопрос: Код AES специально загружает значения в 32-разрядные регистры и выполняет операции над ними. Как он возвращает ответы на остальную часть кода?

Ответ: Оптимизация GCC означает, что регистры вызывающей функции, которые в противном случае перезаписали бы значения по возврату, не сохраняются. Результаты вычислений в функциях языка ассемблера остаются в регистрах для последующего использования кода.

В. Достижение желаемого эффекта теперь:

В значительной степени оставьте это в покое. Единственное, что вы можете сделать, это заменить тип возвращаемого volatile void простым void и добавить атрибут noreturn к функциям. Теоретически это должно иметь точно такой же эффект. На практике он не сломался, не исправляйте его.

ЖЕЛАТЕЛЬНОСТЬ

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

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

В этом примере поддерживается только два компилятора, и только в том случае, если у машин есть определенная аппаратная поддержка, чтобы воспользоваться преимуществами. В противном случае все это обрабатывается стандартным кодом C. Это много усилий. Удостоверьтесь, что он окупится, прежде чем вы это сделаете.

Ответ 2

В соответствии с документацией gcc (до февраля 2015 г.), volatile void как возвращаемое значение функции в C (но не на С++) эквивалентен __attribute__((noreturn)) функции и сообщает компилятору, что функция никогда не возвращается.

Ответ 3

В стандарте C99 говорится об этом в §6.7.3/3:

Свойства, связанные с квалифицированными типами, имеют смысл только для выражений, которые являются lvalues. 114)

114) Реализация может поместить объект const, который не является volatile, в область хранения только для чтения. Более того, реализация не должна выделять хранилище для такого объекта, если его адрес никогда не используется

В §6.2.5/19 говорится:

Тип void содержит пустой набор значений; это неполный тип, который не может быть завершено.

И в §6.3.2.1/1 говорится:

lvalue - это выражение с типом объекта или неполным типом, отличным от void; 53) [...]

Следовательно, void не является lvalue, поэтому классификаторы типов (const, volatile и restrict) не имеют смысла для выражений типа void. Таким образом, в любом компиляторе, совместимом с C99, const void и volatile void бессмысленны (хотя указатели на const void и const volatile имеют смысл).

Кроме того, ограничения в §6.9.1/3 запрещают функцию для возврата квалифицированного типа void:

Возвращаемый тип функции должен быть void или тип объекта, отличный от типа массива.

Поскольку это ограничение, соответствующий компилятор должен выдать диагностику (§5.1.1.3/1). Поэтому функция, возвращающая volatile void, не допускается на C99.

Что касается того, что volatile void мог бы сделать, я понятия не имею и не могу спекулировать. Я бы предположил, что код AES, на который вы смотрите, скорее всего, имеет старый рывок, который никогда не очищался.