池袋バイナリ勉強会(5)に参加しました
10月21日(日)に開催された池袋バイナリ勉強会(5)に参加しました。PDP-11の実行ファイル(a.out形式)の解析に取り組んでいます。
以下、取り組んだ内容のメモです(書かれている内容には間違いがあるかも知れません)。
前回までの復習
前回までの勉強会で学んだことの復習をしました。
write.sファイルからa.outを作成します。
mov $1, r0 sys write hello 6 mov $0, r0 sys exit .data hello: <hello\n>
v6as
でa.outが作られます(アセンブル、リンク)。v6run
でa.outを実行します。実行するとhelloと出力されます。
$ v6as write.s $ v6run a.out hello
v6strip
でシンボル情報を削除します。
$ v6strip a.out
pdp11-aout-objdump -d a.out
で逆アセンブルします(v6strip
でa.outに含まれるシンボル情報を削除しないと正しく逆アセンブルできません)。
~/etc/pdp-11 $ pdp11-aout-objdump -d a.out a.out: ファイル形式 a.out-pdp11 セクション .text の逆アセンブル: 00000000 <.text>: 0: 15c0 0001 mov $1, r0 4: 8904 sys 4 6: 0010 .word 20 8: 0006 rtt a: 15c0 0000 mov $0, r0 e: 8901 sys 1
- 定義されていない命令は、
.word
として表示されるようです。 .word 20
の20は8進表記です。
逆アセンブル/実行を行うスクリプトの作成
先ほどのwrite.sから出力されたa.outに対して、pdp11-aout-objdump
を実行すると逆アセンブル結果が出力されますが、pdp11-aout-objdump
を使わずに、逆アセンブルを行うスクリプトの作成に取り組みました(write.sで使用している命令のみ)。
a.outをバイナリエディタで開いて、pdp11-aout-objdump
での逆アセンブル結果と見比べます。
$ xxd a.out 0000000: 0701 1000 0600 0000 0000 0000 0000 0100 ................ 0000010: c015 0100 0489 1000 0600 c015 0000 0189 ................ 0000020: 6865 6c6c 6f0a hello.
a.outの先頭16バイトはヘッダになっています。ここにテキストサイズ、データサイズ、シンボル情報のサイズなどが書き込まれているようです。17バイト目から命令が始まっています。
逆アセンブルすることが出来たら、次はa.outを実行するスクリプト("hello"と出力するスクリプト)を作成しました。実際には、mov,sysの正しい振る舞いは理解していないので、それっぽく動作するスクリプトを書いただけです。
v6nm
でシンボルテーブル出力
v6nm
でシンボルテーブルが出力されます。
$ v6as write.s $ v6nm a.out 000020d hello
v6strip
でシンボルテーブルを削除してから、v6nm
を再度実行すると、今度は「no name list」を表示されます。
$ v6strip a.out $ v6nm a.out no name list
strip前後のa.outを見比べてみます。
$ v6as write.s $ xxd a.out 0000000: 0701 1000 0600 0000 0c00 0000 0000 0000 ................ 0000010: c015 0100 0489 1000 0600 c015 0000 0189 ................ 0000020: 6865 6c6c 6f0a 0000 0000 0000 0400 0000 hello........... 0000030: 0000 0000 0000 0000 0000 0000 6865 6c6c ............hell 0000040: 6f00 0000 0300 1000 o....... $ v6strip a.out $ xxd a.out 0000000: 0701 1000 0600 0000 0000 0000 0000 0100 ................ 0000010: c015 0100 0489 1000 0600 c015 0000 0189 ................ 0000020: 6865 6c6c 6f0a hello.
strip前のa.outの9, 10バイト目には0c00とありますが、リトルエンディアンなのでひっくり返して000c(10進数で12)がシンボルテーブルのサイズとなります。strip後ではこの部分の値が0になっているのが確認出来ます。v6strip
実行すると、a.outのファイルサイズが72バイトから38バイトになり、34バイト削られていますから、v6strip
はシンボルテーブル以外にも削っている情報があるということでしょうか(よく分かっていません)。
ちなみに、オフセット0000020には、helloっぽいものがありますが、先ほどv6nm
にて表示されたものがこれに対応しているような感じです。
v6ar
でlibc.aを展開
v6ar
でlibc.aを展開すると、.oファイルが出てきます。
$ ls libc.a $ v6ar x libc.a $ ls abort.o dup.o getpid.o mcount.o ptrace.o stat.o abs.o errlst.o getpw.o mdate.o putc.o stime.o alloc.o execl.o getuid.o mknod.o putchr.o stty.o atof.o execv.o gtty.o mon.o qsort.o sync.o atoi.o exit.o hmul.o mount.o read.o time.o cerror.o ffltpr.o kill.o nargs.o reset.o times.o chdir.o fltpr.o ladd.o nice.o rin.o umount.o chmod.o fork.o ldfps.o nlist.o sbrk.o unlink.o chown.o fstat.o libc.a open.o seek.o wait.o close.o getc.o link.o perror.o setgid.o write.o creat.o getchr.o locv.o pipe.o setuid.o csv.o getcsw.o ltod.o printf.o signal.o ctime.o getgid.o makdir.o prof.o sleep.o
v6cc -S
で*.s出力
v6cc -S
でCプログラムからアセンブリコードを出力できます。
$ cat wr.c main() { write(1, "hello\n", 6); } $ v6cc -S wr.c $ cat wr.s .globl _main .text _main: ~~main: jsr r5,csv mov $6,(sp) mov $L2,-(sp) mov $1,-(sp) jsr pc,*$_write cmp (sp)+,(sp)+ L1:jmp cret .globl .data L2:.byte 150,145,154,154,157,12,0
write()の第1引数の整数
- 0を渡すと、stdin
- 1を渡すと、stdout
- 2を渡すと、stderr
$ cat wr.c main() { write(1, "hello\n", 6); } $ v6cc wr.c $ v6run a.out hello
a.outにはcrt0.sがそのまま含まれている
main() {}
test.cをコンパイルして逆アセンブルした結果を見ると、v6src/s4/crt0.sのコードがそのまま含まれているのが確認できます。
/ C runtime startoff .globl savr5 .globl _exit .globl _main start: setd mov sp,r0 mov (r0),-(sp) tst (r0)+ mov r0,2(sp) jsr pc,_main mov r0,(sp) jsr pc,*$_exit sys exit .bss savr5: .=.+2
以下がa.outの逆アセンブル結果です。
$ pdp11-aout-objdump -d a.out a.out: ファイル形式 a.out-pdp11 セクション .text の逆アセンブル: 00000000 <.text>: 0: f009 setd ↓↓↓↓↓↓ crt0.s ↓↓↓↓↓↓ 2: 1180 mov sp, r0 4: 1226 mov (r0), -(sp) 6: 0bd0 tst (r0)+ 8: 1036 0002 mov r0, 2(sp) c: 09f7 0008 jsr pc, 0x18 10: 100e mov r0, (sp) 12: 09df 0020 jsr pc, *$40 16: 8901 sys 1 ↑↑↑↑↑↑ crt0.s ↑↑↑↑↑↑ 18: 0977 000e jsr r5, 0x2a 1c: 0077 0018 jmp 0x38 20: 1166 mov r5, -(sp) 22: 1185 mov sp, r5 24: 1d40 0004 mov 4(r5), r0 28: 8901 sys 1 2a: 1140 mov r5, r0 2c: 1185 mov sp, r5 2e: 1126 mov r4, -(sp) 30: 10e6 mov r3, -(sp) 32: 10a6 mov r2, -(sp) 34: 0be6 tst -(sp) 36: 0048 jmp (r0) 38: 1141 mov r5, r1 3a: 1844 mov -(r1), r4 3c: 1843 mov -(r1), r3 3e: 1842 mov -(r1), r2 40: 1146 mov r5, sp 42: 1585 mov (sp)+, r5 44: 0087 rts pc
その他、学んだこと
mov命令でのPC(プログラムカウンタ)について学びました(ここに書けるほどには理解していませんが……)。
以下の2冊の本を紹介していただきました。
- 作者: John R. Levine,榊原一矢,ポジティブエッジ
- 出版社/メーカー: オーム社
- 発売日: 2001/09
- メディア: 単行本
- 購入: 7人 クリック: 171回
- この商品を含むブログ (54件) を見る
Lions’ Commentary on UNIX (Ascii books)
- 作者: ジョンライオンズ,John Lions,岩本信一
- 出版社/メーカー: アスキー
- 発売日: 1998/07
- メディア: 単行本
- 購入: 12人 クリック: 627回
- この商品を含むブログ (27件) を見る
『Lions’ Commentary on UNIX (Ascii books)』は、さっそく購入しました。