Created
September 3, 2014 21:51
-
-
Save jpoler/8ecbef27861bd06eca27 to your computer and use it in GitHub Desktop.
Code CracklePop written in 32-bit x86 assembly (GAS syntax).
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
### Code CracklePop ### | |
### I have been learning assembly recently | |
### and this project was a good fit for my skill level | |
### to assemble on linux, please use: | |
### as code_crackle_pop.S -o crackle.o | |
### ld crackle.o -o crackle | |
### and run the program with: | |
### ./crackle | |
.section .bss | |
.lcomm buff, 50 | |
.section .data | |
crackle: | |
.ascii "Crackle\n" | |
c_len = . - crackle | |
pop: | |
.ascii "Pop\n" | |
p_len = . - pop | |
cracklepop: | |
.ascii "CracklePop\n" | |
cp_len = . - cracklepop | |
.section .text | |
.globl _start | |
.equ SYS_WRITE, 4 | |
.equ SYS_EXIT, 1 | |
.equ STDOUT, 1 | |
_start: | |
pushl $0x0 # Prime the 5 counter | |
pushl $0x0 # Prime the 3 counter (jk, zero isn't prime) | |
pushl $0x0 # overall counter | |
loop: | |
popl %eax # Pop overall counter into eax | |
popl %ecx # Pop 3 counter into ecx | |
popl %edx # Pop 5 counter into edx | |
incl %eax # Increment all three counters | |
incl %ecx | |
incl %edx | |
cmpl $0x64, %eax # check if we are past 100 | |
jg end_loop # if so, we are done | |
cmpl $0x3, %ecx # check if the 3 counter == 3 | |
pushf # push flags onto the stack | |
popl %ebx # pop flags into ebx | |
andl $0x40, %ebx # we are interested in the 6th bit 2**6 = 0x40 (zero flag) | |
shrl $0x1, %ebx # make room for the result of second comparison | |
cmpl $0x5, %edx # check if the 5 counter == 5 | |
pushf # push flags onto the stack | |
andl $0x40, (%esp) # save only the 6th bit of value pointed to by esp | |
orl (%esp), %ebx # or the comparison results | |
addl $0x4, %esp # take the flags off the stack | |
cmpl $0x60, %ebx # divisible by 5 and 3? | |
je cp # jump to CracklePop (cp) | |
cmpl $0x20, %ebx # divisible by 3? | |
je c # jump to Crackle (c) | |
cmpl $0x40, %ebx # divisible by 5? | |
je p # jump to pop (p) | |
jmp default # jump to default | |
cp: | |
pushl $0x0 # push reset 5 counter onto stack | |
pushl $0x0 # push reset 3 counter onto stack | |
movl $cracklepop, %ecx # buffer for write system call | |
movl $cp_len, %edx # length of buffer | |
jmp print # jump to print | |
c: | |
pushl %edx # push 5 counter onto stack | |
pushl $0 # push reset 3 counter onto stack | |
movl $crackle, %ecx # buffer for write system call | |
movl $c_len, %edx # length of buffer | |
jmp print # jump to print | |
p: | |
pushl $0 # push reset 5 counter on to stack | |
pushl %ecx # push 3 counter on to stack | |
movl $pop, %ecx # buffer for write system call | |
movl $p_len, %edx # length of buffer | |
jmp print # jump to print | |
default: | |
pushl %edx # push 5 counter onto stack | |
pushl %ecx # push 3 counter onto stack | |
pushl %eax # this saves the actual overall counter | |
call wrangle_digits # wrangle digits will convert into ascii string | |
movl %eax, %edx # buffer length is at most 4 | |
movl $buff, %ecx # buffer for write system call | |
movl $SYS_WRITE, %eax # the length of the buffer was returned in eax | |
movl $STDOUT, %ebx # specify standard output for write | |
int $0x80 # system interrupt (call kernel) | |
jmp loop # jump to start of loop | |
print: | |
pushl %eax # save overall counter | |
movl $SYS_WRITE, %eax # SYS_WRITE sytem call | |
movl $STDOUT, %ebx # specify standard output for write | |
int $0x80 # system interrupt | |
jmp loop # jump to start of loop | |
end_loop: | |
movl $SYS_EXIT, %eax # prepare for system call | |
movl $0x0, %ebx # signal that all was well at exit | |
int $0x80 # exit gracefully | |
.type wrangle_digits, @function | |
wrangle_digits: | |
pushl %ebp # save value of base pointer | |
movl %esp, %ebp # set base pointer to equal stack pointer (preamble) | |
movl 8(%ebp), %eax # move integer to be printed into eax | |
pushl $0xa # push a newline onto the stack | |
movl $0xa, %ebx # we will be dividing by 10 | |
dig_loop: | |
cmpl $0x0, %eax # if our integer has reached zero, we are done | |
je write # jump to write if the comparison was true | |
xor %edx, %edx # clear edx (so only eax is the dividend) | |
divl %ebx # divide our integer by 10 | |
addl $0x30, %edx # convert digit to ascii | |
pushl %edx # push least significant digit onto stack | |
jmp dig_loop # repeat | |
write: | |
xor %edi, %edi # clear the index register | |
write_loop: | |
cmpl %ebp, %esp # does the stack point to the base? | |
je end_wrangle # if so, we have printed everything | |
popl %ebx # pop the most recent digit into ebx | |
movb %bl, buff(, %edi, 1) # move the lowest byte of ebx into our buffer offset | |
incl %edi # by our index, and increment index. | |
jmp write_loop # repeat | |
end_wrangle: | |
movl %edi, %eax # return length of string | |
movl %ebp, %esp # reset stack pointer to base | |
popl %ebp # reset base pointer | |
ret |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment