程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 匯編語言 >> hello,world!win32匯編小程序

hello,world!win32匯編小程序

編輯:匯編語言

"hello,world!"win32匯編小程序szText  db "Hello, world!",0

szCaption db "Win32Asm",0

    .code
start:
    push MB_OK
    lea eax,szCaption
    push eax
    lea eax,szText
    push eax
    push NULL
    call messageboxa
    xor eax,eax
    push eax
    call exitprocess
    end start

--------------------------------------------------

編譯鏈接:

分下面兩步進行:

ml  /c /coff 3.asm 

link /subsystem:windows /libpath:d:masm7lib 3.obj

第一步編譯生成3.obj文件

/c 表示只編譯,不鏈接

/coff 表示生成COFF格式的目標文件

第二步鏈接生成3.exe文件

/subsystem:windows 表示生成windows文件

/libpath:d:masm7lib 表示引入庫的路徑為:d:masm7lib。

在安裝Masm32後,引入庫位於Masm32Lib目錄下。

也可設置環境變量Lib的值:在dos提示符下鍵入Set Lib=d:masm7lib,這樣“鏈接”就可簡單寫成:

link /subsystem:windows 3.obj,試想一下,在程序調試過程中,修改源程序是常用的事啦,每次編譯鏈接都要帶/libpath:...那該有多煩人呢。當然,我們也可在源程序中直接給出引入庫的位置,這樣,鏈接時就方便啦,如下:

includelib d:masm7libkernel32.lib

includelib d:masm7libuser32.lib

--------------------------------------------------

執行:在dos提示符下鍵入3,回車,出現一個消息框,哈哈,真正的Win32程序!

--------------------------------------------------

深入分析:

看一下源程序,有這麼兩行:call messageboxacall exitprocess。大家一看都知道,這是子程序調用,但是我們並沒寫這樣的子程序,事實上,這些是API函數。作為函數,我們在調用時可能需要傳送給函數一些參數,程序怎麼知道傳送的參數有哪些,類型是什麼呢?就是通過函數原型定義,如下所示:

ExitProcess PROTO :DWORD

MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORD

可以看出,ExitProcess有一個參數,MessageBoxA有四個參數,這些參數都是DWORD類型。

在Win32中,參數的傳遞都是通過堆棧來完成的。象MessageBoxA這個函數有四個參數,究竟是左邊的先壓入堆棧還是右邊的先入棧呢?.model flat,stdcall給出了答案。stdcall 指定參數是從右到左壓入堆棧的,且調整堆棧是在子程序返回時完成的。在源程序中不需要用“add sp,值”來保持堆棧平衡。對MessageBox,在API手冊中是這樣定義的:

    int MessageBox(
      HWND hWnd,     // handle of owner window
      LPCTSTR lpText,   // address of text in message box
      LPCTSTR lpCaption, // address of title of message box
      UINT uType     // style of message box
      )

;所以會有我們的程序段:

看看上面的程序,不難想到,假如在寫程序時,少往堆棧裡壓入一個數據,那將是一個致命的錯誤。能不能將這種檢查參數個數是否匹配的工作交給計算機來完成呢?這是可以的,INVOKE指令可以幫助我們完成這樣的工作。假如你的參數個數不正確,連接器將給出錯誤提示。所以,極力建議你使用invoke代替call來調用子程序,當然,這不是絕對的。使用invoke上面的指令就可簡寫成下面的樣子,看起來簡煉多啦,查錯也方便啦!

invoke messageboxa, NULL,addr szText,addr szCaption,MB_OK

另外,像NULL,MB_OK都是一些常量,這樣的常量有很多,還有很多的結構,如果在我們的程序中一開始都寫這麼多的東西,可能一下子就把你嚇怕啦,也容易出錯,更不便於看程序的主要部分。hutch整理的windows.inc包含了WIN32編程所需要的常量和結構體的定義,我們可簡單的用一個include指令將這些常量和結構的定義插入到我們的文件中:

include d:masm32includewindows.inc

但是windows.inc中並不包含函數原型的聲明,還要從其他的頭文件中得到函數原型的聲明,比如:messageboxa的原型聲明在user32.inc文件中,exitprocess在kernel32.inc文件中。這些頭文件都放在 masm32include文件夾下。

還有,要用windows.inc,必須使用option casemap:none,它的意思是告訴 MASM 要區分符號的大小寫,譬如:start和START是不一樣的。否則,一個小小的程序,可能會出成百上千的錯誤呀!

其他的,就不再細說啦,到此,上面的程序可重新修改如下:

-----------------------------------------------------------------

;最終的結果;32位程序,要用flat啦!;stadcall,標准調用;數據區,定義2個字符串szText  db "Hello, world!",0

szCaption db "Win32Asm",0

.code;代碼開始執行處

/I d:masm7include 表示*.inc文件的位置,也可設置環境變量Set include=d:masm7include來簡化操作,也可在程序中明確指出*.inc的位置。

前面講的都是用兩條指令來完成編譯鏈接,實際上用一條指令也可完成,如下:

ml /coff /I d:masm7include 3.asm /link /subsystem:windows /libpath:lib

若*.inc及引入庫在源程序中都明確指出其位置,則可簡化為:

ml /coff 3.asm /link /subsystem:windows

累,先寫到這兒吧!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved