注明
李振业
原创作品转载请注明出处
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
一、实验过程
首先创建一个C语言文件
vi main.c
接着编写一段C语言代码
int g(int x) { return x + 32; } int f(int x) { return g(x); } int main(void) { return f(6) + 1; }
结束保存并退出
shift+: wq
利用gcc的功能,将上面的代码编译成32位的汇编代码
gcc -S -o main.s main.c -m32
这样就将main.c编译成main.s文件,如下图
bwlq分别代表8位、16位、32位和64位,而这里的指令是以l结尾,说明该文件内容的确是32位的汇编代码。
将所有以点开头的内容删除,留下来的就是纯汇编代码。
二、汇编分析
分析前先顺便明白以下知识:
1. EIP:Instruction Pointer 是如同指针一样指向内存的某一块区域,E开头则是因为为32位的系统
2. 堆栈是计算机中非常基础性的东西
3. CPU在实际取指令时根据CS:eip来准确定位一个指令
4. 寄存器模式,以%开头的寄存器标示符
5. 立即数是以$开头的寄存器标志符
6. 直接寻址:直接访问一个指定的内存地址的数据
7. 间接寻址:将寄存器的值作为一个内存地址来访问内存
8. 变址寻址:在间接寻址的时候改变寄存器的数值
9. Linux内核使用的是AT&T汇编格式
10.eip寄存器不能被直接修改,只能通过特殊指令间接修改
11.函数调用堆栈是由逻辑上多个堆栈叠加起来的
12.函数的返回值默认使用eax寄存器储存返回给上一级函数
设执行前的栈如图所示,esp与ebp均为0
一 |
二 |
三 |
四 |
五 |
六 |
七 |
从代码里的行数分析:
18-19:(main开始) 入栈 一 = ebp0,esp下移0→1,ebp下移0→1
20:esp下移1→2
21:二 = 6
22:三 = eip(23),esp下移2→3,eip跳转到f(第8行)
9-10:入栈 四 = ebp1,esp下移3→4,ebp下移1→4
11:esp下移4→5
12:变址寻址,eax = 6
13:五=6
14:六=eip(15),esp下移5→6,eip跳转到g(第1行)
2-3:入栈 七=ebp4,esp下移6→7,ebp下移4→7
4:变址寻址,eax=6
5:eax=eax+32=38
6:出栈 ebp上移7→4,esp上移7→6
7:esp上移6→5,eip(15)
15:执行leave,esp上移5→4,ebp上移4→1,esp再上移4→3
16:esp上移3→2,eip(23)
23:eax=eax+1=39
24:执行leave,esp上移2→1,ebp上移1→0,esp再上移1→0
25:ret,结束
可看出栈的执行情况如下,最后经过了从入栈到出栈的过程,eax的值为39
一 = ebp0 |
二 = 6 |
三 = eip(23) |
四 = ebp1 |
五 = 6 |
六 = eip(15) |
七 = ebp4 |
三、总结
没学过汇编和操作系统原理直接学Linux内核分析的确比较吃力,还好坚持下来和做完作业与测试。
希望能再接再厉,继续深入了解。