C反彙編實例(詳細註解版)(二)

那麼有了上述三方面的基礎,我們就可以來逐一解讀那段“傳奇”的彙編代碼了。

初始化i

00411A3E mov dword ptr [i],0

跳轉至條件判斷

00411A45 jmp myfunction+30h (411A50h)

循環表達式,對i每輪加1

00411A47 mov eax,dword ptr [i]

00411A4A add eax,1

00411A4D mov dword ptr [i],eax

條件判斷,若不滿足i < 3,則跳出循環

00411A50 cmp dword ptr [i],3

00411A54 jge myfunction+0AEh (411ACEh)

{ i的循環體

這裏比較特殊,傳說中的“嵌套循環”,可以對比

最前面的C代碼看一下,其實是一樣的

初始化j

00411A56 mov dword ptr [j],0

跳至j循環的條件判斷

00411A5D jmp myfunction+48h (411A68h)

每輪對j1

00411A5F mov eax,dword ptr [j]

00411A62 add eax,1

00411A65 mov dword ptr [j],eax

j循環的條件判斷

00411A68 cmp dword ptr [j],3

00411A6C jge myfunction+0A9h (411AC9h)

{ j的循環體

這裏省略的是數組賦值的過程代碼,會在稍後分析

} j 的循環體結束

跳到jexpr

00411AC7 jmp myfunction+3Fh (411A5Fh)

} i的循環體結束

跳至iexpr

00411AC9 jmp myfunction+27h (411A47h)

    以下我們再詳細分析下上面挖下來的數組賦值的代碼。爲了方便起見,再把C語句貼如下:

c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j];

; 還記得前面所說的彙編訪問二維數組的方式麼?忘記的話,再回過頭去看一下哈

 

; 第i行,每行3個佔4字節的int類型,所以乘以i×12(0Ch),表示行偏移

00411A6E mov eax,dword ptr [i]

00411A71 imul eax,eax,0Ch

 

; 往寄存器送入一些變量

00411A74 mov ecx,dword ptr [a]

00411A77 mov edx,dword ptr [j]

00411A7A mov esi,dword ptr [b]

 

00411A7D mov eax,dword ptr [ecx+eax] ; ecx已經含有a數組的起始地址,這句相當於往

; eax存入基址+i行偏移這個地址開始的int

; 型值,也就是a[i][0]

 

00411A80 imul eax,dword ptr [esi+edx*4] ; 這句比較好理解,esib數組起始地址

                                         ; edx * 4表示列偏移,相當於eax * b[0][j]

                                         ; 也就是eax = a[i][0] * b[0][j]

; 同理,ecx獲得i行偏移量

00411A84 mov ecx,dword ptr [i]

00411A87 imul ecx,ecx,0Ch

00411A8A mov edx,dword ptr [a] ; edx保存的a數組基地址

00411A8D mov esi,dword ptr [j]  ; esi = j

00411A90 mov edi,dword ptr [b]  ; edi保存的b數組基地址

00411A93 mov ecx,dword ptr [edx+ecx+4] ; edx 基址 = a

                                       ; ecx 行偏移 = i

                                       ; 4  列偏移 = 1

                                      ; 綜上,ecx = a[i][1]

; edi b的基址;esi = j,第j列;0Ch,行偏移量,相當於是第1

; 綜上,ecx = ecx * b[1][j],即ecx = a[i][1] * b[1][j]

00411A97 imul ecx,dword ptr [edi+esi*4+0Ch]

; 把第一項a[i][0] * b[0][j]和第二項相加存入eax,從這也可以看出

; 其實eax就是用來保存最後結果的,此時eax = a[i][0] * b[0][j] + a[i][1] * b[1][j]

00411A9C add eax,ecx

; 以下這段不用解釋了吧?依樣花葫蘆,到411AB6爲止

; eax = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j]

00411A9E mov edx,dword ptr [i]

00411AA1 imul edx,edx,0Ch

00411AA4 mov ecx,dword ptr [a]

00411AA7 mov esi,dword ptr [j]

00411AAA mov edi,dword ptr [b]

00411AAD mov edx,dword ptr [ecx+edx+8]

00411AB1 imul edx,dword ptr [edi+esi*4+18h]

00411AB6 add eax,edx

; 首先是老規矩,通過ecxedx找到了c[i][j]的內存地址,411AC4這句就是把

; 前邊eax中的計算結果寫入到內存中代表c[i][j]這個元素的位置

00411AB8 mov ecx,dword ptr [i]

00411ABB imul ecx,ecx,0Ch

00411ABE add ecx,dword ptr [c]

00411AC1 mov edx,dword ptr [j]

00411AC4 mov dword ptr [ecx+edx*4],eax

    這樣就完成了a中第i行每個元素分別與b中第j列的每個元素的乘積保存到c的第i行第j列元素中,這麼一個操作,確實比較複雜。如果看不大懂,不要緊,回過頭多看幾遍,一定會明白的,如果說有些話我的表述不妥當,也請大俠指出,以免誤人子弟J

    我的一些朋友問我,研究彙編,尤其研究C反彙編,到底有什麼用處?我的理解是,除非你是底層開發人員,否則我們的目的並非是學習如何運用匯編寫複雜的算法程序,而是將它應用在排錯、性能優化等方面,如果你能看懂一些彙編代碼,那麼當你的客戶程序崩潰時,你打開調試器,就可以先簡要分析出出錯程序代碼的大致意思,這對你的調試是相當有幫助的。而如果彙編懂得較深的話(我只是皮毛而已),那麼就可以對C目標程序進行有目的的修改以提高程序性能,因爲有時候即便是release模式下的exe文件,仍然有可以優化之處,只是這時一定要謹慎再謹慎,萬一撿了芝麻丟了西瓜就太不划算了。當然了還有另外某些用途,呵呵,比較邪惡,就不點破了……總之希望本文能對大家有所幫助!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章