C是怎么变成汇编的
C代码需要经过编译器编辑才能成为执行文件(二进制)。编译器是怎么做到的呢?
C代码 --> 编译器语法检查 --> 编译器转成汇编 --> … --> 二进制文件
在了解前,需要先了解下面的知识,自然就知道了
1、什么是裸函数?
//先看一下裸函数怎么写,这个裸函数中什么都没有做,编译器编译的时候,
//也不会做任何事,那下一步就不知道做什么事了,于是就会报错
void __declspec(naked) Function()
{...}
上面的函数调用时,为什么会出错?
//该裸函数,什么也没做,但是最后ret了,编译器编译的时候,汇编就会是ret
//于是就不会报错
void __declspec(naked) Function()
{
__asm
ret
}
2、无参数无返回值的函数框架
void __declspec(naked) Function()
{
__asm
{
push ebp // 开栈
mov ebp,esp
sub esp,0x40
push ebx //保护现场
push esi
push edi
lea edi,dword ptr ds:[ebp-0x40] //为缓冲器填充数据 (int 3)
mov eax,0xCCCCCCCC
mov ecx,0x10
rep stosd
pop edi //恢复堆栈
pop esi
pop ebx
mov esp,ebp //降低堆栈
pop ebp
ret //函数返回
}
}
3、有参数有返回值的函数框架
int __declspec(naked) Function(int x,int y)
{
__asm
{
push ebp // 开栈
mov ebp,esp
sub esp,0x40
push ebx //恢复堆栈
push esi
push edi
lea edi,dword ptr ds:[ebp-0x40] //为缓冲器填充数据 (int 3)
mov eax,0xCCCCCCCC
mov ecx,0x10
rep stosd
mov eax,dword ptr ds:[ebp+8] // x,y两个数相加,这里x,y已经在进入函数前放入到了dword ptr ds:[ebp+8] dword ptr ds:[ebp+0xC]
add eax,dword ptr ds:[ebp+0xC]
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
}
}
4、带局部变量的函数框架
int __declspec(naked) Function(int x,int y)
{
__asm
{
push ebp
mov ebp,esp
sub esp,0x40
push ebx
push esi
push edi
lea edi,dword ptr ds:[ebp-0x40]
mov eax,0xCCCCCCCC
mov ecx,0x10
rep stosd
mov dword ptr ds:[ebp-4],2 //函数局部变量存放
mov dword ptr ds:[ebp-8],3
mov eax,dword ptr ds:[ebp+8] //函数外部变量(x,y)相加
add eax,dword ptr ds:[ebp+0xC]
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
}
}