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

C/C++流程與反匯編

編輯:C++入門知識

C/C++流程與反匯編


眾所周知,任何程序都可以由三種基本控制結構組成,分別是循序結構,選擇結構,循環結構。


這三種結構翻譯成匯編語言又是怎樣的呢?這裡主要考慮的是debug版本。對於release版本經過各種優化後結果不一樣,不作考慮。這裡的編譯器采用的是Visual Studio 2008


順序結構沒什麼懸念,這裡就不提了,首先看下選擇結構。


選擇結構,主要有兩種表現方式:if{ }else if{ } else{ }與 switch{case : case : default:}


首先來看下


if判斷分支

	if (a > 0 && b < 0)
00182DCC  cmp         dword ptr [a],0                 ;兩個判斷,不合規范就跳到下一個else if處
00182DD0  jle         foo+51h (182DF1h) 
00182DD2  cmp         dword ptr [b],0 
00182DD6  jge         foo+51h (182DF1h) 
	{                                              ;沒跳走,執行代碼塊的內容
		printf("if (a > 0 && b < 0)");
00182DD8  mov         esi,esp 
00182DDA  push        offset string "if (a > 0 && b < 0)" (185974h) 
00182DDF  call        dword ptr [__imp__printf (1882B4h)] 
00182DE5  add         esp,4 
00182DE8  cmp         esi,esp 
00182DEA  call        @ILT+450(__RTC_CheckEsp) (1811C7h) 
00182DEF  jmp         foo+87h (182E27h)            ;執行完,跳出if
	}
	else if (a < 0)                                    ;還是判斷,不合規范就跳到下一個else
00182DF1  cmp         dword ptr [a],0 
00182DF5  jge         foo+70h (182E10h) 
	{
		printf("else if (a < 0)");
00182DF7  mov         esi,esp 
00182DF9  push        offset string "else if (a < 0)" (1857A8h) 
00182DFE  call        dword ptr [__imp__printf (1882B4h)] 
00182E04  add         esp,4 
00182E07  cmp         esi,esp 
00182E09  call        @ILT+450(__RTC_CheckEsp) (1811C7h) 
	}
	else
00182E0E  jmp         foo+87h (182E27h)       ;我這得這條語句放在前一個else if裡頭更合適
	{
		printf("else");
00182E10  mov         esi,esp 
00182E12  push        offset string "else" (1857A0h) 
00182E17  call        dword ptr [__imp__printf (1882B4h)] 
00182E1D  add         esp,4 
00182E20  cmp         esi,esp 
00182E22  call        @ILT+450(__RTC_CheckEsp) (1811C7h) 
	}

隨便寫的一個if循環,合理安排if的比較會讓代碼更少,但為了演示,也無所謂了。代碼分析完也覺得簡單,就是一開始看有點麻煩。


	cmp <條件>			;多少個條件就多少個判斷跳轉
	jle <下一個分支>	    ;這裡通常與C/C++裡的判斷相反
	……
	cmp <條件>
	jle <下一個分支>

	(代碼塊)

	jmp 			;最後一個if(else)代碼塊沒有這條

switch - case 判斷分支

	switch(a)
00E82DC5  mov         eax,dword ptr [a] 
00E82DC8  mov         dword ptr [ebp-0D0h],eax 
00E82DCE  cmp         dword ptr [ebp-0D0h],0      ;判斷跳轉很頻繁,首先考慮是switch
00E82DD5  je          foo+4Bh (0E82DEBh) 
00E82DD7  cmp         dword ptr [ebp-0D0h],1 
00E82DDE  je          foo+52h (0E82DF2h)        ;這些是符合條件的就跳轉到對應的代碼塊
00E82DE0  cmp         dword ptr [ebp-0D0h],2 
00E82DE7  je          foo+5Bh (0E82DFBh) 
00E82DE9  jmp         foo+64h (0E82E04h)        ;沒有符合條件的,跳到 default
	{
	case 0:
		a = 0;
00E82DEB  mov         dword ptr [a],0            ;這裡沒有break,繼續往下執行
	case 1:
		a =1;
00E82DF2  mov         dword ptr [a],1 
		break;
00E82DF9  jmp         foo+6Bh (0E82E0Bh)        ;break,跳出switch
	case 2:
		a =2;
00E82DFB  mov         dword ptr [a],2 
		break;
00E82E02  jmp         foo+6Bh (0E82E0Bh) 
	default:
		a =3;
00E82E04  mov         dword ptr [a],3 
	}


連續的比較與條件跳轉,容易讓人聯想到switch

對於代碼塊也比較簡單

有break會增加一個無條件跳轉

接下來看下循環結構,


循環結構主要有三種:For循環,While循環,Do-While循環。


至於其他語言的一些repeat until等不作考慮,請自行分析。


For循環

	for (int i = 0;i< 5;i++)
00DB17CE  mov         dword ptr [i],0 
00DB17D5  jmp         foo+30h (0DB17E0h) 
00DB17D7  mov         eax,dword ptr [i] 
00DB17DA  add         eax,1 
00DB17DD  mov         dword ptr [i],eax 
00DB17E0  cmp         dword ptr [i],5 
00DB17E4  jge         foo+53h (0DB1803h) 
	{
		printf("%d",i);
00DB17E6  mov         esi,esp 
00DB17E8  mov         eax,dword ptr [i] 
00DB17EB  push        eax  
00DB17EC  push        offset string "%d" (0DB573Ch) 
00DB17F1  call        dword ptr [__imp__printf (0DB82B4h)] 
00DB17F7  add         esp,8 
00DB17FA  cmp         esi,esp 
00DB17FC  call        @ILT+450(__RTC_CheckEsp) (0DB11C7h) 
00DB1801  jmp         foo+27h (0DB17D7h) 
	}

代碼很簡單,翻譯成匯編之後,就得轉換下思維了,這裡總結個規律出來後就會變得簡單了。下面是一個基本的框架:

for(第一部分;第二部分;第三部分)
{
	循環體;
}

	mov <循環變量>,<初始值>				;第一部分。給循環變量賦初值
	jmp B								;跳到第一次循環處,執行第二部分

A:	(改動循環變量)						;第三部分。修改循環變量

B:	cmp <循環變量>,<限制變量>			;第二部分。檢查循環變量
	jge 跳出循環							;這裡的判斷條件通常與for中看到的相反
	……
	(循環體)
	……
	jmp A								;跳回去第三部分,修改變量循環

While循環

	while(a > 0)
00852DC5  cmp         dword ptr [a],0            ;首先判斷,不合條件跳出while代碼塊
00852DC9  jle         foo+36h (852DD6h) 
	{
		a--;
00852DCB  mov         eax,dword ptr [a] 
00852DCE  sub         eax,1 
00852DD1  mov         dword ptr [a],eax 
	}
00852DD4  jmp         foo+25h (852DC5h)              ;強制跳轉會開頭的判斷

框架很簡單,先判斷,不符合條件就跳出代碼塊,否則繼續執行下去,代碼塊最後跳回來繼續判斷。

A:	cmp <循環變量>,<限制變量>
	jge  B         ;跳出代碼塊
	
	(循環體)
	
	……
	jmp  A        ;往回跳

	
B:			;循環結束

Do - While循環

	do
	{
		a--;
01362DC5  mov         eax,dword ptr [a] 
01362DC8  sub         eax,1 
01362DCB  mov         dword ptr [a],eax 
	}while(a > 0);
01362DCE  cmp         dword ptr [a],0 
01362DD2  jg          foo+25h (1362DC5h) 
		

Do - while就更加簡單了,直接把判斷挪到代碼塊後面。

A:	cmp <循環變量>,<限制變量>
	jge B
	
	(循環體)
	
	……
	jmp A
	
B:			;循環結束

好了,基本介紹完了,此次只是為了告誡我們,在匯編裡面,代碼的理解跟高級語言是有點出入的,得轉換下思維。另外,也說明了同一種邏輯可以通過多種方式來表達。


另外,這只是debug版本下的反匯編代碼,在release版本下,代碼將千變萬化,比如,switch將可能會使用跳轉表等來實現,部分if將直接被優化掉,畢竟使用流水線速度將會大大加快,忽然一個跳轉將會打斷流水線。

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