PowerPC64アセンブリ開発環境の整備
目的
PowerPC64アセンブリの演習のための環境を手元で構築する.
最新情報へのリンク
2015/01/11 以下のように事情が変化している。
- PowerPC64 アセンブリ開発環境の設定メモに、以下の手順を現在行った場合に起きる問題への対処法がある。
- crosstool-ngのバージョンは1.20.0が最新。
- 実は、crosstool-ngを使わなくても、gcc-powerpc-linux-gnuやg++-powerpc-linux-gnuなどをインストールし、powerpc-linux-gnu-gcc等のコンパイラのコマンドに-m64オプションを付けて実行すればよいっぽいこともわかった。
crosstool-ngの導入
必要なパッケージの準備
$ sudo apt-get install build-essential gperf texinfo gawk libtool automake libncurses5-dev
ソースコードを入手してビルド
$ wget http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.19.0.tar.bz2 $ tar jxvf crosstool-ng-1.19.0.tar.bz2 $ cd crosstool-ng-1.19.0 $ ./configure $ make $ sudo make install
PowerPC64用クロスコンパイラのビルド
必要なパッケージを入れる
これらはcross-gdbのビルドに必要(入れていないとビルドの最後のほうで失敗して泣く)
$ sudo apt-get install libexpat1-dev python2.7-dev
ソースを補完するディレクトリを掘る
デフォルトだとホームの下のsrcに設定されている.ディレクトリがないと保存されないので掘っておく
$ mkdir ~/src
作業ディレクトリを掘る
$ mkdir ppc64-toolchain $ cd ppc64-toolchain
設定をいじる
$ ct-ng menuconfig
設定画面の使い方
- 上下: 選択肢の移動
- スペース: 選択肢の選択
- 左右: <Select> / <Exit> / <Help> の間を移動
- Enter: <Select> / <Exit> / <Help> のうち選択されているものを実行
- 上下キーで C compiler ---> に移動,スペースで中に入る
- 上下キーで [*] Fortran に移動,スペースでチェックを消す
- 上下キーで [*] Java に移動,スペースでチェックを消す
- 左右キーで < Exit > を選択,Enterで実行→外に出る
- 左右キーで < Exit > を選択,Enterで実行→設定終了
終了時に設定を保存するか聞かれるのでYesと答える
ビルド実行
$ ct-ng build
あとはひたすら待つと勝手にビルドとインストールを実行してくれる
インストール先はデフォルトでは次のような構成
~/x-tools ~/x-tools/powerpc64-unknown-linux-gnu ~/x-tools/powerpc64-unknown-linux-gnu/bin ~/x-tools/powerpc64-unknown-linux-gnu/include ~/x-tools/powerpc64-unknown-linux-gnu/lib ~/x-tools/powerpc64-unknown-linux-gnu/libexec ~/x-tools/powerpc64-unknown-linux-gnu/powerpc64-unknown-linux-gnu ~/x-tools/powerpc64-unknown-linux-gnu/share
例えば,binの中身は次のようになっている
powerpc64-unknown-linux-gnu-addr2line powerpc64-unknown-linux-gnu-ar powerpc64-unknown-linux-gnu-as powerpc64-unknown-linux-gnu-c++ powerpc64-unknown-linux-gnu-cc powerpc64-unknown-linux-gnu-c++filt powerpc64-unknown-linux-gnu-cpp powerpc64-unknown-linux-gnu-ct-ng.config powerpc64-unknown-linux-gnu-embedspu powerpc64-unknown-linux-gnu-g++ powerpc64-unknown-linux-gnu-gcc powerpc64-unknown-linux-gnu-gcc-4.5.2 powerpc64-unknown-linux-gnu-gccbug powerpc64-unknown-linux-gnu-gcov powerpc64-unknown-linux-gnu-gdb powerpc64-unknown-linux-gnu-gdbtui powerpc64-unknown-linux-gnu-gprof powerpc64-unknown-linux-gnu-ld powerpc64-unknown-linux-gnu-ldd powerpc64-unknown-linux-gnu-nm powerpc64-unknown-linux-gnu-objcopy powerpc64-unknown-linux-gnu-objdump powerpc64-unknown-linux-gnu-populate powerpc64-unknown-linux-gnu-ranlib powerpc64-unknown-linux-gnu-readelf powerpc64-unknown-linux-gnu-size powerpc64-unknown-linux-gnu-strings powerpc64-unknown-linux-gnu-strip
コンパイルする
PATHの追加
環境変数PATHを追加する.
$ export PATH=$HOME/x-tools/powerpc64-unknown-linux-gnu/bin:$PATH
これを毎回実行するのは面倒なので,~/.bashrcに追記する.
$ echo 'export PATH=$HOME/x-tools/powerpc64-unknown-linux-gnu/bin:$PATH' >> ~/.bashrc
サンプルソースコード
次のようなCソースコードをhello.cという名前で作成する.
#include <stdio.h> int main() { puts("Hello, world!"); return 0; }
コンパイル
コンパイルする
$ powerpc64-unknown-linux-gnu-gcc hello.c $ file a.out a.out: ELF 64-bit MSB executable, 64-bit PowerPC or cisco 7500, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.31, not stripped
確かにPowerPC64用のバイナリである.
アセンブリソースの出力
アセンブリのソースを出力してみる
$ powerpc64-unknown-linux-gnu-gcc -S hello.c $ cat hello.s .file "hello.c" .section ".toc","aw" .section ".text" .section .rodata .align 3 .LC0: .string "Hello, world!" .section ".toc","aw" .LC1: .tc .LC0[TC],.LC0 .section ".text" .align 2 .globl main .section ".opd","aw" .align 3 main: .quad .L.main,.TOC.@tocbase,0 .previous .type main, @function .L.main: mflr 0 std 0,16(1) std 31,-8(1) stdu 1,-128(1) mr 31,1 ld 3,.LC1@toc(2) bl puts nop li 0,0 mr 3,0 addi 1,31,128 ld 0,16(1) mtlr 0 ld 31,-8(1) blr .long 0 .byte 0,0,0,1,128,1,0,1 .size main,.-.L.main .ident "GCC: (crosstool-NG 1.19.0) 4.5.2"
確かにPowerPC64のアセンブリコードが出力されている.
実行
生成されたバイナリはPowerPC64用なのでそのままでは実行できない.
$ ./a.out bash: ./a.out: cannot execute binary file
そこで,エミュレーターQEMUのユーザーモードエミュレーション機能を用いる.
qemu-userのインストール
$ sudo apt-get install qemu-user
QEMU_LD_PREFIXの設定
このままでは先ほどのa.outを実行できない.というのも,依存しているライブラリがあり,QEMUがその場所を把握していないからである.
$ export QEMU_LD_PREFIX=$HOME/x-tools/powerpc64-unknown-linux-gnu/powerpc64-unknown-linux-gnu/
これも毎回実行するのは面倒なので,~/.bashrcに追記しておく.
$ echo 'export QEMU_LD_PREFIX=$HOME/x-tools/powerpc64-unknown-linux-gnu/powerpc64-unknown-linux-gnu/' >> ~/.bashrc
a.outを実行してみる
$ qemu-ppc64 ./a.out Hello, world!
無事実行できた!
デバッガの利用
powerpc64-unknwon-linux-gnu-gdb自体はPowerPC64コードを実行する機能をもたないようなので,qemu-ppc64で実行しているものを遠隔操作する方法を用いる.(リモートデバッグという)
プログラムを実行
12345のところはポート番号なので,他の数字でもよい.このポートにgdbから接続する.
$ qemu-ppc64 -g 12345 ./a.out
こうすると,qemu-ppc64は待機状態になる.
デバッガを起動
別の端末を開いて,gdbを起動する.
$ powerpc64-unknwon-linux-gnu-gdb a.out
実行中のqemu-ppc64に接続する.
(gdb) target remote localhost:12345
これでデバッグの準備が整った.
デバッガを使う
ブレークポイントを設定してみる
(gdb) b main Breakpoint 1 at 0x1000051c: file hello.c, line 4.
実行してみる
(gdb) c Continuing. Breakpoint 1, main () at hello.c:4 4 puts("Hello, world!");
r (run) ではなくc (continue) であることに注意!
もう一回continueするとputsが実行されて終了する.このとき,qemu-ppc64を実行している端末でHello, world!が出力されるので確認すること.
(gdb) c Continuing. [Inferior 1 (Remote target) exited normally]
gdbを終了する.
(gdb) q