GNU Assembler x86_64でFizzBuzz

# x86_64でFizzBuzz
うぃーすTrimscashです．
数字を文字列に変換するサブルーチンを作ることに成功したんで
この記事では作ったFizzBuzzのプログラムとSyscall解説，役に立つリンクを共有するぞい

# コード
ちょいときたないかもしれんがゆるしてちょ．いずれ直す．．．と思う
```
.intel_syntax noprefix
.global main

main:
        mov rcx, 0

loop:
        push rcx#index hyouji
        call print_num##
fizz:
        mov rdx, 0#joui byte wararerukazu
        mov rax, rcx#kai byte wararerukazu  
        mov r15, 3#waru kazu
        div r15#waru rdx ni amari     rax ni shou
        cmp rdx, 0#rcx-0 rdx amari rax shou
        jnz fizzend#
        push 4
        lea r11, _fizz
        push r11
        call print#
        pop r15
        pop r15
fizzend:
buzz:
        mov rdx, 0x0#joui byte wararerukazu
        mov rax, rcx#kai byte wararerukazu
        mov r15, 5#waru kazu
        div r15#waru rcx ni amari     rax ni shou
        cmp rdx, 0x0#rcx-0
        jnz buzzend#
        push 4
        lea r11, _buzz
        push r11
        call print
        pop r15
        pop r15
buzzend:
        inc rcx

        push 1
        lea r11,_newline
        push r11
        call print

        cmp rcx, 0xffff
        jnz loop
loopend:
exit:
        mov rax, 60#exit
        mov rdi, 0x1
        syscall

#push num/call print_num
#sei no sei suu wo hyoujun shutu ryoku
print_num:
        push rcx
        push r15
        push r14
        push r13
        push r12
        push rdi
        push rbp
        mov rbp, rsp
        mov r15, [rbp+64]#dai 1 hikisuu
        mov rcx, 0
        mov r14, 1
        push 0#null
print_num_loop:
        mov rax, r14
        mov r14, 10
        mov rdx, 0
        mov rax, r15#wararerukazu
        div r14# rax shou /rdx amari
        mov r13, rdx
        mov r15, rax
        add r13, 48#asciiiiii
        push r13
        inc rcx#ketasuu
        cmp r15, 0
        jnz print_num_loop
print_num_loop_end:
        inc rcx#size ketasuu

        mov rax, 12
        mov rdi, 0
        syscall#brk ni 0 wo watasi gennzaino heap seg no address wo shutoku(rax
        mov r12, rax

        mov rax, 12
        mov rdi, r12
        add rdi, rcx
        syscall#brk ni rcx wo watasi rcx byte wokakuho senntou address ha rax ni

        mov rcx,0
print_num_loop_write_mem:
        pop r13
        cmp r13, 0
        jz print_num_loop_write_mem_end#null gakitara osimai
        mov r15, r12
        add r15, rcx
        mov [r15], r13
        inc rcx
        jmp print_num_loop_write_mem
print_num_loop_write_mem_end:
        push rcx
        push r12
        call print
        pop r12
        pop r12

        pop rbp
        pop rdi
        pop r12
        pop r13
        pop r14
        pop r15
        pop rcx
        ret
#subrootin end



#push address (not string
#print string      push address
print:
        push rax
        push rcx
        push rbp
        mov rbp, rsp
        mov rax, 0x1 #write
        mov rdi, 0x1 #std 1
        mov rsi, [rbp+32] #mojiretu address
        mov rdx, [rbp+40] #size
        syscall
        pop rbp
        pop rcx
        pop rax
        ret#
#subrootin end

_newline:
        .ascii "\n"
_fizz:
        .ascii "fizz"

_buzz:
        .ascii "buzz"
```

# syscall

syscall とは．．OSが用意してくれているサブルーチン


#### 使い方
#### 1.raxレジスタに使用したいsyscallの番号を入れる
```
mov rax, <syscall num>#syscall番号
...
```
#### 2.引数はそのほかのレジスタに入れる
|第n引数|1|2|3|4|5|6|
|----|----|----|----|----|----|----|
|register|rdi|rsi|rdx|r10|r8|r9|
```
mov rax, <syscall num>
mov rdi,<arg1>#第一引数
...
```
#### 3.syscall命令を実行することで呼び出す
```
mov rax, <syscall num>
mov rdi,<arg1>#第一引数
syscall #でsystem callを実行
```
#### 返り値がある場合はrax
返り値は自動でraxに入る．
なのでraxは破壊される．ので保持したい場合はsyscallする前にpushしておく
#### rcxとr11のレジスタは破壊されるぽい
破壊されたくない場合syscallする前にrcxとr11はpushしておく

https://stackoverflow.com/questions/47983371/why-do-x86-64-linux-system-calls-modify-rcx-and-what-does-the-value-mean

#### Syscall一覧
非常にわかりやすいサイトのリンクを載せておく
ダブルクリックで必要な引数を確認できる．

https://filippo.io/linux-syscall-table/

#### 今回使用したSyscall
使用したsystem callは以下の三つ

| sycall num | Name|説明|
| ---- | ---- |----|
| 1 | write|rdi に1を入れてやると標準出力．<br>rsiに文字列の先頭アドレス．<br>rdxに文字数.
| 12 | brk |ヒープセグメントにメモリを確保するSyscall．返り値に先頭のアドレスを返す．<br>これを利用しこのプログラムではまず0 byte確保しヒープセグメントのアドレスを取得している．
| 60 |exit | exit()関数と同じ挙動．プログラムの終わりで使う

詳しい使い方は上記のSyscall一覧を見てほしい

# リンク集
- Syscall一覧↓

https://filippo.io/linux-syscall-table/

- brkの使いかた，アセンブラの入門↓

https://www.mztn.org/lxasm/asm08.html

- アセンブラ入門（少し古め，けどわかりやすい）↓

http://doomo.main.jp/x86asm/

- 命令一覧↓

https://c9x.me/x86/

- Directive 一覧↓ 

https://ftp.gnu.org/old-gnu/Manuals/gas-2.9.1/html_chapter/as_7.html

- 汎用レジスタ一覧↓

https://www.jamieweb.net/info/x86_64-general-purpose-registers-reference/

- 推し，このプログラムを書いたきっかけ

https://www.youtube.com/watch?v=HFzk0fKDm_w&t=2399s&ab_channel=%E4%BD%8E%E3%83%AC%E3%82%A4%E3%83%A4%E3%83%BC%E3%82%AC%E3%83%BC%E3%83%AB

# さいご
コンパイルしてリンクするには
```
$ gcc -c filename.s -o filename.o&&ld -e main -o filename filename.o
```
で行けるはず

これ初めての投稿らしいからわかりにくいの許して．すべて許してタスク全然やってないのも授業中寝ちゃうのもすべて


qiitaにコード貼り付けるときrcxが破壊されることをわすれてrcxをpushしpopするとこを消してしまっていました．(しゅうせいずみ
教えていただきありがとうございます．