写在前面
此系列是本人一个字一个字码出来的,包括示例和实验截图。本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正。 如有好的建议,欢迎反馈。码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作。如想转载,请把我的转载信息附在文章后面,并声明我的个人信息和本人博客地址即可,但必须事先通知我。
你如果是从中间插过来看的,请仔细阅读**(一)羽夏看C语言——简述** ,方便学习本教程。
前篇答疑解惑
答案:不会。 解答:我相信亲手做实验的人都会知道的。
函数
一个程序必须有一个函数,比如C语言中的
main函数
,也可以实现别的函数实现功能。本篇文章将从汇编的角度介绍函数,本次实验的代码十分简单。为了防止干扰,请在项目属性中关闭
增量链接
和
支持仅我的代码调试
(具体作用请搜索科普,它们会生成一些汇编代码来实现相应的功能)。
int main(){int a = 5;return 0;}
得到的反汇编如下:
通过汇编可以看出,函数生成的汇编采用
ebp寻址
的方式。前三句汇编进行用
ebp寻址的准备
和
提栈准备缓冲区
的操作,提供的缓冲区用来给函数内的局部变量用的。
有些生成的反汇编可能是这样的版本:
push ebpmov ebp,espsub esp,0x40push ebxpush esipush edilea edi,[ebp-0x40]mov ecx,0x10mov eax,0xccccccccrep stosdmov dword ptr [ebp-8],5xor eax,eaxpop edipop esipop ebxmov esp,ebppop ebpret
有些人可能看不懂以下代码:
lea edi,[ebp-0x40]mov ecx,0x10mov eax,0xccccccccrep stosd
上面的代码是将
0xCC
填充满整个缓冲区,可帮助检测到堆栈缓冲区溢出,这是一种常见的攻击,威胁程序的安全性。
0xCC
即为我们调试的普通断点,汇编为
int 3
,即
VS
按下
F9
下断点(代码行左边的小红点)。
函数调用
int test(int a, int b){return a + b;}int main(){int a = test(1, 2);return 0;}
然后看一下反汇编:
可以看出函数调用时会通过
push
传递参数,然后
call
一个地址跳转到
test函数
,通过
eax
作为
返回值
。调用完毕后用
add esp,8
平栈,这个所谓的一种
调用约定
,被称为
__cdecl
。当然调用约定不知这一种,你也可以自定义,不过得从汇编上实现。
调用约定
当一个函数被调用时,函数的参数会被传递给被调用的函数和返回值会被返回给调用函数。函数的调用约定就是描述参数是怎么传递和返回值,由谁平衡堆栈,这就是所谓的调用约定。 我们先给出常见的调用约定,其他的调用约定自行科普:
调用约定 | __stdcall | __cdecl | __fastcall | __pascal |
---|---|---|---|---|
参数传递顺序 | 从右到左 | 从左到右 | 从右到左 | 使用寄存器和栈 |
平栈 | 调用者 | 子程序 | 子程序 | 子程序 |
当然,在
IDA
中你可能会看到其他调用约定,比如
__thiscall
等。由于调用约定并不是我想重点讲述的,具体细节自行科普。C语言默认的调用约定为
__cdecl
,所以在 函数调用 部分已有示例。这部分就用
__fastcall
做个为
调用约定
示例。
int __fastcall test(int a, int b){return a + b;}int main(){int a = test(1, 2);return 0;}
如下是反汇编:
下一篇
(七)羽夏看C语言——模板(C++)