私はC関数の魔女が次のように見えます:
int foo(int a, long long b);
アームアセンブリから呼び出そうとしていますが、2番目のパラメータ(long long
)の処理方法がわかりません。
ARM EABI / AAPCSは、64ビットタイプを互いに隣接する2つのレジスタで渡す必要があり、最初のレジスタには偶数番号を付ける必要があることを指定しています。リトルエンディアンモードでは、高い部分は高い番号のレジスタにあり、低い部分は低い番号のレジスタにあります。ビッグエンディアンモードでは、その逆です。
両方の要件は、strd / ldrd命令に対応するためのものであり、1つの命令で2つのレジスタを保存できます。
したがって、リトルエンディアンモードで例の0x0123456789abcdefを渡すには、次の方法でレジスタをロードする必要があります。
mov r0, a
// R1 is unused
ldr r2, =0x89abcdef
ldr r3, =0x01234567
(注意:間違った答え。コメントに情報が含まれているため、削除できません)
ARM ABIによると、2番目のパラメータはレジスタr1
とで渡されますr2
。マシンがリトルエンディアンの場合は、低い部分r1
と高い部分を渡しますr2
(これがビッグエンディアンのマシンの場合と反対かどうかはわかりません)。したがって、0x123456789abcdなどのパラメーターを使用して関数を呼び出すには、次のようにします。
MOV r0, ... (the value of "a")
MOV r1, #0x6789abcd
MOV r2, #0x12345
... (call the function)
コンパイラに聞いてみれば、すべてがわかります...
int foo ( int a, long long b );
int bar ( void )
{
return(foo(0xAABB,0x1122334455667788LL));
}
読みやすいasmにコンパイルするよりも、コンパイルしてからアセンブルする方が好きです。
arm-none-eabi-gcc -c -O2 fun.c -o fun.o
arm-none-eabi-objdump -D fun.o
fun.o: file format elf32-littlearm
Disassembly of section .text:
00000000 <bar>:
0: e92d4008 push {r3, lr}
4: e59f001c ldr r0, [pc, #28] ; 28 <bar+0x28>
8: e28f3010 add r3, pc, #16
c: e893000c ldm r3, {r2, r3}
10: ebfffffe bl 0 <foo>
14: e8bd4008 pop {r3, lr}
18: e12fff1e bx lr
1c: e1a00000 nop ; (mov r0, r0)
20: 55667788 strbpl r7, [r6, #-1928]! ; 0x788
24: 11223344 teqne r2, r4, asr #6
28: 0000aabb ; <UNDEFINED> instruction: 0x0000aabb
2c: e1a00000 nop ; (mov r0, r0)
答えは、r0には最初のパラメーターが含まれ、r1はスキップされ、r2/r3にはlonglongが含まれるというものです。