電気ひつじ牧場

技術メモ

nasmのプリプロセッサでフィボナッチ数列を作ってみたよ

セキュリティキャンプに参加できるようになったのはいいけど低レイヤもx64も全然わからんので最近その辺りを勉強してます。
「低レベルプログラミング(翔泳社)」にnasmのマクロプロセッサで素数判定しようと言う節があったのでそれに倣ってフィボナッチ数列を書いてみます。

fibo.asm

global _start
section .data
    %assign limit 0x14
    fibo: dw 0, 1
    %assign i 0 
    %assign j 1 
    %rep limit
        %assign k i+j 
        dw k
        %assign i j 
        %assign j k 
    %endrep

section .text
ret_fibo:
    xor rax, rax 
    mov ax, [fibo + 2*rdi]  ;dwで数列の要素を書き込んだので2*rdiでアクセスする。
    ret 

_start:
    mov rdi, 0xd ; 0xd(=13)番目の値を取得する
    call ret_fibo
    ;exitシステムコール
    mov rdi, rax 
    mov rax, 0x3c
    syscall
$ nasm -felf64 -g -o fibo.o fibo.asm  // -gオプションを付けないとデバック時にシンボルが見つからないって怒られるぞい
$ ld -o fibo fibo.o
$ ./fibo
$ $?
233: command not found

%rdiにフィボナッチ数列の0xd番目の要素を格納し,$?により終了ステータスとして値を取り出しています。
0xdをハードコードしているのは本質から外れたコードを除きたかったからで、決して読み込みのルーチンを書くのが面倒だったりそんな技術力が無かったりしたわけではありません。

プリプロセッサにより置換された部分を抜粋してみます。
nasm -Eプリプロセッサによりシンボルが展開されたソースを確認することができます。

$ nasm -E fibo.asm

...
fibo: dw 0, 1
%line 12+1 fibo.asm
 dw 1
%line 12+0 fibo.asm
 dw 2
 dw 3
 dw 5
 dw 8
 dw 13
 dw 21
 dw 34
 dw 55
 dw 89
 dw 144
 dw 233
 dw 377
 dw 610
 dw 987
 dw 1597
 dw 2584
 dw 4181
 dw 6765
 dw 10946
%line 13+1 fibo.asm
[section .text]
ret_fibo:
 xor rax, rax
 mov ax, [fibo + 2*rdi]
 ret

_start:
 ...

コードの実行前にはすでにプリプロセッサによりフィボナッチ数列が計算されメモリ上に展開されています。

マクロについて

置換

nasmのマクロプロセッサでは以下のようにして置換を定義することができます。

%define   hoge 0x0+0x1
%xdefine bar    0x0+0x1
%assign   foo   0x0+0x1

mov rax, hoge
mov rax, bar 
mov rax, foo 
$ nasm -E test.asm

%line 1+1 macro.asm

%line 5+1 macro.asm

mov rax, 0x0+0x1
mov rax, 0x0+0x1
mov rax, 1

上の実行結果から見てわかるように、%assignは%defineと異なり遅延評価されません。

for文

%rep n
forがかける!!!すごい!...のか?