61

最後にアームアセンブラをコーディングしてからしばらく経ちましたが、詳細については少しさびています。arm から C 関数を呼び出すと、r0-r3 と lr を保存することだけを気にする必要がありますよね?

C関数が他のレジスタを使用する場合、それらをスタックに保存して復元する責任がありますか? つまり、コンパイラは、C 関数に対してこれを行うコードを生成します。

たとえば、アセンブラ関数で r10 を使用する場合、その値をスタックまたはメモリにプッシュし、C 呼び出しの後にポップ/復元する必要はありませんか?

これは arm-eabi-gcc 4.3.0 用です。

4

5 に答える 5

81

コンパイルするプラットフォームのABIによって異なります。Linuxには、2つのARMABIがあります。古いものと新しいもの。AFAIK、新しいもの(EABI)は、実際にはARMのAAPCSです。完全なEABI定義は、現在ARMのインフォセンターにあります。

AAPCSから、§5.1.1

  • r0-r3は、引数レジスタとスクラッチレジスタです。r0-r1は結果レジスタでもあります
  • r4-r8は呼び出し先保存レジスタです
  • r9は、呼び出し先保存レジスターである場合とそうでない場合があります(AAPCSの一部のバリアントでは、特殊レジスターです)。
  • r10-r11は呼び出し先保存レジスタです
  • r12-r15は特殊レジスターです

呼び出し先保存レジスターは、呼び出し先が保存する必要があります(呼び出し元がレジスターを保存する呼び出し元保存レジスターとは対照的)。したがって、これが使用しているABIである場合、別の関数を呼び出す前にr10を保存する必要はありません(他の関数がそれを保存する責任があります)。

編集:使用しているコンパイラに違いはありません。特にgccは、いくつかの異なるABI用に構成でき、コマンドラインで変更することもできます。生成されるプロローグ/エピローグコードを見ると、関数ごとに調整されており、コンパイラーはレジスターを保存する他の方法(たとえば、関数の途中で保存する)を使用できるため、それほど有用ではありません。


用語:「callee-save」は「non-volatile」または「call-preserved」の同義語です:calleeとcallerが保存したレジスタとは何ですか?
関数呼び出しを行うとき、r4-r11(おそらくr9を除く)の値は(call-preserved)の後も残っていると想定できますが、r0-r3(call-clobbered / volatile)はそうではありません。

于 2008-11-04T10:46:02.167 に答える
27

32 ビット ARM 呼び出し規約はAAPCSによって指定されています

AAPCSから、§5.1.1 コア レジスタ:

  • r0 ~ r3は、引数およびスクラッチ レジスタです。r0-r1は結果レジスタでもあります
  • r4-r8は呼び出し先保存レジスタです。
  • r9は callee-save レジスターである場合とそうでない場合があります (AAPCS の一部のバリアントでは、これは特殊レジスターです)。
  • r10-r11は呼び出し先保存レジスタです。
  • r12~r15は特殊レジスタ

AAPCS から、§5.1.2.1 VFP レジスタの使用規則:

  • s16–s31 (d8–d15, q4–q7)は保存する必要があります
  • s0–s15 (d0–d7, q0–q3)およびd16–d31 (q8–q15)は保存する必要はありません

元の投稿:
arm-to-c-calling-convention-neon-registers-to-save


64 ビット ARM 呼び出し規約はAAPCS64で指定されています

汎用レジスタセクションでは、保持する必要があるレジスタを指定します。

  • r0r7はパラメータ/結果レジスタです
  • r9r15は一時レジスタ
  • r19r28は、呼び出し先保存レジスタです。
  • 他のすべて ( r8r16 - r18r29r30SP ) は特別な意味を持ち、一時レジスタとして扱われるものもあります。

SIMD および浮動小数点レジスターは、Neon および浮動小数点レジスターを指定します。

于 2011-03-29T04:44:50.660 に答える
20

64 ビット ARM、A64の場合(ARM 64 ビット アーキテクチャのプロシージャ コール標準より)

A64 命令セットから見える 31 個の 64 ビット汎用 (整数) レジスタがあります。これらはr0-r30とラベル付けされています。64 ビットのコンテキストでは、これらのレジスタは通常x0-x30という名前を使用して参照されます。32 ビットのコンテキストでは、レジスタはw0-w30を使用して指定されます。さらに、スタック ポインター レジスターSPは、限られた数の命令で使用できます。

  • SPスタックポインタ
  • r30 LR リンク レジスタ
  • r29 FP フレーム ポインタ
  • r19…r28呼び出し先保存レジスタ
  • r18必要に応じて、プラットフォーム レジスタ。それ以外の場合は、一時レジスター。
  • r17 IP1 2 番目のプロシージャー呼び出し内一時レジスター (呼び出しベニアおよび PLT コードで使用できます)。それ以外の場合は、一時レジスターとして使用できます。
  • r16 IP0 最初のイントラプロシージャ コール スクラッチ レジスタ (コール ベニアおよび PLT コードで使用できます)。それ以外の場合は、一時レジスターとして使用できます。
  • r9…r15一時レジスタ
  • r8間接結果格納レジスタ
  • r0…r7パラメータ/結果レジスタ

最初の 8 つのレジスタr0 ~ r7は、引数値をサブルーチンに渡し、関数から結果値を返すために使用されます。また、ルーチン内で中間値を保持するために使用することもできます (ただし、一般的には、サブルーチン呼び出し間のみ)。

レジスタr16 (IP0)r17 (IP1)は、リンカによって、ルーチンとそれが呼び出すサブルーチンの間のスクラッチ レジスタとして使用できます。また、サブルーチン呼び出し間の中間値を保持するために、ルーチン内で使用することもできます。

レジスタr18の役割はプラットフォーム固有です。プラットフォーム ABI で、プロシージャ間の状態 (スレッド コンテキストなど) を運ぶ専用の汎用レジスタが必要な場合は、その目的のためにこのレジスタを使用する必要があります。プラットフォーム ABI にそのような要件がない場合は、追加の一時レジスタとして r18 を使用する必要があります。プラットフォーム ABI 仕様は、このレジスターの使用法を文書化する必要があります。

SIMD

ARM 64 ビット アーキテクチャには、さらに 32 個のレジスタv0-v31があり、SIMD および浮動小数点演算で使用できます。レジスタの正確な名前は、アクセスのサイズを示すように変更されます。

注: AArch32 とは異なり、AArch64 では、SIMD および浮動小数点レジスタの 128 ビットおよび 64 ビット ビューは、より狭いビューで複数のレジスタをオーバーラップしないため、q1、d1、および s1 はすべてレジスタ内の同じエントリを参照します。銀行。

最初の 8 つのレジスタv0-v7は、引数値をサブルーチンに渡し、関数から結果値を返すために使用されます。また、ルーチン内で中間値を保持するために使用することもできます (ただし、一般的には、サブルーチン呼び出し間のみ)。

レジスタv8 ~ v15は、サブルーチン呼び出し間で呼び出し先によって保持される必要があります。残りのレジスター ( v0-v7、v16-v31 ) は保持する必要はありません (または呼び出し元が保持する必要があります)。さらに、 v8 ~ v15に格納されている各値の下位 64 ビットのみを保持する必要があります。より大きな値を保持するのは呼び出し元の責任です。

于 2015-04-13T10:23:23.507 に答える