日々

link permalink

RISC-V のバイナリダンプを逆アセンブルする

相変わらず空き時間に RISC-V のエミュレータを書いています。RV64IMAC くらいが必要なのですが、意外と命令の種類が多くていっぺんにやるのは面倒なので、HiFive Unleashed のファームウェアを動かしてみて、足りない命令から実装していくスタイルで開発しています。

HiFive Unleashed の電源を入れたときに真っ先に起動してくるファームウェアというかブートローダは ZSBL(Zeroth Stage Boot Loader), FSBL(First Stage Boot Loader)という名前です。

なんと親切なことにソースコードが公開されていますGitHub - Freedom U540-C000 Bootloader Code のリンク)。素晴らしいですね……。

なぜか Unleashed から引っこ抜いてきたバイナリと、手元でコンパイルした ZSBL, FSBL のバイナリが一致しません。何か間違っているのかも?ちょっと気になります。しかしながら、ソースコードが公開されている意義は非常に大きいです。

メモリマップも公開されています。SiFive Freedom U540 SoC のサイトからダウンロードできます。

Unleashed リセット〜ZSBL を例に解説

U540 のマニュアルによると、リセット直後の PC は 0x1004 で、その後は MSEL の値を見て、適切な場所に飛ぶとあります。MSEL というのは、Unleashed ボード上の DIP スイッチのことです。購入後、変えていなければ状態だと全部 ON、つまり 0xf になっていると思います。

リセット直後に実行される領域の周辺バイナリをダンプしてみましょう。ダンプには拙作の memaccess(GitHub へのリンク)を使っています。

Unleashed 0x1000〜0x1040 領域のダンプ
# ma db 0x1000 0x40
00001000  0f 00 00 00 97 02 00 00  03 a3 c2 ff 13 13 33 00
00001010  b3 82 62 00 83 a2 c2 0f  67 80 02 00 00 00 00 00
00001020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00001030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00001040

何かが書いてあるようですが、RISC-V のバイナリがスラスラ読めるほど達人ではないので、ファイルにダンプして逆アセンブルします。

Unleashed 0x1000〜0x1040 領域の逆アセンブル
$ riscv64-unknown-elf-objdump -EL -D -b binary -m riscv:rv64 --adjust-vma=0x1000 reset.bin
reset.bin:     file format binary

Disassembly of section .data:

0000000000001000 <.data>:
    1000:       0000000f                fence   unknown,unknown
    1004:       00000297                auipc   t0,0x0
    1008:       ffc2a303                lw      t1,-4(t0) # 0x1000
    100c:       00331313                slli    t1,t1,0x3
    1010:       006282b3                add     t0,t0,t1
    1014:       0fc2a283                lw      t0,252(t0)
    1018:       00028067                jr      t0
        ...

先頭が変な命令に見えますが、これは命令ではなく MSEL です。値は先程も言ったとおり 0xf です。実行されるのは 0x1004 からです。大した量でもないし、1行毎に見ていきます。

0x1004: auipc t0, 0x0
PC + 0 を t0 にロードします。t0: 0x1004 です。
0x1008: lw t1,-4(t0) # 0x1000
レジスタ t1 にアドレス t0 - 4 = 0x1004 - 4 = 0x1000 つまり MSEL をロードします。t1: 0xf です。
0x100c: slli t1,t1,0x3
レジスタ t1 を 3ビット左シフト(= 8倍)します。t1: 0xf << 3 = 0x78 です。
0x1010: add t0,t0,t1
レジスタ t0 と t1 を足します。t0: です。t0: 0x1004 + 0x78 = 0x107c です。
0x1014: lw t0,252(t0)
レジスタ t0 に t0 + 252 のアドレスからロードします。アドレスは 0x107c + 252 = 0x1178 です。後述のとおり t0: 0x10000 です。
1018: jr t0
レジスタ t0 のアドレスにジャンプします。すなわち 0x10000 にジャンプします。

参考として、アドレス 0x1178 に何が書いてあるか示しておきます。付近の領域 0x1100〜0x1180 には MSEL の値に応じたジャンプ先のアドレスが書いてあります。MSEL が他の値になったらどこにジャンプするか、眺めてみると面白いかと思います。

Unleashed 0x1000〜0x1040 領域のダンプ
# ma dd 0x1100 0x80
00001100  00001004 00000000  20000000 00000000
00001110  30000000 00000000  40000000 00000000
00001120  60000000 00000000  00010000 00000000
00001130  00010000 00000000  00010000 00000000
00001140  00010000 00000000  00010000 00000000
00001150  00010000 00000000  00010000 00000000
00001160  00010000 00000000  00010000 00000000
00001170  00010000 00000000  00010000 00000000    ★0x1178 には 0x10000 が書いてある
00001180

マニュアルの言うとおり、MSEL が 0xf の場合、リセット後 ZSBL にジャンプ、アドレスで言うと 0x10000 にジャンプすることが確認できました。

以降も同様に 0x10000 付近をダンプし、逆アセンブルしたり、エミュレータに実行させてみたりして、開発を進めています。今は ZSBL は通過して、FSBL の先頭の方まで実行できるようになりました。いうなれば、砂山にトンネルを掘っているような気分でしょうか、なかなか面白いです。

通常は逆アセンブルだけだと処理の意図を掴むことが難しいですけども、その点 U540 はソースコードが読めるため、当たりを付けることが比較的容易です。しばらくは素敵なおもちゃになりそうなボードです。

[編集者: すずき]
[更新: 2019年 10月 13日 23:20]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

台風 19号

あの台風 15号(Faxai)(2019年 9月 8日の日記参照)を超える、かつてない規模の台風 19号(Hagibis)が来るということで、窓にガラス飛散防止でダンボールを貼ってみたり、食料、水を買い込んで備えていました。

都内だと多摩川沿いの一部堤防のない地域が水浸し、東日本だと長野、宮城が洪水で大変なことになっているそうで、東京の治水事業には感謝しかありません。

我が家は北と東に窓がありまして、台風15号のときは北からガンガン風と雨が吹き付けていたため、あまりの風圧に、雨が窓サッシの隙間から侵入していました。壁に飛来物が当たり、ものすごい音もしていました(窓の真横に当たり、窓にはギリギリ当たらず本当に幸運だった)。今回はどうやら西、ないし、南から吹き付けていたようで、15号のときほど被害はありませんでした。

今回は全体的に幸運でしたが、災害への備えは日頃からやっておいて損はないですね。

家財

家の外にある家財は車くらいしかないので、台風が過ぎた後に見に行ってみましたが、特に飛来物が当たった形跡もなく、何ともなかったです。良かった良かった。

[編集者: すずき]
[更新: 2019年 10月 13日 22:04]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



こんてんつ

open/close wiki
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報