ARM сборка. Безопасно ли использовать r13 (указатель стека) в качестве регистра общего назначения? - PullRequest
2 голосов
/ 06 марта 2019

Я пишу чрезвычайно оптимизированную конечную функцию, и чтобы она работала быстрее, я хочу использовать R13 в качестве регистра общего назначения.Я сохраняю R13, перемещая его в один из регистров VFP перед его использованием, и прежде чем вернуться из функции, я восстанавливаю его, перемещая обратно.Это выглядит так:

/* Start of the function */
push { r4 - r12, r14 }
vmov s0, r13
/* Body of the function. Here I use R13
 * as a general purpose register */
vmov r13, s0
pop { r4 - r12, r14 }
bx lr

И это работает.Но я читал, что некоторые операционные системы предполагают, что R13 всегда используется в качестве указателя стека, и использование его в качестве регистра общего назначения может вызвать сбои.Следует также сказать, что эта функция предназначена для запуска только на Android (Linux).Спасибо!

Ответы [ 2 ]

5 голосов
/ 06 марта 2019

Очевидно, вы должны учитывать это, только если вы уже используете все другие регистры GP, включая lr, и не можете перенести часть своей работы в регистры NEON например, использование упакованного целого числа, даже если вы заботитесь только о младших 32 битах.

(Использование SIMD-регистров для большего скалярного целого числа обычно полезно, только если в вашем алгоритме есть изолированный набор значений, которые не взаимодействуют с другими значениями, и вам не нужно переходить на них или использовать их в качестве указателей На некоторых процессорах ARM медленная передача между int и SIMD.)

Это очень нестандартный и только возможно безопасный в пользовательском пространстве, а не ядро ​​


Если у вас установлены обработчики сигналов, указатель стека должен быть действителен при поступлении одного из этих сигналов. (И это асинхронно.)

В Linux нет другого асинхронного использования указателя стека пользовательского пространства, кроме обработчиков сигналов. (За исключением случаев, когда вы отлаживаете с помощью GDB и используете print foo(123), где foo - функция в целевом процессе .)

Как уже упоминалось в комментариях к Могу ли я использовать rsp в качестве регистра общего назначения (эквивалент этого вопроса в x86-64), есть обходной путь даже для сигналов:

Используйте sigaltstack для настройки альтернативного стека и укажите SA_ONSTACK в флагах для sigaction при установке обработчика.

Как указывает @Timothy, если ваше начальное значение SP может быть целым числом, которое оказывается "точкой" в стеке alt, механизм диспетчеризации сигнала будет предполагать, что это вложенный сигнал, а не будет изменить SP (потому что в фактическом случае вложенного сигнала это перезапишет первый обработчик сигнала, все еще используемый в стеке). Таким образом, вы можете находиться на расстоянии push от SP, переходя на непопечатанную страницу, если только вы не выделите в два раза больше, чем вам нужно, и только передаете верхнюю половину на sigaltstack. (Может быть, только 2 КБ или 4 КБ для простых обработчиков сигналов, которые возвращаются после небольшого выполнения).

Это должно быть безопасно даже для вложенных сигналов: только самый внешний обработчик сигналов может запускаться около нижней части стека alt и использовать часть выделенного пространства за пределами фактического altstack. Другой сигнал будет использовать пространство ниже этого, если SP все еще находится в пределах altstack. Или он будет использовать верхнюю часть altstack, если SP вышел за пределы altstack.

Или вы можете избежать необходимости такого перераспределения, используя SP для хранения указателя на что-то другое, что определенно не является стеком alt, если любой из ваших регистров GP должен быть указателем. Наличие это будет действительный указатель, открывающий вас к повреждению, а не к сбоям, если отладчик для чего-то использует текущий SP, или если вы неправильно используете механизм altstack. Но это только разница в режиме отказа: либо катастрофически.


Аппаратные прерывания сохраняют состояние сохранения в стеке ядра, а не в стеке пользовательского пространства . Если они использовали пользовательский стек:

  1. пространство пользователя может привести к сбою ОС при наличии недопустимого SP.
  2. пространство пользователя может получить привилегии ядра, если другой поток пространства пользователя изменит данные стека ядра (включая адреса возврата).

(Все потоки пользовательского пространства процесса совместно используют одну и ту же таблицу страниц и могут читать / записывать сопоставления стека друг друга.)

Linux / Android очень отличается от облегченной ОСРВ без виртуальной памяти или строгого принудительного разделения привилегий.

1 голос
/ 06 марта 2019

Когда переключатель контекста / irq сработает во время выполнения вашего кода, OS / hw, вероятно, предположит, что R13 является TOS, поэтому он сохранит его в идее, что он может восстановить TOS, когда возобновит выполнение.

Это может быть проблемой в вашем случае.

Разумным подходом было бы сделать кусок кода критическим и каким-то образом заставить системный тик / irq отложиться до завершения процедуры / восстановления R13.

Возможно, вам лучше использовать LR(R14), если вам действительно нужен дополнительный регистр.

...