アセンブリ言語でFizzBuzzをやってみる


このくらい出来なきゃと思い、実践。

感想

  • 二桁以上の数値出力に手こずった。
  • スタックポインタを手動で戻すことが出来たのが嬉しい。
  • 一旦アセンブリはこのくらいにしておく。

ソースコード

.intel_syntax noprefix
.global _start

# gcc fizzbuzz.s -c -o fizzbuzz.o 
# ld -o fizzbuzz.bin fizzbuzz.o

# div
# 割られる数: RDX:RAX(128bit)を <r>(64bit)で割る
# 割る数    : div <r>
# 答え      : rax
# 余り      : rdx

_start:
    mov rcx, 1

loop:
    # count % 15 == 0
    mov r15, 15
    mov rdx, 0
    mov rax, rcx
    div r15
    cmp rdx, 0
    jz print_fizzbuzz 

    # count % 5 == 0
    mov r15, 5
    mov rdx, 0
    mov rax, rcx
    div r15
    cmp rdx, 0
    jz print_buzz

    # count % 3 == 0
    mov r15, 3
    mov rdx, 0
    mov rax, rcx
    div r15
    cmp rdx, 0
    jz print_fizz

    # 数値出力
    mov r12, 0
    # 1の桁、10の桁
    mov rdx, 0
    mov rax, rcx
    mov r15, 10
    div r15
    add rdx, 0x30 # asciiコードにする
    push rdx
    inc r12
    add rax, 0x30
    push rax
    inc r12
    # 100の桁
    mov rdx, 0
    mov rax, rcx
    mov r15, 100
    div r15
    add rax, 0x30
    push rax
    inc r12

print_rsp:
    cmp r12, 0
    jz count
    dec r12

    mov rax, 1      # write
    mov rdi, 1      # stdout
    lea rsi, [rsp]  # buf メモリ番地代入
    mov rdx, 1      # buflen
    push rcx # syscallで壊れるので退避
    syscall
    pop rcx
    add rsp, 8
    jmp print_rsp

count:
    lea r14, [newline]
    mov r13, 1
    call print

    # loop
    inc rcx
    cmp rcx, 101
    je exit
    jmp loop

exit:
    mov eax, 60 # exit
    syscall

print_fizzbuzz:
    lea r14, [fizzbuzz]
    mov r13, 8
    call print
    jmp count

print_buzz:
    lea r14, [buzz]
    mov r13, 4
    call print
    jmp count

print_fizz:
    lea r14, [fizz]
    mov r13, 4
    call print
    jmp count

print:
    mov rax, 1      # write
    mov rdi, 1      # stdout
    lea rsi, [r14]  # buf メモリ番地代入
    mov rdx, r13    # buflen
    push rcx # syscallで壊れるので退避
    syscall
    pop rcx
    ret

fizzbuzz:
    .ascii "fizzbuzz"
buzz:
    .ascii "buzz"
fizz:
    .ascii "fizz"
newline:
    .ascii "\n"

環境

# uname -a
Linux 29b342e56b09 4.19.121-linuxkit #1 SMP Tue Dec 1 17:50:32 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
# cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"
# gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.