surge 发表于 2006-9-29 13:51:08

源码阅读之hello.asm

;以下为\masm32\tutorial\console\demo1\hello.asm中的内容:
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;               Build this with the "Project" menu using
;                     "Console Assemble and Link"
;
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    .486                                    ; create 32 bit code
    .model flat, stdcall                  ; 32 bit memory model
    option casemap :none                  ; case sensitive

    include \masm32\include\windows.inc   ; always first
    include \masm32\macros\macros.asm       ; MASM support macros

; -----------------------------------------------------------------
; include files that have MASM format prototypes for function calls
; -----------------------------------------------------------------
    include \masm32\include\masm32.inc
    include \masm32\include\gdi32.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc

; ------------------------------------------------
; Library files that have definitions for function
; exports and tested reliable prebuilt code.
; ------------------------------------------------
    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\gdi32.lib
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib

    .code                     ; Tell MASM where the code starts

;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

start:                        ; The CODE entry point to the program

    print chr$("Hey, this actually works.",13,10)
    exit

;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

end start                     ; Tell MASM where the program ends

;可以用Quick Editor(masm32安装目录中qeditor.exe)来构建这个程序
;必需先File->Set Current Directory(或直接Ctrl+F12)设置为hello.asm所在目录
;然后Project->Console Assenble and Link就可以构建了
;这是一个工作在控制台下的程序,打开一个cmd窗口,切换到生成的hello.exe所在目录
;运行之后显示:Hey, this actually works.

;print是一个宏,在maxros.asm中定义如下,这个文件已经被包含进来了
;include \masm32\macros\macros.asm       ; MASM support macros

    print MACRO arg1:REQ,varname:VARARG      ;; 显示一个0结束的字符串
      invoke StdOut,reparg(arg1)
      IFNB <varname>
      invoke StdOut,chr$(varname)
      ENDIF
    ENDM
;调用StdOut函数,在控制台显示一个字符串

;repareg是一个宏,在maxros.asm中定义如下,这个文件已经被包含进来了
; -----------------------------------------------------------
; This macro replaces quoted text with a DATA section OFFSET
; and returns it in ADDR "name" format. It is used by other
; macros that handle optional quoted text as a parameter.
; -----------------------------------------------------------
    reparg MACRO arg
      LOCAL nustr
      quot SUBSTR <arg>,1,1
      IFIDN quot,<">            ;; if 1st char = "
      .data
          nustr db arg,0      ;; write arg to .DATA section
      .code
      EXITM <ADDR nustr>      ;; append name to ADDR operator
      ELSE
      EXITM <arg>             ;; else return arg
      ENDIF
    ENDM
;如果arg是一个字符串地址,直接返回这个地址,
;如果arg是一个"字符串",在.data中声明并返回
;这个偏移地址
   
;chr$是一个宏,在macros.asm中定义如下

      chr$ MACRO any_text:VARARG
      LOCAL txtname
      .data
          txtname db any_text,0
      .code
      EXITM <OFFSET txtname>
      ENDM
;chr$("Hey, this actually works.",13,10)
;经编译器处理后变为
;.data
;txtname    db    Hey, this actually works.",13,10,0
;.code
;并返回textname的偏移给print继续展开
;invoke StdOut,addr textname

;exit是一个宏,在macros.asm中定义如下
; --------------------------------------------------------
; exit macro with an optional return value for ExitProcess
; --------------------------------------------------------
    exit MACRO optional_return_value
      IFNDEF optional_return_value
      invoke ExitProcess, 0
      ELSE
      invoke ExitProcess,optional_return_value
      ENDIF
    ENDM
;exit直接展开为
;invoke ExitProcess, 0

;关于宏的详细参考D:\masm32\help\masm32.hlp中的MACRO Reference
;也可以参考也可以参考masm程序员指南.

;StdOut是一个自定义的库函数,源码在\masm32\m32lib\stdout.asm
;这是对操作系统中有关控制台操作的封装。
; #########################################################################

    .386
    .model flat, stdcall
    option casemap :none   ; case sensitive

    include \masm32\include\windows.inc
    include \masm32\include\kernel32.inc

    StrLen PROTO :DWORD

    .code

; #########################################################################

StdOut proc lpszText:DWORD

    LOCAL hOutPut:DWORD
    LOCAL bWritten :DWORD
    LOCAL sl       :DWORD

    invoke GetStdHandle,STD_OUTPUT_HANDLE
    mov hOutPut, eax

    invoke StrLen,lpszText
    mov sl, eax

    invoke WriteFile,hOutPut,lpszText,sl,ADDR bWritten,NULL

    mov eax, bWritten
    ret

StdOut endp

; #########################################################################

end
;源码中还用到了一个自定义的库函数StrLen源码在\masm32\m32lib\strlen.asm
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    .486
    .model flat, stdcall
    option casemap :none   ; case sensitive

    .code

;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

align 4

StrLen proc item:DWORD

; -------------------------------------------------------------
; This procedure has been adapted from an algorithm written by
; Agner Fog. It has the unusual characteristic of reading up to
; three bytes past the end of the buffer as it uses DWORD size
; reads. It is measurably faster than a classic byte scanner on
; large linear reads and has its place where linear read speeds
; are important.
; -------------------------------------------------------------

    mov   eax,             ; get pointer to string
    push    ebx
    lea   edx,             ; pointer+3 used in the end
@@:   
    mov   ebx,               ; read first 4 bytes
    add   eax, 4                  ; increment pointer
    lea   ecx,   ; subtract 1 from each byte
    not   ebx                     ; invert all bytes
    and   ecx,ebx               ; and these two
    and   ecx, 80808080h
    jz      @B                      ; no zero bytes, continue loop

    test    ecx,00008080h         ; test first two bytes
    jnz   @F
    shr   ecx,16                  ; not in the first 2 bytes
    add   eax,2
@@:
    shl   cl,1                  ; use carry flag to avoid branch
    sbb   eax,edx               ; compute length
    pop   ebx

    ret   4

StrLen endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

end
;GetStdHandle和WriteFile是操作系统kernel32.dll提供的函数这可查MSDN
;或者在MSHELP中找到相关C语言描述。


;最后这个程序被编译器编译成什么样子呢?
;用OllyDBG打开看一下
00401005 >/$ >jmp   start
0040100A|>int3
0040100B|>int3
0040100C|>int3
0040100D|>int3
0040100E|>int3
0040100F|>int3
00401010 >|> >push    offset ??0019                  ; print chr$("Hey, this actually works.",13,10)
00401015|. >call    StdOut
0040101A|. >push    0                              ; exit
0040101C\. >call    ExitProcess
;下面是Stdout
00401028 >/$ >push    ebp
00401029|. >mov   ebp, esp
0040102B|. >add   esp, -0C
0040102E|. >push    -0B                              ; /DevType = STD_OUTPUT_HANDLE
00401030|. >call    GetStdHandle                     ; \GetStdHandle
00401035|. >mov   , eax
00401038|. >push    dword ptr
0040103B|. >call    StrLen
00401040|. >mov   , eax
00401043|. >push    0                              ; /pOverlapped = NULL
00401045|. >lea   eax,                      ; |
00401048|. >push    eax                              ; |pBytesWritten
00401049|. >push    dword ptr                 ; |nBytesToWrite
0040104C|. >push    dword ptr                 ; |Buffer
0040104F|. >push    dword ptr                 ; |hFile
00401052|. >call    WriteFile                        ; \WriteFile
00401057|. >mov   eax,
0040105A|. >leave
0040105B\. >retn    4
;下面是StrLen
00401060 >/$ >mov   eax,
00401064|. >push    ebx
00401065|. >lea   edx,
00401068|> >/mov   ebx,
0040106A|. >|add   eax, 4
0040106D|. >|lea   ecx,
00401073|. >|not   ebx
00401075|. >|and   ecx, ebx
00401077|. >|and   ecx, 80808080
0040107D|.^>\je      short 00401068
0040107F|. >test    ecx, 8080
00401085|. >jnz   short 0040108D
00401087|. >shr   ecx, 10
0040108A|. >add   eax, 2
0040108D|> >shl   cl, 1
0040108F|. >sbb   eax, edx
00401091|. >pop   ebx
00401092\. >retn    4

;宏减少了击键次数,在一定程度上提高了可读性
;对于工具的使用应该更多关注官方发布的手册

angelwings 发表于 2007-1-26 20:47:21

支持一下,楼主应该讲解的再详细点

caterpilla 发表于 2007-1-26 22:46:55

支持一下。。。。。
页: [1]
查看完整版本: 源码阅读之hello.asm