Skip to content

Instantly share code, notes, and snippets.

@hdorothea
Created July 27, 2016 14:59
Show Gist options
  • Save hdorothea/216adfa913a887c8f9203f5db2c86b40 to your computer and use it in GitHub Desktop.
Save hdorothea/216adfa913a887c8f9203f5db2c86b40 to your computer and use it in GitHub Desktop.
CracklePop in x86 assembly
.section .data
number:
.quad 0 # we start out with 0
crackle_output:
.ascii "Crackle\n"
pop_output:
.ascii "Pop\n"
cracklepop_output:
.ascii "CracklePop\n"
number_output:
.ascii " \n"
# constants
.equ CRACKLE_LENGTH, 8
.equ POP_LENGTH, 4
.equ NUMBER_OUTPUT_LENGTH, 3
.equ CRACKLEPOP_LENGTH, 11
.equ CRACKLE_NUMBER, 3
.equ POP_NUMBER, 5
.equ BASE, 10
.equ SYS_WRITE, 4 # write system call number
.equ SYS_EXIT, 1 # exit system call number
.equ STDOUT, 1 # file descriptor
.equ LINUX_SYSCALL, 0x80
# stack positions
.equ ST_OUTPUT_LENGTH, -8 # outputlength
.equ ST_OUTPUT_ADDRESS, -16 # outputaddress
.equ ST_NUMBER_OFFSET, -24 # numberoffset
.equ ST_CRACKLE_BOOL, -25 # cracklebool
.equ ST_POP_BOOL, -26 # popbool
.equ ST_CRACKLEPOP_BOOL, -27 # cracklepopbool
.equ ST, 27
.section .text
.globl _start
_start:
movq %rsp, %rbp # save the stack pointer
subq $ST, %rsp # allocate space for stack variables
loop:
movb $0, %al
movb %al, ST_CRACKLE_BOOL(%rbp) # (re)set crackle_bool
movb $0, %al
movb %al, ST_POP_BOOL(%rbp) # (re)set pop_bool
cmpq $100, number # compare current number with 100
jg leave # if it is greater jump to leave
# set up crackle bool
movq $0, %rdx # empty %rdx for the division
movq number, %rax # the number is the dividend. It needs to be in %rax
movq $CRACKLE_NUMBER, %rbx # 3 is the divisor. Move it to any memory location
divq %rbx # perform the division
cmpq $0, %rdx # compare the remainder of the division(in %rdx) with 0
jne set_up_pop_bool # if it is not 0 jump to set_up_pop_bool
movb $1, %al
movb %al, ST_CRACKLE_BOOL(%rbp) # set cracklebool to 1
set_up_pop_bool:
movq $0, %rdx # empty %rdx for the division
movq number, %rax # the number is the dividend. It needs to be in %rax
movq $POP_NUMBER, %rbx # 5 is the divisor. Move it to any memory location
divq %rbx # perform the division
cmpq $0, %rdx # compare the remainder of the division(in %rdx) with 0
jne set_up_cracklepop_bool # if is not 0 jump to set_up_cracklepop_bool
movb $1, %al
movb %al, ST_POP_BOOL(%rbp) # set popbool to 1
set_up_cracklepop_bool:
movb ST_CRACKLE_BOOL(%rbp), %al # move cracklebool to any general purpose register
andb ST_POP_BOOL(%rbp), %al # compute 'logical and' of cracklebool and popbool
movb %al, ST_CRACKLEPOP_BOOL(%rbp) # set cracklepopbool to the result of the 'logical and' of cracklebool and popbool
is_it_cracklepop_output:
movb ST_CRACKLEPOP_BOOL(%rbp), %al # move cracklepopbool to any general purpose register
cmpb $1, %al # compare cracklepopbool with 1
jne is_it_crackle_output # if it is not 1 jump to is_it_crackle_output
movq $cracklepop_output, %rax # move the address of cracklepop_output to any general purpose register
movq %rax, ST_OUTPUT_ADDRESS(%rbp) # set the outputaddress to the address of cracklepop_output
movq $CRACKLEPOP_LENGTH, %rax # move the length of cracklepop_output to any general purpose register
movq %rax, ST_OUTPUT_LENGTH(%rbp) # set the outputlength to the length of cracklepop_output
jmp write_output # jump to write_output
is_it_crackle_output:
movb ST_CRACKLE_BOOL(%rbp), %al # move cracklebool to any register
cmpb $1, %al # compare cracklebool with 1
jne is_it_pop_output # if it is not one jump to is_it_pop_output
movq $crackle_output, %rax # move the address of crackle_output to any register
movq %rax, ST_OUTPUT_ADDRESS(%rbp) # set the outputaddress to the address of crackle_output
movq $CRACKLE_LENGTH, %rax # move the length of crackle_output to any general purpose register
movq %rax, ST_OUTPUT_LENGTH(%rbp) # set the outputlength to the length of crackle_output
jmp write_output # jump to write_output
is_it_pop_output:
movb ST_POP_BOOL(%rbp), %al # move popbool to any register
cmpb $1, %al # compare popbool with 1
jne set_up_number_output # if it is not one jump to set_up_number_output
movq $pop_output, %rax # move the address of pop_output to any register
movq %rax, ST_OUTPUT_ADDRESS(%rbp) # set the outputaddress to the address of pop_output
movq $POP_LENGTH, %rax # move the length of pop_output to any general purpose register
movq %rax, ST_OUTPUT_LENGTH(%rbp) # set the outputlength to the length of pop_output
jmp write_output # jump to write_output
set_up_number_output:
movq $0, %rax
movq %rax, ST_NUMBER_OFFSET(%rbp) # set the numberoffset to 0
movq $0, %rdx # empty %rdx for the division
movq number, %rax # the number is the dividend it needs to be in %rax
movq $BASE, %rbx # 10 is the divisor move it to any memory location
divq %rbx # perform the division
cmpq $0, %rax # # The result of the divison(in %rax) is the first digit. Compare it with 0
je zeroth_digit # if it is 0 we have a zero digit number. Jump to zeroth_digit
addq $48, %rax # Get the ascii code of the first digit
movb %al, number_output # move the result to number_output
addq $1, ST_NUMBER_OFFSET(%rbp) # add 1 to number_offset
zeroth_digit:
addq $48, %rdx # The remainder of the divison(in %rdx) is the 0th digit. Get its ascii code
movq ST_NUMBER_OFFSET(%rbp), %rax # move the number_offset to any register
movb %dl, number_output(%rax) # move the zeroth digit to number_output plus number_offset
movq $number_output, %rax # move the address of number_output to any register
movq %rax, ST_OUTPUT_ADDRESS(%rbp) # move the address of number_output to outputaddress
movq $NUMBER_OUTPUT_LENGTH, %rax # move the length of number_output to any general purpose register
movq %rax, ST_OUTPUT_LENGTH(%rbp) # move the length of number_output to outputlength
write_output:
movq $SYS_WRITE, %rax # the (write) system call number needs to be in %rax
movq $STDOUT, %rbx # the (standard output) file descriptor needs to be in %rbx
movq ST_OUTPUT_ADDRESS(%rbp), %rcx # the starting address of the buffer to write needs to be in %rcx
movq ST_OUTPUT_LENGTH(%rbp), %rdx # the length of the buffer to write needs to be in %rdx
int $LINUX_SYSCALL # call the Linux kernel
incq number # increment the number
jmp loop # jump to the beginning of the loop
leave:
movq $SYS_EXIT, %rax # the (exit) system call number needs to be in %rax
int $LINUX_SYSCALL # call the Linux kernel
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment