Ответ 1
ЛИТЕРАТУРЫ
-
https://github.com/nmoinvaz/minizip/blob/master/aes/aes_via_ace.h См. строки с 323 по 333 и строки с 399 по 492. Существует множество других мест для поиска этого кода, это был только первый, с которым я споткнулся.
-
http://www.open-std.org/jtc1/sc22/wg14/docs/rr/dr_113.html Спасибо @ouah!
-
http://opencores.org/ocsvn/openrisc/openrisc/trunk/gnu-old/binutils-2.18.50/gas/testsuite/gas/i386/padlock.d Включил поиск "f3 0f a7" и идентифицирует коды операций как специализированные операции шифрования.
-
Документация GCC "info".
ДОКАЗАТЕЛЬСТВА
-
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. Это много усилий. Удостоверьтесь, что он окупится, прежде чем вы это сделаете.