6.47.5.1 Определение глобальных регистровых переменных
Вы можете определить глобальную регистровую переменную и связать ее со специфицированным регистром следующим образом:
register int *foo asm ("r12");
Здесь r12 — имя регистра, который должен использоваться. Обратите внимание, что это тот же синтаксис, который используется для определения локальных регистровых переменных, но для глобальной переменной объявление находится вне функции. Ключевое слово register обязательно и не может быть комбинировано с static. Имя регистра должно быть допустимым именем регистра для целевой платформы.
Не используйте квалификаторы типа, такие как const и volatile, так как результат может быть не таким, как ожидалось. В частности, использование квалификатора volatile не полностью предотвращает компилятор от оптимизации доступа к регистру.
Регистры являются ограниченным ресурсом на большинстве систем, и предоставление компилятору возможности управлять их использованием обычно приводит к лучшему коду. Однако в особых случаях может иметь смысл зарезервировать некоторые глобально. Например, это может быть полезно в программах, таких как интерпретаторы языков программирования, которые имеют несколько глобальных переменных, к которым часто обращаются.
После определения глобальной регистровой переменной для текущего блока компиляции:
- Если регистр — регистр, сохраняемый при вызове функции, то это влияет на ABI вызова: регистр не будет восстановлен в последовательностях эпилога функций после того, как переменной было присвоено значение. Поэтому функции не могут безопасно вернуться к вызывающим сторонам, которые предполагают стандартный ABI.
- Напротив, если регистр — регистр, уничтожаемый при вызове функции, то создание вызовов функциям, использующим стандартный ABI, может привести к потере содержимого переменной. Такие вызовы могут создаваться компилятором даже если они не видны в исходной программе, например, когда функции libgcc используются для компенсации отсутствующих инструкций.
- Доступ к переменной может быть оптимизирован как обычно, и регистр остается доступным для выделения и использования в любых вычислениях, при условии, что наблюдаемые значения переменной не изменяются.
- Если переменная ссылается на встроенное ассемблерное кодирование, тип доступа должен быть предоставлен компилятору через ограничения (см. Ограничения для операндов
asm). Доступ из базовых ассемблерных инструкций не поддерживается.
Обратите внимание, что эти пункты только применяются к коду, который компилируется с этим определением. Поведение кода, который просто подключается (например, код из библиотек), не изменяется.
Если вы хотите перекомпилировать исходные файлы, которые фактически не используют вашу глобальную регистровую переменную, чтобы они не использовали указанный регистр для любой другой цели, вам не нужно фактически добавлять объявление глобального регистра в их исходный код. Достаточно указать параметр компилятора -ffixed-reg (см. Параметры для конвенций генерации кода) для резервирования регистра.
Объявление переменной
Глобальные регистровые переменные не могут иметь начальных значений, потому что исполняемый файл не имеет способа предоставить начальное содержимое для регистра.
При выборе регистра выберите тот, который обычно сохраняется и восстанавливается вызовами функций на вашей машине. Это гарантирует, что код, который не знает об этом резервировании (например, библиотечные функции), восстановит его перед возвратом.
На машинах с окнами регистров убедитесь, что выбранный глобальный регистр не изменяется магическим образом механизмом вызова функции.
Использование переменной
При вызове процедур, которые не знают об этом резервировании, будьте осторожны, если эти процедуры вызывают код, который использует их. Например, если вы вызываете системную библиотечную версию qsort, она может перезаписать ваши регистры во время выполнения, но (если вы выбрали соответствующие регистры) она восстановит их перед возвратом. Однако она не восстановит их перед вызовом сравнительной функции qsort. В результате глобальные значения не будут надёжно доступны сравнительной функции, если сама функция qsort не перекомпилирована.
Аналогично, не безопасно обращаться к глобальным регистровым переменным из обработчиков сигналов или из более чем одной потоковой задачи. Если вы не перекомпилируете их специально для данной задачи, системные библиотечные процедуры могут временно использовать регистр для других целей. Кроме того, поскольку регистр не зарезервирован исключительно для переменной, обращение к нему из обработчиков асинхронных сигналов может привести к наблюдению не относящихся к делу временных значений, находящихся в регистре.
На большинстве машин longjmp восстанавливает для каждой глобальной регистровой переменной значение, которое у неё было в момент setjmp. Однако на некоторых машинах longjmp не изменяет значение глобальных регистровых переменных. Для обеспечения переносимости функция, которая вызвала setjmp, должна принять другие меры для сохранения значений глобальных регистровых переменных и их восстановления в longjmp. Таким образом, происходит то же самое, независимо от того, что longjmp делает.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-13.3.0/gcc/Global-Register-Variables.html