堆棧
堆棧指令
push: 把32位操作數壓入堆棧,壓入成功後esp被減4.
pop: 將32位操作數彈出堆棧,彈出之前esp被加4.
可涉及堆棧操作的指令
sub: 通常被減數放入寄存器中,第二個參數放在堆棧上;
add: 第一個參數放在eax寄存器上,第二參數放在堆棧上;
ret: 返回。類似於pop與jmp的組合指令。
call: 調用函數。類似於push與jmp的組合指令。
數據傳送指令
mov: 數據移動。第一個爲目的參數,第二個爲源參數。
xor: 異或。邏輯操作比移動操作速度快。
lea: 取得地址後放入到前面寄存器中。
stos: 串存儲指令。將eax中的數據放入edi所致的地址中,同時,edi會增加4個字節。
rep: 重複執行ecx次。
跳轉與比較指令
jmp: 無條件跳轉。
jg: 大於時跳轉。
jl: 小於時跳轉。
jge: 大於或等於時跳轉。
cmp: 比較指令。執行跳轉前的比較。
注意: esp總是指向棧頂。即在棧中的地址最小。
乘除
mul: 無符號乘法;
imul: 有符號乘法;
div: 無符號除法;
函數調用規則
_cdecl C調用規則
- 參數從右到左進入堆棧。
- 在函數返回後,主調函數負責清理堆棧,所以這種調用常會生成較大的可執行程序。
_stdcall又稱爲WINAPI
- 參數從右到左進入堆棧;
- 被調用函數在返回前自行清理堆棧,所以生成代碼比cdecl小。
Pascal調用規則
- 參數從左到右進入堆棧;
- 被調函數在返回前自行清理堆棧。
- 不支持可變參數的函數調用。
_fastcall
- 用於Windows內核中。
this call
- C++編譯器
常用語句解析
for循環
for(int i=0;i<100;++i);
mov <循環變量>,<初始值>
jmp B
A:(改動變量)
...
B:cmp <循環變量>,<限制變量>
jge 跳出循環
..
jmp A
do循環
do{}while(false);
cmp <循環變量>,<限制變量>
jl <循環開始點>
while循環
while(i<20){++i}
A: cmp <循環變量>,<限制變量>
jge B
(循環體)
jmp A
B: (循環結束)
if-else
cmp <條件>
jmp <下一個分支>
注:存在多個else if時進入下個條件之前執行相同的兩個操作。
switch-case
cmp <條件>
ja B
mov ecx,<case value>
jmp [ecx*4+case 表地址>
<執行語句>
B: <結束位置>
class、union、enum
class使用內存對齊的方式處理多個變量,本質是基於第一個成員變量的地址偏移;union和enum主要是方便程序員而設計的數據結構,本質上就是一個基本數據類型或class類型
測試代碼
int fun(int a, int b)
{
return a + b;
}
int myFun(int a, int b)
{
int c = a + b;
int i;
for (i = 0; i < 50; ++i)
{
c += i;
}
return c;
}
int main01()
{
int sum = 0;
int a = 1, b = 2, c = 3;
sum = fun(a, b);
sum = sum - a;
sum = myFun(a, b);
for (int i = 0; i < 20; ++i)
{
sum++;
}
do
{
sum++;
} while (sum < 100);
while(sum<101)
{
sum++;
}
if (sum < 200)
{
sum++;
}
else if(sum<300)
{
sum--;
}
else
{
sum += 9;
}
typedef struct {
int a;
int b;
}TT;
switch (sum)
{
case 0:
sum += 2;
break;
case 1:
sum += 3;
break;
case 2:
sum += 9;
break;
case 3:
sum += 10;
break;
default:
break;
}
TT m;
m.a = 12;
m.b = 23;
char ch='a';
getc(ch);
return 0;
}