AArch64アセンブリの練習
ヨロシク・ワールド
簡単なアセンブリプログラミングを書いてコンパイル→リンク→実行してみる
4649(ヨロシク)を返すだけのプログラム。x0レジスタにセットした値が返り値として扱われる
code:4649.S
// return 4649
.text
.globl _prog_start
.p2align 2
_prog_start:
mov x0, 4649
ret
prog_start関数の返り値をターミナルへ表示する。
code:stub.c
extern int prog_start(char *, char *);
int main() {
char *hp, *sp;
sp = alloca(1000000); hp = malloc(4000000);
if (hp == NULL || sp == NULL) {
fprintf(stderr, "malloc or alloca failed\n");
return 1;
}
fprintf(stderr, "sp = %p, hp = %p\n", sp, hp);
int result = prog_start(sp, hp);
fprintf(stderr, "result = %d\n", result);
return 0;
}
実行してみる。result = 4649 が表示されればOK
code:sh
$ gcc 4649.S stub.c -o 4649
$ ./4649
sp = 0x16d85a818, hp = 0x120008000
result = 4649
加算
code:add.S
// return 10 + 20
.text
.globl _prog_start
.p2align 2
_prog_start:
mov x1, 10
mov x2, 20
add x3, x1, x2
mov x0, x3
ret
レジスタの使われ方
https://gyazo.com/adfb0e2bc03beb555e7a07269910f5d1
「x0〜x30」は64ビットレジスタ
「w0〜w30」は32ビットレジスタ
結果レジスタ
「x0」
パラメータレジスタ
「x0」〜「x7」
揮発レジスタ
「x0」から「x17」までは揮発レジスタ
不揮発レジスタ
「x18」から「x30」
その他
「x29/fp」フレームポインタ
「x30/lr」リンクレジスタ
その他のレジスタ
スタックポインタ
「sp」
ゼロレジスタ
32ビットのゼロレジスタ「wzr」
64ビットのゼロレジスタ「xzr」
命令
str
ストア命令。レジスタに格納されてる値をメモリに書き込む
stp
二つのレジスタの値をメモリ中の指定したアドレスへ書き込む
stur
メモリ中の指定したアドレスへレジススタの値を書き込む
(strとの違いがよく分からない...)
mov
レジスタからレジスタへの値のコピー、即値のロードなどに利用する
ret
return。指定したレジスタのアドレスに無条件分岐する。レジスタを指定しない場合はリンクレジスタ x30 を指定したことになる
bl
関数呼び出し的な?
必要そうな命令
add (加算)
sub (減算)
and (論理積)
orr (論理和)
lsl (論理左シフト)
asr (算術右シフト)
lsr (論理右シフト)
ldr (ロード、メモリからレジスタへコピー)
str (ストア、レジスタからメモリへコピー)
mov (ムーブ、レジスタからレジスタへコピー)
b (無条件分岐、ラベルを指定)
bl (無条件分岐。リンクレジスタへ戻り先が格納されるため、blで呼び出した関数からretで戻ることができる)
ret (blの呼び出し元へ戻る)
cmp + beq
cmp + bne
cmp + bge (bgt)
cmp + ble (blt)
svc (Supervisor Call、x8にシステムコール番号を、x0からx5にシステムコールの引数を指定)
参考
ARM命令セット
Linux で Arm64 アセンブリプログラミング (05) ストア命令
Arm64のレジスタ
分岐命令