Created
May 13, 2015 20:59
-
-
Save adamnew123456/128e0030408abf86cbe6 to your computer and use it in GitHub Desktop.
FizzBuzz In x86 Assembly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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