2013-03-16 52 views
2

我是程序集新手,我試圖創建一個計數高達10,000的程序並退出。我使用FASM`程序集計數程序

include 'include/win32ax.inc' 

    .data 

    inchar  DB ? 
    numwritten DD ? 
    numread DD ? 
    outhandle DD ? 
    inhandle DD ? 
    strFormat DB "Number %d ",0 
    strBuff RB 64 

    .code 
    start: 


    ;set up console 
    invoke AllocConsole 
    invoke GetStdHandle,STD_OUTPUT_HANDLE 
    mov [outhandle],eax 
    invoke GetStdHandle,STD_INPUT_HANDLE 
    mov [inhandle],eax 

    ;loop starts here 
    mov eax, 0 
    LoopStart: 
    add eax,1 



    invoke wsprintf, strBuff, strFormat, eax ;convert number to String. 

    ;the number eax is now in string form in strBuff 

      ;find out the string length of strBuff 
    mov ecx,-1 
    mov al,0 
    mov edi,strBuff 
    cld 
    repne scasb 
    not ecx 
    dec ecx 
     ;ecx is now the length. 



    invoke WriteConsole,[outhandle],strBuff,ecx,numwritten,0 ;write to console 
    ;loop 
    cmp eax, 10000;loop compare 
    jne LoopStart;jump to start of loop 

    invoke ReadConsole,[inhandle],inchar,1,numread,0 ;give the user a chance to read console output before exit 
    invoke ExitProcess,0 


    .end start                           ` 

它應該打印1號2號3號等,而是將其打印數量2 2 2號2號2號等了一會兒,然後退出,無需等待用戶輸入。我的代碼有什麼問題?

編輯:我得到它的工作!工作代碼:

include 'include/win32ax.inc' 

    .data 

     inchar  DB ? 
     numwritten DD ? 
     numread DD ? 
     outhandle DD ? 
     inhandle DD ? 
     strFormat DB "Number %d ",0 
      strBuff RB 64 
     number DD ? 

      .code 
     start: 


      ;set up console 
     invoke AllocConsole 
      invoke GetStdHandle,STD_OUTPUT_HANDLE 
      mov [outhandle],eax 
      invoke GetStdHandle,STD_INPUT_HANDLE 
      mov [inhandle],eax 

     ;loop starts here 
      mov eax, 0 
     LoopStart: 
       add eax,1 
      mov [number],eax 
      mov edi, eax 
      push eax 
      invoke wsprintf, strBuff, strFormat, edi ;convert number to String. 
      add  esp, 4 * 3 


      pop eax 
      ;the number eax is now in string form in strBuff 

      ;find out the string length of strBuff 
      mov ecx,-1 
      mov al,0 
       mov edi,strBuff 
       cld 
       repne scasb 
      not ecx 
       dec ecx 
       ;ecx is now the length. 


       push eax 
     invoke WriteConsole,[outhandle],strBuff,ecx,numwritten,0 ;write to console 
    pop eax 
    ;loop 
    mov eax, [number] 
    cmp eax, 10000;loop compare 
    jne LoopStart;jump to start of loop 

    invoke ReadConsole,[inhandle],inchar,1,numread,0 ;give the user a chance to read console output before exit 
    invoke ExitProcess,0 

.END開始

+1

打印將破壞EAX中的值。調用其他函數時必須保存並恢復它。 – 2013-03-16 15:42:12

+0

@BoPersson這將如何完成?我嘗試在內存位置123存儲eax並在打印後恢復它,但我的程序說:Test.exe遇到錯誤,需要關閉。我們對這種不便表示抱歉。 – user2097804 2013-03-16 15:46:01

+1

@ user2097804你爲什麼要寫內存地址'123'?首先,你是如何知道該內存地址不包含某些代碼或數據的?然後,你寫入特定內存地址的動機是什麼?你似乎沒有用'malloc'或類似的東西來保留任何內存。可能操作系統不會給你寫入該內存地址的權利,因此試圖導致分段錯誤。 – nrz 2013-03-16 15:56:49

回答

3

庫函數使用的寄存器針對自己的需求,不把它們恢復到原來的值。如果你不想失去它,你需要在內存中保持價值。最簡單的方法是使用堆棧:

push eax ; put value of eax on the top of stack 

pop eax ; remove value from top of stack, save it in eax. 
+0

它打印:編號4198401編號4198401等,當我把wsprinf和WriteConsole之前的推eax和wsprinf和WriteConsole之後的彈出eax。是這些函數之一修改堆棧? – user2097804 2013-03-16 15:58:26

+0

@ user2097804,它們確實放了一些東西,而不是刪除它('invoke'本身會這樣做),但不應該改變已經堆疊的東西,除非另有規定。 – zch 2013-03-16 16:15:12

+0

@ user2097804,你的代碼查找長度也使用'al',它是'eax'的一部分。嘗試一個「推」和一個「流行」。 – zch 2013-03-16 16:34:16

1

你並不需要找到字符串的長度調用wsprintf後,它會返回複製到緩衝區中的字符數。

接下來,就是所謂Application binary interface (ABI)其中包括許多細節,比如Calling Conventions

當你正在處理與Windows API或C運行時,他們按照這些調用約定,其中esiediebxebp ,並且esp保存在函數調用中。這意味着,如果您在其中一個寄存器中有值,請調用API函數,該值在調用後仍然保持不變。

eax,ecxedx不必保存,所以在調用之前你在這些寄存器中的任何內容都不能保證是相同的。如果您在這些寄存器中有某些東西,並且在通話後需要該值,則需要將其保存到變量或堆棧中。push

eax用於返回值。

話雖這麼說,在此示例中,我使用ebx作爲循環計數器,並esi作爲當前數字打印,因爲這些值將保持跨API調用相同。

這是NASM,但它會給你和想法。

%include "externs.inc" 

%define  STD_OUTPUT_HANDLE -11 
%define  STD_INPUT_HANDLE - 10 
%define  NULL 0 

SECTION .data       
strFormat DB "Number %d ",13,10,0    


SECTION .bss 
buf    resb 16 
stdout   resd 1 
stdin   resd 1 
lpNumRead  resd 1 
inChar   resb 1 

global start2 

SECTION .text     

start2:  

    push STD_OUTPUT_HANDLE    
    call GetStdHandle      
    mov  [stdout], eax      

    push STD_INPUT_HANDLE    
    call GetStdHandle      
    mov  [stdin], eax 

    mov  ebx, 10000 
    mov  esi, 1 
CountOut: 

    push esi 
    push strFormat 
    push buf 
    call wsprintf 
    add  esp, 4 * 3 

    push NULL        
    push lpNumRead      
    push eax      
    push buf       
    push dword [stdout]     
    call WriteConsole       

    inc  esi 
    dec  ebx 
    jnz  CountOut 

    push NULL 
    push lpNumRead 
    push 1 
    push inChar 
    push dword [stdin] 
    call ReadConsole 

    push 0 
    call ExitProcess