6.47.5.1 Определение глобальных регистровых переменных
Вы можете определить глобальную регистровую переменную и связать её со специфическим регистром так:
register int *foo asm ("r12");
Здесь r12 — имя регистра, который следует использовать. Обратите внимание, что это тот же синтаксис, что и для определения локальных регистровых переменных, но для глобальной переменной объявление находится вне функции. Ключевое слово register обязательно и не может быть совмещено с static. Имя регистра должно быть валидным именем регистра для целевой платформы.
Не используйте квалификаторы типов, такие как const и volatile, так как результат может быть неожиданным. В частности, использование квалификатора volatile не полностью предотвращает компилятор от оптимизации доступа к регистру.
Регистры являются дефицитным ресурсом на большинстве систем, и предоставление компилятору управления их использованием обычно приводит к лучшему коду. Однако в особых случаях может иметь смысл зарезервировать некоторые глобально. Например, это может быть полезно в программах, таких как интерпретаторы языков программирования, которые имеют несколько глобальных переменных, к которым часто обращаются.
После определения глобальной регистровой переменной для текущей единицы компиляции:
- Если регистр является регистром, сохраняемым при вызовах (call-saved register), ABI вызова затронут: регистр не будет восстановлен в последовательностях эпилога функций после присвоения переменной. Следовательно, функции не могут безопасно возвращаться вызывающим сторонам, которые предполагают стандартный ABI.
- И наоборот, если регистр является регистром, уничтожаемым при вызовах (call-clobbered register), выполнение вызовов функций, использующих стандартный ABI, может привести к потере содержимого переменной. Такие вызовы могут создаваться компилятором даже если они не очевидны в исходной программе, например, при использовании функций libgcc для компенсации отсутствующих инструкций.
- Доступ к переменной может быть оптимизирован как обычно, и регистр остаётся доступным для распределения и использования в любых вычислениях при условии, что наблюдаемые значения переменной не изменяются.
- Если переменная используется в inline assembly, тип доступа должен быть предоставлен компилятору через ограничения (см. Ограничения). Доступ из basic asms не поддерживается.
Обратите внимание, что эти пункты только применяются к коду, который компилируется с определением. Поведение кода, который просто подключается (например, код из библиотек), не затрагивается.
Если вы хотите перекомпилировать исходные файлы, которые фактически не используют вашу глобальную регистровую переменную, чтобы они не использовали указанный регистр для других целей, вам не нужно фактически добавлять объявление глобальной регистровой переменной в их исходный код. Достаточно указать опцию компилятора -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-12.2.0/gcc/Global-Register-Variables.html