函数调用
int plus(int x, int y)
{
return x + y;
}
int main()
{
plus(1, 2);
return 0;
}
对应的汇编分析
plus(1, 2);
00231DAF push 2 将参数2压入堆栈 参数的入栈顺序是从右往左
00231DB1 push 1 将参数1压入堆栈
00231DB3 call 00231370 调用plus 这里使用vs2017 00231370是一个jmp 002318B0
00231DB8 add esp,8 平衡堆栈 2个参数
int plus(int x, int y)
{
002318B0 push ebp 将ebp压入堆栈临时保存
002318B1 mov ebp,esp ebp = esp
002318B3 sub esp,0C0h 开辟方法栈空间 48(0x30)个空间
002318B9 push ebx 保存ebx 保存现场
002318BA push esi 保存ebx 保存现场
002318BB push edi 保存edi 保存现场
002318BC lea edi,[ebp+FFFFFF40h] [ebp+FFFFFF40h] = [ebp - 0c0H]
002318C2 mov ecx,30h ecx = 0x30 循环0x30次 用于将新开辟的栈空间 置0xcc
002318C7 mov eax,0CCCCCCCCh eax = 0xCCCCCCCC 0xcc表示断点如果访问出问题可以断点异常
002318CC rep stos dword ptr es:[edi] 将 eax的值存入 [edi] 然后edi +=4 rep 按(ecx)中的次数重复执行字符串指令
002318CE mov ecx,23B000h
002318D3 call 00231203
return x + y; 这里我重新编译了一下代码地址有点问题
mov eax,dword ptr [ebp+8] 函数参数1 最后一个压入堆栈的参数
add eax,dword ptr [ebp+0Ch] 函数参数2
}
002318DA pop edi 从堆栈中拿出 edi 还原现场
002318DB pop esi 从堆栈中拿出 esi 还原现场
002318DC pop ebx 从堆栈中拿出 ebx 还原现场
002318DD add esp,0C0h 释放栈空间
002318E3 cmp ebp,esp
002318E5 call 0023120D
002318EA mov esp,ebp esp = ebp 恢复 esp
002318EC pop ebp 恢复ebp
002318ED ret 函数返回
堆栈变化
变量
全局变量
1)编译的时候就已经确定了内存地址和宽度,变量名就是内存地址的别名。
2)如果不重写编译,全局变量的内存地址不变。游戏外挂中的找“基址”,其实就是找全局变量。|
3)全局变量中的值任何函数都可以改,是公用的。
例子:CE搜索基址
int x;
int main()
{
x = 0x456;
return 0;
}
x = 0x456;
00EF1DA8 mov dword ptr ds:[00EF9148h],456h 将0x456保存到全局变量中
局部变量
1)局部变量是函数内部申请的,如果函数没有执行,那么局部变量没有内存空间。
2)局部变量的内存是在堆栈中分配的,程序执行时才分配。我们无法预知程序何时执行,这也就意味着,我们无法确定局部变量的内存地址。
3)因为局部变量地址内存是不确定的,所以,局部变量只能在函数内部使用,其他函数不能使用。
函数参数和局部变量在方法中的访问
int plus(int x, int y)
{
int z = x + y;
return z;
}
int main()
{
plus(1, 2);
return 0;
}
对应汇编
int main()
{
00311D80 push ebp
00311D81 mov ebp,esp
00311D83 sub esp,0C0h
00311D89 push ebx
00311D8A push esi
00311D8B push edi
00311D8C lea edi,[ebp+FFFFFF40h]
00311D92 mov ecx,30h
00311D97 mov eax,0CCCCCCCCh
00311D9C rep stos dword ptr es:[edi]
00311D9E mov ecx,31B000h
00311DA3 call 00311203
plus(1, 2);
00311DA8 push 2
00311DAA push 1
plus(1, 2);
00311DAC call 00311370
00311DB1 add esp,8
return 0;
00311DB4 xor eax,eax
}
00311DB6 pop edi
00311DB7 pop esi
00311DB8 pop ebx
00311DB9 add esp,0C0h
00311DBF cmp ebp,esp
00311DC1 call 0031120D
00311DC6 mov esp,ebp
00311DC8 pop ebp
00311DC9 ret
int plus(int x, int y)
{
003124A0 push ebp
003124A1 mov ebp,esp
003124A3 sub esp,0CCh
003124A9 push ebx
003124AA push esi
003124AB push edi
003124AC lea edi,[ebp+FFFFFF34h]
003124B2 mov ecx,33h
003124B7 mov eax,0CCCCCCCCh
003124BC rep stos dword ptr es:[edi]
003124BE mov ecx,31B000h
003124C3 call 00311203
int z = x + y;
003124C8 mov eax,dword ptr [ebp+8]
003124CB add eax,dword ptr [ebp+0Ch]
003124CE mov dword ptr [ebp-8],eax
return z;
003124D1 mov eax,dword ptr [ebp-8]
}
003124D4 pop edi
003124D5 pop esi
003124D6 pop ebx
003124D7 add esp,0CCh
003124DD cmp ebp,esp
003124DF call 0031120D
003124E4 mov esp,ebp
003124E6 pop ebp
003124E7 ret
数据类型与数据存储
C语言数据类型 | 汇编数据宽度 |
---|---|
char | byte |
short | word |
int | dword |
long | dword |
-
无符号跟有符号,在内存中存储的是一样的,根据使用的人来决定
-
默认有符号,类型转换--比较大小--数学运算要注意
-
jbe跟jle 低于等于,小于等于
浮点类型
这部分就是计算机组成原理
float的存储方法
12.5 在内存中存储为
整数部分: 12
计算 | 余数 |
---|---|
12/2=6 | 0 |
6/2=3 | 0 |
3/2=1 | 1 |
1/2=0 | 1 |
从下往上: 1100
小数部分: 0.5
计算 | 小数 |
---|---|
0.5*2=1.0 | 1 |
从上往下:1
1100.1=1.1001*2的3次方
1位符号位 中间8位指数 后面23位尾数
尾数从左往右写就行
中间8位开头,左移为1,右移为0,
后面7位,存储指数-1,比如3次方,就是存10,如果是-2次方就是-3,也就是fd, 11111101,然后只取后7位
127 +(3) = 130 = 0x82 = 1000 0010 这里直接加指数
0 10000010 10010000000000000000000
0100 0001 0100 1000 0000 0000 0000 0000
41480000
如果是-12.5呢
就变成
1100 0001 0100 1000 0000 0000 0000 0000
C1480000
编码
ASCII 英文字符
GB2312或GB2312-80 中文字符中国定义的中文标准,两个字节一个汉字(两个大于127的字符表示一个中文)
在半角的情况下英文字符不变占一个字节,全角的情况下英文也被重新定义用2个字节表示
分支语句
if else语句
int main()
{
int x = 10;
int y = 20;
if (x > y)
{
printf("true");
}
else
{
printf("false");
}
return 0;
}
int main()
{
01381870 push ebp 保存ebp
01381871 mov ebp,esp ebp作为新的栈底
01381873 sub esp,0D8h 开辟局部变量空间
01381879 push ebx 保存现场
0138187A push esi 保存现场
0138187B push edi 保存现场
0138187C lea edi,[ebp+FFFFFF28h] 初始化局部变量开始的位置
01381882 mov ecx,36h 循环次数
01381887 mov eax,0CCCCCCCCh 局部变量的初值
0138188C rep stos dword ptr es:[edi] 填充初值
0138188E mov ecx,138C003h
01381893 call 01381217
int x = 10;
01381898 mov dword ptr [ebp-8],0Ah 局部变量x 初值
int y = 20;
0138189F mov dword ptr [ebp-14h],14h 局部变量y 初值
if (x > y)
013818A6 mov eax,dword ptr [ebp-8] 把局部变量x赋值给eax
013818A9 cmp eax,dword ptr [ebp-14h] 比较x和y
013818AC jle 013818BD 小于或等于跳转(这里是会跳转)
{
printf("true");
013818AE push 1387B30h 参数压入堆栈
013818B3 call 0138104B 调用printf
013818B8 add esp,4 平栈
}
else
013818BB jmp 013818CA 执行完true部分的代码直接跳走
{
printf("false");
013818BD push 1387B38h
013818C2 call 0138104B
013818C7 add esp,4
}
return 0;
013818CA xor eax,eax
}
if else if
int main()
{
int n = 10;
if (n == 1)
{
printf("1");
}
else if(n == 10)
{
printf("10");
}
else if (n == 20)
{
printf("20");
}
else
{
printf("else");
}
return 0;
}
int main()
{
01184EB0 push ebp
01184EB1 mov ebp,esp
01184EB3 sub esp,0CCh
01184EB9 push ebx
01184EBA push esi
01184EBB push edi
01184EBC lea edi,[ebp+FFFFFF34h]
01184EC2 mov ecx,33h
01184EC7 mov eax,0CCCCCCCCh
01184ECC rep stos dword ptr es:[edi]
01184ECE mov ecx,118C003h
01184ED3 call 01181217
int n = 10;
01184ED8 mov dword ptr [ebp-8],0Ah 局部变量10
if (n == 1)
01184EDF cmp dword ptr [ebp-8],1 局部变量和1比较
01184EE3 jne 01184EF4 不相等的时候跳转到下一个判断 相等执行里面的内容
{
printf("1");
01184EE5 push 1187B30h
01184EEA call 0118104B
01184EEF add esp,4
01184EF2 jmp 01184F2B 跳到if结束的后一条语句
}
else if(n == 10)
01184EF4 cmp dword ptr [ebp-8],0Ah 局部变量和10比较
01184EF8 jne 01184F09 不相等时跳转到下一个判断
{
printf("10");
01184EFA push 1187B38h
01184EFF call 0118104B
01184F04 add esp,4
01184F07 jmp 01184F2B 里面的内容执行完毕后跳出整个if
}
else if (n == 20)
01184F09 cmp dword ptr [ebp-8],14h 局部变量和20比较
01184F0D jne 01184F1E 不相等时跳转到else
{
printf("20");
01184F0F push 1187B34h
01184F14 call 0118104B
01184F19 add esp,4
}
else
01184F1C jmp 01184F2B 里面的内容执行完毕后跳出整个if
{
printf("else");
01184F1E push 1187BE8h
01184F23 call 0118104B
01184F28 add esp,4
}
return 0;
01184F2B xor eax,eax
}
switch语句
小于3个分支
int main()
{
int n = 10;
switch (n)
{
case 1:
{
printf("1");
}
break;
case 2:
{
printf("2");
}
case 3:
{
printf("3");
}
break;
default:
{
printf("default");
}
break;
}
return 0;
}
int main()
{
01151850 push ebp
01151851 mov ebp,esp
01151853 sub esp,0D0h
01151859 push ebx
0115185A push esi
0115185B push edi
0115185C lea edi,[ebp+FFFFFF30h]
01151862 mov ecx,34h
01151867 mov eax,0CCCCCCCCh
0115186C rep stos dword ptr es:[edi]
0115186E mov ecx,115C003h
01151873 call 01151217
int n = 10;
01151878 mov dword ptr [ebp-8],0Ah 局部变量n赋初值
switch (n)
0115187F mov eax,dword ptr [ebp-8] 局部变量赋值给eax
01151882 mov dword ptr [ebp+FFFFFF30h],eax eax传给一个临时局部变量
01151888 cmp dword ptr [ebp+FFFFFF30h],1 这个临时局部变量和1比较
0115188F je 011518A5 je相等时跳转到case 1处执行
01151891 cmp dword ptr [ebp+FFFFFF30h],2 和2比较
01151898 je 011518B4 je相等时跳转到case 2处执行
0115189A cmp dword ptr [ebp+FFFFFF30h],3 和3比较
011518A1 je 011518C1 je相等时跳转到case 3处执行
011518A3 jmp 011518D0 如果都不能跳转跳到default
{
case 1:
{
printf("1");
011518A5 push 1157B30h
011518AA call 0115104B
011518AF add esp,4
}
break;
011518B2 jmp 011518DD
case 2:
{
printf("2");
011518B4 push 1157B38h
011518B9 call 0115104B
011518BE add esp,4
}
case 3: 这里case 2没有写break也就没有了jmp
{
printf("3");
011518C1 push 1157B34h
011518C6 call 0115104B
011518CB add esp,4
}
break;
011518CE jmp 011518DD
default:
{
printf("default");
011518D0 push 1157BDCh
011518D5 call 0115104B
011518DA add esp,4
}
break;
}
return 0;
011518DD xor eax,eax 返回0
}
增加分支
int main()
{
int n = 10;
switch (n)
{
case 1:
{
printf("1");
}
break;
case 2:
{
printf("2");
}
case 3:
{
printf("3");
}
break;
case 4:
{
printf("4");
}
break;
case 10:
{
printf("10");
}
break;
default:
{
printf("default");
}
break;
}
return 0;
}
int main()
{
011B4EB0 push ebp
011B4EB1 mov ebp,esp
011B4EB3 sub esp,0D0h
011B4EB9 push ebx
011B4EBA push esi
011B4EBB push edi
011B4EBC lea edi,[ebp+FFFFFF30h]
011B4EC2 mov ecx,34h
011B4EC7 mov eax,0CCCCCCCCh
011B4ECC rep stos dword ptr es:[edi]
011B4ECE mov ecx,11BC003h
011B4ED3 call 011B1217
int n = 10;
011B4ED8 mov dword ptr [ebp-8],0Ah 临时局部变量10
switch (n)
011B4EDF mov eax,dword ptr [ebp-8]
011B4EE2 mov dword ptr [ebp+FFFFFF30h],eax
011B4EE8 mov ecx,dword ptr [ebp+FFFFFF30h]
011B4EEE sub ecx,1 减去case的最小值 所有case值从0开始重新计算
011B4EF1 mov dword ptr [ebp+FFFFFF30h],ecx
011B4EF7 cmp dword ptr [ebp+FFFFFF30h],9 //case最大值-最小值也就是重新计算后的最大值
011B4EFE ja 011B4F56 大于直接跳转到default
011B4F00 mov edx,dword ptr [ebp+FFFFFF30h] 将重新计算的case值 从0开始
011B4F06 jmp dword ptr [edx*4+011B4F7Ch] 用一个数组保存所有case的地址
{
case 1:
{
printf("1");
011B4F0D push 11B7B30h
011B4F12 call 011B104B
011B4F17 add esp,4
}
break;
011B4F1A jmp 011B4F63
case 2:
{
printf("2");
011B4F1C push 11B7B38h
case 2:
{
printf("2");
011B4F21 call 011B104B
011B4F26 add esp,4
}
case 3:
{
printf("3");
011B4F29 push 11B7B34h
011B4F2E call 011B104B
011B4F33 add esp,4
}
break;
011B4F36 jmp 011B4F63
case 4:
{
printf("4");
011B4F38 push 11B7BDCh
011B4F3D call 011B104B
011B4F42 add esp,4
}
break;
011B4F45 jmp 011B4F63
case 10:
{
printf("10");
011B4F47 push 11B7B3Ch
011B4F4C call 011B104B
011B4F51 add esp,4
}
break;
011B4F54 jmp 011B4F63
default:
{
printf("default");
011B4F56 push 11B7BE0h
011B4F5B call 011B104B
011B4F60 add esp,4
}
break;
}
return 0;
011B4F63 xor eax,eax 返回0
}
上面的地址表 [edx*4+011B4F7Ch]
0x011B4F7C 0d 4f 1b 01 重新计算的case 0 原来的case 1
0x011B4F80 1c 4f 1b 01 重新计算的case 1 原来的case 2
0x011B4F84 29 4f 1b 01 重新计算的case 2 原来的case 3
0x011B4F88 38 4f 1b 01 重新计算的case 3 原来的case4
0x011B4F8C 56 4f 1b 01 重新计算的case 4 原来的case5 没有这个case所以地址为defalut的地址
0x011B4F90 56 4f 1b 01 重新计算的case 5 原来的case6 没有这个case所以地址为defalut的地址
0x011B4F94 56 4f 1b 01
0x011B4F98 56 4f 1b 01
0x011B4F9C 56 4f 1b 01
0x011B4FA0 47 4f 1b 01 重新计算的case 9 原来的case10
大于255就采用了平衡二叉树方式优化算法
循环语句
for循环
int main()
{
for (int i = 0; i < 10; i++)
{
printf("%d\n", i);
}
return 0;
}
int main()
{
00824EB0 push ebp
00824EB1 mov ebp,esp
00824EB3 sub esp,0CCh
00824EB9 push ebx
00824EBA push esi
00824EBB push edi
00824EBC lea edi,[ebp+FFFFFF34h]
00824EC2 mov ecx,33h
00824EC7 mov eax,0CCCCCCCCh
00824ECC rep stos dword ptr es:[edi]
00824ECE mov ecx,82C003h
00824ED3 call 00821217
for (int i = 0; i < 10; i++)
00824ED8 mov dword ptr [ebp-8],0 局部变量初始0
00824EDF jmp 00824EEA 无条件跳到判断语句
00824EE1 mov eax,dword ptr [ebp-8] 循环变量赋值给eax
00824EE4 add eax,1 eax自增1
00824EE7 mov dword ptr [ebp-8],eax eax传给循环变量
00824EEA cmp dword ptr [ebp-8],0Ah 比较循环变量和10
00824EEE jge 00824F03 大于等于跳出循环
{
printf("%d\n", i);
00824EF0 mov eax,dword ptr [ebp-8] 执行循环体
00824EF3 push eax
00824EF4 push 827B30h
00824EF9 call 0082104B
00824EFE add esp,8
}
00824F01 jmp 00824EE1 循环体执行完毕后,无条件跳到循环变量自增
return 0;
00824F03 xor eax,eax
}
while循环
int main()
{
int i = 0;
while (i < 10)
{
printf("%d\n", i);
i++;
}
return 0;
}
int main()
{
01054EB0 push ebp
01054EB1 mov ebp,esp
01054EB3 sub esp,0CCh
01054EB9 push ebx
01054EBA push esi
01054EBB push edi
01054EBC lea edi,[ebp+FFFFFF34h]
01054EC2 mov ecx,33h
01054EC7 mov eax,0CCCCCCCCh
01054ECC rep stos dword ptr es:[edi]
01054ECE mov ecx,105C003h
01054ED3 call 01051217
int i = 0;
01054ED8 mov dword ptr [ebp-8],0 局部变量初值
while (i < 10)
01054EDF cmp dword ptr [ebp-8],0Ah 局部变量和10比价
01054EE3 jge 01054F01 大于等于跳转
{
printf("%d\n", i);
01054EE5 mov eax,dword ptr [ebp-8] 循环体内容
01054EE8 push eax
01054EE9 push 1057B30h
01054EEE call 0105104B 打印i
01054EF3 add esp,8 平栈
i++;
01054EF6 mov eax,dword ptr [ebp-8] 局部变量传给eax
01054EF9 add eax,1 eax自增1
01054EFC mov dword ptr [ebp-8],eax eax传给局部变量
}
01054EFF jmp 01054EDF 跳到判断
return 0;
01054F01 xor eax,eax 返回0
}
do while循环
int main()
{
int i = 0;
do
{
printf("%d\n", i);
i++;
} while (i < 10);
return 0;
}
int main()
{
01214EB0 push ebp
01214EB1 mov ebp,esp
01214EB3 sub esp,0CCh
01214EB9 push ebx
01214EBA push esi
01214EBB push edi
01214EBC lea edi,[ebp+FFFFFF34h]
01214EC2 mov ecx,33h
01214EC7 mov eax,0CCCCCCCCh
01214ECC rep stos dword ptr es:[edi]
01214ECE mov ecx,121C003h
01214ED3 call 01211217
int i = 0;
01214ED8 mov dword ptr [ebp-8],0 局部变量初值
do
{
printf("%d\n", i); 循环体内容
01214EDF mov eax,dword ptr [ebp-8]
01214EE2 push eax
01214EE3 push 1217B30h
01214EE8 call 0121104B 打印i
01214EED add esp,8
i++;
01214EF0 mov eax,dword ptr [ebp-8] 自增1
01214EF3 add eax,1
01214EF6 mov dword ptr [ebp-8],eax
} while (i < 10);
01214EF9 cmp dword ptr [ebp-8],0Ah 局部变量和10比较
01214EFD jl 01214EDF 小于跳转到循环体
return 0;
01214EFF xor eax,eax
}
数组
一维数组
int main()
{
int arr[5] = { 1, 2, 3, 4, 5 };
for (int i = 0; i < 5; i++)
{
printf("%d\n", arr[i]);
}
system("pause");
return 0;
}
int main()
{
011E1D50 push ebp
011E1D51 mov ebp,esp
011E1D53 sub esp,0E8h
011E1D59 push ebx
011E1D5A push esi
011E1D5B push edi
011E1D5C lea edi,[ebp+FFFFFF18h]
011E1D62 mov ecx,3Ah
011E1D67 mov eax,0CCCCCCCCh
011E1D6C rep stos dword ptr es:[edi]
011E1D6E mov ecx,11F0028h
011E1D73 call 011E133E
int arr[5] = { 1, 2, 3, 4, 5 };
011E1D78 mov dword ptr [ebp-18h],1 数组初始化 数组元素0赋值1
011E1D7F mov dword ptr [ebp-14h],2 数组初始化 数组元素1赋值2
011E1D86 mov dword ptr [ebp-10h],3 数组初始化 数组元素2赋值3
011E1D8D mov dword ptr [ebp-0Ch],4 数组初始化 数组元素3赋值4
011E1D94 mov dword ptr [ebp-8],5 数组初始化 数组元素4赋值5
for (int i = 0; i < 5; i++)
011E1D9B mov dword ptr [ebp-24h],0 循环变量初始为0
011E1DA2 jmp 011E1DAD 跳到判断语句
011E1DA4 mov eax,dword ptr [ebp-24h]
011E1DA7 add eax,1
011E1DAA mov dword ptr [ebp-24h],eax
011E1DAD cmp dword ptr [ebp-24h],5 循环变量和5比较
011E1DB1 jge 011E1DCD 大于等于跳转
{
printf("%d\n", arr[i]);
011E1DB3 lfence
011E1DB6 mov eax,dword ptr [ebp-24h] 循环变量
011E1DB9 mov ecx,dword ptr [ebp+eax*4-18h] 数组开始地址ebp-18H eax*4为偏移int大小为4
011E1DBD push ecx 打印函数
011E1DBE push 11EBB54h
011E1DC3 call 011E15AA
011E1DC8 add esp,8
}
011E1DCB jmp 011E1DA4 跳到判断语句是否继续循环
system("pause");
011E1DCD mov esi,esp
011E1DCF push 11EBB30h
011E1DD4 call dword ptr ds:[011EF1E0h]
011E1DDA add esp,4
011E1DDD cmp esi,esp
011E1DDF call 011E1357
return 0;
011E1DE4 xor eax,eax
}
多维数组
int main()
{
int arr[][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
printf("%d\n", arr[1][2]);
system("pause");
return 0;
}
int main()
{
01091D53 sub esp,0F8h
01091D59 push ebx
01091D5A push esi
01091D5B push edi
01091D5C lea edi,[ebp+FFFFFF08h]
01091D62 mov ecx,3Eh
01091D67 mov eax,0CCCCCCCCh
01091D6C rep stos dword ptr es:[edi]
01091D6E mov ecx,10A0028h
01091D73 call 0109133E
int arr[][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
01091D78 mov dword ptr [ebp-34h],1 多维数组初始化和一维数组没有区别
01091D7F mov dword ptr [ebp-30h],2
01091D86 mov dword ptr [ebp-2Ch],3
01091D8D mov dword ptr [ebp-28h],4
01091D94 mov dword ptr [ebp-24h],5
01091D9B mov dword ptr [ebp-20h],6
01091DA2 mov dword ptr [ebp-1Ch],7
01091DA9 mov dword ptr [ebp-18h],8
01091DB0 mov dword ptr [ebp-14h],9
01091DB7 mov dword ptr [ebp-10h],0Ah
01091DBE mov dword ptr [ebp-0Ch],0Bh
01091DC5 mov dword ptr [ebp-8],0Ch
printf("%d\n", arr[1][2]);
01091DCC mov eax,10h 二维数组的列数为4 int大小为4 4*4=10h
01091DD1 shl eax,0 左移0位
01091DD4 lea ecx,[ebp+eax-34h] 行地址为ebp-34数组开始地址+eax数组偏移个数
01091DD8 mov edx,4 int大小
01091DDD shl edx,1 左移1位 *2
01091DDF mov eax,dword ptr [ecx+edx] 数组行地址加上第二个元素的位置8 4*2
01091DE2 push eax
01091DE3 push 109BB54h
01091DE8 call 010915AA
01091DED add esp,8
system("pause");
01091DF0 mov esi,esp
01091DF2 push 109BB30h
01091DF7 call dword ptr ds:[0109F1E0h]
01091DFD add esp,4
01091E00 cmp esi,esp
01091E02 call 01091357
return 0;
01091E07 xor eax,eax
}
调用约定
常用的调用约定分为四种:
_stdcall(windowsAPI默认调用方式):参数压栈方式右到左,函数内平衡,函数结束ret xxx 注意使用windows API函数指针时
声明的时候要带_stdcall
_cdecl(c/c++默认调用方式):参数压栈方式右到左,函数外平衡堆栈,call后面跟着add esp,xxx
_fastcall:参数压栈方式右到左,寄存器方式传参,函数内平衡堆栈
_thiscall:参数压栈方式右到左,ecx传递this指针,函数内平衡堆栈
————————————————
版权声明:本文为CSDN博主「ly1390811049」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ly1390811049/article/details/104933854