ARM: Зачем мне нужно вызывать/записывать два регистра при вызовах функций?
Я понимаю, что мне нужно нажать Link Register в начале вызова функции и поместить это значение в Program Couter перед возвратом, так что выполнение может нести одно из того, где оно было до вызова функции.
Я не понимаю, почему большинство людей делают это, добавляя дополнительный регистр в push/pop. Например:
push {ip, lr}
...
pop {ip, pc}
Например, здесь Hello World в ARM, предоставленном официальным блоком ARM
Вопрос 1: какая причина для "фиктивного регистра", как они его называют? Почему бы просто не нажать {lr} и pop {pc}? Говорят, что он поддерживает выравнивание в 8 байт, но не соответствует ли 4-байтовый стек?
Вопрос 2: какой регистр является "ip" (т.е. r7 или что?)
Ответы
Ответ 1
какая причина для "фиктивного регистра", как они его называют? Почему бы просто не нажать {lr} и pop {pc}? Говорят, что он поддерживает выравнивание в 8 байт, но не соответствует ли 4-байтовый стек?
Стек требует только 4-байтового выравнивания; но, если шина данных имеет ширину 64 бита (как на многих современных ARM), более эффективно поддерживать ее при 8-байтовом выравнивании. Затем, например, если вы вызываете функцию, которая должна складывать два регистра, это можно сделать в одной 64-разрядной записи вместо двух 32-разрядных записей.
ОБНОВЛЕНИЕ: По-видимому, это не только для эффективности; это требование официального стандартного вызова процедуры, как указано в комментариях.
Если вы нацеливаете старые 32-битные ARM, то дополнительный стековый регистр может немного ухудшить производительность.
какой регистр является "ip" (т.е. r7 или что?)
r12
. См., Например, здесь для полного набора псевдонимов регистра, используемых стандартом вызова процедуры.
Ответ 2
8-байтовое выравнивание является требованием для взаимодействия между объектами, соответствующими AAPCS.
У ARM есть консультативная записка по этому вопросу:
ABI для ARM® Architecture Advisory Note - SP должен быть 8-байтовым, выровненным при входе в AAPCS-совместимые функции
В статье упоминаются две причины использования 8-байтового выравнивания
-
Ошибка выравнивания или непобедимое поведение. (Связанные с оборудованием/архитектурой причины - LDRD/STRD может вызвать ошибку выравнивания или показать поведение НЕПРЕРЫВНОСТИ на архитектурах, отличных от ARMv7)
-
Ошибка приложения. (Компилятор - различия в допуске Runtime, они дают в качестве примера va_start
и va_arg
)
Конечно, это все об открытых интерфейсах, если вы делаете статический исполняемый файл без дополнительной привязки, вы можете выровнять стек с 4 байтами.
Ответ 3
Поскольку вы хотите сохранить и восстановить их после выполнения своей функции.
На входе функции он сохраняет регистры ip
и lr
(с именем prolog
).
После завершения функции он назначает оба (epilog
):
pc <- lr
ip <- old_ip
ИЗМЕНИТЬ
Регистр r12
также упоминается как ip
и используется как регистр ошибок внутри процедуры процедуры, см. .
Согласие заключается в том, что функция вызываемого абонента может изменить ip,r0-r3
, поэтому вы должны восстановить их, зависит от соглашения о вызовах
EDIT2:
Почему мы можем захотеть, чтобы стек был выровнен по 8 на ARM.
Если стек не выравнивается по восемью байтам, использование LDRD и STRD (загрузка и сохранение двойного слова) может вызывают ошибку выравнивания, в зависимости от цели и конфигурации б.
Заметьте что у нас такая же проблема на X86, и на Mac OS у нас есть выравнивание по 16 байт