Yeah, pretty much. This prints factorials until they overflow (20! ?). It is very old - obsolete "-f obj" format. It might still work... or maybe can be tweaked to work.
; assemble: nasm -f obj file.asm
; link: alink -oPE file.obj win32.lib
extern MessageBoxA
extern ExitProcess
segment data use32
title1: db 'Factorials',0
title2 db 'Game Over!',0
overmsg db 'Overflows 64 bits!',0
segment bss use32
buffer resb 80h
segment code use32
..start
mov ecx,1 ; start with n=1
nextfact:
; show n
xor edx,edx ; clear high dword - we don't want it
mov eax,ecx ; edx:eax = n
mov edi,buffer ; buffer for "conversion"
call U64TODA ; 64 bit number to string at edi
mov al,'!'
stosb
mov al,' '
stosb
mov al,'='
stosb
mov al,' '
stosb
mov eax,1 ; set up for mult loop
push ecx ; save our old n - loop will decrement ecx
factmult:
mov ebx,eax ; save old low dword
mov eax,edx ; multiply old high dword
mul ecx ; by n, n-1, n-2, etc
or edx,edx ; have we got a "too high" dword?
jnz overflow ; bail out if we do
xchg ebx,eax ; get old low dword back, stash new high dword
mul ecx ; multiply the low dword by n, n-1,...
add edx,ebx ; add high dword result to high dword from this mult
jc overflow ; does that put us over 64 bits?
loop factmult ; dec ecx (n) and repeat if not zero
; show n!
call U64TODA
push dword 01h ; OK button
push dword title1
push dword buffer
push dword 0
call MessageBoxA
cmp eax,1
jz noexit
pop ecx
jmp exit
noexit:
pop ecx ; get our last n back
inc ecx ; bump it
jmp nextfact ; and do the next one
overflow:
pop ecx ; we had it saved on stack when we exited loop
mov esi,overmsg
copy:
lodsb
stosb
or al,al
jnz copy
push dword 01h ; OK button
push dword title2
push dword buffer
push dword 0
call MessageBoxA
exit:
push dword 0
call ExitProcess
;--------------------------------------------------------------
; U64TODA - converts (64 bit) integer in edx:eax
; to (comma delimited) decimal representation in
; zero terminated string in buffer pointed to by edi
; returns with edi pointed to the zero
;-----------------------------------------------------------------
U64TODA :
push eax
push ebx
push ecx
push edx
push esi
mov ebx,edx ; stash high dword
mov esi,0Ah ; prepare to divide by 10
xor ecx,ecx ; zero the digit count
jmp highleft ; check is high dword 0 ?
highword:
xchg eax,ebx ; swap high & low dwords
xor edx,edx ; zero edx for the divide!
div esi ; divide high dword by 10
xchg eax,ebx ; swap 'em back
div esi ; divide low dword including remainder
push edx ; remainder is our digit - save it
inc ecx ; count digits
highleft:
or ebx,ebx
jnz highword
lowleft:
xor edx,edx ; zero high dword
div esi ; divide low dword by 10
push edx ; our digit
inc ecx ; count it
or eax,eax ; 0 yet ?
jne lowleft
cmp ecx,04h ; commas needed ?
jl write2buf ; nope
xor edx,edx ; zero high dword for divide
mov eax,ecx ; number of digits
mov ebx,3
div ebx
mov esi,edx ; remainder = number digits before comma
or edx,edx
jnz write2buf ; no remainder?
mov esi,3 ; we can write 3 digits, then.
write2buf:
pop eax ; get digit back - in right order
add al,30H ; convert to ascii character
stosb ; write it to our buffer
dec esi ; digits before comma needed
jnz moredigits ; no comma needed yet
cmp ecx,2 ; we at the end?
jl moredigits ; don't need comma
mov al,',' ; write a comma
stosb
mov esi,03h ; we're good for another 3 digits
moredigits:
loop write2buf ; write more digits - cx of 'em
mov al,00h ; terminate buffer with zero
stosb
dec edi
pop esi
pop edx
pop ecx
pop ebx
pop eax
ret
;-------------------------------------------------------------
This is far from optimized. Used to work, as I recall. Might, still. Good luck!
Best,
Frank