読者です 読者をやめる 読者になる 読者になる

ShiftCrops つれづれなる備忘録

CTF関連の事やその他諸々

BrainfuckインタプリタをAssemblyで書き直してみた。

Assembly その他

先日の池袋バイナリ勉強会に行ったときの記事を覚えてますでしょうか?

バイナリ勉強会#1

ここにあるようにC++Brainfuckインタプリタを書いたのですが、このコードをコンパイルした実行ファイルの大きさがゆうに100kBいってしまっていて、もっと軽くならないものかと思ってたんですよね・・・

 

そこで、今回はBrainfuckインタプリタをAssembly言語で最初から書き直してみました。

それではどうぞ!

[c]

;Brainfuck.asm bits 16 org 100h

;メモリ初期化 mov cx,799h set: mov bx,cx mov byte [mem+bx],0 loop set

;コード変換 mov ah,09h mov dx,msg0 int 21h mov ah,01h int 21h sub al,30h mov byte [cvt],al

;Inputメッセージ mov ah,09h mov dx,crlf int 21h mov dx,msg1 int 21h mov dx,crlf int 21h

;Brainfuckコード入力 mov ah,01h input: int 21h cmp al,0dh jz domsg inc word [len] mov bx,[len] mov byte [cmd+bx],al jmp input

;コード実行 domsg: mov ah,09h mov dx,crlf int 21h mov dx,msg2 int 21h mov dx,crlf int 21h

main: inc word [cps] mov bx,[cps]

cmp byte [cmd+bx],'-' jz decr

cmp byte [cmd+bx],'>' jz next

cmp byte [cmd+bx],'<' jz back

cmp byte [cmd+bx],',' jz getc

cmp byte [cmd+bx],'.' jz putc

;変換分岐 cmp byte [cvt],1 jz cnvrt

;変換不必要 cmp byte [cmd+bx],'+' jz incr

cmp byte [cmd+bx],'[' jz lin

cmp byte [cmd+bx],']' jz lout

;変換必要 cnvrt: cmp byte [cmd+bx],':' jz incr

cmp byte [cmd+bx],']' jz lin

cmp byte [cmd+bx],'\' jz lout

done: mov bx,[mps] cmp byte [mem+bx],0 js err cmp word [mps],0 js err mov dx,[len] cmp [cps],dx js main mov ax,4c00h int 21h

;エラー処理 err: mov ah,09h mov dx,msg3 int 21h mov ax,4c00h int 21h

;+ incr: mov bx,[mps] inc byte [mem+bx] jmp done

;- decr: mov bx,[mps] dec byte [mem+bx] jmp done

;> next: inc word [mps] jmp done

;< back: dec word [mps] jmp done

;. putc: mov bx,[mps] mov dl,[mem+bx] mov ah,02h int 21h jmp done

;, getc: mov ah,08h int 21h mov bx,[mps] mov byte [mem+bx],al jmp done

;[ lin: mov bx,[mps] cmp byte [mem+bx],0 jz skip mov bx,[cps] push bx jmp done

skip: inc word [cps] mov bx,[cps] ;変換分岐 cmp byte [cvt],1 jz scnvrt ;変換不要 cmp byte [cmd+bx],'[' jz li cmp byte [cmd+bx],']' jz ld ;変換必要 scnvrt: cmp byte [cmd+bx],']' jz li cmp byte [cmd+bx],'\' jz ld jmp skip

li: inc byte [lev] jmp skip

ld: cmp byte [lev],0 jz done dec byte [lev] jmp skip

;] lout: pop bx mov word [cps],bx dec word [cps] jmp done

msg0 db "Do you need convert code? (Y:1,N:other)>>$" msg1 db "Input Brainfuck code!$" msg2 db "Output$" msg3 db "Error!!$" crlf db 0dh,0ah,"$" cvt db 0 cmd resb 800h cps dw 0 mem resb 800h mps dw 0 len dw 0 lev db 0

[/c]

ソースコードは多少長く長くなりましたが、実行ファイルの大きさはなんと4.5kB!びっくりするほど小さくなりました~

あ、でもここでは命令用・実行用メモリをそれぞれ0x800個、つまり十進数で2048個取っているのですが、Brainfuckの仕様通りに実行用メモリの数を30000個取るようにすると30kBほどに膨れ上がってしまうんです。その代わり、やはり演算は相変わらずめちゃくちゃ早いですw

ダウンロードは先日と同様こちらからどうぞ。Brainfuckインタプリタ

 

また来週くらいに同様の勉強会があるようなので、続きをやりに行こうと思います!!