%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