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