; 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