Linux下程序的机器级表示学习心得
2016-10-19 01:20
211 查看
Linux下程序的机器级表示学习心得
上周学习完Linux程序的机器级表示后,对于其中有些还是掌握的不太透彻。对于老师提出的关于本章一些细节的问题还是有不会,所以又重新温习了一下上周的学习内容,以下为学习心得。分析反汇编
操作过程
分析反汇编采用了书上的一个简单案例。C语言代码如下。int a(int x) { returnx+1; } int b(int x) { return a(x); } int main (void) { return b(8)+14; }
使用
vim编辑器编译代码
main.c。
使用命令
gcc -S main.c -o main.s得到汇编代码。(此时的汇编代码有以.开头的代码,删除它们之后就是正常书中给出的汇编代码。
得到的汇编代码
使用
gdb的
bt/frame/up/down指令动态查看调用线帧的情况。
分析
从main:开始执行,保存帧指针
%ebp,并设置新的帧指针
pushl $8分配4字节的栈空间,并且设置
arg1=8
调用b:
call b
b同样初始化帧指针,分配栈空间,和之前的main函数相同
pushl 8(%ebp)将
%esp中的立即数8存入栈中
调用a:
call a
a被调用,初始化栈指针,分配栈空间
将
%eax与立即数 1 相加
在a结束前弹栈
ret返回b中
call的调用位置
b也结束,
return返回
main中
call调用的位置
main继续
%eax加14的操作
leave为返回准备栈,相当于
%ebp出栈,最后
ret结束
即:调用者P和被调用者Q,则Q的参数放在P的栈帧中,当P调用Q的时候,P中的返回地址被压入栈中,形成P的栈帧末尾。返回地址就是当程序从Q返回时应继续执行的地方,Q栈帧从保存的帧指针的值开始后是保存其他寄存器的值。
结合backtrace命令分析栈帧
首先backtrace/bt用来打印栈帧指针,也可以在该命令后加上要打印的栈帧的个数,查看程序执行到此时,是经过哪些函数呼叫的程序,程序“调用堆栈”是当前函数之前的所有已调用函数的列表(包括当前函数)。每个函数及其变量都分配了一个“帧”,最近调用的函数在0号帧中(“底部”帧)
命令有
- `fame farme1 `用于打印指定栈帧 - ` info reg `查看寄存器使用情况 - ` info stack` 产看堆栈使用情况 - `up/down` 跳到上一层/下一层函数
综述:
- 先将调用者(A)的堆栈的基址(`%ebp`)入栈,以保存之前任务的信息。 - 然后将调用者(A)的栈顶指针(`%esp`)的值赋给`%ebp`,作为新的基址(即被调用者B的栈底)。 - 然后在这个基址(被调用者B的栈底)上开辟(一般用sub指令)相应的空间用作被调用者B的栈空间。 - 函数B返回后,从当前栈帧的%ebp即恢复为调用者A的栈顶(`%esp)`,使栈顶恢复函数B被调用前的位置;然后调用者A再从恢复后的栈顶可弹出之前的%ebp值(可以这么做是因为这个值在函数调用前一步被压入堆栈)。这样,`%ebp`和`%esp`就都恢复了调用函数B前的位置,也就是栈恢复函数B调用前的状态。这样就解释了栈帧的出现和消失
这个过程在AT&T汇编中通过两条指令完成,即:
leave、
ret。这两条指令更直白点就相当于:
mov %ebp , %esp、
pop %ebp
下面我们使用GDB调试
main.c的代码,使用刚才编译好的main镜像。
-
gdb start(启动gdb)
-
(gdb) file main(加载镜像文件)
-
(gdb) break main(把
main()设置为断点,注意gdb并没有把断点设置在main的第一条指令,而是设置在了调整栈指针为局部变量保留空间之后)
-
(gdb) run(运行程序)
-
(gdb) stepi(单步执行,
stepi命令执行之后显示出来的源代码行或者指令地址,注意:都是即将执行的指令,而不是刚刚执行完的指令!对于更复杂的例子会有明显的变化)
利用gdb对寄存器进行分析
通过gdb调试可执行文件查看
%eip,
%ebp,
%esp等寄存器内容如何变化。
在linux中gdb调试汇编文件需要先用
gcc -g3 -o * *.c的命令来将c语言文件编译成可调试汇编的可执行文件。
通过调试过程中的
stepi和
print /x $***可以查询到相应寄存器的内容:
根据之前的main函数逐步使用上面的代码,可以获得不同寄存器的变化。
| number | %eax寄存器变化| %esp寄存器变化|%ebp寄存器变化时间|
| -----------| :-----------:|:------------:|:---------------:|
| 1 | Ox4004fc | Oxffffde18 | Oxffffde20
| 2 | Ox4004fc | Oxffffde18 | Oxffffde20
| 3 | Ox8 | Oxffffde18 | Oxffffde20
| 4 | Ox8 | Oxffffde18 | Oxffffde20
| 5 | Ox8 | Oxffffde10 | Oxffffde20
| 6 | Ox8 | Oxffffde08 | Oxffffde20
| 7 | Ox8 | Oxffffde08 | Oxffffde08
| 8 | Ox8 | Oxffffde08 | Oxffffde08
| 9 | Ox8 | Oxffffde08 | Oxffffde08
| 10 | Ox9 | Oxffffde08 | Oxffffde08
| 11 | Ox9 | Oxffffde10 | Oxffffde20
| 12 | Ox9 | Oxffffde18 | Oxffffde20
| 13 | Ox9 | Oxffffde28 | Oxffffde30
| 14 | Ox9 | Oxffffde30 | Oxffffde30
| ... | ... | ... | ...
如果想观察三个寄存器的每一步的变化配合
gdb stepi可以重复上述步骤。
部分过程截图。
由上图可以看到三个寄存器的初始值
由上图可以看到三个寄存器在执行完第一条指令之后的内容的变换
注意:在64位中
rip就是
eip,
rbp就是
ebp,
rsp就是。
相关文章推荐
- Linux系统学习笔记:程序的机器级表示
- 在Ubuntu上为Android系统内置C可执行程序测试Linux内核驱动程序 (学习老罗的)
- 木其工作室(专业程序代写服务)[转]Linux设备驱动程序学习-中断处理
- linux驱动学习心得--以I2C做实例
- Linux学习必备程序
- 黑马程序员-------关于今天的一个程序学习心得
- 学习LINUX心得
- Linux 学习之监控程序命令
- linux学习心得之vim/Cvim篇
- linux学习心得之vim/Cvim篇
- linux学习心得之目录树开端与/etc(图文)
- linux学习心得之目录树开端与/etc(图文)
- Linux系统学习笔记:运行程序
- Linux系统学习笔记:信息的表示
- linux学习笔记之--vim 程序编辑器
- linux学习笔记之--vim 程序编辑器
- 今日学习linux心得体会
- 学习了LINUX下用C语言遍历文件夹,一些心得 分类: arm-linux-Ubuntu 2013-09-11 14:09 885人阅读 评论(1) 收藏
- 学习了LINUX下用C语言遍历文件夹,一些心得
- 学习了LINUX下用C语言遍历文件夹,一些心得