Вопрос

I am new to assembly and I am trying to make a program that counts up to 10,000 and exits. I am using 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                                                                                                          `

It is supposed to print Number 1 Number 2 Number 3 etc. but instead it prints Number 2 Number 2 Number 2 Number 2 Number 2 etc. for a while then exits, without waiting for the users input. what is wrong with my code?

Edit: I got it to work! The working code:

 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 start

Это было полезно?

Решение

Library functions use registers for their own needs and do not restore them to original value. You need to keep value in memory if you don't want to lose it. The simplest way is to use stack:

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

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

Другие советы

You do not need to find the length of the string after the call to wsprintf as it returns the number of characters copied to the buffer.

Next, there is what is called Application binary interface (ABI) which covers many details such as Calling Conventions

When you are dealing with the Windows API, or C runtimes, they follow these calling conventions, where esi, edi, ebx, ebp, and esp are saved across the function call. Which means, if you have a value in one of those registers, then call an API function, that value will still be the same after the call.

eax, ecx, and edx do not have to be saved, so anything you have in those registers before a call is NOT guaranteed to be the same. if you have something in those registers, and you need that value after a call, you need to save to a variable or the stack with push

eax is used for return values.

That being said, in this sample, I use ebx as the loop counter, and esi as the current number to print, as those values will stay the same across API calls.

This is NASM, but it will give you and idea.

%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 
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top