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                                                                                                          `

它应该打印 Number 1 Number 2 Number 3 等,但它会打印 Number 2 Number 2 Number 2 Number 2 Number 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 开始

4

2 回答 2

3

库函数根据自己的需要使用寄存器,并且不会将它们恢复为原始值。如果您不想失去它,则需要将价值保留在内存中。最简单的方法是使用堆栈:

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

pop eax  ; remove value from top of stack, save it in eax.
于 2013-03-16T15:52:16.157 回答
1

您不需要在调用后查找字符串的长度,wsprintf因为它返回复制到缓冲区的字符数。

接下来是所谓的应用程序二进制接口(ABI),它涵盖了许多细节,例如调用约定

当您处理 Windows API 或 C 运行时,它们遵循这些调用约定,其中esi, edi, ebx, ebp, 并esp在函数调用中保存。这意味着,如果您在其中一个寄存器中有一个值,然后调用 API 函数,则该值在调用后仍将相同。

eax, ecx, 并且edx不必保存,因此不能保证在调用之前您在这些寄存器中的任何内容都是相同的。如果您在这些寄存器中有某些内容,并且在调用后需要该值,则需要将其保存到变量或堆栈中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 
于 2013-03-16T16:56:42.137 回答