Hello World.
ブログでははじめまして!
東京オフィスに3週間前に入ったアルバイトの古橋と申します.
大学に入って4年勉強していますが,まだまだ未熟者なプログラマーです.
さてさて,書くこともないので私の最近興味あることについて書いていきます.
It's VM Machine!
ずばり,仮想マシンについてです.
仮想化技術といってもいろいろありますが,私はVMマシンについて興味があります.
まずはかなり低レイヤーのことについて書いていきます.
0,1の羅列が嫌いな方はここで回れ右するのが賢明だと思います(笑)
アーキテクチャはVAXでやっていきます.
ってことでまずはVAXの特徴について説明していきます!
About VAX
VAXはVirtual Address eXtensionのことで、32bitの仮想アドレスを使用しています.
仮想アドレスなので,実際のアドレスを指しておらず,オペレーティングシステムの制御のもとでプロセッサによってメインメモリにアクセスします.
なので,メインメモリをより効率的に制御することができます.
VAXは基本,6種類のデータタイプを扱います.
データタイプ | サイズ |
---|---|
バイト | 8bit |
ワード | 16bit |
ロングワード | 32bit |
クォドワード | 64bit |
オクタワード | 128bit |
浮動小数点 | 32~128bit |
これに符合ありかなしか,また浮動小数点にも4種類あり,パック10進数か,...など,細かくすると色々あります!
レジスタの使い方にも種類があり,レジスタモードとアドレシングモードに分かれます.
汎用レジスタは32bitが16個用意されています.
そして,アドレシングモード…これが肝です!
肝と言いましたが,なかなか複雑なので後々説明するかもです.
Decryption of the source code
はい,もう細々言っても伝わりづらいと思うんで面白いことしましょうか.
ソースコードをDisAssembleしましょう.
みなさん,アセンブラ好きですか?私は大好きです.(錯乱)
みなさん,バイナリ読むのは好きですか?私は大好きです.(錯乱)×2
では解析してみましょう.
こちらアセンブラ言語で書かれたものです.
1: .globl _main 2: _main: .word 0 3: 4: pushl $6 5: pushl $hello 6: pushl $1 7: calls $3, _write 8: 9: pushl $0 10: calls $1, _exit 11: 12: hello: .byte 'h, 'e, 'l, 'l, 'o, 10
上のところはいいとして,これの解説いきます.
まずは4~7についてです.
これはwrite関数を呼んでいます.
pushlで引数を格納しています.pushlはpush longwordの略です.
つまり,書き換えると,write(6, hello, 1)です.
callsの3はwriteの番号のことです.これはどこかのファイルに定義されています.
9,10はexit()を呼んでいます.つまり終了です.
ほとんどの人はわかってると思いますが,これ,helloって出力してるだけです.
Let's analyze
これをバイナリにしてみましょ〜DON!
0000000 : 08 01 00 00 8C 00 00 00 04 00 00 00 04 00 00 00 0000010 : 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000020 : 00 00 C2 08 5E D0 AE 08 6E 9E AE 0C 50 D0 50 AE 0000030 : 04 D5 80 12 FC D1 50 BE 04 19 02 D5 70 D0 50 AE 0000040 : 08 D0 50 EF D8 01 00 00 FB 03 EF 0D 00 00 00 DD 0000050 : 50 FB 01 EF 28 00 00 00 BC 01 00 00 00 00 DD 06 0000060 : DD 8F 58 00 00 00 DD 01 FB 03 EF 21 00 00 00 DD 0000070 : 00 FB 01 EF 08 00 00 00 68 65 6C 6C 6F 0A 00 00 0000080 : 00 00 FB 00 EF 03 00 00 00 BC 01 00 00 00 04 00 0000090 : 00 00 BC 04 1E 06 17 EF 04 00 00 00 04 00 00 00 00000A0 : D0 50 EF 7D 01 00 00 CE 01 50 04 00 00 00 00 00 00000B0 : 63 72 74 30 2E 6F 00 00 04 00 00 00 00 00 00 00 00000C0 : 65 78 69 74 00 00 00 00 02 00 00 00 01 00 00 00 00000D0 : 68 65 6C 6C 6F 32 2E 6F 04 00 00 00 3C 00 00 00 00000E0 : 68 65 6C 6C 6F 00 00 00 04 00 00 00 58 00 00 00 00000F0 : 65 78 69 74 2E 6F 00 00 04 00 00 00 60 00 00 00 0000100 : 63 6C 65 61 6E 75 70 2E 04 00 95 01 6C 00 00 00 0000110 : 77 72 69 74 65 2E 6F 00 04 00 95 01 70 00 00 00 0000120 : 63 65 72 72 6F 72 2E 6F 04 00 49 02 80 00 00 00 0000130 : 5F 65 78 69 74 00 00 00 05 00 28 03 60 00 00 00 0000140 : 73 74 61 72 74 00 00 00 05 00 AB 01 00 00 00 00 0000150 : 5F 6D 61 69 6E 00 00 00 05 00 18 02 3C 00 00 00 0000160 : 5F 65 6E 76 69 72 6F 6E 07 00 25 01 00 02 00 00 0000170 : 5F 77 72 69 74 65 00 00 05 00 2D 04 70 00 00 00 0000180 : 5F 5F 63 6C 65 61 6E 75 05 00 95 01 6C 00 00 00 0000190 : 63 65 72 72 6F 72 00 00 05 00 49 02 80 00 00 00 00001A0 : 5F 65 72 72 6E 6F 00 00 09 00 35 00 04 02 00 00
わ〜きれい(棒)
最初の方にheaderと呼ばれるコードの情報が書かれているのでこれを解析します.
MAGIC : 0x00000108 TEXT : 0x0000008C DATA : 0x00000004 BSS : 0x00000004 SYMS : 0x00000100 ENTRY : 0x00000000 TRSIZE : 0x00000000 DRSIZE : 0x00000000
これにより,TEXTデータは0x8Cの長さってことがわかります.
ってことは,TEXTデータは以下のようになります.
*** memorytext *** 00 00 C2 08 5E D0 AE 08 6E 9E AE 0C 50 D0 50 AE 04 D5 80 12 FC D1 50 BE 04 19 02 D5 70 D0 50 AE 08 D0 50 EF D8 01 00 00 FB 03 EF 0D 00 00 00 DD 50 FB 01 EF 28 00 00 00 BC 01 00 00 00 00 DD 06 DD 8F 58 00 00 00 DD 01 FB 03 EF 21 00 00 00 DD 00 FB 01 EF 08 00 00 00 68 65 6C 6C 6F 0A 00 00 00 00 FB 00 EF 03 00 00 00 BC 01 00 00 00 04 00 00 00 BC 04 1E 06 17 EF 04 00 00 00 04 00 00 00 D0 50 EF 7D 01 00 00 CE 01 50 04 00
ここにたくさんのじょうほうがかきこまれています.
これをさらにかいせきします.
*** pc : 00000000 textBuf[pc] : 00 HALT *** pc : 00000001 textBuf[pc] : 00 HALT *** pc : 00000002 textBuf[pc] : C2 SUBL2 レジスタモード val1 : 8 Register : SP val2 : FFFFB setValue : FFFF3 *** pc : 00000005 textBuf[pc] : D0 MOVL バイトディスプレイメント ope.setVal(memory.readMemory(FFFFB, 4)) Register : SP readVal : 0 レジスタディファードモード mov val : 0 writeMemory(FFFF3, 0, 4) *** pc : 00000009 textBuf[pc] : 9E MOVAB バイトディスプレイメント ope.setVal(memory.readMemory(FFFFF, 1)) Register : SP readVal : 0 レジスタモード val1 : FFFFF R0 val : FFFFF *** pc : 0000000D textBuf[pc] : D0 MOVL レジスタモード バイトディスプレイメント ope.setVal(memory.readMemory(FFFF7, 4)) Register : SP readVal : 0 mov val : FFFFF writeMemory(FFFF7, FFFFF, 4) *** pc : 00000011 textBuf[pc] : D5 TSTL Inc val : 4 val : FFFFF val1 : FFFFF N : FALSE,Z : FALSE,V : FALSE,C : FALSE *** pc : 00000013 textBuf[pc] : 12 BNEQ PC : 13 val : 11 val1 : 11 BName BNEQ *** pc : 00000015 textBuf[pc] : D1 CMPL レジスタモード addr : FFFF7 val : FFFFF val1 : FFFFF val2 : 0 *** pc : 00000019 textBuf[pc] : 19 BLSS PC : 19 val : 1D val1 : 1D BName BLSS *** pc : 0000001B textBuf[pc] : D5 TSTL オートデクリメント addr : FFFFB val : 0 val1 : 0 N : FALSE,Z : TRUE,V : FALSE,C : FALSE *** pc : 0000001D textBuf[pc] : D0 MOVL レジスタモード バイトディスプレイメント ope.setVal(memory.readMemory(FFFFB, 4)) Register : SP readVal : 0 mov val : FFFFF writeMemory(FFFFB, FFFFF, 4) *** pc : 00000021 textBuf[pc] : D0 MOVL レジスタモード ロングリラティブディファード addr : 200 val : 0 mov val : FFFFF *** pc : 00000028 textBuf[pc] : FB CALLS ロングリラティブディファード addr : 3C val : 0 calls val1 : 3 val2 : 3C val : FFFEF last : 3 entryMask : 0 nextPC : 2F maskInfo : E0000000 PC : 3E *** pc : 0000003E textBuf[pc] : DD PUSHL val1 : 6 *** pc : 00000040 textBuf[pc] : DD PUSHL val1 : 58 *** pc : 00000046 textBuf[pc] : DD PUSHL val1 : 1 *** pc : 00000048 textBuf[pc] : FB CALLS ロングリラティブディファード addr : 70 val : 0 calls val1 : 3 val2 : 70 val : FFFC8 last : 0 entryMask : 0 nextPC : 4F maskInfo : 20000000 PC : 72 *** pc : 00000072 textBuf[pc] : BC CHMK val : 4 index : FFFC8 dataNum : 3 index : FFFC8 index : FFFCC dataNum : 1 index : FFFCC index : FFFD0 dataNum : 58 index : FFFD0 index : FFFD4 dataNum : 6 index : FFFD4 ap : 000FFFC8 val1 : 3, val2 : 1, val3 : 58 val4 : 6 write(1, 0x58, 6) sysWrite hello len : 6 R0 : 6 *** pc : 00000074 textBuf[pc] : 1E BCC PC : 74 val : 7C val1 : 7C BName BCC C = false *** pc : 0000007C textBuf[pc] : 04 RET *** pc : 0000004F textBuf[pc] : DD PUSHL val1 : 0 *** pc : 00000051 textBuf[pc] : FB CALLS ロングリラティブディファード addr : 60 val : 0 calls val1 : 1 val2 : 60 val : FFFC0 last : 0 entryMask : 0 nextPC : 58 maskInfo : 20000000 PC : 62 *** pc : 00000062 textBuf[pc] : FB CALLS ロングリラティブディファード addr : 6C val : 0 calls val1 : 0 val2 : 6C val : FFFA8 last : 0 entryMask : 0 nextPC : 69 maskInfo : 20000000 PC : 6E *** pc : 0000006E textBuf[pc] : 04 RET *** pc : 00000069 textBuf[pc] : BC CHMK val : 1 index : FFFC0 dataNum : 1 index : FFFC0 index : FFFC4 dataNum : 0 index : FFFC4 exit(0)
一つ一つ説明していきます.
その前に…PCとはプログラムカウンタのことでこの値の番地の命令が行われます.
これを操作することでifとかjumpとかやるわけです.
上から見てみましょう.
halt : 特に何もしません.実際はやってますが初期化みたいなものです.
subl2 : longwordの引数を2つ取ってきて引き算します.
movab : byteのアドレスの引数を二つ取ってきて第一引数のアドレスの内容を第二引数のアドレスに格納します.
movl : longwordの引数を2つ取ってきて第一引数に第二引数を格納します.
tstl : longwordの引数を持ってきて,それによって条件を付与します.0ならZフラグをtrueにマイナスならNフラグをtrueにしたりします.
bneq : branch on not equal の略で,Zフラグがtrueなら引数の番地にジャンプします.
cmpl : 第一引数と第二引数を引き算して,0ならZフラグをtrueにマイナスならNフラグをtrueにしたりします.
blss : Branch on lessの略で,Nフラグがtrueなら引数の番地にジャンプします.
calls : カーネルモードに移行して関数を実行します.いろいろやってて読み解くのが難しいです.
ret : callsで保存した内容を元に戻します.関数を実行する前の状態に戻すと言ったほうが正しいですかね.
pushl : longwordの引数を持ってきて,スタックにプッシュします.
chmk : カーネルモードに移行します.これの引数によって実行する関数が違います.4の場合はwrite,1の場合はexitです.
bcc : Branch on Carry Clearの略で,Cフラグ(キャリーフラグ)がtrueの時に引数の番地にジャンプします.
あんな短かったコードでもこんなことやってるんです!
複雑でしょ?うん,でもこれ理解できるとかなり面白いんです.
面白いんです!
ってことでこれを解説出来る機会があればいいな…
これが面白そうって思った人は私と同じ人種です!
では,中途半端ですが,See you next time!