%macro imprt 2-*
%define %%dll %1
%rep %0-1
%rotate 1
extern %1_
import %1_ %%dll %1
%1: jmp [%1_]
%endrep
%endmacro
section text USE32
imprt kernel32.dll, ExitProcess, GetStdHandle, WriteFile
global ..start
..start:
mov ecx, 40 ;ecx will countdown from 40 to 0
xor eax, eax ;eax will hold the current number
xor ebx, ebx ;ebx will hold the next number
inc ebx ;ebx is originally 1
.fibo
;print fibonacci number eax
pushad ;save registers while converting and printing
push dword buf+32 ;push pointer to end of buffer
push eax ;push number to convert
call int2ascii ;convert
push edi ;length of string
push ebx ;pointer to beginning of string
call output ;call print to stdout
popad ;restore register
;next number
mov edx, eax ;save the current number
mov eax, ebx ;next number is now current
add ebx, edx ;get the new next number
dec ecx ;count down
jnz .fibo ;if not done counting, do some more
;VOID ExitProcess(
; UINT uExitCode
;);
push byte 0 ;push exit value
call ExitProcess ;exit
;######### int2ascii ###########
;# expects on stack: #
;# number to convert #
;# pointer to end of buffer #
;# returns: #
;# pointer to string in ebx #
;# length of string in edi #
;# uses: #
;# eax, ebx, edx, edi, esi #
;######### int2ascii ###########
int2ascii
mov eax, [esp + 4] ;save number to print in eax
mov ebx, [esp + 8] ;save pointer to end of buffer in ebx
;pop edi ;save EIP
;pop eax ;number to print in eax
;pop ebx ;pointer to end of buffer
;push edi ;push EIP on stack
xor edi, edi ;clear edi register (counter)
mov esi, 10 ;divide by 10
mov byte [ebx], 32 ;push space at the end of string
dec ebx ;decrece pointer
inc edi ;increse counter
.top
xor edx, edx ;clear edx
div esi ;quotient in eax, remainder in edx
add dl, '0' ;convert to ascii
mov byte [ebx], dl ;move number to buffer
dec ebx ;point ebx to previous byte
inc edi ;increse counter
or eax, eax ;test for zero quotient
jnz .top ;repeat if not
inc ebx ;the pointer is 1 behind the first value
ret 8 ;clean up stack
;########## output ############
;# expects on stack: #
;# length of string #
;# pointer to string #
;# returns: #
;# result from syscall in eax #
;# length of string in edi #
;# uses: #
;# eax, ebx, ecx #
;########## output ############
output:
mov ebx, [esp + 4] ;save pointer to output string in ebx
mov ecx, [esp + 8] ;save string length in ecx
;pop eax ;save EIP
;pop ebx ;output string pointer
;pop ecx ;output string length
;push eax ;push EIP back on stack
;HANDLE GetStdHandle(
; DWORD nStdHandle
;);
push byte -11 ;STDOUT
call GetStdHandle
;BOOL WriteFile(
; HANDLE hFile,
; LPCVOID lpBuffer,
; DWORD nNumberOfBytesToWrite,
; LPDWORD lpNumberOfBytesWritten,
; LPOVERLAPPED lpOverlapped
;);
push 0 ;lpOverlapped
push 0 ;lpNumbersOfBytesWritten docs says it can't be NULL but it looks like it can
push ecx ;output string length
push ebx ;output string pointer
push eax ;STDOUT return from GetStdHandle
call WriteFile
ret 8
section data USE32
number dd 123456789
section bss USE32
buf resb 32