標籤:art dev 調試 名稱 www. 如何 issue text vista
Windows X64彙編入門(1)
tankaiha
最近斷斷續續接觸了些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進行編譯了。
第二個推薦的編譯器是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)。
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;文法:GoASMDATA SECTIONtext db ‘Hello x64!‘, 0caption db ‘My First x64 Application‘, 0CODE SECTIONSTART:sub rsp,28hxor r9d,r9dlea r8, captionlea rdx, textxor rcx,rcxcall MessageBoxAadd rsp,28hret
???? 這段代碼是在GoASM中編譯,指令部分GoASM與ML64差不多,關鍵是一些宏的定義有差別。比如masm中的.code,在這裡就成了CODE SECTION。下面再說區別,先編譯。GoASM中編譯分兩步:
(1) 編譯:goasm /x64 1.asm
(2) 連結:golink 1.obj user32.dll
如果一些正常,命令列中應顯示圖3的內容。
運行一下,我們的第一個64位windows程式就運行了。
GoASM還有一個特點是支援宏:ARG和INVOKE,使用這兩個宏可以免除程式員自己對椎棧進行操作。不過初學嗎,還是從基礎掌握比較好。下面的一段代碼相同的功能的MASM代碼,注意看看區別。ML64至今仍不支援宏,所以每一步工作都要自己做。
代碼:
;範例程式碼2.asm;文法:ML64extrn MessageBoxA: proc.datatext db ‘Hello x64!‘, 0caption db ‘My First x64 Application‘, 0.codeMain procsub rsp,28hxor r9d,r9dlea r8, captionlea rdx, textxor rcx,rcxcall MessageBoxAadd rsp,28hretMain ENDPend
???? 編譯這段代碼的命令列是:ml64 2.asm /link /subsystem:windows /entry:Main user32.lib。如果正常,應該5顯示那樣。
很有意思吧,在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》
jpg改rar
Windows X64彙編入門(1)