罗晓波 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-10000290
通过实验“通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的”,通过反汇编,得到一段C程序的对应的汇编代码,笔者将结合汇编代码细致分析各个寄存器和堆栈的变化,以此来说明计算机的工作方式。
1.反汇编,分析汇编代码
1.1 实验环境:
1.2 简单的一段C程序:
int g(int x)
{
return x + 6;
}
int f(int x)
{
return g(x);
}
int main(void)
{
return f(2) + 3;
}
通过 gcc –S –o main.s main.c -m32 得到汇编代码(已经删除汇编代码元数据的汇编代码)如下图:
1.3 汇编代码分析
分析上述汇编代码,从main标签开始。
假设内存栈地址从0标记处开始,(0,1,2,3....等各标记表示4字节内存单元,当然,栈地址是向下增长的,在此处为了方便讲述)。18,19行开始初始化ebp,esp 寄存器,如下图,ebp,esp都指向内存单元1处。这是因为 pushl %ebp 即为subl $4,%esp 、movl %ebp %esp 。
在调用函数f之前,call f ;函数需要将参数压栈,在这里参数2入栈,那么call f 在这里做了什么呢?第一,将eip寄存器入栈,此时的eip指向call f 的下一个指令,即 addl $3,%eax;第二,将f开始执行的指令地址放入到eip中,接下来的g函数调用也是如此道理。来个示意图吧:
接下来到f标签处:
首先,前两个指令,压栈ebp,并且将ebp和esp指向同一位置,即指向4标记处。subl $4,%esp,接下来11,12,13 这三条指令,也是为了将参数压栈,该参数依旧是2。再来一张图:
接下来又进行一次函数调用,来到了g标签处:压栈eip,压栈ebp,取出参数2,addl指令,进行加运算,将2+6的值放入eax寄存器中,再附图一张~:
接下来将数值存在eax寄存器中之后,就开始不断的弹栈了。在弹栈的过程中,需要注意的一点是leave 指令, leave指令 是movl %ebp %esp ;popl %ebp,leave指令来释放被调用函数的堆栈空间,并恢复自己的基栈地址。ret指令就是popl %eip 。
最终结果保存在eax寄存器中。
2.简述单核计算机工作方式
2.1 单任务下:
2.2 多任务下: