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

アセンブラ短歌を詠みつつブログを始めてみた

NetBSD

あけましておめでとうございます。

2014年の幕開けにあわせて、人もすなる日記といふものを始めようと思いたちました。

最初の日記は新年らしく(?)アセンブラ短歌を詠んでみることにしました。

アセンブリ短歌とは、http://kozos.jp/asm-tanka/で紹介されているように、機械語命令がちょうど五・七・五・七・七の並びにおさまるようにしたプログラムのことであります。

さっそく九九の表を出力するアセンブラ短歌を読んでみます。環境はNetBSD-6.1-i386です。
(数値を出力したかったのですが、ASCII文字にマッピングした文字を出力しています...)

コメントの5,7,5...の部分が五・七・五の切れ目になっており、このmain関数はアセンブラ短歌が2首入っています。

.globl  main
main:
        mov     $0x01, %eax     # 5
xloop:  mov     $0x01, %ebx
yloop:  push    %eax
        nop                     # 7
        imul    %ebx
        add     $0x1f, %eax     # 5
        call    my_putchar
        mov     $0x20, %al      # 7
        call    my_putchar
        pop     %eax
        inc     %ebx            # 7
        cmp     $0x0a, %ebx
        jnz     yloop           # 5
ybreak: inc     %eax
        cmp     $0x0a, %al
        jz      xbreak
        push    %eax
        nop                     # 7
        mov     $0xa, %eax      # 5
        call    my_putchar
        pop     %eax
        nop                     # 7
        jmp     xloop
xbreak: nop
        nop
        nop
        nop
        ret                     # 7

.globl  my_putchar
my_putchar:
        sub     $0x10, %esp
        mov     %eax,(%esp)
        mov     %esp,%eax
        movl    $0x1, 0xc(%esp)
        movl    %eax, 0x8(%esp)
        movl    $0x1, 0x4(%esp)
        mov     $0x4, %ax
        int     $0x80
        add     $0x10, %esp
        ret

コンパイルと実行結果は以下のようになります。

$ gcc -Wall -Werror -g kuku.s
$ ./a.out
  ! " # $ % & ' (
! # % ' ) + - / 1
" % ( + . 1 4 7 :
# ' + / 3 7 ; ? C
$ ) . 3 8 = B G L
% + 1 7 = C I O U
& - 4 ; B I P W ^
' / 7 ? G O W _ g
( 1 : C L U ^ g p

1首目の短歌を逆アセンブルして見てみます。五・七・五・七・七のリズムで機械語命令を区切ることができます。

$ objdump -d a.out | grep -A20 '<main>:'
080486a0 <main>:
 80486a0:       b8 01 00 00 00          mov    $0x1,%eax

080486a5 <xloop>:
 80486a5:       bb 01 00 00 00          mov    $0x1,%ebx

080486aa <yloop>:
 80486aa:       50                      push   %eax
 80486ab:       90                      nop
 80486ac:       f7 eb                   imul   %ebx
 80486ae:       83 c0 1f                add    $0x1f,%eax
 80486b1:       e8 28 00 00 00          call   80486de <my_putchar>
 80486b6:       b0 20                   mov    $0x20,%al
 80486b8:       e8 21 00 00 00          call   80486de <my_putchar>
 80486bd:       58                      pop    %eax
 80486be:       43                      inc    %ebx
 80486bf:       83 fb 0a                cmp    $0xa,%ebx
 80486c2:       75 e6                   jne    80486aa <yloop>

080486c4 <ybreak>:
 80486c4:       40                      inc    %eax

アセンブラ短歌の詠み方としては、以下のような流れになります。

  1. アセンブリ言語でプログラムを書く
  2. アセンブルして動かしてみる(この段階では五・七・五は考えない)
  3. objdump -dで逆アセンブルし、五・七・五...になるよう調整する

x86アーキテクチャでは、意外と最初から五・七・五...になっていることも多いです。
機械語命令がうまいこと五・七・五...にならない場合、以下の方法で命令数を調整します。

  • nop(1byte命令)で埋める
  • movで代入するレジスタをeax→al等にして命令数を増減させる
  • 機械語命令の順番を入れ替える(入れ替えても問題がない場合のみ)

これ他にも機械語命令数の調整方法はあるかと思います。筆者は上記の3パターンで何とかアセンブラ短歌を詠めています。

皆様も新年はアセンブラ短歌で(プログラムの)書き初めをしてみてはいかがでしょうか。

【1/4追記】環境の記述が抜けていたので追記しました。