diff options
author | Gentoo <installgentoo@endianness.com> | 2021-03-27 09:44:50 +1100 |
---|---|---|
committer | Gentoo <installgentoo@endianness.com> | 2021-03-27 09:44:50 +1100 |
commit | f88388985dd557c3e71325b3f264c503b3610874 (patch) | |
tree | 559b59911d8893eb5364d116b260394671467f39 /fizzbuzz.asm | |
download | fizzbuzz-asm-static-f88388985dd557c3e71325b3f264c503b3610874.tar.gz fizzbuzz-asm-static-f88388985dd557c3e71325b3f264c503b3610874.tar.bz2 fizzbuzz-asm-static-f88388985dd557c3e71325b3f264c503b3610874.zip |
Diffstat (limited to 'fizzbuzz.asm')
-rw-r--r-- | fizzbuzz.asm | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/fizzbuzz.asm b/fizzbuzz.asm new file mode 100644 index 0000000..aaf5036 --- /dev/null +++ b/fizzbuzz.asm @@ -0,0 +1,141 @@ +; Version : 2.1 +; Last update : 25/5/2020 +; Description : FizzBuzz, but in assembly. Just a test of static memory usage. +; Licence : GPLv3 + +section .bss + Buff resb 422 ;Precalculated size + bufflen equ $-Buff + +section .data +fizz db 'Fizz' +buzz db 'Buzz' +fizzbuzz db 'FizzBuzz' + +section .text +global _start +_start: +xor r12,r12 ;counter register, set to count 0 to 100 +xor esi,esi ;used to store position in static memory +xor r9,r9 ;r9 is used as a boolean to record if modulus 3 is achieved + +jmp skip ;skip incrementing the first time round so 0 is kept + +increment: inc r12 ;increment the counter +skip: cmp r12,101 ;check if 100 has been reached +jz exit ;exit if numbers 0 to 100 have been calculated and written to Buff + +check3: imul r8d,r12d,0xaaaaaaab;calculate modulus 3 quickly by multiplying the counter by 0xaaaaaaab and truncuating the result into r8d. +cmp r8d,0x55555555 +ja check5 ;if r8d is larger than 0x55555555; (r12 % 3 !=0) and so modulus 5 is directly jumped to. + +;falls through if (r12 % 3 == 0) +mov r9,1 ; set the fizz boolean to true + +check5: imul r8d,r12d,0xcccccccd ;calculate modulus 5 quickly by multiplying the counter by 0xcccccccd and truncuating the result into r8d. +cmp r8d,0x33333333 +ja checkfizz ;if r8d is larger than 0x33333333; (r12 % 5 !=0). The state of fizz needs to be check to determine if anything needs printing. + +;; fall through if (r12 % 5 == 0) +test r9,r9 ;r9 is the fizz boolean +je buzzonly ;if there is no fizz, only print buzz + +;; fall through if both fizz and buzz are achieved; it's fizzbuzz time +printfizzbuzz: +mov rax,[fizzbuzz] ;copy fizzbuzz into rax +mov qword[Buff+esi],rax ;copy fizzbuzz in rax into Buff +add esi,8 + +mov byte[Buff+esi], 0xA +inc esi + +xor r9,r9 ;zero out the fizz boolean +jmp increment + +checkfizz: test r9,r9 ;check if fizz is achieved +je printnum ;if not, print current number + +;; fall through if fizz is achieved +fizzonly: +mov rax,[fizz] ;Copy 4 characters from fizz into rax +mov qword[Buff+esi],rax ;Copy rax into Buff +add esi,4 ;Increment Buff's pointer by 4 characters + +mov al,0xA ;Copy a newline into al (no need for static string usage) +mov byte[Buff+esi], al ;write the newline into Buff +inc esi ;increment Buff's pointer + +xor r9,r9 ;zero out the fizz boolean +jmp increment + +buzzonly: +mov rax,[buzz] +mov qword[Buff+esi],rax +add esi,4 + +mov al,0xA ;Copy a newline into al (no need for static string usage) +mov byte[Buff+esi], al +inc esi + +jmp increment + +printnum: +mov rax,r12 ;rax = counter +mov r10,0xcccccccd ;used in division by 10 below + +xor edi,edi ;used to keep count of digits + +;;todo: Use a conversion method that doesn't print digits in the reverse order +;; ecx=remainder = low digit = 0..9. eax/=10 +toascii_digit: +mov ecx,eax ;copy eax to ecx for later usage in modulus. + +imul rax,r10 ;sign multiply rax by 0xcccccccd to complete the first step of division by 10 +shr rax,0x23 ;shift rax right by 35 to finish off rax/=10 + +mov edx,eax ;move eax to edx so modulus can be done on it without clobbering eax +lea edx,[rdx+rdx*4] ;multiply edx by 5 as the first step of modulus +add edx,edx ;multiply edx by 2 as the second step of modulus +sub ecx,edx ;subtract edx from the original number (before /=10) to finish off modulus 10 + +;; the remainder(ecx) is the next calculated digit +add ecx,'0' ;add 48 to ecx to turn it into the ASCII representation of the number +mov byte[Buff+esi],cl ;shove cl(lower 8 bits in rcx) onto the stack +inc esi ;write digits reversed... + +inc edi ;Count the number of digits generated + +test eax,eax +jnz toascii_digit ;if eax does not equal zero, there are more ASCII chars to generate + +mov byte[Buff+esi],0xA ;Write a newline after the digits +inc esi + + +cmp edi,1 +ja two ;if above one digit check for two digits +jmp increment ;One digit is in the correct order + +two: +cmp edi,2 +ja exit ;above 2 characters won't work (sanely) for this method, so exit + +mov al,byte[Buff+esi-2] ;copy first digit to al +mov cl,byte[Buff+esi-3] ;copy second digit to cl + +mov byte[Buff+esi-2],cl ;copy second digit over first digit +mov byte[Buff+esi-3],al ;copy first digit over second digit + +jmp increment + +;;print Buff and exit +exit: +mov eax,1 ;sys_write +mov edi,1 ;fp = stdout +mov edx,bufflen ;length of Buff +mov rsi,Buff ;Memory location of Buff +syscall ;print all the bytes on the stack + +mov eax, 60 ;code for sys_exit +xor edi, edi ;return value of 0 +syscall ;do sys_exit |