C语言的流程和处理
程序分为Dubug版与Release(发行版)
调试版一般不优化,Release会优化代码,即减去没必要的汇编部分。
一、C语言的循环汇编
1.for循环
测试代码:
for (i = 0; i < 5; i++)
{
c = c + 1;
}
查看反汇编:
for (i = 0; i < 5; i++)
00164464 mov dword ptr [i],0
0016446B jmp main+46h (0164476h)
0016446D mov eax,dword ptr [i]
00164470 add eax,1
00164473 mov dword ptr [i],eax
00164476 cmp dword ptr [i],5
0016447A jge main+57h (0164487h)
{
c = c + 1;
0016447C mov eax,dword ptr [c]
0016447F add eax,1
00164482 mov dword ptr [c],eax
}
00164485 jmp main+3Dh (016446Dh)
大致是这样的结构:
mov <循环变量>,<初始值> ;给循环变量赋值
jmp B ;跳到第一个循环处
A: (改动循环变量) ;修改循环变量
...
B: cmp <循环变量>,<限制变量> ;检查循环条件
jge 跳出循环
(循环体)
...
jmp A ;跳回去修改循环变量
2.while
测试代码:
while (c < 100){
c = c + 1;
}
查看反汇编:
while (c < 100){
00AC4464 cmp dword ptr [c],64h
00AC4468 jge main+45h (0AC4475h)
c = c + 1;
00AC446A mov eax,dword ptr [c]
00AC446D add eax,1
00AC4470 mov dword ptr [c],eax
}
00AC4473 jmp main+34h (0AC4464h)
共有3条指令实现:
A: cmp <循环变量>,<限制变量>
jge B
...
jmp A
B: 循环结束,下一个指令
3.do-while
测试代码:
do {
c = c + 1;
} while (c < 100);
查看反汇编:
do {
c = c + 1;
00E14464 mov eax,dword ptr [c]
00E14467 add eax,1
00E1446A mov dword ptr [c],eax
} while (c < 100);
00E1446D cmp dword ptr [c],64h
00E14471 jl main+34h (0E14464h)
do循环就是用一个简单的条件比较指令跳转回去。只有两个指令。
cmp <循环变量>,<限制变量>
jl <循环开始点>
二、C语言的判断与选择
1.if-else
源码:
int main()
{
int c = 1;
if (c > 0 &&c < 10)
{
printf("c>0\n");
}
else if (c>10 && c < 100)
{
printf("c>10%%c<100\n");
}
else {
printf("c>100||c<0");
}
return 0;
}
主要代码为:
cmp <条件>
jle <下一个分支>
开始的反汇编:
int c = 1;
00C3538E mov dword ptr [c],1
if (c > 0 &&c < 10)
00C35395 cmp dword ptr [c],0
00C35399 jle main+4Ah (0C353BAh)
00C3539B cmp dword ptr [c],0Ah
00C3539F jge main+4Ah (0C353BAh)
{
printf("c>0\n");
00C353A1 mov esi,esp
00C353A3 push 0C3CC84h
00C353A8 call dword ptr ds:[0C40188h]
00C353AE add esp,4
00C353B1 cmp esi,esp
00C353B3 call __RTC_CheckEsp (0C312DAh)
00C353B8 jmp main+86h (0C353F6h)
}
大致都是这样的:
else if (c>10 && c < 100)
00C353BA cmp dword ptr [c],0Ah
00C353BE jle main+6Fh (0C353DFh)
00C353C0 cmp dword ptr [c],64h
00C353C4 jge main+6Fh (0C353DFh)
2.switch-case
代码:
int c = 1;
switch (c)
{
case 0:
printf("c>0");
case 1:
{
printf("c>10&c<100");
break;
}
default:
printf("cccc");
}
看反汇编:
连续的比较与条件跳转让人想到switch。
至于case和default都非常简单。如果有break,则会增加一个无条件跳转:在没有break的情况下,没有任何流程控制代码。
三、C语言的数组与结构
写一个简单的结构体和数组。
测试代码:
typedef struct {
int a;
int b;
int c;
}mystruct;
int main()
{
unsigned char *buf[100];
mystruct *strs = (mystruct *)buf;
int i;
for (i = 0; i < 5; i++)
{
strs[i].a = 0;
strs[i].b = 1;
strs[i].c = 2;
}
return 0;
}
看反汇编:
int i;
for (i = 0; i < 5; i++)
00AB4614 mov dword ptr [i],0 ;典型的for循环结构
00AB461E jmp main+4Fh (0AB462Fh)
00AB4620 mov eax,dword ptr [i]
00AB4626 add eax,1
00AB4629 mov dword ptr [i],eax
00AB462F cmp dword ptr [i],5
00AB4636 jge main+98h (0AB4678h)
{
strs[i].a = 0;
00AB4638 imul eax,dword ptr [i],0Ch ;吧i*0c放入到eax中
;0ch是结构体的大小
00AB463F mov ecx,dword ptr [strs] ;ecx为strs的首地址
00AB4645 mov dword ptr [ecx+eax],0 ;给首地址+i*0c赋值为0
strs[i].b = 1;
00AB464C imul eax,dword ptr [i],0Ch
00AB4653 mov ecx,dword ptr [strs]
00AB4659 mov dword ptr [ecx+eax+4],1 ;给首地址+i*0c+4赋值为1
strs[i].c = 2;
00AB4661 imul eax,dword ptr [i],0Ch
00AB4668 mov ecx,dword ptr [strs]
00AB466E mov dword ptr [ecx+eax+8],2 ;给首地址+i*0c+8赋值为2
}
00AB4676 jmp main+40h (0AB4620h)
return 0;
00AB4678 xor eax,eax
imul指令让人联想到结构体数组,这是一个特征。
四、C语言的共用体和枚举类型
//定义一个枚举类型
typedef enum{
ENUM_1 = 1,
ENUM_2 = 2,
ENUM_3,
ENUM_4,
}myebum;
//定义一个结构体
typedef struct {
int a;
int b;
int c;
}mystruct;
typedef union {
mystruct s;
myebum e[3];
}myunion;
int main()
{
unsigned char *buf[100];
myunion *uns = (myunion *)buf;
int i;
for (i = 0; i < 5; i++)
{
uns[i].s.a = 0;
uns[i].s.b = 1;
uns[i].e[2] = ENUM_4;
}
return 0;
}
myunion *uns = (myunion *)buf;
00034608 lea eax,[buf]
0003460E mov dword ptr [uns],eax
int i;
for (i = 0; i < 5; i++)
00034614 mov dword ptr [i],0
0003461E jmp main+4Fh (03462Fh)
00034620 mov eax,dword ptr [i]
00034626 add eax,1
00034629 mov dword ptr [i],eax
0003462F cmp dword ptr [i],5
00034636 jge main+9Eh (03467Eh)
{
uns[i].s.a = 0;
00034638 imul eax,dword ptr [i],0Ch
0003463F mov ecx,dword ptr [uns]
00034645 mov dword ptr [ecx+eax],0
uns[i].s.b = 1;
0003464C imul eax,dword ptr [i],0Ch
uns[i].s.b = 1;
00034653 mov ecx,dword ptr [uns]
00034659 mov dword ptr [ecx+eax+4],1
uns[i].e[2] = ENUM_4;
00034661 imul eax,dword ptr [i],0Ch
00034668 add eax,dword ptr [uns]
0003466E mov ecx,4
00034673 shl ecx,1
00034675 mov dword ptr [eax+ecx],4
}
0003467C jmp main+40h (034620h)
return 0;
0003467E xor eax,eax
对比结构体基本没有什么区别。
对于编译器处理来说,它们并不引入额外的指令。