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-10.5.0/gcc/Global-Register-Variables.html