Skip to content

Instantly share code, notes, and snippets.

@adamnew123456
Created May 13, 2015 20:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adamnew123456/128e0030408abf86cbe6 to your computer and use it in GitHub Desktop.
Save adamnew123456/128e0030408abf86cbe6 to your computer and use it in GitHub Desktop.
FizzBuzz In x86 Assembly
// FizzBuzz in x86 assembly - written on 32-bit Linux using the GNU ASsembler
.data
FIZZSTR:
.asciz "Fizz"
BUZZSTR:
.asciz "Buzz"
NEWLINE:
.asciz "\n"
// strtoa stores its data here. Since FizzBuzz runs 1-100, it won't need more than 3 bytes
// to output any numbers
STRTOABUFF:
.byte 0, 0, 0
.text
// Converts a positive integer into a string
// Inputs:
// %eax - The number to convert to a string
// %ebx - The end of the buffer to use
// %ecx - The maximum number of digits to process
// Outputs:
// %eax - The starting pointer for the resulting data
// %ebx - The number of characters produced
strtoa:
// We have to handle 0 now, since it wouldn't print anything in
// strtoa_loop
cmp $0, %eax
je strtoa_zero
// We have to save the current max length so we can work out how much
// we will have used when we're done
pushl %ecx
strtoa_loop:
// At this point, we can't do any more work - there isn't any space left
cmp $0, %ecx
je strtoa_done
pushl %ecx
pushl %edx
// Clear the top 32 bits of the divisor, and divide %eax by 10
// This puts the remainder into %edx (which is the value we'll
// end up ASCIIfying and saving to the buffer) and the quotient
// into %eax (which is what we'll use to work our way upto the
// next digit)
xor %edx, %edx
movl $10, %ecx
div %ecx
// Get an ASCII numeral by shifting ahead 48 (since ASCII 48 = '0')
add $48, %edx
movb %edx, (%ebx)
popl %edx
popl %ecx
dec %ecx
// If our quotient is 0, then the number was below 10, and we have no
// more digits to process
cmp $0, %eax
je strtoa_done
// Move further back into the buffer so we can get the digit in the
// higher ten's place
dec %ebx
jmp strtoa_loop
strtoa_zero:
// ASCII 48 = '0'
movl $48, (%ebx)
strtoa_done:
movl %ebx, %eax
// Save the current number of remaining characters into %ebx
// and pull down our original maximum (which we pushed above)
mov %ecx, %ebx
popl %ecx
// Figure out how many characters were used (limit - remaining)
sub %ebx, %ecx
movl %ecx, %ebx
ret
// Prints the contents of %eax to standard output:
// Inputs:
// %eax - The address of the string to print
// %ebx - The length of the string to print
print:
pushl %ecx
pushl %edx
movl %eax, %ecx
movl %ebx, %edx
movl $4, %eax // System call 4 is sys_write on Linux
movl $1, %ebx // File descriptor 1 (stdout)
int $0x80
popl %edx
popl %ecx
ret
// Prints a newline to standard output
newline:
pushl %eax
pushl %ebx
movl $NEWLINE, %eax
movl $1, %ebx
call print
popl %ebx
popl %eax
ret
// Terminates the program with a 0 exit code
exit:
movl $1, %eax // Linux's sys_exit
xor %ebx, %ebx // The return code
int $0x80
.globl _start
_start:
// Overview:
//
// - %eax indicates the 'overall counter', which runs 1-100
// - %ebx is the 'secondary counter' which runs from 0-14
//
// Note that %ebx = %eax (mod 15) - we have to reset the counter,
// but that's easier than running a division.
movl $1, %eax
movl $1, %ebx
fizzbuzz:
cmp $100, %eax
jg exit
// It would be posible to do this in three modulus operations,
// but frankly, there are few enough cases that embedding the
// data in the control flow is significantly easier.
cmp $0, %ebx
je fizzbuzz_print_fifteen
cmp $3, %ebx
je fizzbuzz_print_three
cmp $5, %ebx
je fizzbuzz_print_five
cmp $6, %ebx
je fizzbuzz_print_three
cmp $9, %ebx
je fizzbuzz_print_three
cmp $10, %ebx
je fizzbuzz_print_five
cmp $12, %ebx
je fizzbuzz_print_three
// Only print the number if nothing else applies
jmp fizzbuzz_print_number
fizzbuzz_print_fifteen:
pushl %eax
pushl %ebx
movl $FIZZSTR, %eax
movl $4, %ebx
call print
movl $BUZZSTR, %eax
movl $4, %ebx
call print
popl %ebx
popl %eax
jmp fizzbuzz_inc
fizzbuzz_print_three:
pushl %eax
pushl %ebx
movl $FIZZSTR, %eax
movl $4, %ebx
call print
popl %ebx
popl %eax
jmp fizzbuzz_inc
fizzbuzz_print_five:
pushl %eax
pushl %ebx
movl $BUZZSTR, %eax
movl $4, %ebx
call print
popl %ebx
popl %eax
jmp fizzbuzz_inc
fizzbuzz_print_number:
pushl %eax
pushl %ebx
movl $STRTOABUFF, %ebx
add $2, %ebx
movl $3, %ecx
call strtoa
call print // These calls can be done this way since strtoa is written
// to be directly compatable with print
popl %ebx
popl %eax
fizzbuzz_inc:
call newline
inc %eax
fizzbuzz_inc_cycle:
inc %ebx
// We have to reset the counter, but only if it's fifteen
cmp $15, %ebx
jne fizzbuzz
fizzbuzz_clear_cycle:
xor %ebx, %ebx
jmp fizzbuzz
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment