13

関数呼び出しの開始時にリンク レジスタをプッシュし、戻る前にその値をプログラム カウンターにポップする必要があることを理解しています。これにより、関数呼び出しの前の場所から実行が実行できるようになります。

私が理解していないのは、プッシュ/ポップに追加のレジスタを追加することで、ほとんどの人がこれを行う理由です。例えば:

push {ip, lr}
...
pop {ip, pc}

たとえば、ARM の公式ブログで提供されている ARM の Hello World は次のとおりです。

.syntax unified

    @ --------------------------------
    .global main
main:
    @ Stack the return address (lr) in addition to a dummy register (ip) to
    @ keep the stack 8-byte aligned.
    push    {ip, lr}

    @ Load the argument and perform the call. This is like 'printf("...")' in C.
    ldr     r0, =message
    bl      printf

    @ Exit from 'main'. This is like 'return 0' in C.
    mov     r0, #0      @ Return 0.
    @ Pop the dummy ip to reverse our alignment fix, and pop the original lr
    @ value directly into pc — the Program Counter — to return.
    pop     {ip, pc}

    @ --------------------------------
    @ Data for the printf calls. The GNU assembler's ".asciz" directive
    @ automatically adds a NULL character termination.
message:
    .asciz  "Hello, world.\n"

質問 1 : 「ダミー レジスタ」と呼ばれる理由は何ですか? 単純に {lr} を押して {pc} をポップしないのはなぜですか? スタックを 8 バイトに揃えるためだと言われていますが、スタックは 4 バイトに揃えられていませんか?

質問 2 : "ip" とはどのレジスターですか (つまり、r7 ですか?)

4

3 に答える 3

5

彼らがそれを呼ぶ「ダミーレジスタ」の理由は何ですか? 単純に {lr} を押して {pc} をポップしないのはなぜですか? スタックを 8 バイトに揃えるためだと言われていますが、スタックは 4 バイトに揃えられていませんか?

スタックには 4 バイトのアラインメントのみが必要です。ただし、データ バスが 64 ビット幅の場合 (最近の多くの ARM と同様)、8 バイト アラインメントに保つ方が効率的です。次に、たとえば、 2 つのレジスタをスタックする必要がある関数を呼び出す場合、2 回の 32 ビット書き込みではなく、1 回の 64 ビット書き込みで実行できます。

更新: どうやらそれは効率のためだけではありません。コメントに記載されているように、これは公式のプロシージャ コール標準の要件です。

古い 32 ビット ARM をターゲットにしている場合、追加のスタック レジスタによってパフォーマンスがわずかに低下する可能性があります。

「ip」とはどのレジスターですか (つまり、r7 か何か?)

r12. たとえば、プロシージャ コール標準で使用されるレジスタ エイリアスの完全なセットについては、こちらを参照してください。

于 2013-04-20T12:32:49.583 に答える