ARM栈帧与编译选项
看到一篇文章《冬之焱:谈谈Linux内核的栈回溯与妙用》,来自微信公众号"Linux阅码场"。文章主要写了Linux Backtrace的方法,里面提到ARM栈时,有这么一个图:
文章认为除了unwind模式,arm函数调用后都会压入PC,LR,SP,FP(即R15,R14,R13,R11)几个寄存器;但是,在平常ARM汇编代码中,很少能看到函数调用会压栈这么多寄存器。
实际上,压栈哪些寄存器,很大程度上是由编译选项决定的,下面是相关验证。代码很简单,就是在main 函数中调用了zperf_main进行测试:
1. gcc默认编译,无任何选项:
arm-linux-gnueabi-gcc -o test test.c
压栈了寄存器R4,R11和R14,R4为zperf_main函数中会改变的通用寄存器,R11作为FP指针使用(程序中不会改变),R14作为LR。
2. 加编译选项 -O0
与不加选项完全一致,说明不加选项默认就是O0优化
3. 加编译选项 -O1 或者编译选项-O(两者一致)
arm-linux-gnueabi-gcc -O1 -o test1 test.c
压栈了寄存器R3-R11和R14,此时R14作为LR保存,R3-R11都是作为通用寄存器保存,R11并不作为FP,可以看到后面程序会将它作为通用寄存器使用。
4. 加编译选项 -O2
arm-linux-gnueabi-gcc -O2 -o test2 test.c
压栈了寄存器R3-R10和R14,此时R14作为LR保存,R3-R10都是作为通用寄存器保存,相比O1优化了R11的保存恢复。
5. 加编译选项 -O3
arm-linux-gnueabi-gcc -O3 -o test3 test.c
由于程序比较简单,编译后与O2完全一致。
6. 加编译选项 -fomit-frame-pointer
该选项的作用,在gcc手册中是这么描述的:
Don't keep the frame pointer in a register for functions that don't need one. This avoids the instructions to save, set up and restore frame pointers; it also makes an extra register available in many functions. It also makes debugging impossible on some machines。
简单来说就是通过不保存FP来优化程序性能。
arm-linux-gnueabi-gcc -fomit-frame-pointer -o testf test.c
与不开优化选项的程序相比,可以看到这段代码已不再保存FP。
事实上gcc的所有级别的优化(-O1, -O2, -O3等)都会打开-fomit-frame-pointer,该选项的功能是函数调用时不保存frame指针,在ARM上就是fp,故我们无法按照APCS中的约定来回溯调用栈。但是GDB中仍然可以使用bt命令看到调用栈,为什么?得知GDB v6之后都是支持DWARF2的,也就意味着它可以不依赖fp来回溯调用栈(详见http://gcc.gnu.org/ml/gcc/2003-10/msg00322.html)。
7. 加编译选项 -mapcs
arm-linux-gnueabi-gcc -mapcs -o testm test.c
这个选项使程序严格遵守ARM Procedure Call Standard(ARM过程调用标准规范)中关于arm寄存器的使用、过程调用时出栈和入栈的约定。
可以看到,此时程序才严格按照图1的规律,每个函数调用都会压栈PC,LR,SP,FP作为寄存器栈帧进行保存。
转载于:https://www.cnblogs.com/DF11G/p/9706063.html
ARM栈帧与编译选项相关推荐
- arm gcc栈帧结构(1)
2019独角兽企业重金招聘Python工程师标准>>> 摘要:先看个例子: void test2(int a,int b,int c) { int k=a,j=b,m=c; } GC ...
- 计算机科学基础知识(六)理解栈帧
一.前言 本文以一个简单的例子来描述ARM linux下的stack frame. 本文也是对tigger网友问题的回复. 二.源代码 #include <stdio.h> static ...
- X86-64寄存器和栈帧--牛掰降解汇编函数寄存器相关操作
X86-64寄存器和栈帧 概要 说到x86-64,总不免要说说AMD的牛逼,x86-64是x86系列中集大成者,继承了向后兼容的优良传统,最早由AMD公司提出,代号AMD64:正是由于能向后兼容,AM ...
- x86-64寄存器与栈帧(转载)
概要 说到x86-64,总不免要说说AMD的牛逼,x86-64是x86系列中集大成者,继承了向后兼容的优良传统,最早由AMD公司提出,代号AMD64:正是由于能向后兼容,AMD公司打了一场漂亮翻身战. ...
- C++ 反汇编/栈帧
文章目录 查看 C++ ASM 在线 C++ 反汇编 g++ -S VS 调试时断点查看反汇编信息 VS 在项目属性的文件输出源码+汇编 Debug 下的:[ProjectName].asm Rele ...
- java 参数类型不确定_详细解析Java虚拟机的栈帧结构
什么是栈帧? 正如大家所了解的,Java虚拟机的内存区域被划分为程序计数器.虚拟机栈.本地方法栈.堆和方法区.(什么?你还不知道,赶紧去看看<Java虚拟机内存结构及编码实战>)这次要介绍 ...
- java虚拟机栈帧_Java虚拟机,运行时栈帧结构
业余生活要有意义,不要越轨.--华盛顿 引导语 "虚拟机"是一个相对于"物理机"的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器. ...
- 函数调用过程,栈帧的一点理解
栈帧图例一张 寄存器理解 程序寄存器组是唯一能被所有函数共享的资源.虽然某一时刻只有一个函数在执行,但需保证当某个函数调用其他函数时,被调函数不会修改或覆盖主调函数稍后会使用到的寄存器值.因此,IA3 ...
- 函数调用过程详解:函数栈帧的创建与销毁
前言:我们在学习C语言的过程中,可以会产生很多疑问,比如: 局部变量是怎么创建的 为什么局部变量的值不做初始化就是随机值 函数是怎么传参的?传参的顺序是怎么样的? 形参和实参是什么关系? 函数调用是怎 ...
最新文章
- 二叉树的最小高度,最大高度(深度)和宽度
- RabbitMQ之TTL(Time-To-Live 过期时间)
- [概率论]如何通俗地理解“最大似然估计法”?
- c语言与java负数补码,详解原码、反码与补码存储与大小
- 项目升级-加密的参数传递到后台然后解密(相当于重新封装下request)
- 使用 IntraWeb (2) - Hello IntraWeb
- URLClassLoader使用方法及事例程序
- 【水果识别】基于matalb GUI灰度、二值化、滤波水果分级【含Matlab源码 1848期】
- PHP表单省市县三级联动,用php做省份的三级联动 附带数据库
- 一位平凡毕业生的大学四年
- 吴恩达深度学习第三周
- UE4中实现PBKDF2加密验证
- doe五步法_DOE方法介绍
- Arduino相关语法和函数
- 程序猿头头(防抖节流)
- NOIWC2018滚粗记
- 深度强化学习中的对抗攻击和防御
- MYSQL 判断一个时间段是否在另一个时间段内。
- SimMatch 论文分享
- Caché程序员必须知道符号与缩写 第二章 ObjectScript中使用的缩写
热门文章
- Jmeter+jenkins+ant自动化测试环境搭建
- 真机上装不上测试应用,Installation error: INSTALL_FAILED_INSUFFICIENT_STORAGE
- 前端面试汇总(Bootstrap框架)
- 闩锁电流_IGBT——闩锁(Lanchup)效应
- linux rpm 查找,Linux下 rpm 命令查询方法
- windows采集音频
- Linux下coredump调试1:使用
- 我参与的一个项目的继续总结:经验篇
- shell学习笔记二则:统计空间
- charles 代理手机连不上网_「技巧」不想接电话?这样可以让手机变成空号,还不影响上网...