x86 反彙編/分支示例
此函式接受哪些引數?它使用什麼呼叫約定?它返回什麼型別的值?編寫此函式的完整 C 語言原型。假設所有值都是無符號值。
push ebp
mov ebp, esp
mov eax, 0
mov ecx, [ebp + 8]
cmp ecx, 0
jne _Label_1
inc eax
jmp _Label_2
:_Label_1
dec eax
: _Label_2
mov ecx, [ebp + 12]
cmp ecx, 0
jne _Label_3
inc eax
: _Label_3
mov esp, ebp
pop ebp
ret
此函式在 [ebp + 8] 和 [ebp + 12] 處的堆疊上訪問引數。這兩個值都被載入到 ecx 中,因此我們可以假設它們是 4 位元組值。此函式不清理自己的堆疊,並且值不是在暫存器中傳遞的,所以我們知道該函式是 CDECL。eax 中的返回值是 4 位元組值,我們被告知假設所有值都是無符號的。將所有這些組合在一起,我們可以構建函式原型
unsigned int CDECL MyFunction(unsigned int param1, unsigned int param2);
此函式中有多少個獨立的分支結構?它們是什麼型別?你能根據這些分支的結構,給_Label_1、_Label_2 和_Label_3 更具描述性的名稱嗎?
push ebp
mov ebp, esp
mov eax, 0
mov ecx, [ebp + 8]
cmp ecx, 0
jne _Label_1
inc eax
jmp _Label_2
:_Label_1
dec eax
: _Label_2
mov ecx, [ebp + 12]
cmp ecx, 0
jne _Label_3
inc eax
: _Label_3
mov esp, ebp
pop ebp
ret
此函式中有多少個獨立的分支結構?剝離掉入口和退出序列後,我們剩下的程式碼如下:
mov ecx, [ebp + 8]
cmp ecx, 0
jne _Label_1
inc eax
jmp _Label_2
:_Label_1
dec eax
: _Label_2
mov ecx, [ebp + 12]
cmp ecx, 0
jne _Label_3
inc eax
: _Label_3
觀察程式碼,我們看到 2 個cmp 語句。第一個 cmp 語句將 ecx 與零比較。如果 ecx 不為零,我們就跳轉到 _Label_1,遞減 eax,然後直接執行到 _Label_2。如果 ecx 為零,我們就遞增 eax,直接跳轉到 _Label_2。寫出一些虛擬碼,我們對第一部分有以下結果:
if(ecx doesnt equal 0) goto _Label_1 eax++; goto _Label_2 :_Label_1 eax--; :_Label_2
由於 _Label_2 發生在這個結構的末尾,我們可以將它重新命名為更具描述性的名稱,例如 "End_of_Branch_1" 或 "Branch_1_End"。第一個比較測試 ecx 與 0 的關係,然後在不等於時跳轉。我們可以反轉條件,說 _Label_1 是一個else 塊
if(ecx == 0) ;ecx is param1 here
{
eax++;
}
else
{
eax--;
}
因此,我們可以將 _Label_1 重新命名為其他具描述性的名稱,例如 "Else_1"。Branch_1_End (_Label_2) 之後程式碼塊的其餘部分如下:
mov ecx, [ebp + 12]
cmp ecx, 0
jne _Label_3
inc eax
: _Label_3
我們可以立即看到 _Label_3 是此分支結構的末尾,因此我們可以立即將其稱為 "Branch_2_End" 或其他名稱。在這裡,我們再次將 ecx 與 0 進行比較,如果不相等,我們就跳轉到塊的末尾。但是,如果它等於零,我們就遞增 eax,然後從分支的底部退出。我們可以看到此分支結構中沒有else 塊,因此我們不需要反轉條件。我們可以直接寫一個if 語句
if(ecx == 0) ;ecx is param2 here
{
eax++;
}
編寫此函式的等效 C 語言程式碼。假設所有引數和返回值都是無符號值。
push ebp
mov ebp, esp
mov eax, 0
mov ecx, [ebp + 8]
cmp ecx, 0
jne _Label_1
inc eax
jne _Label_2
:_Label_1
dec eax
: _Label_2
mov ecx, [ebp + 12]
cmp ecx, 0
jne _Label_3
inc eax
: _Label_3
mov esp, ebp
pop ebp
ret
從答案 1 中的 C 語言函式原型和答案 2 中的條件塊開始,我們可以將一個虛擬碼函式拼湊起來,不包含變數宣告或返回值
unsigned int CDECL MyFunction(unsigned int param1, unsigned int param2)
{
if(param1 == 0)
{
eax++;
}
else
{
eax--;
}
if(param2 == 0)
{
eax++;
}
}
現在,我們只需要建立一個變數來儲存 eax 中的值,我們將它稱為 "a",並將其宣告為register 型別
unsigned int CDECL MyFunction(unsigned int param1, unsigned int param2)
{
register unsigned int a = 0;
if(param1 == 0)
{
a++;
}
else
{
a--;
}
if(param2 == 0)
{
a++;
}
return a;
}
當然,此函式不是一個特別有用的函式,但至少我們知道它在做什麼。