冯诺依曼体系结构:核心思想为存储程序计算机。两个层面:
(1)硬件的角度(计算机主板):一个CPU,一块内存,之间有总线连接。CPU内部有一个IP计算器,IP指向内存中的指令,并依次加一执行;
(2)另一个层面,程序员的角度:存储程序计算机工作模型(如下图)
API:应用程序编程接口(程序员与计算机的接口界面)。
ABI:二进制接口,指令编码(程序员与CPU的接口界面)。
立即寻址,把立即数直接放在寄存器,立即数是以$开头的数值;
直接寻址,直接访问一个指定的内存地址的数据;
间接寻址:将寄存器的值作为一个内存地址来访问内存;
变址寻址:在间接寻址之时改变寄存器的数值。
popl 出栈,从堆栈栈顶取32位放到寄存器eax里面,有两个动作:首先间接寻址,把栈顶数值放到eax里面,再把栈顶加4。
call 函数调用,把当前的eip压栈,给eip赋新值;
注意:*是指这些指令是伪指令,程序员不能直接修改这些,即eip寄存器不能被直接修改,只能通过特殊指令间接修改。
简单的c语言程序:
输入gcc –S –o 20189220main.s 20189220main.c -m32 ,删除多余的代码从而形成汇编代码,如图:
当开始执行改程序的时候,eip是指向main函数入口地址,即eip指向18行存放的指令。设默认的堆栈栈低寄存器ebp的值为1000,则堆栈栈顶指针也为1000。
1、pushl %ebp: 把ebp的值压入堆栈,esp=996,栈顶值为1000
2、movl %esp,%ebp: 将esp的值传给ebp,则ebp值为996
3、subl $4,%esp:将esp的值减去4,则esp的值为992
4、movl $24,(%esp): 将esp所指的值为地址(寄存器间接寻址)的值 赋为6(堆栈的栈顶存放6)
此时堆栈:
5、call f:相当于pushl eip和movl f eip。堆栈先压入eip(23),esp=esp-4=988。然后把f函数的入口函数地址赋值给eip(存放第9行的指令代码)
此时堆栈:
6、pushl %ebp: 在堆栈中压入ebp的值,esp=esp-4=984
7、movl %esp,%ebp: 把esp的值赋给ebp。ebp=esp=984
8、subl $4,%esp: 把esp的值减去4。esp=esp-4=980
9、movl 8(%ebp),%eax: 把ebp+8的地址上所存的值赋给eax,即把地址为992,值为6赋值给eax寄存器
10、movl %eax,(%esp): 相当于压栈
此时堆栈:
11、call g: 相当于pushl eip和movl g eip。栈堆先压入eip(15),在把函数g的入口地址赋给eip
此时堆栈:
12、pushl %ebp: 堆栈压入ebp的值
13、movl %esp,%ebp: 把esp的值赋给ebp
14、movl 8(%ebp),%eax: 将ebp的值加8作为地址,其值赋给eax。即,eax值为6
15、addl $4,%eax: 将eax的值加4。eax的值为10
16、popl %ebp:堆栈弹出,其值赋给ebp。
此时堆栈:
17、ret : 相当于popl %eip(*)。堆栈弹出,其值赋给eip。则eip指向了存储15行代码的地址。
此时堆栈:
18、leave: 相当于movl %ebp,%esp和popl %ebp。将ebp的值赋给esp,堆栈弹出,其值赋给ebp。相当于销毁g的函数堆栈意思。esp=988,ebp=996。
此时堆栈:
19、ret : 相当于popl %eip(*)。堆栈弹出,其值eip(23)赋给eip
20、addl $2,%eax: 把eax的值加上2,eax的值为10+2=12。
21、leave :相当于movl %ebp,%esp和popl %ebp。将ebp的值赋给esp,堆栈弹出,其值赋给ebp。相当于销毁f的函数堆栈意思。esp=1000,ebp=1000
此时堆栈:
20189220 余超《Linux内核原理与分析》第二周作业
原文:https://www.cnblogs.com/yuchao123/p/9819641.html