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しておく
Syscall一覧
非常にわかりやすいサイトのリンクを載せておく
ダブルクリックで必要な引数を確認できる.
今回使用したSyscall
使用したsystem callは以下の三つ
sycall num | Name | 説明 |
---|---|---|
1 | write | rdi に1を入れてやると標準出力. rsiに文字列の先頭アドレス. rdxに文字数. |
12 | brk | ヒープセグメントにメモリを確保するSyscall.返り値に先頭のアドレスを返す. これを利用しこのプログラムではまず0 byte確保しヒープセグメントのアドレスを取得している. |
60 | exit | exit()関数と同じ挙動.プログラムの終わりで使う |
詳しい使い方は上記のSyscall一覧を見てほしい
リンク集
- Syscall一覧↓
- brkの使いかた,アセンブラの入門↓
- アセンブラ入門(少し古め,けどわかりやすい)↓
- 命令一覧↓
- Directive 一覧↓
- 汎用レジスタ一覧↓
- 推し,このプログラムを書いたきっかけ
さいご
コンパイルしてリンクするには
$ gcc -c filename.s -o filename.o&&ld -e main -o filename filename.o
で行けるはず
これ初めての投稿らしいからわかりにくいの許して.すべて許してタスク全然やってないのも授業中寝ちゃうのもすべて
qiitaにコード貼り付けるときrcxが破壊されることをわすれてrcxをpushしpopするとこを消してしまっていました.(しゅうせいずみ
教えていただきありがとうございます.