x86 反彙編/迴圈示例
這個函式的功能是什麼?它接受什麼型別的引數,並且它返回什麼型別的結果(如果有)?
push ebp
mov ebp, esp
mov esi, [ebp + 8]
mov ebx, 0
mov eax, 0
mov ecx, 0
_Label_1:
mov ecx, [esi + ebx * 4]
add eax, ecx
inc ebx
cmp ebx, 100
jne _Label_1
mov esp, ebp
pop ebp
ret 4
該函式迴圈遍歷一個由 esi 指向的 4 位元組整數陣列,並將每個條目相加。它在 eax 中返回總和。唯一的引數(位於 [ebp + 8] 中)是指向整數陣列的指標。ebx 和 100 之間的比較表明輸入陣列包含 100 個條目。指標偏移量 [esi + ebx * 4] 表明陣列中的每個條目都是 4 位元組寬的。
這個函式的 C 原型是什麼?確保包含引數、返回值和呼叫約定。
push ebp
mov ebp, esp
mov esi, [ebp + 8]
mov ebx, 0
mov eax, 0
mov ecx, 0
_Label_1:
mov ecx, [esi + ebx * 4]
add eax, ecx
inc ebx
cmp ebx, 100
jne _Label_1
mov esp, ebp
pop ebp
ret 4
請注意 **ret** 函式如何從堆疊中清除其引數?這意味著該函式是一個 STDCALL 函式。我們知道該函式以指向整數陣列的指標作為其唯一引數。然而,我們不知道這些整數是有符號的還是無符號的,因為 **je** 命令用於兩種型別的值。我們可以假設其中一個,為了簡單起見,我們可以假設無符號值(在這個函式中,無符號值和有符號值實際上將以相同的方式工作)。我們還知道返回值是一個 4 位元組整數,與引數陣列中找到的型別相同。由於該函式沒有名稱,我們可以將其簡單地稱為 “MyFunction”,並且我們可以將引數稱為 “array”,因為它是一個數組。從這些資訊中,我們可以確定 C 中的以下原型
unsigned int STDCALL MyFunction(unsigned int *array);
將此程式碼反編譯成等效的 C 原始碼。
push ebp
mov ebp, esp
mov esi, [ebp + 8]
mov ebx, 0
mov eax, 0
mov ecx, 0
_Label_1:
mov ecx, [esi + ebx * 4]
add eax, ecx
inc ebx
cmp ebx, 100
jne _Label_1
mov esp, ebp
pop ebp
ret 4
從上面的函式原型和對該函式功能的描述開始,我們可以開始為該函式編寫 C 程式碼。我們知道該函式在迴圈之前初始化了 eax、ebx 和 ecx。但是,我們可以看到 ecx 只是用作中間儲存位置,從陣列中接收連續的值,然後將其新增到 eax。
我們將建立兩個無符號整數,a(用於 eax)和 b(用於 ebx)。我們將在 **register** 限定符的幫助下定義 a 和 b,這樣我們就可以指示編譯器不要在堆疊上為它們建立空間。對於每個迴圈迭代,我們都將陣列在位置 ebx*4 處的值新增到執行總和 eax。將此轉換為我們的 a 和 b 變數,並使用 C 語法,我們看到
a = a + array[b];
迴圈可以是 **for** 迴圈或 **while** 迴圈。我們看到迴圈控制變數 b 在迴圈之前初始化為 0,並且在每次迴圈迭代中遞增 1。迴圈在 *遞增後* 對 b 進行 100 的測試,因此我們知道 b 在迴圈主體內部從不等於 100。利用這些簡單的事實,我們將以 3 種不同的方式編寫迴圈
首先,使用 **while** 迴圈。
unsigned int STDCALL MyFunction(unsigned int *array)
{
register unsigned int b = 0;
register unsigned int a = 0;
while(b != 100)
{
a = a + array[b];
b++;
}
return a;
}
或者,使用 **for** 迴圈
unsigned int STDCALL MyFunction(unsigned int *array)
{
register unsigned int b;
register unsigned int a = 0;
for(b = 0; b != 100; b++)
{
a = a + array[b];
}
return a;
}
最後,使用 **do-while** 迴圈
unsigned int STDCALL MyFunction(unsigned int *array)
{
register unsigned int b = 0;
register unsigned int a = 0;
do
{
a = a + array[b];
b++;
}while(b != 100);
return a;
}