今年もやって来ましたカーネル/VM Advent Calendar!今日は2日目で私の番でございます。それで今回やる内容は『Boot Sector Brainfuck』!...あれ?2年前にも同じようなことをやったぞ?って感じだけど、ちょっと違います。2年前のやつはブートローダとメインプログラムとBrainfuckのソースコードから構成されていて、Brainfuckのソースコードを修正するたびにブートローダとメインプログラムをくっつけなければいけなかった!でも今回のやつはブートセクタ内で全てを終わらせるので、くっつける必要がないのです。
それでBrainfuckのソースコードはどうするのか?ということですが、『Boot Sector Brainfuck』起動後にキーボード入力を受け付けるようにしてるので、そこでソースコード入力してね!ということです。
それで、ちょっと『Boot Sector Brainfuck』プログラムの解説をします。キーボード入力に関してですが、AHレジスタを0にしてINT 0x16を呼び出すと、キー入力を待ちます。そこで1文字入力が来ると、ALレジスタに文字コードが入ります。ただそれだけだと画面に文字が表示されなくて困るので、INT 0x10で入力された文字を表示します。ついでに入力された文字をBrainfuckのソースコードアリア(自分で勝手に定義)にコピーします。Enterが押されたらBrainfuckインタプリタに移ります。あとはKernel/VM Advent Calendar 15日目: リアルモード Brainfuckとほぼ同じ。ただコードサイズの最適化を少しかけてバイナリのサイズが少し小さくなっています。やったのは『ADD AL, 1』みたいなのを『INC AL』にしたり、0チェックを『AND AX, AX』に変えたこと。
次に『Boot Sector Brainfuck』の使い方。qemuを準備して以下のファイルをダウンロードして
qemu -fda bf
と入力するだけ。起動後はBrainfuckのソースコードを入力していきましょう!バックスペースは無効になってるので注意。見た目上直せるところもあるけど、メモリ上では変なコードになります。
bf
以下ソースコード
[BITS 16] mov ax, 0x7C00 mov ds, ax xor ah, ah mov al, 0x03 int 0x10 mov di, 0x200 input: xor ah, ah int 0x16 call printc cmp al, 0x0d je input_end mov byte [di], al inc di jmp input input_end: mov al, 0x0a call printc mov byte [di], 0x00 jmp bf_start printc: mov ah, 0x0E mov bx, 0x15 int 0x10 ret bf_start: mov si, 0x200 call memset mov di, 0x8000 main: mov al, [si] inc si cmp al, '>' je incdi cmp al, '<' je decdi cmp al, '+' je incmem cmp al, '-' je decmem cmp al, '.' je dischar cmp al, '[' je loopstart cmp al, ']' je loopend jmp bfend incdi: inc di jmp main decdi: dec di jmp main incmem: inc byte [di] jmp main decmem: dec byte [di] jmp main dischar: mov al, [di] call printc jmp main loopstart: mov al, [di] and al, al jne main mov bp, 1 toend: and bp, bp je main mov al, [si] inc si cmp al, '[' je incnestfs cmp al, ']' je decnestfs jmp toend loopend: mov bp, 1 dec si tostart: and bp, bp je main dec si mov al, [si] cmp al, ']' je incnestfe cmp al, '[' je decnestfe jmp tostart tomain: inc si jmp main incnestfs: inc bp jmp toend decnestfs: dec bp jmp toend incnestfe: inc bp jmp tostart decnestfe: dec bp jmp tostart memset: mov di, 0x8000 mov ax, 0 mov cx, 30000 rep stosb ret bfend: jmp bfend times 510 - ($ - $$) db 0 db 0x55, 0xAA