Arm汇编学习笔记(六)——函数调用栈空间以及fp寄存器
来源:互联网 发布:淘宝如何设置主营类目 编辑:程序博客网 时间:2024/05/22 17:26
Arm上函数调用的规则在ARM System Developer's Guide文档中的ATPCS部分有详细的定义,这里主要通过函数调用过程中函数栈的情况来说明fp和sp等寄存器的作用。有关ATPCS的详细内容可以去文档中看。
fp叫做frame pointer寄存器,即栈帧指针寄存器;sp叫做stack pointer寄存器,即栈指针寄存器。那么它们具体的作用是什么呢?
首先,大家知道每个进程都有自己独立的栈空间,进程中有千千万万的函数调用,这些函数共享进程的这个栈空间,那么问题就来了,函数运行过程中会有非常多的入栈出栈的过程,当函数返回backtrace的时候怎样能精确定位到返回地址呢?还有子函数所保存的一些寄存器的内容?这样就有了栈帧的概念,即每个函数所使用的栈空间是一个栈帧,所有的栈帧就组成了这个进程完整的栈。而fp就是栈基址寄存器,指向当前函数栈帧的栈底,sp则指向当前函数栈帧的栈顶。通过sp和fp所指出的栈帧可以恢复出母函数的栈帧,以此类推就可以backtrace出所有函数的调用顺序。
那一个函数的栈帧具体的范围什么呢?fp和sp具体应该指向什么位置呢?请看下图:
图1
上图描述的是ARM的栈帧布局方式,main stack frame为调用函数的栈帧,func1 stack frame为当前函数(被调用者)的栈帧,栈底在高地址,栈向下增长。此图是网上的图,理论上应该是上图的格式,fp、sp、lr和pc这四个寄存器是非常特殊的寄存器,它们记录了当前正在运行的函数一些重要信息,在刚进入一个新的函数开始执行的时候,它们保存的是上个函数的信息,需要将它们入栈保存起来,这很重要!这些并没有定义在ATPCS中,ATPCS规定的是函数调用的时候参数如何传递,以及函数返回值的保存等。上面的这些个人觉得是一种默契,定义函数现场的保存及恢复,这些默契包括ATPCS都是人为的一种约束,目的是为了保证程序运行中不会出错,具体怎样实现应该是不同的编译器不尽相同。
下面我为了验证arm的gcc编译器的实现,自己写了个小实验程序:
main.c:#include <stdio.h>int func(int i);int main(void){ int i = 25; func(i); return 0;}
func.cint func(int i){ int a = 2; return a * i;}
main.c中调用了func函数,而func函数的实现在func.c文件中。下面是用arm-linux-androideabi-gcc编译后的执行文件反汇编出来的代码:
Disassembly of section .text:0000822c <func>: 822c:e52db004 push{fp}; (str fp, [sp, #-4]!) 8230:e28db000 addfp, sp, #0 8234:e24dd014 subsp, sp, #20 8238:e50b0010 strr0, [fp, #-16] 823c:e3a03002 movr3, #2 8240:e50b3008 strr3, [fp, #-8] 8244:e51b3008 ldrr3, [fp, #-8] 8248:e51b2010 ldrr2, [fp, #-16] 824c:e0030392 mulr3, r2, r3 8250:e1a00003 movr0, r3 8254:e24bd000 subsp, fp, #0 8258:e49db004 pop{fp}; (ldr fp, [sp], #4) 825c:e12fff1e bxlr00008260 <main>: 8260:e92d4800 push{fp, lr} 8264:e28db004 addfp, sp, #4 8268:e24dd008 subsp, sp, #8 826c:e3a03019 movr3, #25 8270:e50b3008 strr3, [fp, #-8] 8274:e51b0008 ldrr0, [fp, #-8] 8278:ebffffeb bl822c <func> 827c:e3a03000 movr3, #0 8280:e1a00003 movr0, r3 8284:e24bd004 subsp, fp, #4 8288:e8bd8800 pop{fp, pc}
上面的汇编代码可以看到,并没有想上面图中所画的,将fp, sp, lr, pc全部都入栈,而是只入栈这四个寄存器中有改动的。fp是肯定要保存的,它指向的是每个函数栈帧的栈基址,而sp一般不用入栈,因为它的值一般保存在fp中,因为刚进入一个函数的时候,将上个函数的fp入栈保存以后,当前函数的栈空间应该是空的,fp应该指向与sp相同的位置,然后才会对sp做减法来分配栈空间保存临时变量。而如果当前函数中没有对其它函数的调用的时候,是不会对lr寄存器做修改的,所以也就不用保存了。
但是上面对main函数和func函数的fp指针所指向的位置也不完全相同,main函数中fp指向的是上个fp保存的内存地址,而func中的fp指向的是sp相同的位置。但是只要恢复的时候相对应不出错就可以了,上面也说过ATPCS这些规定都是人为的一种约束,保证backtrace的时候可以把正确的内容恢复到寄存器中,具体怎么实现并没有特别死板的定义。
另外一个比较重要的东西就是出入栈的顺序,在ARM指令系统中是地址递减栈,入栈操作的参数入栈顺序是从右到左依次入栈,而参数的出栈顺序则是从左到右的你操作。包括push/pop和LDMFD/STMFD等。
比如指令 push {fp, sp, lr, pc}执行的结果就是图1中栈的样子,pc被首先入栈存在高地址,从右到左依次入栈,fp存在低地址。
这些是比较细节和基础的东西,同时也是需要搞清楚的。
参考链接:
1. http://www.linuxidc.com/Linux/2013-03/81247.htm
2. http://www.cnblogs.com/chyl411/p/4579053.html
3. http://www.cnblogs.com/fanzhidongyzby/p/5250116.html
- Arm汇编学习笔记(六)——函数调用栈空间以及fp寄存器
- Arm汇编学习笔记(八)——寄存器的使用
- Arm汇编学习笔记(四)——Arm的37个寄存器和异常处理
- ARM汇编笔记(2)——函数调用规则
- ARM汇编笔记(1)——寄存器、常用指令
- 1.ARM汇编学习——CPSR寄存器、CPSR_cxsf
- C语言栈区的讲解(基于ARM)以及ARM sp,fp寄存器的作用
- ARM的FP寄存器
- ARM的FP寄存器
- ARM的FP寄存器
- ARM汇编学习之寄存器
- 汇编学习笔记--寄存器
- 朱老师ARM裸机学习笔记(六):ARM汇编
- ARM汇编调用函数
- Arm汇编学习笔记(三)——GCC内联汇编
- 什么是寄存器——汇编学习笔记(一)
- 汇编入门学习笔记 (一)—— 基础知识、寄存器
- 关于arm中的fp寄存器
- VC6.0 debug和release的区别及如何设置
- SuperMap iDesktop常见问题解答集锦 (十)
- Androird长度单位解析
- linux下查看和添加PATH环境变量
- 继续学习
- Arm汇编学习笔记(六)——函数调用栈空间以及fp寄存器
- clipboard.js实现无flash复制内容到剪贴板
- leetcode 83. Remove Duplicates from Sorted List
- C++ 贪吃蛇基本算法
- powerdesigner16.5将name字段附到comment中,并生成sql
- 面试问题解答记录(2016-08-18)
- Selenium3.0beta版本启动firefox浏览器的问题
- RestFul协议接口和SOAP协议接口
- 二叉树