by shigemk2

当面は技術的なことしか書かない

池袋バイナリ勉強会 コンパイルとアセンブラの話 #ikebin

資料

7shi / ikebin / wiki / pdp11 — Bitbucket

最終目標はOSとコンパイラを作る

40年前のUNIX v6 1975

  • 昔のOSであるため簡単であること
  • Cのコンパイラがセットになっている
  • 「比較的」シンプル

これ以上簡単なものになってしまうと実用性が皆無になる

自分でコンパイラを作ってOSを作ろうとしたけど、 アセンブラって何?ってところから始まってしまった

コンパイラはOSの上で動くので、OSのことが分かってないとコンパイラのことも分からないし、作れない

題材をだしてやっていく。

v6ccで昔のバイナリを呼び出す

UNIX V6 OS(40年前) PDP-11 CPU(40年前)

V6を8086(x86の初期)に移植する作業をやってる

CPUの命令やバイナリの仕組みを覚えておいて損はない (ただしオペランド(引数)の細かいところには大きな違いがある)

逆アセンブル

右側の命令群がアセンブリ言語で、命令群を数字に変換するのがアセンブル。

C→アセンブリ→バイナリ Cからアセンブリに変換するのをコンパイル、 アセンブルからバイナリに変更することをアセンブルという。

逆にバイナリからアセンブリに変換することを逆アセンブルという。

[crt0.o]
start:
0000: f009            setd
0002: 1180            mov sp, r0
0004: 1226            mov (r0), -(sp)
0006: 0bd0            tst (r0)+
0008: 1036 0002       mov r0, 2(sp)
000c: 09f7 0008       jsr pc, 0018 ; _main
0010: 100e            mov r0, (sp)
0012: 09df 024e       jsr pc, *$024e ; _exit
0016: 8901            sys 1 ; exit

上に書いてあるアセンブリはPDP11のものなので、CPUが違うと命令の書き方も変わる。

レジスタ

CPUのなかには変数があって、その変数をレジスタとよんで差し支えない。

フラグはレジスタとはまた別。

実際に実行しながら表示しているので、メモリに数字が格納されてる。

$ 7run -m a.out
 r0   r1   r2   r3   r4   r5   sp  flags pc
start:
0000 0000 0000 0000 0000 0000 fff6 ---- 0000:f009           setd
0000 0000 0000 0000 0000 0000 fff6 ---- 0002:1180           mov sp, r0
fff6 0000 0000 0000 0000 0000 fff6 -N-- 0004:1226           mov (r0), -(sp) ;[fff6]0001 ;[fff4]0000
fff6 0000 0000 0000 0000 0000 fff4 ---- 0006:0bd0           tst (r0)+ ;[fff6]0001
fff8 0000 0000 0000 0000 0000 fff4 ---- 0008:1036 0002      mov r0, 2(sp) ;[fff6]0001
fff8 0000 0000 0000 0000 0000 fff4 -N-- 000c:09f7 0008      jsr pc, 0018 ;[0018]0977
_main:
fff8 0000 0000 0000 0000 0000 fff2 -N-- 0018:0977 023c      jsr r5, 0258 ;[0258]1140
csv:
fff8 0000 0000 0000 0000 001c fff0 -N-- 0258:1140           mov r5, r0
001c 0000 0000 0000 0000 001c fff0 ---- 025a:1185           mov sp, r5
001c 0000 0000 0000 0000 fff0 fff0 -N-- 025c:1126           mov r4, -(sp) ;[ffee]0000
001c 0000 0000 0000 0000 fff0 ffee Z--- 025e:10e6           mov r3, -(sp) ;[ffec]0000
001c 0000 0000 0000 0000 fff0 ffec Z--- 0260:10a6           mov r2, -(sp) ;[ffea]0000

変数の呼び出しがかかるとメモリの間を行ったりきたりしている

逆アセンブルはただ解析しているだけ。

CPUがアップデートすると、言語のコンパイラもそれにあわせてアップデートしていかないといけない。

メーカーによっても型番によってもCPUが異なる

AMD vs Intel vs ARM

AMDはIntelでコンパイルしたやつに意地でも対応しようとするけどARMはそんなに頑張ろうとしてない

クロスコンパイラには時間がかかる

シンボル

printf とか main とか、コンパイルしたときに残っている名前のこと

$ v6nm a.out
001116T _exit
001014T _flush
001276B _fout
000030T _main
000054T _printf
000736T _putchar
000320t charac
001146T cret
000000a crt0.o
001130T csv
001130a csv.o
000242t decimal
001116a exit.o
000724a ffltpr.o
001030t fl
000464t float
001266b formp
000640t gnum
000030a hello.o
000362t hex
000256t logical
000100t loop
001272b ndfnd
001274b ndigit
000370t octal
000724T pfloat
000532t prbuf
000054a printf.o
000542t prstr
000724T pscien
000736a putchr.o
000520t remote
001270b rjust
001262B savr5
000502t scien
000000t start
000336t string
001174d swtab
001264b width
000030t ~main
アドレス 種類 名前
001116 T _exit
001014 T _flush
001276 B _fout
000030 T _main
000054 T _printf
000736 T _putchar
000320 t charac
001146 T cret
000000 a crt0.o
001130 T csv

場所と名前がシンボル情報を表示している

  • nmコマンドは8進数
  • -dコマンドは16進数

ゆえにアドレスの表示が違う

(豆知識)Pythonで16進数 8進数変換

>>> 030
24
>>> 0x18
24
>>> hex(030)
'0x18'
>>> hex(030)
'0x18'
>>> oct(0x18)
'030'

(当時のCPUは8進数がデフォルト)

ファイルサイズの縮小

シンボルを削ればファイルサイズを縮小できる。というのも、シンボルそのものはファイルの実行に関係ないから。

(あったらあったで便利だけど。読みやすいし。)

シンボル情報 = 名前 シンボルを削ると、nmコマンドが使えなくなる。

☁$  l a.out
-rwxrwxrwx  1 shige  staff  1186  2  1 14:14 a.out
☁$ v6strip a.out
☁$ l a.out
-rwxrwxrwx  1 shige  staff  706  2  1 14:55 a.out
$ v6nm a.out
no name list

逆アセンブルを影響を及ぼす。 シンボル情報が消えて、どこがなんだったのか分からなくなる。

バイナリを読むときに、シンボルがあったほうが圧倒的に楽。

そして、シンボルなしに読めるようにする必要もない。

$ 7run -d a.out
0000: f009            setd
0002: 1180            mov sp, r0
0004: 1226            mov (r0), -(sp)
0006: 0bd0            tst (r0)+
0008: 1036 0002       mov r0, 2(sp)
000c: 09f7 0008       jsr pc, 0018
0010: 100e            mov r0, (sp)
0012: 09df 024e       jsr pc, *$024e
0016: 8901            sys 1 ; exit
0018: 0977 023c       jsr r5, 0258
001c: 15ce 0274       mov $274, (sp)
0020: 09df 002c       jsr pc, *$002c
0024: 0a00            clr r0
0026: 0100            br 0028
0028: 0077 023a       jmp 0266
002c: 0977 0228       jsr r5, 0258
0030: e5c6 007e       sub $7e, sp