从今天开始学习网易云课堂孟宁老师的《Linux内核分析》课程,链接地址:http://mooc.study.163.com/course/USTC-1000029000#/info,记录课程学习笔记。
第一周的内容主要介绍了冯诺依曼体系结构、ATT格式的32位x86汇编语言以及一个简单的c程序反汇编成汇编代码的执行分析过程。
冯诺依曼体系结构的核心是存储程序,将数据和代码都存储在存储器中,都是二进制数据,通过特定的模块来分辨数据与代码。冯诺依曼体系结构的计算机包括运算器、控制器、存储器、输入单元、输出单元五大件。
8位寄存器:ah、al、bh、bl、ch、cl、dh、dl
16位寄存器:ax、bx、cx、dx、bp、si、di、sp
32位寄存器:eax、ebx、ecx、edx、ebp、edi、esi、esp
注意:
1、8位寄存器与16位寄存器是独立的,例如低8位寄存器al的运算结构溢出并不会影响到高8位寄存器ah,同样16位寄存器ax不会影响到32位寄存器eax的高16位
2、通常情况下eax作为累加器,ebx作为基址寄存器,ecx作为计数器,edx作为数据寄存器,ebp作为堆栈基指针寄存器(栈底),esi、edi作为变址寄存器,esp作为堆栈顶指针寄存器。
cs代码段寄存器
ds数据段寄存器
ss栈段寄存器
es扩展段寄存器
gs、fs附加段寄存器
mov: 数据传送,可分为movb、movw、movl三种,分别传送一个字节、一个字、双字。
pushl:入栈,pushl %eax相当于:
subl $4, %esp movl %eax, (%esp)
popl:出栈, popl %eax相当于:
movl (%esp), %eax add $4, %esp
call:call f:相当于
pushl %eip
movl f, %eip
ret: ret相当于:
popl %eip
enter:相当于:
pushl %ebp
movl %esp, %ebp
leave:相当于:
movl %ebp, %esp pop %ebp
注意:
Intel汇编与ATT汇编在多个操作数的时候,列出的操作数的顺序是相反的。
虽然上面对pushl和popl的解释中修改了eip,实际中程序员不能够手动直接操作eip,可以通过其他指令间接修改。
实验环境:https://www.shiyanlou.com/courses/running/555
编写c代码:
编译生成汇编代码:
gcc –S –o main.s main.c –m32
观察分析汇编代码
删除无关信息后的汇编代码main.s:
观察上面汇编代码的每个函数main、f、g发现,每个函数的开始和结束都是一样的:
pushl %ebp movl %esp, %ebp leave ret
上面两条指令相当于enter,用来构建一个函数堆栈框架,leave表示退出当前框架,分析如下:
进入函数前的初始状态:
进入函数enter:
中间进行一系列其他操作后,执行leave:
最终又恢复到进入函数之前的状态
同c程序从main函数开始执行一样,汇编代码从main标签开始执行:
①从18行开始执行至22后:
此时取出22行代码call f, %eip = 23
②执行22行 call f,先将当前eip(23)入栈,然后将f的地址传入eip
pushl %eip
movl f, %eip
③进入f,构造f的堆栈框架,执行至11行:
执行
movl 8(%ebp), %eax movl %eax, (%esp)
此时%eax = 8
④执行call g,进入g,构建g的堆栈框架:
执行至6行: %eax = 11
执行popl %ebp,销毁g堆栈框架:
执行ret 即popl %eip后, %eip = 15
⑤继续执行15行leave,销毁f的堆栈框架:
pushl %ebp, %esp
popl %ebp
执行16行ret:
此时 %eip = 23
执行23行, %eax = 12
⑥执行24行,leave,销毁main的堆栈框架:
又恢复到初始状态,而函数的返回值默认存放在%eax中,即%eax = 12,
后面ret,恢复至进入main之前的状态。
至此,上述c程序的汇编代码分析完毕。
原文:http://www.cnblogs.com/codcompiling/p/5293985.html