Соглашения о вызовах функции ARMv6
Когда функции (подпрограммы) вызывают другие функции (подпрограммы), они, возможно, должны передать параметры им. Вызванные подпрограммы получают доступ к этим параметрам как к параметрам. С другой стороны некоторые подпрограммы передают результат или возвращаемое значение к их вызывающим сторонам. В среде ARMv6 параметры могут быть переданы стеку этапа выполнения или в регистрах; кроме того, некоторые аргументы вектора также передаются, передал в регистрах. Результаты возвращаются в регистрах или в памяти. Для эффективной передачи значений между вызывающими сторонами и вызываемыми GCC соблюдает строгие правила, когда он генерирует объектный код программы.
Эта статья описывает типы данных, которые могут использоваться для управления параметрами и результатами вызовов подпрограммы, как подпрограммы передают параметры подпрограммам, которые они вызывают, и как подпрограммы, обеспечивающие возвращаемое значение, передают результат своим вызывающим сторонам. Эта статья также перечисляет регистры, доступные в архитектуре ARMv6 и сохраняется ли их значение после вызова подпрограммы.
Функциональные соглашения о вызовах, используемые в среде ARMv6, совпадают с используемыми в Стандарте Вызова процедуры для Архитектуры ARM (выпуск 1.07) за следующими исключениями:
Штабель составляет 4 байта, выровненные при вызовах функции.
Большие типы данных (больше, чем 4 байта) составляют выровненные 4 байта.
Регистр R7 используется в качестве указателя кадра
Регистр R9 имеет специальное использование.
Содержание этой статьи в основном основано на содержании в Стандарте Вызова процедуры для Архитектуры ARM (AAPCS), доступно в http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042c/
Типы данных и выравнивание данных
Используя правильные типы данных для Ваших переменных помогает максимизировать производительность и мобильность Ваших программ. Выравнивание данных указывает, как данные размечаются в памяти. Естественное выравнивание типа данных указывает выравнивание по умолчанию значений того того типа.
Таблица 1 перечисляет ANSI C скалярные типы данных и их размеры и естественное выравнивание в этой среде.
Тип данных | Размер (в байтах) | Естественное выравнивание (в байтах) |
---|---|---|
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 2 | 2 |
| 2 | 2 |
| 4 | 4 |
| 4 | 4 |
| 4 | 4 |
| 4 | 4 |
| 8 | 4 |
| 8 | 4 |
| 4 | 4 |
| 8 | 4 |
| 8 | 4 |
указатель | 4 | 4 |
Это некоторые важные подробные данные об этой среде:
Байт 8 битов длиной.
Нулевой указатель имеет значение
0
.Эта среда использует схему порядка байтов с прямым порядком байтов сохранить числовой и типы данных указателя. Т.е. младшие значащие байты идут сначала, сопровождаемые старшими значащими байтами.
Это правила выравнивания, соблюденные в этой среде:
Скалярные типы данных используют свое естественное выравнивание.
Составные типы данных (массивы, структуры и объединения) берут выравнивание элемента с самым высоким выравниванием. Массив принимает то же выравнивание как свои элементы. Размер составного типа данных является кратным числом своего выравнивания (дополнение может требоваться).
Вызовы функции
Следующие разделы детализируют процесс вызова подпрограммы и передающих параметров к ней, и как возвращаемые значения подпрограмм к их вызывающим сторонам.
Вызывание функции
В iOS можно вызвать подпрограммы с помощью или Ползунка или систем команд ARM. Основное различие между этими системами команд - то, как Вы устанавливаете штабели и списки параметров.
Весь вызов подпрограммы и последовательности возврата должны поддерживать взаимодействие между состояниями Ползунка и ARM. Это означает, что необходимо использовать надлежащее BLX
и BX
инструкции (вместо MOV
инструкция) для всех вызовов к указателям функции. Для получения дополнительной информации об использовании этих инструкций в Ваших вызовах см. документ AAPCS.
Структура штабеля
Среда ARM использует штабель, который — при вызовах функции — составляет выровненные 4 байта, становится нисходящим, и содержит локальные переменные и параметры функции. Рисунок 1 показывает штабель прежде и во время вызова подпрограммы. (Чтобы помочь предотвратить выполнение вредоносного кода на штабеле, лязг защищает штабель от выполнения.)
Указатель вершины стека (SP) указывает на нижнюю часть штабеля. Стековые фреймы содержат следующие области:
Область параметра хранит параметры, которые вызывающая сторона передает вызванной функции или хранит пространство для них, в зависимости от типа каждого параметра и доступности регистров. Эта область находится в стековом фрейме вызывающей стороны.
Область связи содержит адрес следующей инструкции вызывающей стороны.
Сохраненный (дополнительный) указатель кадра содержит базовый адрес стекового фрейма вызывающей стороны.
Локальная область хранения содержит локальные переменные подпрограммы и значения регистров, которые должны быть восстановлены перед вызванными функциональными возвратами. Посмотрите Сохранение Регистра для подробных данных.
Сохраненная область регистров содержит значения регистров, которые должны быть восстановлены перед вызванными функциональными возвратами. Посмотрите Сохранение Регистра для подробных данных.
В этой среде не фиксируется размер стекового фрейма.
Прожурналы и эпилоги
Вызванная подпрограмма ответственна за выделение ее собственного стекового фрейма. Эта работа выполняется разделом кода, названного Прологом, который компилятор помещает перед организацией функции. После организации функции компилятор помещает эпилог для восстановления процесса к состоянию, которым это было до вызова подпрограммы.
Пролог выполняет следующие задачи:
Продвигает значение регистра ссылки (LR) на штабель.
Продвигает значение указателя кадра (R7) на штабель.
Устанавливает указатель кадра (R7) в значение указателя вершины стека (SP). (Обновляющий R7 таким образом дает отладчику способ найти предыдущие стековые фреймы.)
Продвигает значения регистров, которые должны быть сохранены (см. Сохранение Регистра) на штабель.
Выделяет площадь в стековом фрейме для локального хранения.
Эпилог выполняет эти задачи:
Освобождает пространство, использованное для локального хранения в штабеле.
Восстанавливает сохраненные регистры (см. Сохранение Регистра) путем сования значений экономил на штабеле Прологом.
Восстанавливает значение указателя кадра (R7) путем сования его от штабеля.
Возвраты путем сования сохраненного регистра ссылки (LR) в счетчик команд (PC).
Примеры режима ARM
Перечисление 1 показывает пример Пролога в режиме ARM. В этом примере Пролог сохраняет содержание регистров VFP и выделяет дополнительные 36 байтов локального хранения.
Пролог перечисления 1 В качестве примера к ARM (ARMv6)
stmfd sp!, {r4-r7, lr} // save LR, R7, R4-R6 |
add r7, sp, #12 // adjust R7 to point to saved R7 |
stmfd sp!, {r8, r10, r11} // save remaining GPRs (R8, R10, R11) |
fstmfdd sp!, {d8-d15} // save VFP registers D8-D15 |
// (aka S16-S31 aka Q4-Q7) |
sub sp, sp, #36 // allocate space for local storage |
Перечисление 2 показывает пример эпилога в режиме ARM. Этот пример освобождает локальное хранение и восстанавливает регистры, сохраненные в Прологе, показанном в Перечислении 1.
Эпилог перечисления 2 В качестве примера для ARM (ARMv6)
add sp, sp, #36 // deallocate space for local storage |
fldmfdd sp!, {d8-d15} // restore VFP registers |
ldmfd sp!, {r8, r10, r11} // restore R8-R11 |
ldmfd sp!, {r4-r7, pc} // restore R4-R6, saved R7, return to saved LR |
Примеры режима ползунка
Перечисление 3 показывает пример Пролога в Ползунке. В этом примере Пролог не сохраняет энергонезависимые регистры VFP, потому что Ползунок 1 не может получить доступ к тем регистрам.
Пролог перечисления 3 В качестве примера к Ползунку (ARMv6)
push {r4-r7, lr} // save LR, R7, R4-R6 |
mov r6, r11 // move high registers to low registers so |
mov r5, r10 // they can be saved. (Can be skipped if the |
mov r4, r8 // routine does not use R8, R10 or R11) |
push {r4-r6} // save R8, R10, R11 (now in R4-R6) |
add r7, sp, #24 // adjust R7 to point to saved R7 |
sub sp, #36 // allocate space for local storage |
Перечисление 4 показывает возможный эпилог в Ползунке. Этот пример восстанавливает регистры, сохраненные в Прологе, показанном в Перечислении 3.
Эпилог перечисления 4 В качестве примера для Ползунка (ARMv6)
add sp, #36 // deallocate space for local storage |
pop {r2-r4} // pop R8, R10, R11 |
mov r8, r2 // restore high registers |
mov r10, r3 |
mov r11, r4 |
pop {r4-r7, pc} // restore R4-R6, saved R7, return to saved LR |
Передача параметров
Компилятор обычно придерживается правил передачи параметров, найденных в документе AAPCS. Необходимо консультироваться с тем документом для подробных данных того, как параметры передаются, но следующие элементы стоит отметить:
В целом первые четыре скалярных параметра входят в базовые регистры (R0, R1, R2, R3), и любые остающиеся параметры передаются штабелю. Это может не всегда иметь место все же. Для определенных подробных данных о том, как параметры отображаются на регистрах или штабеле, см. документ AAPCS.
Большие типы данных (больше, чем 4 байта) составляют выровненные 4 байта.
Для параметров с плавающей точкой используется Основной Стандартный вариант Стандарта Вызова процедуры. В этом различном, с плавающей точкой (и вектор) параметры передаются в регистрах общего назначения (GPRs) вместо в регистрах VFP),
Возврат результатов
Компилятор обычно придерживается правил передачи параметров, найденных в документе AAPCS. Это означает, что большинство значений возвращается в R0, если размер возвращаемого значения не гарантирует различную обработку. Для получения дополнительной информации см. документ AAPCS.
Сохранение регистра
Таблица 2 перечисляет регистры архитектуры ARM, используемые в этой среде и их энергозависимости в вызовах процедуры. Регистры, которые должны сохранить их значение после вызова функции, вызывают энергонезависимые.
Ввести | Имя | Сохраненный | Примечания |
---|---|---|---|
Регистр общего назначения | R0-R3 | Нет | Эти регистры используются для передачи параметров и результатов. Они доступны для общего использования в подпрограмме и между вызовами функции. |
R4-R6 | Да | ||
R7 | Да | Указатель кадра. Обычно точки к ранее сохраненному стековому фрейму и сохраненному регистру ссылки. | |
R8 | Да | ||
R9 | Особенный | R9 имеет специальные ограничения, описанные ниже. | |
R10-R11 | Да | ||
R12 | Нет | R12 является регистром царапины внутрипроцедуры, также известным как IP. Это используется динамическим компоновщиком и энергозависимо через все вызовы функции. Однако это может использоваться в качестве регистра царапины между вызовами функции. | |
R13 | Особенный | Указатель вершины стека (SP). | |
R14 | Особенный | Регистр ссылки (LR). Набор к обратному адресу на вызове функции. | |
R15 | Особенный | Счетчик команд (PC). | |
Регистр состояния программы | CPSR | Особенный | Биты условия (27-31) и биты GE (16-19) не сохраняются вызовами функции. E укусил, должен остаться нулем (режим с прямым порядком байтов) при вызове или возврате из функции. T укусил, должен только быть установлен подпрограммой ответвления. Все другие биты не должны быть изменены. |
Регистр VFP | D0-D7 | Нет | Также известный как S0-S15. Эти регистры не доступны от режима Thumb на ARMv6. |
D8-D15 | Да | Также известный как S16-S31. Эти регистры не доступны от режима Thumb на ARMv6. | |
Регистр состояния VFP | FPSCR | Особенный | Биты кода условия (28-31) и биты насыщенности (0-4) не сохраняются вызовами функции. Управление исключением (8-12), округляя режим (22-23) и сброс к нулю (24) биты должны быть изменены только определенными подпрограммами, влияющими на состояние приложения (включая API-функции платформы). Короткая векторная длина (16-18) и шаг (20-21) биты должны быть нулем на функциональном входе и выходе. Все другие биты не должны быть изменены. |
Следующие примечания должны также быть учтены относительно использования регистра:
Несмотря на то, что документ AAPCS определяет R7 как энергонезависимый регистр общего назначения, iOS использует его в качестве указателя кадра. Отказ использовать R7 в качестве указателя кадра может препятствовать тому, чтобы отладка и инструменты производительности генерировали допустимые следы. Кроме того, некоторые среды ARM используют мнемонический FP для обращения к R11. В iOS R11 является энергонезависимым регистром общего назначения. В результате термин FP не используется для предотвращения беспорядка.
В iOS 2.x, зарегистрируйтесь, R9 резервируется для использования операционной системы и не должен использоваться кодом приложения. Отказ сделать так может привести к сбоям приложения или аномальному поведению. Однако в iOS 3.0 и позже, зарегистрируйтесь, R9 может использоваться в качестве энергозависимого регистра царапины. Эти инструкции отличаются от общего использования, предусмотренного документом AAPCS.
Доступ к регистрам VFP от режима Thumb (в ARMv6) не поддерживается. При необходимости в доступе к регистрам VFP необходимо выполнить код в режиме ARM. В iOS, переключающемся между режимом ARM и Thumb, может быть сделан только на функциональных границах.