2013-03-08 45 views
7

我試圖尋找關於用例子或一本好書英特爾的x64彙編教程,但我甚至沒有在英特爾網站上找到。英特爾X86-64組裝教程或書

所以,你可以建議我一個很好的教程或書嗎? 我在linux上使用nasm。

感謝

+2

我不瞭解有關nasm教程,但可以獲取[Intel Software Developer Manuals](http://www.intel.com/content/www/us/en/processors/architectures-software-developer- manuals.html),你應該發現很有幫助。 – 2013-03-08 15:48:14

+0

intel.com上的教程?這聽起來像個可笑的玩笑。從[Paul Carter的教程](http://www.drpaulcarter.com/pcasm/)開始。令人驚訝的是,它基於NASM。當您掌握32位程序集時,請切換到64. – 2013-03-08 16:27:52

+0

我推薦Ray Seyfarth介紹適用於Linux的64位英特爾彙編語言編程。本書使用YASM而不是NASM,但YASM接受AFAIK幾乎所有的NASM代碼,並且還支持DWARF2調試數據格式等。本書也有一些SSE和AVX代碼,並且它只假定一些編程背景並解釋二進制和十六進制數字等。我已經在DOS時間學習了x86程序集,但是本書可以作爲Linux x86-64程序集中有用的參考。 – nrz 2013-03-08 21:39:05

回答

15

誠然這是個人的偏見,你怎麼喜歡學習編程。

但相對於在特定的彙編語言,我發現了一個辦法這對我來說已經不是閱讀彙編語言指令集參考手冊和/或書籍(如有的話)更爲有用。

我通常做找出如何組裝一個新的CPU工作/一個CPU不知道的我一個操作系統平臺,我不還製作是利用開發工具鏈。像這樣:

  • 爲自己安裝目標CPU的(交叉)編譯器和反彙編程序。現在,GNU gcc的/ binutils無處不在通常意味着這是gccobjdump -d

  • 創建一批的小程序/小片的源代碼,如:

extern int funcA(int arg); 
extern int funcB(int arg1, int arg2); 
extern int funcC(int arg1, int arg2, int arg3); 
extern int funcD(int arg1, int arg2, int arg3, int arg4); 
extern int funcE(int arg1, int arg2, int arg3, int arg4); 
extern int funcF(int arg1, int arg2, int arg3, int arg4, int arg5); 
extern int funcG(int arg1, int arg2, int arg3, int arg4, int arg5, int arg6); 
extern int funcH(int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, 
       int arg7); 

int main(int argc, char **argv) 
{ 
    printf("sum of all funcs: %d\n", 
     funcA(1) + funcB(2, 3) + funcC(4, 5, 6) + funcD(7, 8, 9, 10) + 
     funcE(11, 12, 13, 14, 15) + funcF(16, 17, 18, 19, 20, 21) + 
     funcG(22, 23, 24, 25, 26, 27, 28) + funcH(29, 30, 31, 32, 33, 34, 35)); 
    return 12345; 
}
  • 編譯這些與編譯器優化和拆卸生成目標代碼。
    代碼的結構非常簡單,足以說明如何運行。到函數調用,傳遞參數返回值,管理寄存器空間 wrt。在進行函數調用時寄存器被保留/不穩定。它還會顯示一些用於初始化常量數據的基本彙編代碼,以及像堆棧訪問和管理那樣的「粘合」。

  • 將此擴展爲簡單的C語言結構,如循環和if/elseswitch語句。始終保持對外部未定義功能幾個電話,因爲這樣做會防止編譯器優化,從扔你所有的「測試代碼」出來的,而當你使用if()測試switch(),對argc(或其他功能參數)謂詞,因爲編譯器無法預測即(並且因此優化代碼的「構建塊」)。

  • 延伸此使用含有不同的基本數據類型的序列struct {}class {}定義,以便找出編譯器在存儲器中,其中彙編指令用於訪問字節/字/整型/多頭/浮標如何安排這些等
    所有這些作品的測試代碼,你可以故意改變(例如,使用不同的操作比+),和/或進行更復雜,以瞭解更多有關指令集和ABI的某些片段。

你做了之後,看着在輸出中,找到平臺ABI的副本(電子或沒有)。其中包含規則手冊,說明如何完成上述工作/爲什麼完成上述工作,它將幫助您瞭解這些規則適用於特定平臺的原因。瞭解上述內容非常重要,因爲在編寫自己的彙編代碼時,必須將其與其他非彙編代碼(除非用於純演示)進行交互。這就是你需要遵守規則的地方,所以即使你不瞭解他們,至少知道規則手冊在哪裏。

只有在那之後,我才建議你實際追蹤特定平臺的指令集參考。

這是因爲,當你通過上述第一消失了,那麼你已經有足夠的經驗/你已經看到已經足以啓動一個小的C程序,編譯它到彙編源,修改了一下,組裝並鏈接它,看看你的修改是否做它應該做的。

試圖在這個階段使用一些更少見的/專門的指令會容易得多,因爲你已經看到了函數調用是如何工作的,需要什麼樣的粘合代碼來將你的程序集與界面的其他部分程序,你已經使用了工具鏈,所以你不需要從頭開始完全。

即,要總結這一切,我的建議是從學習彙編自上而下,而不是從下往上

旁註:

爲什麼我建議使用編譯器優化這種簡單的例子分析編譯器生成的彙編代碼是什麼時候?
那麼,答案是因爲,違反直覺的一些,生成的彙編代碼是簡單得多如果你讓編譯器優化地獄的東西。沒有優化,編譯器通常會創建「愚蠢的」代碼,例如將所有變量放入堆棧,從那裏保存並恢復它們,無論您看到什麼原因,註冊保存/恢復/初始化只是爲了覆蓋下一條指令以及更多這樣的內容。因此,發射的代碼量要大得多。它夾雜着粗糙,而且很難理解。編譯器優化可以將這個問題修剪到最基本的部分,這就是你想要了解平臺ABI以及可以理解的東西。因此,使用編譯器優化。

+0

這是一個非常好的idead/answer。非常感謝。 – gideon 2014-02-18 07:03:44

+0

這是我見過的最好的答案之一。 – 2016-05-07 07:55:13