Что регистрирует для сохранения в Конвенции вызова ARM C?

прошло некоторое время с тех пор, как я последний раз кодировал ARM assembler, и я немного заржавел в деталях. Если я вызываю функцию C из arm, мне нужно только беспокоиться о сохранении r0-r3 и lr, верно?

Если функция C использует любые другие регистры, отвечает ли она за сохранение и восстановление этих регистров в стеке? Другими словами, компилятор будет генерировать код для этого для функций C.

например, если я использую r10 в функции ассемблера, мне не нужно нажимать его значение в стеке или в память и pop / restore его после вызова C, не так ли?

Это для arm-eabi-gcc 4.3.0.

5 ответов


зависит от ABI для платформы, для которой вы компилируете. В Linux есть два ARM ABIs; старый и новый. AFAIK, новый (EABI) на самом деле является AAPCS ARM. Полные определения EABI в настоящее время живут здесь на инфоцентре ARM.

с AAPCS, §5.1.1:

  • r0-r3 являются регистры аргументов и царапин;r0-r1 также в результате регистры
  • r4-r8 являются callee-сохранить регистры
  • r9 может быть вызываемый-сохранить регистр или нет (на некоторых вариантах AAPCS это специальный регистр)
  • r10-r11 являются callee-сохранить регистры
  • r12-r15 специальные регистры

вызываемый-сохранить регистр должен быть сохранен вызываемым (в отличие от вызывающего-сохранить регистр, где вызывающий сохраняет Регистрация); Итак,если это ABI, который вы используете, вам не нужно сохранять r10 перед вызовом другой функции (другая функция отвечает за ее сохранение).

Edit: какой компилятор вы используете, не имеет значения; gcc, в частности, может быть настроен для нескольких разных ABIs, и его можно даже изменить в командной строке. Просмотр кода пролога/эпилога, который он генерирует, не так полезен, поскольку он адаптирован для каждой функции и компилятор может использовать другие способы сохранения регистра (например, сохранение ее в процессе выполнения функции).


чтобы добавить недостающую информацию о неоновых регистрах:

с в ААСУП, §5.1.1 базовые регистры:

  • r0-r3 являются регистры аргументов и царапин;r0-r1 также являются регистрами результатов
  • r4-r8 являются callee-сохранить регистры
  • r9 может быть вызываемый сохранить реестр или нет (на некоторые варианты ААСУП это особый Регистрация)
  • r10-r11 являются callee-сохранить регистры
  • от R12-R15 на специальные регистры

из AAPCS, §5.1.2.1 соглашения об использовании регистра VFP:

  • s16-s31 (d8–d15, q4–q7) необходимо сохранить
  • s0-s15 (d0–d7, q0–q3) и d16–d31 (q8-q15) не нужно сохранять

Оригинал сообщение:
рука-к-с-вызова-конференц-неон-регистры-чтобы-сохранить


для 64-битного ARM, A64 (из стандартного вызова процедуры для 64-разрядной архитектуры ARM)

существует тридцать один, 64-разрядный, общего назначения (целое число) регистры, видимые для набора команд A64; они помечены r0-r30. В 64-разрядном контексте эти регистры обычно ссылаются на использование имен x0-x30; в 32-разрядном контексте регистры задаются с помощью В0-камера W30. Кроме того, регистр указателя стека, SP, может использоваться с ограниченным количеством инструкций.

  • SP Указатель Стека
  • r30 LR ссылка Регистрация
  • r29 FP указатель кадра
  • r19...r28 Callee-сохраненные регистры
  • r18 регистр платформы, если необходимо; в противном случае временный регистр.
  • r17 iP1 является второй intra-procedure-вызов временного регистра (может использоваться винирами и кодом PLT); в другое время может использоваться как временный регистр.
  • r16 IP0 первый регистр царапин intra-procedure-call (может использоваться вызовом облицовки и код ПЛТ); в другое время смогите быть использовано как а временный регистр.
  • r9...r15 временные регистры
  • r8 косвенный результат место регистрации
  • r0...r7 Регистры параметров / результатов

первые восемь регистров, r0-r7, используются для передачи значений параметров в подпрограмму и возврата значений из функции. Они также могут использоваться для хранения промежуточных значений в подпрограмме (но, как правило, только между вызовами подпрограмм).

регистры r16 (IP0) и П17 (iP1 является) может использоваться компоновщиком в качестве регистра нуля между подпрограммой и любой вызываемой подпрограммой. Они может также использоваться в подпрограмме для хранения промежуточных значений между вызовами подпрограмм.

роль регистра r18 специфическая платформа. Если платформа ABI нуждается в специальном регистре общего назначения для выполнения межпроцедурного состояния (например, контекст потока), то она должна использовать этот регистр для этой цели. Если платформа ABI не имеет таких требований, то она должна использовать r18 в качестве дополнительного временного регистра. Спецификация платформы ABI должна документируйте использование этого регистра.

SIMD

64-разрядная архитектура ARM также имеет еще тридцать два регистра,v0 в-v31, который может использоваться SIMD и операциями с плавающей запятой. Точное название регистра изменится с указанием размера доступа.

Примечание: В отличие от AArch32, в AArch64 128-разрядные и 64-разрядные представления регистра SIMD и с плавающей запятой не перекрывают несколько регистров в более узкий взгляд,таким образом, q1, d1 и s1 относятся к одной и той же записи в банке регистров.

первые восемь регистров, v0 в-В7, используются для передачи значений параметров в подпрограмму и возврата значений из функции. Они также могут использоваться для хранения промежуточных значений в подпрограмме (но, как правило, только между вызовами подпрограмм).

регистры В8-программы V15 должен быть сохранен вызываемым через вызовы подпрограмм; остальные регистры (v0 в-В7, V16 под-v31) не должны быть сохранены (или должны быть сохранены абонента). Кроме того, только нижние 64-бит каждого значения хранятся в В8-программы V15 необходимо сохранить; это ответственность вызывающего абонента, чтобы сохранить большие значения.


ответы Цезарба и Павла предоставили цитаты из AAPCS,но открытые вопросы остаются. Вызываемый абонент сохраняет r9? Насчет П12? Насчет С14? Кроме того, ответы были очень общими, а не конкретными для цепочки инструментов arm-eabi, как было запрошено. Вот практический подход, чтобы узнать, какие регистры являются callee-saved, а какие нет.

следующий код C содержит встроенный сборочный блок, который утверждает, что изменяет регистры r0-r12 и r14. Компилятор будет генерировать код для сохранения регистров, требуемых ABI.

void foo() {
  asm volatile ( "nop" : : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14");
}

используйте командную строку arm-eabi-gcc-4.7 -O2 -S -o - foo.c и добавьте переключатели для вашей платформы (например,-mcpu=arm7tdmi например). Команда напечатает сгенерированный код сборки на STDOUT. Это может выглядеть примерно так:

foo:
    stmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
    nop
    ldmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
    bx  lr

обратите внимание, что сгенерированный компилятором код сохраняет и восстанавливает r4-r11. Компилятор не сохраняет r0-r3, r12. То, что он восстанавливает r14 (псевдоним lr), является чисто случайным, поскольку я знаю по опыту, что код выхода может также загрузить сохраненный lr в r0, а затем сделать "bx r0 "вместо"bx lr". Либо добавив -mcpu=arm7tdmi -mno-thumb-interwork и с помощью -mcpu=cortex-m4 -mthumb мы получаем немного другой код сборки, который выглядит следующим образом:

foo:
    stmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
    nop
    ldmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc}

опять же, R4-r11 сохраняются и восстанавливаются. Но r14 (псевдоним lr) не восстанавливается.

подведем итоги:

  • r0-r3 являются не callee-saved
  • R4-r11 являются callee-saved
  • r12 (псевдоним ip) является не callee-saved
  • R13 (псевдоним sp) является callee-saved
  • r14 (псевдоним lr) является не callee-saved
  • r15 (псевдоним pc) является счетчиком программы и имеет значение lr до вызова функции

это имеет место, по крайней мере, для ARM-eabi-GCC по умолчанию. Существуют переключатели командной строки (в частности, переключатель-mabi), которые могут влиять на результаты.


существует также разница, по крайней мере, по архитектуре Cortex M3 для вызова функции и прерывания.

Если прерывание происходит, то оно сделает автоматический нажим R0-R3,R12,LR,ПК на стог и когда возвращенный поп формы IRQ автоматический. Если вы используете другие регистры в IRQ routine, вы должны нажать/вставить их в стек вручную.

Я не думаю, что этот автоматический толчок и поп сделаны для вызова функции (инструкция перехода). Если соглашение говорит, что R0-R3 может использоваться только как аргумент, результат или scratch регистры, поэтому нет необходимости хранить их перед вызовом функции, потому что не должно быть никакого значения, используемого позже после возврата функции. Но так же, как и в прерывании, вы должны хранить все другие регистры процессора, если вы используете их в своей функции.