低レイヤ教育研究会2015-11-08作業メモ
前回まで
とりあえず頂いたお題のBrainf*ckを作ったので、次のお題に入ることにした。
次のお題は、逆アセンブラを作ること。
逆アセンブラを作るための作業工程
- ファイル内容を16進数で表示できること
- Cross-Compiler環境を構築すること
- 以下、続く...
ファイル内容を16進数で表示できること
どのCPU/OS向けの逆アセンブラを作るにしても、ファイル内容の16進数表示は必要。 まずはファイルを読んで、16進数で標準出力へ出力するプログラムを書いた。
Cross-Compiler環境を構築すること
Cross-Compiler環境を構築することの意義
逆アセンブラを作るときに、Cross-Compiler環境を構築することの意義を確認します。 どのCPU用逆アセンブラを作るか選ぶときに、作成の難易度が現実的なことを大切にしました。 現実的なところを狙うと、最新のCPUと比較して古いCPUの方が、仕様が小さくていいだろうとなります。 では古いCPU用実行ファイルの逆アセンブラを作りましょうとなると、お手本や分析の対象になる、古いCPU用実行ファイルが欲しいところです。 ですが現代的な開発環境では、古いCPU用へのコンパイルができません。 その古いCPU用実行ファイルを自前で整えられるようにするのが、Cross-Compiler環境を構築する意義です。
作業環境
Mac OS X EI Capitan 10.11.1 x86_64
作業記録
こちらを参考に環境構築をしました。
$ # 作業用ディレクトリ作成 $ mkdir cross $ cd cross $ # ソースの取得と展開 $ curl -O http://ftp.gnu.org/gnu/binutils/binutils-2.25.tar.bz2 $ curl -O http://ftp.gnu.org/gnu/gcc/gcc-4.6.4/gcc-core-4.6.4.tar.bz2 $ tar xvf binutils-2.25.tar.bz2 $ tar xvf gcc-core-4.6.4.tar.bz2 $ # ビルド用ディレクトリ作成 $ mkdir powerpc-elf $ cd powerpc-elf/ $ # binutilsをビルド $ mkdir binutils $ cd binutils/ $ ../../binutils-2.25/configure --prefix=/opt/cross --target=powerpc-elf $ make -j2 $ sudo make install $ # gccをビルド $ cd .. $ mkdir gcc $ cd gcc $ ../../gcc-4.6.4/configure --prefix=/opt/cross --target=powerpc-elf configure: error: Building GCC requires GMP 4.2+, MPFR 2.3.1+ and MPC 0.8.0+. Try the --with-gmp, --with-mpfr and/or --with-mpc options to specify their locations. Source code for these libraries can be found at their respective hosting sites as well as at ftp://gcc.gnu.org/pub/gcc/infrastructure/. See also http://gcc.gnu.org/install/prerequisites.html for additional info. If you obtained GMP, MPFR and/or MPC from a vendor distribution package, make sure that you have installed both the libraries and the header files. They may be located in separate packages. $ # エラーになった。エラーメッセージや参考記事にもある依存ライブラリをインストール $ brew install gmp $ brew install xz ; # brew info mpfrのDependenciesを見ると要りそうなので導入 $ brew install mpfr $ brew install libmpc $ brew info gmp gmp: stable 6.0.0a (bottled) GNU multiple precision arithmetic library https://gmplib.org/ /usr/local/Cellar/gmp/6.0.0a (15 files, 3.2M) * Poured from bottle From: https://github.com/Homebrew/homebrew/blob/master/Library/Formula/gmp.rb ==> Options --32-bit Build 32-bit only --c++11 Build using C++11 mode $ brew info xz xz: stable 5.2.1 (bottled) General-purpose data compression with high compression ratio http://tukaani.org/xz/ /usr/local/Cellar/xz/5.2.1 (59 files, 1.6M) * Poured from bottle From: https://github.com/Homebrew/homebrew/blob/master/Library/Formula/xz.rb ==> Options --universal Build a universal binary $ brew info mpfr mpfr: stable 3.1.3 (bottled) C library for multiple-precision floating-point computations http://www.mpfr.org/ /usr/local/Cellar/mpfr/3.1.3 (24 files, 3.6M) * Poured from bottle From: https://github.com/Homebrew/homebrew/blob/master/Library/Formula/mpfr.rb ==> Dependencies Build: xz ✔ Required: gmp ✔ ==> Options --32-bit Build 32-bit only $ brew info libmpc libmpc: stable 1.0.3 (bottled) C library for the arithmetic of high precision complex numbers http://multiprecision.org /usr/local/Cellar/libmpc/1.0.3 (10 files, 380K) * Poured from bottle From: https://github.com/Homebrew/homebrew/blob/master/Library/Formula/libmpc.rb ==> Dependencies Required: gmp ✔, mpfr ✔ $ # gccをビルド再挑戦 $ # --with-xxx=の指定は、brew info xxxの内容を参照した $ ../../gcc-4.6.4/configure --prefix=/opt/cross --target=powerpc-elf --with-gmp=/usr/local/Cellar/GMP/6.0.0a --with-mpfr=/usr/local/Cellar/libmpc/1.0.3 --with-mpc=/usr/local/Cellar/mpfr/3.1.3 $ make -j2 all-gcc $ sudo make install-gcc $ /opt/cross/bin/powerpc-elf-gcc --version powerpc-elf-gcc (GCC) 4.6.4 Copyright (C) 2011 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ # ビルドしたgccでCompileしてみるテスト $ cd .. $ mkdir test $ cd test $ cat add.c ; # ソースはある前提 int add(int a, int b) { return a + b; } $ export PATH="/opt/cross/bin:$PATH" $ powerpc-elf-gcc -nostdlib -g -O add.c /opt/cross/lib/gcc/powerpc-elf/4.6.4/../../../../powerpc-elf/bin/ld: 警告: エントリシンボル _start が見つかりません。デフォルトとして 0000000001800054 を使用します $ powerpc-elf-objdump -S a.out a.out: ファイル形式 elf32-powerpc セクション .text の逆アセンブル: 01800054 <add>: int add(int a, int b) { return a + b; } 1800054: 7c 63 22 14 add r3,r3,r4 1800058: 4e 80 00 20 blr $ # できたようだ
参考
http://wiki.osdev.org/GCC_Cross-Compiler
[追記] 同じことを--target=vax-netbsdelfでもやってみた
$ mkdir vax-netbsdelf $ cd vax-netbsdelf $ mkdir binutils $ cd binutils $ ../../binutils-2.25/configure --prefix=/opt/cross --target=vax-netbsdelf $ make -j2 $ sudo make install $ cd .. $ mkdir gcc $ cd gcc $ ../../gcc-4.6.4/configure --prefix=/opt/cross --target=powerpc-elf --with-gmp=/usr/local/Cellar/GMP/6.0.0a --with-mpfr=/usr/local/Cellar/libmpc/1.0.3 --with-mpc=/usr/local/Cellar/mpfr/3.1.3 $ make -j2 all-gcc $ sudo make install-gcc $ cd .. $ mkdir test $ cd test $ export PATH="/opt/cross/bin:$PATH" $ cat add.c int add(int a, int b) { return a + b; } $ vax-netbsdelf-gcc -nostdlib -g -O add.c /opt/cross/lib/gcc/vax-netbsdelf/4.6.4/../../../../vax-netbsdelf/bin/ld: 警告: エントリシンボル _start が見つかりません。デフォルトとして 0000000000010054 を使用します $ vax-netbsdelf-objdump -S a.out a.out: ファイル形式 elf32-vax セクション .text の逆アセンブル: 00010054 <add>: int add(int a, int b) { 10054: 00 00 .word 0x0000 # Entry mask: < > 10056: c2 04 5e subl2 $0x4,sp return a + b; } 10059: c1 ac 04 ac addl3 0x4(ap),0x8(ap),r0 1005d: 08 50 1005f: 04 ret