2013-03-16 51 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