「オープンソース」を使ってみよう (第33回 アセンブラ短歌)
03/28
Use it ! OSS No Comments
Tweet
アセンブラ短歌
KOZOSプロジェクト代表
坂井弘亮(さかい・ひろあき)
目次
- 1 アセンブラ短歌とは何か?
- 2 オープンソースです
- 3 セミナーやイベントが行われています
- 4 コンテストが行われています
- 4.1 最優秀作品「虹」
- 4.2 優秀作品「6502の憂鬱」
- 4.3 作品「黄金律は遠い」
- 4.4 作品「ミサカじゃないよ」
- 4.5 作品「ワビサビと書こうと思い頑張ったメモリ不足でワビで妥協す」
- 4.6 作品「うどんに思いを馳せて」
- 5 作品を実行してみよう
- 6 アセンブラの説明
- 7 作品を鑑賞してみよう
- 8 おわりに
1 アセンブラ短歌とは何か?
「アセンブラ短歌」は五・七・五・七・七の三十一バイト(みそひとバイト)から成る
機械語コードでプログラムを書いてみるという近未来の文化的趣味であり,近年,
国内のハッカー間で密かなブームが起きています.
リスト1.1: アセンブラ短歌の作品「夏休み」
6a 00 58 50 40
68 79 61 6d 61 50 40
6a 08 5a 5b 40
68 57 61 6b 61 54 40
59 cd 80 58 58 58 c3
2 オープンソースです
作品の制作は,筆者は主にFreeBSD上でgccを用いて行っています.
他にもZ80や6502といった旧来のマイコンや,VAXなどでの実施例もあります.
これらのためにはオープンソースのアセンブラやシミュレータなどが多く利用
されています.
またアセンブラ短歌は機械語コードとアセンブラの作品を鑑賞するものなので,
当然ながら,作品自体がオープンソースです.
このようにアセンブラ短歌は,オープンソースとの親和性が非常に高い
芸術となっています.
3 セミナーやイベントが行われています
アセンブラ短歌はオープンソースカンファレンス2013Tokyo/Springの
ライトニングトークで初お披露目されました.
さらにOSC2013Nagoyaで初のセミナーが行われています.
セミナーはその後,OSC2013Hokkaido,OSC2013Tokyo/Fall,OSC2014Tokyo/Springでも引続き行われました.セミナー中ではアセンブラ短歌の紹介と説明から始まり,
短歌作品の解説や鑑賞などが行われています.
(OSCでのアセンブラ短歌の発表歴)
- OSC2013Tokyo/Spring ライトニングトーク
- OSC2013Nagoya セミナー・ライトニングトーク
- OSC2013Hokkaido セミナー・ライトニングトーク (レポート)
- OSC2013Tokyo/Fall セミナー・ライトニングトーク
- OSC2014Tokyo/Spring セミナー
またアセンブラ短歌はOSCの他にも,
様々なイベントで積極的に紹介が行われています.
- 2013/ 3/29 第2回APASEC+第2期サイボウズ・ラボユース合同勉強会
発表「アセンブラ短歌」 - 2013/ 8/13~17 セキュリティ・キャンプ2013
キャンプ内BoF「アセンブラ短歌 ~デジタルな侘び寂びの世界~」 - 2013/10/5~6 SECCON2013 信州大会
前日勉強会「アセンブラ短歌 品評会」 - 2013/11/30 TechLION vol.15
ライトニングトーク「アセンブラ短歌」 - 2014/ 1/17 CROSS2014
セミナー「アセンブラ短歌×バイナリかるた」 - 2014/ 1/20 二〇一四 アセンブラ短歌詠みはじめ
書籍発刊記念イベントとして開催 - 2014/ 1/29 Network Security Forum 2014
パネルディスカッション「触媒としてのセキュリティコンテスト ~SECCONの現在までの取組とこれからの展望」内でアセンブラ短歌について紹介 - 2014/ 2/16 AVTOKYO2013.5
発表「わびさびの世界~アセンブラ短歌」 - 2014/ 3/ 1~2 SECCON 2013 全国大会カンファレンス
カンファレンス「アセンブラ短歌 最優秀賞 発表」
アセンブラ短歌コンテスト
4 コンテストが行われています
SECCONというセキュリティ関連のコンテスト大会があります.
2012年度は主にCTF(Capture The Flag)というセキュリティ競技が行われましたが,
2013年度はそれと並行してアセンブラかるた(図4.1),バイナリかるた,
Wiresharkパケット・コンテストなどの様々な競技やコンテストが行われました.
3月には全国大会があり,カンファレンスではアセンブラ短歌のコンテストの
最優秀作品の発表が行われています.当日は受賞者の発表に加え,
和装に扮した歌人による発表が行われました.
アセンブラ短歌のプラットホームはPCで広く利用されているx86アーキテクチャに
限るわけではないのですが,コンテストでは初代ファミコンやApple IIで名を馳せた6502,往年の国産パソコンで利用され今でも現役のZ80,またPC-9801やPC-8001
などの懐かしのアーキテクチャの作品が応募され,掛軸になって展示されました.
表4.1: アセンブラ短歌コンテストの応募作品の一覧
歌人 | 作品名 | アーキ テクチャ |
作品 |
---|---|---|---|
山口文彦 | 黄金律は遠い | x86 |
31 c0 40 89 c3 93 fe c9 7e 06 01 C3 89 c0 eb f5 c3 8b 44 24 08 8b 40 04 8a 08 83 e9 30 eb e1 |
hirosk | ミサカじゃないよ | 6502 |
d0 03 c8 98 60 98 d0 04 c8 ca 50 f4 88 c8 88 8a 48 20 04 06 a8 68 aa 8a ca aa ca aa ca 50 e1 |
大坪雄平 | 虹 | x86 |
BB 00 A2 8E C3 93 F8 B1 04 BF 93 F8 D3 EF 83 C7 17 B0 07 FD 04 20 AA 4F 79 FA B8 00 4C CD 21 |
テツの橘 | ワビサビと 書こうと思い 頑張った メモリ不足で ワビで妥協す |
Z80 |
21 00 80 06 06 11 39 F1 22 50 F3 AF 21 00 F3 28 07 13 79 F0 8A 03 03 00 1A 77 13 23 10 FA C9 |
みむら | うどんに思いを馳せて | MSIL |
20 4A 46 69 93 0A 06 15 1E 62 66 5F 20 00 30 00 00 58 28 01 00 00 0A 06 1E 64 0A 06 2D E8 2A |
安田豊 | 6502 の憂鬱 | 6502 |
A9 00 48 A9 4D 48 A9 4F 48 AA A9 54 48 8A 48 A9 52 68 68 A9 53 48 BA E8 8A A0 01 20 1E AB 60 |
以下に,各作品について紹介させていただきます.
なおアセンブラ短歌コンテストの応募作品については,マイナビより発刊予定の書籍
「0と1のコンピュータ世界 -バイナリで遊ぼう-」にて,さらに詳しい解説つきで紹介させていただくつもりです.
様々なユニークな作品に溢れていますので,こちらもぜひご期待ください.
4.1 最優秀作品「虹」
図4.3は最優秀賞に輝いた,大坪雄平さんによる作品「虹」です.
- 歌人:大坪雄平
- 作品のテーマ:
実行するとテキストのアトリビュートエリアを書き換え画面いっぱいに7色で虹を表現します.画面いっぱいに虹を表現しつつ2句目の1〜2バイト目及び6〜7バイト目がSHIFT-JISで「虹」(93F8)となっており,主虹と副虹を表現しています.最後はシステムコールできれいに終了し,雨上がりに現れる虹の爽やかさを表現しています.
(作品の総評)
MS-DOS/PC-9801(x86)の作品です.テキストVRAMに色属性(上位3ビット)を変化させながらストリング命令で書き込むことで,カラーバー状の虹を生成しています.偶数位置に書き込むため,ストリング命令で減算されることに加えDEC命令が追加されています. ループ回数を漢字コードから演算によって生成されており,「虹」という文字の埋め込みのため2重になった虹が表現されていることには,作者の強いこだわりが感じられます.またダミーのxchg命令とclc命令によりさらに「虹」の1文字を置くことで,主虹と副虹を表現している工夫も見られます.最後がコードゼロで終了することも,雨上がりの雲ひとつ無い青空が表現されているようで晴れやかです. |
リスト4.1: 「虹」のアセンブラ・リスト
BB 00 A2 mov BX,0A200h
8E C3 mov ES,BX
93 xchg AX,BX
F8 clc
B1 04 mov cl,4
BF 93 F8 mov DI,0F893h
D3 EF shr di,cl ;F893 -> 0F89
83 C7 17 add di,17h ;0F89 -> 0FA0 (80*25*2)
B0 07 mov AL,7
FD std
04 20 Loop1: add AL,020h
AA stosb
4F dec DI
79 FA jns Loop1
B8 00 4C mov AX,4C00h; AH=4Ch:終了, AL=DOSへの戻り値。
CD 21 int 21h ; DOSへ戻る
4.2 優秀作品「6502の憂鬱」
- 歌人:安田豊
- 作品のテーマ:
これは 6502 に自分のメーカー名を出力させるプログラムです.
Commodore 64 上で実行すると SOM と出力されます.
(左右逆順で MOS technology 社の MOS となる)
6502 は余りにも多くの人から MOTOROLA 製だと勘違いされ続け,ついに最近では自分でも混乱しはじめました.
今日,久々にメーカー名を尋ねられて,ついに自分でも「もとろー・・・」と口走ってしまいます.(ここまで上の句)
しかしその途中,「あっ」と気がついて慌ててスタックから余計なTとOを回収して,めでたく S を入れて出力することに成功しました.(下の句)
上の句と下の句できれいに処理が分かれ,上の句の最後に「あー」と R を途中まで読み込んだところでハッと我に返って慌てて Pull Stack を連発するところに6502の疲れが読み取れます.
本来OUTSTRルーチンはスタックに逆順に文字列を積まなければならないところを頭から積んでしまったのは気の早い 6502 のご愛敬,ということで.
(作品の総評)
確かに誤解の多い6502とMOSテクノロジーですが,6502で動作しているCommodore 64自身が何も考えずに「MOTOR…」と言いかけて,慌てて言い直す点には洒落が利いており,全体的にコミカルな作品に仕上がっています.2回使われる「O」を保存までしている点も,自信満々ぶりと,自信満々に間違えている様子が見てとれて愛敬があります. ついでに「MOTOROLA」でなく,これも間違いの多い「MOTOLORA」と言いかけるようなうっかりぶりもあるとなお作品が映えたかもしれませんね.(6502にとってはモトローラは他メーカーなので,間違えてしまうのはいたしかたないことかと思います) スタックに積む順番の都合で文字列が逆順に出てしまう点も,おっちょこちょいの少年のような6502のイメージがうまく表現されているようで好感が持てます. |
リスト4.2: 「6502の憂鬱」のアセンブラ・リスト
A9 00 LDA #$00 ; NULL
48 PHA ; Push
A9 4D LDA #$4D ; Load 'M'
48 PHA ; Push
A9 4F LDA #$4F ; Load 'O'
48 PHA ; Push
AA TAX ; A -> X
A9 54 LDA #$54 ; Load 'T'
48 PHA ; Push
8A TXA ; X -> A (‘O’)
48 PHA ; Push
A9 52 LDA #$52 ; Load 'R'
68 PLA ; Pull
68 PLA ; Pull
A9 53 LDA #$53 ; Load 'S'
48 PHA ; Push
BA TSX ; SP -> X
E8 INX ; INC X
8A TXA ; X -> A
A0 01 LDY #$01 ; 1 -> Y
20 1E AB JSR $AB1E ; OUSTR
60 RTS ; return
4.3 作品「黄金律は遠い」
- 歌人:山口文彦
- 作品のテーマ:
上の句がフィボナッチ数を計算するサブルーチン、下の句が main です。
このように上の句と下の句の役割を分けて詠めば、連歌もできたりして…
上の句のうち、初句で初期化、二句と三句で計算をしています。
main ではコマンドラインから一桁の数値を読んで、そのフィボナッチ数を終了コードに返します。とは言っても fib の返戻値が %eax に入って帰ってくるので、main からはただ帰るだけ、call – ret を jmp にしています。
なお、上の句の末尾で韻を踏んでみました。
Ubuntu での動作を確認していますが、他の UNIX でも動きそうです。
コマンドラインの一文字で数値を表していますがアスキーコードから引き算しているだけなので、10 は : 11 は ; 12 は < を入れればよいことになります。
しかし、終了コードは 255 までなので、13 以上の入力に対しては下位 8bit が出てきます…
フィボナッチ数列の隣り合う二項は比を取ると黄金律に収束しますが、5桁くらいまでしか近づけませんでした。^_^;
(作品の総評)
Linux/x86の作品です.処理の内容を句分けしてきれいに57577に収めている点,main()関数を下の句にそのまま含めている点は見事です.さらに異なる命令による押韻が行われており,全体的に非常に完成度の高い作品です. フィボナッチ数の計算にxchg命令を用いている点,関数末尾での関数コールをジャンプ命令で代用している点も,命令削減の効果を生んでいて流麗です. |
リスト4.3: 「黄金律は遠い」のアセンブラ・リスト
31 c0 40 89 c3 fib: clr %eax
inc %eax
mov %eax,%ebx
93 fe c9 7e 06 01 C3 loop: xchg %eax,%ebx
decb %cl
jle end
add %eax,%ebx
89 c0 eb f5 c3 mov %eax,%eax
jmp loop
end: ret
8b 44 24 08 8b 40 04 main: mov 8(%esp),%eax
mov 4(%eax),%eax
8a 08 83 e9 30 eb e1 movb 0(%eax),%cl
sub $48,%ecx
jmp fib
4.4 作品「ミサカじゃないよ」
- 歌人:hirosk
- 作品のテーマ:
アッカーマン関数A(m,n)を計算します.実行時間も比較的長く,末尾再帰および末尾再帰では除去できないものは普通の再帰呼び出しも行っており,複雑な動作をします.
作品名は日本古来よりの萌え文化を大切にしたいので少し萌えた感じで付けました.3句,5句で韻も踏んでいます.
mをXレジスタ,nをYレジスタにいれ,JSR命令でL0をコールするとAレジスタに答えが入ります.ただし,呼び出すときにはYレジスタ,Xレジスタの順に設定してください.
http://skilldrick.github.io/easy6502/ でエミュレートが可能です.
下記のコードを入力して「Assemble」「Run」とすれば,Aレジスタに結果が返されます.アッカーマン関数なのでAに結果が入るところにもこだわりました.A(3,3)までは結果が求まります.それ以上はスタックが足りません.
(作品の総評)
6502の1バイト命令が強力に活かされている作品です. アッカーマン関数は1の加減算が多いためインクリメント/デクリメント命令を 効果的に利用可能で,アセンブラ短歌に非常に向いた処理であることを認識させ られます. 様々な箇所でジャンプ命令を駆使した再帰呼出しが行われており工夫が感じられます. アッカーマン関数の演算が各句に納められていることにもまとまりがあります. また3句目のDEY/INY,4句目のTAX/TXA,5句目のDEX/TAXが単なるNOPでなく 韻を踏むために2命令を繰り返し呼び出している点には小気味よいリズムがあり, 軽快な作品に仕上がっています. |
リスト4.4: 「ミサカじゃないよ」のアセンブラ・リスト
L0: ;; 5 // ack(x,y)=y+1 when x=0
d0 03 BNE L1 ;; x!=0 goto L1
c8 INY ;; y=y+1
98 TYA ;; result is in a
60 RTS
L1: ;; 7 // ack(x,y)=ack(x-1,1) when y=0
98 TYA ;; a=y, y=0?
d0 04 BNE L2 ;; y!=0 goto L2
c8 INY ;; y=1
ca DEX ;; x=x-1
50 f4 BVC L0 ;; get ack(x-1,1)
L2: ;; 5 // ack(x-1, ack(x,y-1)) otherwise
88 DEY
c8 INY
88 DEY ;; y=y-1
8a TXA ;; a=x
48 PHA ;; save x into stack
20 04 06 JSR L0 ;; 7 // get ack(x,y-1)
a8 TAY ;; set y=ack(x,y-1)
68 PLA ;; recover x into a
aa TAX ;;
8a TXA ;;
;; 7 //
ca DEX ;;
aa TAX ;;
ca DEX ;;
aa TAX ;; x=a
ca DEX ;; x=x-1
50 e1 BVC L0 ;; get ack(x-1, ack(x,y-1))
4.5 作品「ワビサビと書こうと思い頑張ったメモリ不足でワビで妥協す」
- 歌人:テツの橘
- 作品のテーマ:
プラットフォームのPC-8001およびZ80の特徴を最大限いかし、わびさびを
表現しようと考えました。
プログラムの動きは単純で、あらかじめ用意した”ワビ”のグラフィック
データをVRAMに直接書き込むだけです。
工夫した点としては、韻を踏むために、57577の先頭は、すべて2xと
1xで統一し、かつ5の段は2x、7の段は1xで始まるようにしました。
また、NOPでの調整を極力さけるため、データ領域を末尾にもってこずに、
0xF139からはじまる中間に埋め込み、その直前で、相対ジャンプを使って、
0xF140からのコピーループに飛ばしています。
また同じくNOPをいれないために、JRではなく、JR Zを使い、0xF133で、
Zフラグを立てるために、XOR Aをしています。
また、このXOR Aは、Z80では多様されていたテクニック※で、
今回、私がどうしても埋め込みたかったコードです。
唯一0xF13Fに、0x00を埋め込みましたが、これは調整のためのNOPではなく、
あくまでデータ列の最後を意味する0x00です。
今回、唯一残念なのは、0xF12Dで、絶対アドレスを指定しているため、
コードがリロケータブルでなくなってしまった点です。
※XOR Aは、次の二つの用途で利用されていた
・LD A,0x00(2バイト)と等価の動作を、XOR Aでは1バイトですむ
エコなコーディング
・XOR Aは演算で必ず0になるため、Z-FLAGをセットするために利用される
(作品の総評)
PC-8001(Z80)のテキストベースグラフィック(低解像度グラフィック)を利用した作品です.4句目にきれいに納められた出力データを,0xf300から始まるテキストVRAM領域に直接書き込むことでグラフィック描画しています.各句の先頭で小さい値で韻が踏まれているため,軽めのリズムが感じられます. Z80オリジナルで8080には存在しないDJNZ命令,またZ80で多用された「XOR A」が利用されていることには,熟練したプログラマによる十分に熟成した鮒ずしのような風味を感じさせ,タイトルにある「ワビ」の境地がうまく表現されています. |
リスト4.5: 「ワビサビと書こうと思い頑張ったメモリ不足でワビで妥協す」のアセンブラ・リスト
F128 LD HL,0x8000 ; PC-8001 VRAM ATTRIBUTE(GRAPHICS)
F12B LD B,0x06 ; SET LOOP COUNTER
F12D LD DE,0xF139 ; SET START ADDRESS OF DATA
F130 LD (0xF350),HL ; SET VRAM ATTRIBUTES
F133 XOR A ; SET Z-FLAG
F134 LD HL,0xF300 ; SET START ADDRESS OF PC-8001 VRAM
F137 JR Z,+0x07 ; JUMP TO COPY ROUTINE WHEN Z-FLAG IS TRUE
F139 DATA 0x13 0x79 0xF0 0x8A 0x03 0x03 0x00 ; OUTPUT GRAPHIC DATA
F140 LD A,(DE) ; READ FROM DATA
F141 LD (HL),A ; WRITE TO VRAM
F142 INC DE ; INCREMENT POINTER FOR READ
F143 INC HL ; INCREMENT POINTER FOR WRITE
F144 DJNZ 0xFA ; LOOP
F146 RET ; RETURN TO N-BASIC
4.6 作品「うどんに思いを馳せて」
- 歌人:みむら
- 作品のテーマ:
香川にぶらりと立ち寄った際、ふと短歌を一句詠みたくなり、
普段お世話になっている Microsoft .NET 環境を用いて作成しました。
「おうどん」という文字列の文字一つ一つが、0x30?? で表現できること、
そしてldc 命令を用いて値設定を行うと5バイトになることを使用して
三十一バイトに納めました。
定数設定が5バイト、それ以外が7バイトというところや、ループをして文字を出力した後、きれいにループを抜けて ret で美しく終わらせている点、出力される文字列がひらがなである点がアピールポイントではないかと考えています。
(作品の総評)
4文字の先頭バイトが共通していることを利用して,4バイトデータからシフト演算により1バイトデータを順次取り出すことで,出力データを圧縮している点に工夫が見られます.アーキテクチャがスタックベースであるためPUSH/POPが繰り返されており,長時間こねられた腰の強いうどんになりそうです. |
リスト4.6: 「うどんに思いを馳せて」のアセンブラ・リスト
ldc.i4 0x9369464A
stloc.0
Write:
ldloc.0
ldc.i4.m1
ldc.i4.8
shl
not
and
ldc.i4 0x3000
add
call void [mscorlib]System.Console::Write(char)
ldloc.0
ldc.i4.8
shr.un
stloc.0
ldloc.0
brtrue.s Write
ret
5 作品を実行してみよう
リスト1.1で紹介した作品「夏休み」を動かすことで,
アセンブラ短歌に入門してみましょう.
まずなんらかのGNU/Linuxディストリビューション環境で,バイナリエディタによって
「夏休み」のバイトコードをファイル化します.
筆者はCentOS上で,hexeditというバイナリエディタを使いました.
作成した natsuyasumi.bin を objdump で逆アセンブルすることで,
アセンブラを出力させます.
リスト5.1: objdumpで逆アセンブルする
$ objdump -b binary -m i386 -D natsuyasumi.bin
natsuyasumi.bin: file format binary
Disassembly of section .data:
00000000 <.data>:
0: 6a 00 push $0x0 ┐
2: 58 pop %eax │1句目
3: 50 push %eax │5バイト
4: 40 inc %eax ┘
5: 68 79 61 6d 61 push $0x616d6179 ┐
a: 50 push %eax │2句目
b: 40 inc %eax ┘7バイト
c: 6a 08 push $0x8 ┐
e: 5a pop %edx │3句目
f: 5b pop %ebx │5バイト
10: 40 inc %eax ┘
11: 68 57 61 6b 61 push $0x616b6157 ┐
16: 54 push %esp │4句目
17: 40 inc %eax ┘7バイト
18: 59 pop %ecx ┐
19: cd 80 int $0x80 │
1b: 58 pop %eax │5句目
1c: 58 pop %eax │7バイト
1d: 58 pop %eax │
1e: c3 ret ┘
$ └───────┘ └─────────┘
機械語コード ニーモニック
リスト5.1を見てみてください.
左側に出力されている機械語コードは,
5バイト,7バイト,5バイト,7バイト,7バイトの位置で区切ることができます.
つまり「5・7・5・7・7」のようになっているわけです.
このようなアセンブラ・プログラムを「アセンブラ短歌」と呼んでいます.
さらにニーモニック部分を切り出し,適当なヘッダをつけることで
アセンブルできる状態にします.
$ printf "\t.section .text\n" > natsuyasumi.S $ printf "\t.global main\n" >> natsuyasumi.S $ printf "\t.type main, @function\n" >> natsuyasumi.S $ printf "main:\n" >> natsuyasumi.S $ objdump -b binary -m i386 -D natsuyasumi.bin | tail -n 20 | cut -c 28- >> natsuyasumi.S
gccでアセンブルして見ましょう.
$ cat natsuyasumi.S .section .text .global main .type main, @function main: push $0x0 pop %eax push %eax inc %eax push $0x616d6179 push %eax inc %eax push $0x8 pop %edx pop %ebx inc %eax push $0x616b6157 push %esp inc %eax pop %ecx int $0x80 pop %eax pop %eax pop %eax ret $ gcc natsuyasumi.S -o natsuyasumi $ ./natsuyasumi Wakayama$
bashのプロンプトの「$」が続いているためわかりにくいですが,
「Wakayama」と出力されています.
6 アセンブラの説明
アセンブラによるプログラミングには馴染みの無いかたも多いでしょうから,
ここで簡単に説明しておきましょう.
6.1 機械語コードとニーモニック
リスト5.1では中央の「6a 00」「58」「50」のような16進数コードの列が
「機械語コード」,右側の「push $0x0」「pop %eax」「push %eax」などと
なっている列が「ニーモニック」と呼ばれる部分です.
CPUは機械語コードを実行します.つまりメモリ上には
「6a 00 58 50…」のようなバイト列が置かれていて,
CPUはメモリ上からバイト列を読み込みながら実行します.
例えば「6a 00」ならば,スタック上にゼロという値を格納します.
「58」ならばスタックからレジスタに値を復旧する,という動作をします.
数値に対応する動作をするように,CPU内部の回路が設計してあるわけです.
これはCPUがネイティブに実行できる命令です.
しかしCPUへの命令を,「6a 00」「58」などのように数字として扱うのでは,
我々人間にはわかりにくくてしょうがありません.
そこで「6a 00」は便宜上「push $0x0」と表記することにします.
このような人間向きの表記を「ニーモニック」と呼びます.
さらに「push $0x0」というニーモニックがあったら「6a 00」という
バイトコードに変換するようなツールを作成すれば,我々人間はわかり
やすいニーモニックでプログラミングすることができます.
これが「アセンブラ」と呼ばれるツールです.
6.2 命令を3つだけ覚えてみよう
リスト5.1をもう一度見てみましょう.
ニーモニックの部分を見ると,「push」「pop」「inc」という3つの命令が
使われています.つまり,この3つの命令だけ覚えてしまえば,
リスト5.1の動作は読み解けます.
「push」はスタックへの「プッシュ」と呼ばれ,引数で与えられた値を
スタックに保存します.具体的には,スタックポインタの値を減算し,
さらにスタックポインタの指す先のメモリ上に引数の値を書き込みます.
「pop」は「ポップ」と呼ばれその逆の動作で,スタックから値を読み込みます.
「push」の引数には,「$0x0」「$0x616d6179」のような定数値が指定されています.
つまりこれらの定数値をスタック上に書き込むわけです.
また「%eax」「%ebx」のようなものが指定されている箇所もあります.
これらは「レジスタ」と呼ばれるもので,CPUが持っている固定の変数だと思って
いただいて構いません.「push %eax」ならばEAXレジスタに格納されている値を
スタックに書き込み,「pop %edx」ならばスタック上の値をEDXレジスタに読み込む,
ということになります.
そして「inc」はインクリメントと呼ばれる命令で,引数を1,増加させます.
例えば「inc %eax」ならば,EAXレジスタの値を1増加させることになります.
さて,リスト5.1のプログラムは,ここまでの説明でほとんどの部分を読み解くことが
できます.動きを追ってみましょう.
6.3 1句目
まず最初の1句目の5バイトは,push,pop,incから構成されています.
0: 6a 00 push $0x0 2: 58 pop %eax 3: 50 push %eax 4: 40 inc %eax
「0x」は16進数で,という意味です.「0x0」という値,つまりゼロをスタックに
保存します.が,直後のpopですぐに取り出してEAXレジスタに読み込みます.
ということはこれは,スタックを経由してEAXレジスタに「ゼロ」という値を
設定していることになります.
さらにその直後のpushでEAXレジスタの値をスタックに書き込みます.
これでスタックにはゼロが積まれることになります.さらにincでEAXレジスタを
インクリメントすることで,EAXは「1」という値になります.
6.4 2句目
次に2句目の7バイトの部分です.
5: 68 79 61 6d 61 push $0x616d6179 a: 50 push %eax b: 40 inc %eax
push命令により「0x616d6179」という4バイトの値をスタックに積んでいます.
これはASCIIコードで「yama」という文字列になります.
つまりスタック上に,「yama」という文字列が積まれることになります.
リトルエンディアンなので,順番が逆になっていることに注意してください.
EAXにはいま「1」という値が格納されています.2つ目のpushによってEAXの値,
つまり「1」をスタックに積み,incによってEAXをインクリメントします.
これによりEAXの値は2になります.
6.5 3句目
さらに3句目の5バイトの部分に続きます.
c: 6a 08 push $0x8 e: 5a pop %edx f: 5b pop %ebx 10: 40 inc %eax
まずスタックに「8」という値をpushしています.その後それらをEDXとEBXレジスタ
にpopします.これによりEDXには「8」,EBXには先ほどのEAXのpushにより保存された「1」という値がスタック経由で格納されることになります.
なおEAXはinc命令によってさらに増加し,「3」という値になります.
6.6 4句目
次に4句目の7バイトの部分です.
11: 68 57 61 6b 61 push $0x616b6157 16: 54 push %esp 17: 40 inc %eax
push命令により「0x616b6157」という4バイト値がスタックに積まれます.
これは「Waka」という文字列になりますので,「Waka」の4文字がスタックに
積まれることになります.スタック上には先ほど積まれた「yama」という
文字列がありますのでこれらは連結し,「Wakayama」という文字列が
置かれていることになります.
さらにESPというレジスタの値をpushしています.ESPはスタックポインタです.
またEAXレジスタはinc命令により増加し「4」という値になります.
6.7 5句目
スタックに保存したESPの値は,最後の5句目の先頭のpop命令によりECXに
戻されます.
18: 59 pop %ecx
このためスタックポインタの値がスタックを経由してECXレジスタにコピーされる
ことになります.スタックポインタは実は先ほどの「Wakayama」という文字列を
指していますので,ECXは「Wakayama」という文字列を指すことになります.
続けて5句目を見ていきましょう.
19: cd 80 int $0x80
これはシステムコール命令というもので,システムコールを呼び出します.
これでLinuxカーネルに処理が渡り,あとはカーネルがシステムコールの処理を
実行します.
さてここで,レジスタの値は以下のように設定されています.
- EAX … 4
- EBX … 1
- ECX … “Wakayama”
- EDX … 8
そしてLinuxのシステムコールは,EAXレジスタでシステムコール番号,
EBX/ECX/EDXで第1/2/3引数を渡すことになっています.
システムコール番号が「4」のシステムコールは,writeシステムコールです.
よってこれは以下のようなシステムコールが呼ばれることになります.
write(1, "Wakayama", 8);
これで標準出力に「Wakayama」の8文字が出力されることになります.
最後は後始末です.
1b: 58 pop %eax 1c: 58 pop %eax 1d: 58 pop %eax 1e: c3 ret
スタック上には”Wakayama”の文字列が置かれていますが,これらをpopで回収し,
整合をとります.さらに3つ目のpopでは,最初のほうでスタックに積んでおいた
「ゼロ」という値がEAXレジスタに読み込まれます.これにより関数からの戻り値
として「ゼロ」が設定されます.
最後に「ret」命令は,関数から戻る命令です.これで関数から返ることになります.
7 作品を鑑賞してみよう
このアセンブラ・プログラムはLinuxのwriteシステムコールによって単に
「Wakayama」の8文字を出力するだけのものです.
が,実はプログラム中には,以下のような工夫が入れ込まれています.
- writeシステムコール番号の「4」という値を生成するのに4つのinc命令を
使っている. - さらにそれらを各句の末尾に配置することで,各句の末尾で韻をふんでいる.
(最初にあげた「夏休み」のダンプで,各句の末尾が「40」になっていることに注目)
本来,EAXに「4」という値を格納するには直接代入してしまっても構わないのですが,韻を踏むためにあえて4つのinc命令を呼んでいるわけです.
もう一度,作品「夏休み」のバイトコードを見てみましょう.
各句の終端に注目してください.「40」で韻が踏まれていることがわかるでしょうか.
6a 00 58 50 40
68 79 61 6d 61 50 40
6a 08 5a 5b 40
68 57 61 6b 61 54 40
59 cd 80 58 58 58 c3
単なる文字列出力のプログラムではなく,このように趣向を凝らして味わい深さを
追求するものが「アセンブラ短歌」です.
そして作品「夏休み」には,以下のような総評をしています.
「夏休み」というタイトルの意味がおわかりいただけるでしょうか.
最初にゼロ設定したEAXがinc命令で1ずつ増加していく際に,その値を流用して EBXや戻り値のEAXを設定していくさまは,流れる小川のせせらぎのようです. またニーモニックを見ると「push-pop-push-inc, push-push-inc」 「push-pop-pop-inc, push-push-inc」というスキップするようなリズムがあり, 小川のほとりで遊ぶ子供たちの情景が浮かんできます.このため「夏休み」という タイトルにしました. 最後に同じpopが連続していることはいつまでも続くかのような余韻が感じられ, しかしいつかは(retで)終わってしまうというはかなさもあり,「夏休み」という テーマがよく表現されています. 各句が40というバイトコードで終了することで韻を踏んでいることも小気味よく, 命令調整のための安易なnopが無いことも爽やかに感じられます. |
8 おわりに
いかがだったでしょうか.
アセンブラ短歌は31バイトという短いサイズでプログラムを書くため,
アセンブラ・コーディングの練習用の手軽な題材として扱えます.
このため,アセンブラ学習の入門向けとして良い教材になるのではないかと
思っています.
初心者が学習するためには,教科書となる書籍が必要です.そのようなわけで,
「31バイトでつくるアセンブラプログラミング 〜アセンブラ短歌の世界〜」
という書籍がSECCON関係者によって執筆されています.
- (マイナビ) https://book.mynavi.jp/ec/products/detail/id=24267
- (達人出版会) http://tatsu-zine.com/books/assenbly-language-programing-tanka
またアセンブラ短歌が気軽に試せるWebページ「Assembler Tanka on Javascript」
が著者のひとりである愛甲健二さんによって作成されています.
http://07c00.com/asmtanka_on_js/
「スマフォで気軽にアセンブラ短歌」がウリ文句ですので,
ぜひ遊び感覚で気軽に試してみてはいかがでしょうか?