6.44.1 Определение глобальных регистровых переменных
Глобальную регистровую переменную в GNU C можно определить так:
register int *foo asm ("a5"); Здесь a5 — имя регистра, который следует использовать. Выберите регистр, который обычно сохраняется и восстанавливается вызовами функций на вашей машине, чтобы библиотечные процедуры не перезаписывали его.
Естественно, имя регистра зависит от процессора, поэтому необходимо условное ветвление в вашей программе в зависимости от типа процессора. Регистр a5 — хороший выбор для переменной типа указатель на 68000. На машинах с оконными регистрами убедитесь, что выбранный «глобальный» регистр не изменяется волшебным образом механизмом вызова функций.
Кроме того, разные операционные системы на одном и том же процессоре могут по-разному называть регистры; тогда вам потребуются дополнительные условные ветвления. Например, в некоторых операционных системах для 68000 этот регистр называется %a5.
В конечном итоге может появиться способ попросить компилятор автоматически выбрать регистр, но сначала нам нужно понять, как он должен выбрать и как позволить вам направить выбор. Очевидного решения нет.
Определение глобальной регистровой переменной в определенном регистре полностью резервирует этот регистр для этого использования, по крайней мере, в рамках текущей компиляции. Регистр не выделяется ни для каких других целей в функциях текущей компиляции и не сохраняется и не восстанавливается этими функциями. Записи в этот регистр никогда не удаляются, даже если они, по-видимому, «мертвы», но ссылки могут быть удалены, перемещены или упрощены.
Доступ к глобальным регистровым переменным из обработчиков сигналов или из более чем одной потоковой задачи небезопасен, поскольку системные библиотечные процедуры могут временно использовать регистр для других целей (если вы не перекомпилируете их специально для данной задачи).
Небезопасно для одной функции, использующей глобальную регистровую переменную, вызывать другую такую функцию foo через третью функцию lose, которая компилируется без знания этой переменной (т. е. в другом исходном файле, в котором переменная не объявлена). Это происходит потому, что lose может сохранить регистр и поместить туда другое значение. Например, вы не можете ожидать, что глобальная регистровая переменная будет доступна в функции сравнения, которую вы передаете в qsort, так как qsort могла поместить в этот регистр что-то другое. (Если вы готовы перекомпилировать qsort с той же глобальной регистровой переменной, вы можете решить эту проблему.)
Если вы хотите перекомпилировать qsort или другие исходные файлы, которые фактически не используют вашу глобальную регистровую переменную, чтобы они не использовали этот регистр для других целей, достаточно указать параметр компилятора -ffixed-reg. Вам не нужно фактически добавлять объявление глобальной регистровой переменной в их исходный код.
Функцию, которая может изменить значение глобальной регистровой переменной, нельзя безопасно вызывать из функции, скомпилированной без этой переменной, потому что она может перезаписать значение, которое вызывающий код ожидает найти там при возврате. Поэтому функция, являющаяся точкой входа в часть программы, использующей глобальную регистровую переменную, должна явно сохранить и восстановить значение, которое принадлежит её вызывающей стороне.
На большинстве машин longjmp восстанавливает для каждой глобальной регистровой переменной значение, которое она имела в момент setjmp. Однако на некоторых машинах longjmp не изменяет значение глобальных регистровых переменных. Для обеспечения переносимости функция, вызвавшая setjmp, должна принять другие меры для сохранения значений глобальных регистровых переменных и восстановления их в longjmp. Таким образом, происходит то же самое независимо от того, что делает longjmp.
Все объявления глобальных регистровых переменных должны предшествовать всем определениям функций. Если такое объявление могло бы появиться после определений функций, оно было бы слишком поздно, чтобы предотвратить использование регистра для других целей в предшествующих функциях.
Глобальные регистровые переменные не могут иметь начальных значений, поскольку исполняемый файл не имеет способов обеспечить начальное содержимое для регистра.
На SPARC есть сообщения о том, что регистры g3 ... g7 являются подходящими, но некоторые библиотечные функции, такие как getwd, а также подпрограммы для деления и остатка, изменяют g3 и g4. g1 и g2 являются локальными временными переменными.
На 68000 a2 ... a5 должны быть подходящими, как и d2 ... d7. Конечно, не следует использовать более нескольких из них.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gcc/Global-Reg-Vars.html