2017/02/16

AArch64 armasm の勉強 サブルーチン編

前回(親知らずの日記: 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 CenterBX 命令がない...。「復帰」で検索かけたら 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 使っている。

サブルーチン側では、

  1. スタック領域確保する
  2. スタックに引数を積み上げる
  3. サブルーチンの処理結果をレジスタ 0 に格納する
  4. 確保したスタック領域を返却する

のような流れっぽい。 スタックは、アドレスの少ないほうに伸びていくっぽい。

本日はここまで。 明日、余裕があったら引数の数増やして確認してみる。

0 件のコメント: