前回(親知らずの日記: AArch64 armasm の勉強 システムレジスタ編)、システムレジスタの値を MRS, MSR で読み書きできそうということが分かったので、取得した値を表示してみたい。
そのためには、 C 言語から armasm のサブルーチンを呼び出せるようにしないといけない。
そのあたりの勉強をする。
座学
ARM Information Center - ARM® コンパイラ armasm ユーザガイド を見てみたが、 AArch64 の章に、サブルーチンに関する話が載っていなかった。
仕方がないので ARM Information Center - 6.3 サブルーチン呼び出しでのレジスタの使用方法 を参照する。
これによると、
- レジスタ 0 から 3 までを引数用に使用
- レジスタ 0 を 戻り値用に使用
- サブルーチン呼び出しには
BL
命令を使用 - サブルーチンからの復帰には
BX LR
命令を使用
のようだ。
それぞれの命令の意味を確認しようと思ったら、 ARM Information Center に BX
命令がない...。「復帰」で検索かけたら RET
命令が見つかった。AArch64 では RET
命令でサブルーチンからの復帰を行うみたい。
ここまでわかったので、実際作ったプログラムをアセンブリプログラムに変換して確かめてみる。
実践
検証環境
ツールチェインは gcc-linaro-6.2.1-2016.11-i686-mingw32_aarch64-linux-gnu
。
検証用プログラムの作成
caller.c
extern int getOne(void);
extern int add(int a, int b);
int main() {
int one = getOne();
int number = add(1, 2);
while (1);
return 0;
}
callee.c
int getOne() {
return 1;
}
int add(int a, int b) {
return a + b;
}
上記の C コードをアセンブリコードへ変換する。
アセンブリコードの確認
aarch64-linux-gnu-gcc -S ./caller.c -o caller.S
aarch64-linux-gnu-gcc -S ./callee.c -o callee.S
で、結果が下記。
caller.S
.arch armv8-a
.file "caller.c"
.text
.align 2
.global main
.type main, %function
main:
stp x29, x30, [sp, -32]!
add x29, sp, 0
bl getOne
str w0, [x29, 28]
mov w1, 2
mov w0, 1
bl add
str w0, [x29, 24]
.L2:
b .L2
.size main, .-main
.ident "GCC: (Linaro GCC 6.2-2016.11) 6.2.1 20161016"
.section .note.GNU-stack,"",@progbits
callee.S
.arch armv8-a
.file "callee.c"
.text
.align 2
.global getOne
.type getOne, %function
getOne:
mov w0, 1
ret
.size getOne, .-getOne
.align 2
.global add
.type add, %function
add:
sub sp, sp, #16
str w0, [sp, 12]
str w1, [sp, 8]
ldr w1, [sp, 12]
ldr w0, [sp, 8]
add w0, w1, w0
add sp, sp, 16
ret
.size add, .-add
.ident "GCC: (Linaro GCC 6.2-2016.11) 6.2.1 20161016"
.section .note.GNU-stack,"",@progbits
まとめ
ドキュメントに書いてある通り、引数と戻り値を設定しているみたい。 そして、復帰は RET
使っている。
サブルーチン側では、
- スタック領域確保する
- スタックに引数を積み上げる
- サブルーチンの処理結果をレジスタ 0 に格納する
- 確保したスタック領域を返却する
のような流れっぽい。 スタックは、アドレスの少ないほうに伸びていくっぽい。
本日はここまで。 明日、余裕があったら引数の数増やして確認してみる。
0 件のコメント:
コメントを投稿