1. 之前只知道程序都是从从main()函数开始执行,然后在内部调用其它函数,但一直不理解其内部机理,今天借此机会来分析一下其中的原理,看看内存里面到底怎么运行的
2.我们以一个最简单的程序为例来分析
分析平台:ubuntu16.04
编译环境:GCC
分析工具:gdb
创建一个文件:mkdir test; 再创建一个文件touch add.c,输入一下代码
-
#include<stdio.h>
int Add(int x, int y)
{
int z = 0;
z = x + y;
return z;
}int main()
{
int a = 10;
int b = 20;
int c = Add(a, b);
return 0;
} -
借此我们来回顾一下编译过程:预编译、编译、汇编、链接
-
OK,开始来编译程序,为了了解其中每一个不走,我生成了每个过程的文件
-
预编译:gcc -E -o add.i add.c 生成了add.i文件
-
编译:gcc -S add.i 生成add.s文件,此为汇编文件
-
汇编:gcc -c add.i 生成add.o文件
-
链接:gcc add.o -o add
-
感兴趣的可以去查看每个步骤生成的文件是什么
3. gdb调试
用gdb -version查看是否安装了gdb工具,如果没有安装的话用sudo apt-get install gdb来安装
然后输入gdb进入调试界面
然后输入file add
此时发现
这个问题,原来是bian编译过程中没有加入-g命令,那么我们重新编译一下 gcc -g -c -o add add.c
gdb
file add
没问题了,我们先来查看main函数的反汇编代码
disas main
emmm,好像全是汇编ming命令,不用担心,我们一点点来分析
+0 rbp,在64位系统中是栈底指针,当然,我们一般认为栈是向下增长的
+1 将rsp指向rbp,这是一个初始化的过程吧,代表栈空
+4 rsp=rsp-16,分配16个字节的栈空间,
+8 我们程序中定义了一个变量a = 10, 放在 rbp -12的位置
+15 b=20放在rbp -8的位置
+22 将b的值放入edx(数据寄存器)里
+25 将a的值放入eax(累加ji寄存器)里
+28 edx -> esi(bi变址寄存器)
+30 eax-> edi
+32 调用Add函数了,我们接下来分析Add函数
disad Add
然后建立Add函数函数自己的堆栈,建立形参x,y的空间,然后是局部变量z,将传入的参数相加后放在eaxji寄存器里,最后最后将eax的值保存在z里,但是Add函数diao调用完成后会销毁栈,那返回值怎么传给main()函数呢,+28又将z的值放在eax里了,这样当Add函数结束后main函数还能去eaxji'c寄存器里取这个值