Windows X64匯編入門(1)


最近斷斷續續接觸了些64位匯編的知識,這里小結一下,一是階段學習的回顧,二是希望對64位匯編新手有所幫助。我也是剛接觸這方面知識,文中肯定有錯誤之處,大家多指正。
文章的標題包含了本文的四方面主要內容:
(1)Windows:本文是在windows環境下的匯編程序設計,調試環境為Windows Vista 64位版,調用的均為windows API。
(2)X64:本文討論的是x64匯編,這里的x64表示AMD64和Intel的EM64T,而不包括IA64。至於三者間的區別,可自行搜索。
(3)匯編:顧名思義,本文討論的編程語言是匯編,其它高級語言的64位編程均不屬於討論范疇。
(4)入門:既是入門,便不會很全。其一,文中有很多知識僅僅點到為止,更深入的學習留待日后努力。其二,便於類似我這樣剛接觸x64匯編的新手入門。
  本文所有代碼的調試環境:Windows Vista x64,Intel Core 2 Duo。

1.  建立開發環境
1.1  編譯器的選擇
    對應於不同的x64匯編工具,開發環境也有所不同。最普遍的要算微軟的MASM,在x64環境中,相應的編譯器已經更名為ml64.exe,隨Visual Studio 2005一起發布。因此,如果你是微軟的忠實fans,直接安裝VS2005既可。運行時,只需打開相應的64位命令行窗口(圖1),便可以用ml64進行編譯了。
名稱:  1.jpg
查看次數: 529
文件大小:  55.4 KB

    第二個推薦的編譯器是GoASM,共包含三個文件:GoASM編譯器、GoLINK鏈接器和GoRC資源編譯器,且自帶了Include目錄。它的最大好外是小,不用為了學習64位匯編安裝幾個G 的VS。因此,本文的代碼就在GoASM下編譯。

    第三個Yasm,因為不熟,所以不再贅述,感興趣的朋友自行測試吧。
不同的編譯器,語法會有一定差別,這在下面再說。

1.2  IDE的選擇
    搜遍了Internet也沒有找到支持asm64的IDE,甚至連個Editor都沒有。因此,最簡單的方法是自行修改EditPlus的masm語法文件,這也是我采用的方法,至少可以得到語法高亮。當然,如果你懶得動手,那就用notepad吧。
    沒有IDE,每次編譯時都要手動輸入不少參數和選項,做個批處理就行了。

1.3  硬件與操作系統
    硬件要求就是64位的CPU。操作系統也必須是64位的,如果在64位的CPU上安裝了32位的操作系統,就算編譯成功也無法運行程序。

2.  寄存器的改變
    匯編是直接與寄存器打交道的語言,因此硬件對語言影響很大。先來看看x64與x32相比在硬件上多了什么,變了什么(圖2)。
名稱:  2.jpg
查看次數: 524
文件大小:  63.8 KB

    X64多了8個通用寄存器:R8、R9、R10、R11、R12、R13、R14、R15,當然,它們都是64位的。另外還增加了8個128位XMM寄存器,不過通常用不着。
    X32中原有的寄存器在X64中均為擴展為64位,且名稱的第一個字母從E改為R。不過我們還是可以在64位程序中調用32位的寄存器,如RAX(64位)、EAX(低32)、AX(低16位)、AL(低8位)、AH(8到15位),相應的有R8、R8D、R8W和R8B。不過不要在程序中使用如AH之類的寄存器,因為在AMD的CPU上這種用法會與某些指令產生沖突。

3.  第一個x64匯編程序
    本節,我們開始編寫自己的第一個x64匯編程序。在這之前,先講一下calling convention的改變。
3.1  API調用方式
    把Calling convention放在第一個講,代表它的重要性。在32位匯編中,我們調用一個API時,采用的是stdcall,它有兩個特點:一是所有參數入棧,通過椎棧傳遞;二是被調用的API負責棧指針(ESP)的恢復,我們在調用MessageBox后不用add esp,14h,因為MessageBox已經恢復過了。
而在x64匯編中,兩方面都發生了變化。一是前四個參數分析通過四個寄存器傳遞:RCX、RDX、R8、R9,如果還有更多的參數,才通過椎棧傳遞。二是調用者負責椎棧空間的分配與回收。
    下面給出一段代碼,功能是顯示一個簡單的MessageBox,注意對RSP的操作:

代碼:
;示例代碼1.asm
;語法:GoASM
DATA SECTION
text     db 'Hello x64!', 0
caption  db 'My First x64 Application', 0

CODE SECTION
START:
sub rsp,28h
xor r9d,r9d
lea r8, caption
lea rdx, text
xor rcx,rcx
call MessageBoxA
add rsp,28h
ret
  

????    這段代碼是在GoASM中編譯,指令部分GoASM與ML64差不多,關鍵是一些宏的定義有差別。比如masm中的.code,在這里就成了CODE SECTION。下面再說區別,先編譯。GoASM中編譯分兩步:
(1)  編譯:goasm /x64 1.asm
(2)  鏈接:golink 1.obj user32.dll
    如果一些正常,命令行中應顯示圖3的內容。
名稱:  3.jpg
查看次數: 515
文件大小:  29.4 KB

    運行一下,我們的第一個64位windows程序就運行了。
名稱:  4.jpg
查看次數: 509
文件大小:  6.3 KB

    GoASM還有一個特點是支持宏:ARG和INVOKE,使用這兩個宏可以免除程序員自己對椎棧進行操作。不過初學嗎,還是從基礎掌握比較好。下面的一段代碼相同的功能的MASM代碼,注意看看區別。ML64至今仍不支持宏,所以每一步工作都要自己做。

代碼:
;示例代碼2.asm
;語法:ML64
extrn MessageBoxA: proc

.data
text     db 'Hello x64!', 0
caption  db 'My First x64 Application', 0

.code
Main proc
sub rsp,28h
xor r9d,r9d
lea r8, caption
lea rdx, text
xor rcx,rcx
call MessageBoxA
add rsp,28h
ret

Main ENDP
end
  

????    編譯這段代碼的命令行是:ml64 2.asm /link /subsystem:windows /entry:Main user32.lib。如果正常,應該如圖5顯示那樣。
名稱:  5.jpg
查看次數: 511
文件大小:  37.8 KB

    很有意思吧,在64位系統下,我們仍然調用user32的API。可能是名稱用習慣了,微軟自己都懶得改了吧。

3.2  64位的椎棧
    代碼中還有一處值得注意,那就是sub rsp,28h和add rsp,28h。28h這個數值是怎么來的呢?
首先,x64中椎棧被擴展為64位;其次,我們在調用MessageBoxA時,要給四個參數外加一個返回地址留空間,因此8(位)*5=40=28h。
    另外一些小問題要注意,AMD64不支持push 32bit寄存器的指令,最好的方法就是push和pop都用64位寄存器。EM64T如何?看了下Intel的開發手冊,各個指令都分三種情況:純32位、純64位和32與64位混合。下面是手冊的片段:

Opcode*      Instruction        64-Bit Mode       Compat/Leg Mode      Description
FF /6         PUSH r/m16         Valid                 Valid            Push r/m16.
FF /6         PUSH r/m32         N.E.                  Valid            Push r/m32.
FF /6         PUSH r/m64         Valid                  N.E.           Push r/m64. 
Default operand size 64-bits.

    沒別的好方法,使用中多注意,盡量在64位程序中保用64位寄存器。

4.  一些參考資料
    寫完了第一個hello world,本文就此打住。本還想寫一些內容,但掌握不深,留待下回吧。感覺有些資料不得不在第一篇文章中放出來,因為它們是現有學習x64匯編的最好教材了,文中很多代碼和知識點也來自於這些資料。
(1)《Moving to Windows x64》,出自:http://www.ntcore.com/Files/vista_x64.htm
(2)GoASM的幫助文檔,目前最好的64位匯編教程。出自:www.jorgon.freeserve.co.uk
(3)《開始進行 64 位 Windows 系統編程之前需要了解的所有信息》,出自:http://www.microsoft.com/china/MSDN/library/Windev/64bit/issuesx64.mspx
(4)來自CodeGurus的兩篇文章
《Assembler & Win64》,
http://www.codegurus.be/codegurus/Programming/assembler&win64_en.htm
《bout RIP relative addressing》
http://www.codegurus.be/codegurus/Programming/riprelativeaddressing_en.htm
(5)AMD開發手冊
(6)Intel開發手冊,注意是新的《ntel® 64 and IA-32 Architectures software Developer's Manual》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM