ぐだぐだ低レベルプログラミング(59) ARM64(AArch64)、スマホで lldb

Joseph Halfmoon

スマホ上で clang の使用開始。「ARM64(AArch64)できるな」と気づきました。「できる」といってアセンブラです。以前Armをやったときは32ビットでした。手元のラズパイは皆32ビットOSで動かしているので、64ビットArmはできなかったのです。OS入れ替えるのはメンドイ。しかしスマホであれば64ビット。

※「ぐだぐだ低レベルプログラミング」投稿順indexはこちら

手元のスマホはそれなりの年月を経た「普及価格帯」の品です。それでもCortex-A73/Cortex-A53 各4コアの bigLITTLE であり、ARM64(正しくはAArch64というべきか)で走っています。

最近、Termuxを復活させたお陰で、Go言語などをスマホで走らせて喜んでいますが、デフォルトで clang/llvm のツールチェーンがインストール済です。clang はほぼほぼ gcc 互換のソースを受け入れる筈なので、gcc + gas(gnu assember)のつもりでアセンブラも書ける筈。また、lldb という これまた gdb とコマンドの互換性の高い llvm系のデバッガもインストール済です。

ARM64やるしかない。

最初はABI

ARM64の命令セットについてはホンワカしたところしか記憶にないのです。しかし、ARMの64ビットのときのABI(アプリケーション・バイナリ・インタフェース)さえわかれば「とりあえず」のサンプルプログラムくらい書けるでしょう。ABI、バイナリ者必携とな。

流石にArmです。ARM64 ABIとかで検索すれば大量に見つかります。その中でご本家のABIの定義が置かれているらしいのが以下です。

Arm Software /abi-aa

このごろはマイクロソフト社もARM64版のWindowsとか出しているので、MS版の日本語資料(多分自動翻訳の日本語だけれども)もありました。

ARM64 ABI 規則の概要

極小のサンプルプログラムを書いてみる

gas に食わせるつもりで、以下の極小プログラム書いてみました。引数2個とって戻り値1個返す関数、というより実質1命令。

addsub.s

.globl	addsub
.text
.balign	4

addsub:
    add	x0, x0, x1
    ret

上記のアセンブラ関数を呼び出すCのメインプログラムが以下に

main.c 

#include <stdio.h>

extern uint32_t addsub(uint32_t, uint32_t);

int main(void)
{
    uint32_t result, arg1, arg2;

    arg1 = 111;
    arg2 = 222;
    
    result = addsub(arg1, arg2);
    printf("Result: %d\n", result);
    
    return 0;
}
スマホ(Termux)上でのビルドと実行

実はTermux上でデフォルトのまま gcc と打っても動きます。実際に走るのは clangです。勿論 gcc 以下の本物をダウンロードしてインストールすることもできるのですが、Termuxの中の人はclang派みたいだし、そのままでいこうと。

ビルドは gcc 同様以下のようなコマンドラインでできました。

$ clang -g -O0 -o asm000 main.c addsub.s

後でデバッガにかけるので、-g を指定。最適化されると困るので -O0だと。

実行は普通にできます。111に222を足しているので Resultは333だと。

$ ./asm000
Result: 333
いよいよデバッガ lldb

gdb の代わりに lldb として起動してみます。

$ lldb ./asm000

起動するとこんな感じ。なお以下は、スマホにPCから ssh 接続してその様子をキャプチャしております。まずはソースリストを確認し、ブレークポイントをセット。

lldb000

runしたところが以下に。ブレークポイントで止まっておりますな。lldb001

肝心のアセンブリ言語での表現なのですが、disassembleするしかないみたいです。display/i $pc とかもやってみましたが動かないみたい。コマケーところでgdbとlldbの差があるのか、単なるバージョンなのか?

まずはmainの逆アセンブル。流石64ビット環境です。アドレスの桁の多さに目が回ります。

lldb002

上のリストから得た 関数のアドレスを逆アセンブル。予定通りの実質1命令。しかし、アドレス2桁増えただけなのに入力の辛さは何?桁間違う、普通に打っていたらきっと間違うと思います。

lldb003

続いてお楽しみのレジスタダンプ。ARM32の32ビット16本からすると巨大な64ビットレジスタ32本。まあ、RISC-Vの64ビット見ていたら同じか。

lldb004

とりあえず step over で関数への引数受け渡しと戻り値部分を。

lldb005

第1引数はx0に入っていますな。0x6fは10進で111です。

lldb006

もうワンステップ。今度は第2引数がx1に入っておると。0xdeは222です。

lldb007

step overで、アセンブラ関数を呼び出した直後まで進めれば、戻り値がx0に入っている筈。0x14dは333であります。

lldb008

極小のアセンブラ関数をスマホの上でアセンブルして、実行OK。実際に働いたのはビッグな方だか、リトルな方だかは不明ですが、いずれにせよARM64(AArch64。)

次回からはARM64を勉強して行きたいと思います。

ぐだぐだ低レベルプログラミング(58) RISC-V、整数と浮動小数の変換命令 へ戻る

ぐだぐだ低レベルプログラミング(60) ARM64(AArch64)、レジスタ一覧描いてみた へ進む