nasmで1~100まで数える


はじめに

nasmで1~100を表示させるコードを書いたので、ここにメモしました。
基本的には前回の応用です。読んでください。

コード

ソースコード

; 初期設定
extern  printf                  ; printf関数を持ってくる

; データセクション
section .data
    fmt: db "%d", 10, 0         ; printfで用いるフォーマット

; コードセクション
section .text
    global _start               ; _startを指名

; スタート
_start:
    ; 1. 必要な値の代入
    mov     rdx, 1              ; カウントの初期化

    mov     rcx, 100            ; ループ回数

; 2. ループの先頭
_loop:
    ; 3. 維持して置きたい値の避難
    push   rcx                  ; rcxの避難
    push   rdx                  ; rdxの避難

    ; printfに用いる値のセット
    mov    rdi, fmt             ; フォーマット
    mov    rsi, rdx             ; カウントしている値

    ; コール
    call   printf               ; printfをコール

    ; 4. スタックの値をレジスタに戻す
    pop    rdx                  ; rdxを持ってくる
    pop    rcx                  ; rcxを持ってくる

    ; 5. インクリメントする
    add    rdx, 1               ; rdxに1加算

    ; 6. ループバック
    loop _loop                  ; ループバック

; 後処理
fin:
    mov    rax, 1               ; システムコール番号(sys_exit)
    mov    rbx, 0               ; 終了ステータスコード
    int    0x80                 ; システムコール

実行

$ nasm -f elf64 ファイル名
$ gcc 生成したオブジェクトファイル名 -nostartfiles -no-pie
$ ./a.out
1
2
3
4
.
.
.
97
98
99
100

解説

1. 各値の指定 

表示するようの値としてrdxを用いるので、初期値として1を代入します
x86-64だとrcxに置いた回数だけループされるので、以下のコードでrcxに100を入れます。

mov     rdx, 1 
mov     rcx, 100

2. 6. ループをセット

_loopというラベルを貼り、loop _loopが来たときrcxがゼロ以外ならループします。

_loop:
ここにコード
loop _loop

3. 維持して置きたい値の避難

printfのコール時にレジスタの値が消えてしまうので、スタックに避難させます。

push    rcx
push    rdx

4. 避難させたスタックをレジスタに戻す

上記のスタックに避難させた各値をレジスタに戻します。

pop    rcx
pop    rdx

5. rdxに1加算

rdxに1加算します。

add    rdx, 1 

さいごに

こんな感じで、1~100を呼び出しました。
何か間違ったこと等あればコメントください。