视频
一. 存储程序计算机工作模型
冯诺依曼体系结构:存储程序计算机
从硬件角度:CPU上的IP总指向内存的某一块区域,CPU执行其所指向的指令
从程序员角度:内存保存指令和数据,CPU解释执行
二. X86汇编基础
通用寄存器:
段寄存器:
注:CPU实际取指令时根据cs:eip来准确定位一个指令
几种寻址方式
寄存器寻址(register):movl %eax,%edx
立即数寻址(immediate):movl $0x123,%edx
直接寻址(direct):movl 0x123,%edx
间接寻址(indirect):movl (%ebx),%edx
变址寻址(displaced):movl 4(%ebx),%edx
注: A&T汇编格式与Intel汇编格式不同,Linux内核使用A&T汇编格式
其他:
Eip寄存器不能被程序员直接修改,存在安全隐患,所以只能通过特殊指令间接修改
函数调用堆栈是由逻辑上多个堆栈叠加起来的
函数返回值默认存储在%eax寄存器中
三. 汇编一个简单的C程序分析其汇编指令执行过程
函数返回值默认存在eax寄存器返回给上级函数
64位环境的注意事项:
汇编C代码并分析
1. main.c代码
2. 汇编代码
使用命令 gcc –S –o main.s main.c -m32编译成汇编代码
-S:仅汇编
-m32:生成32位的指令格式
3. 分析
程序从main开始执行,最初的堆栈为空,esp和ebp指向同一个地址
然后执行18:pushl %ebp, 保存旧的ebp地址,把旧的ebp地址压入堆栈
执行19:movl %esp, %ebp 将esp的值放入ebp中,执行之后堆栈的状态如下,此时ebp和esp又指向同一地址
执行20:subl $4, %esp 将esp的值减4
执行21:movl $8, (%esp) 将立即数8放入esp所指向的地址中
执行22:call f, 将eip(23)压入栈中,然后跳转到f:处执行
执行9:pushl %ebp,将老的ebp地址压入栈中
执行10:movl %esp, %ebp,将esp的地址赋给ebp
执行11:subl $4, %esp, 将esp的值减4
执行12:movl 8(%ebp), %eax, 将ebp + 8所存放的值,放入eax寄存器中,ebp+8存放的值为8,所以此时eax寄存器存放的值为8. 此时堆栈无变化
执行13:movl %eax, (%esp), 将eax寄存器存放的值,放入esp所执行的地址中
执行14:call g 将eip(15)压入堆栈,并且跳转到函数g执行
执行2:pushl %ebp, 将老的ebp压入堆栈
执行3:movl %esp, %ebp, 将esp存放的值放入ebp中
执行4:movl 8(%ebp), %eax, 将ebp + 8所指向的内容放入eax寄存器中,ebp + 8存放的内容为8,所以eax寄存器存放的内容为8,此时堆栈无变化
执行5: addl $11, %eax, 将eax寄存器的内容与11相加,并且将结果放入eax寄存器中, 此时eax寄存器为19,堆栈无变化
执行6:popl %ebp,将栈顶元素弹出,放入ebp寄存器中,即将old ebp还原
执行7:ret 程序将执行15行代码
执行15:leave 将ebp寄存器的值放入esp寄存器中,并且弹出栈顶元素,存放到ebp中
执行16:ret 程序将执行23行代码
执行23:addl $7, %eax 将eax寄存器的值加上7,并且将结果放入eax寄存器,执行此指令前,eax寄存器的值为19(上面已经计算得出),执行之后,eax寄存器变为26,此时堆栈无变化
执行24:leave 此时堆栈还原到最初的状态
总结
通过学习了第一周的课学到了一些的计算机的底层知识,是计算机工作原理的基础部分。计算机可抽象理解为由CPU和内存两部分组成,内存中存有指令和数据,CPU通过eip不断从内存中读取指令,并且将当前正在执行的程序的相关指令的数据都暂时保存在堆栈中以便于取用和计算,随着程序的执行,堆栈随之增减,直到程序运行结束,程序结果计算完成,堆栈中的相关数据也得到清空,相当于将程序变成了CPU上的指令流。