linux64栈帧,ARM栈帧与编译选项 - osc_tkri6ggp的个人空间 - OSCHINA - 中文开源技术交流社区...

本文主要是介绍linux64栈帧,ARM栈帧与编译选项 - osc_tkri6ggp的个人空间 - OSCHINA - 中文开源技术交流社区...,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

看到一篇文章《冬之焱:谈谈Linux内核的栈回溯与妙用》,来自微信公众号"Linux阅码场"。文章主要写了Linux Backtrace的方法,里面提到ARM栈时,有这么一个图:

0c7d0fe0d60adb0bd6012cabd86d0143.png

文章认为除了unwind模式,arm函数调用后都会压入PC,LR,SP,FP(即R15,R14,R13,R11)几个寄存器;但是,在平常ARM汇编代码中,很少能看到函数调用会压栈这么多寄存器。

实际上,压栈哪些寄存器,很大程度上是由编译选项决定的,下面是相关验证。代码很简单,就是在main 函数中调用了zperf_main进行测试:

1. gcc默认编译,无任何选项:

arm-linux-gnueabi-gcc -o test test.c

935eacb1de38621cb5442f0371f36ee3.png

压栈了寄存器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

68deeb8387a62d075344eafcd151c08a.png

压栈了寄存器R3-R11和R14,此时R14作为LR保存,R3-R11都是作为通用寄存器保存,R11并不作为FP,可以看到后面程序会将它作为通用寄存器使用。

4.  加编译选项 -O2

arm-linux-gnueabi-gcc -O2 -o test2 test.c

eadd81cb423d1fc346da8d714c5af335.png

压栈了寄存器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

eb8d53b66e5b9118e926905505ff43aa.png

与不开优化选项的程序相比,可以看到这段代码已不再保存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寄存器的使用、过程调用时出栈和入栈的约定。

56e710ca4a2b3316c8b606545fe4ac8f.png

可以看到,此时程序才严格按照图1的规律,每个函数调用都会压栈PC,LR,SP,FP作为寄存器栈帧进行保存。

这篇关于linux64栈帧,ARM栈帧与编译选项 - osc_tkri6ggp的个人空间 - OSCHINA - 中文开源技术交流社区...的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/410270

相关文章

Python中高级文本模式匹配与查找技术指南

《Python中高级文本模式匹配与查找技术指南》文本处理是编程世界的永恒主题,而模式匹配则是文本处理的基石,本文将深度剖析PythonCookbook中的核心匹配技术,并结合实际工程案例展示其应用,希... 目录引言一、基础工具:字符串方法与序列匹配二、正则表达式:模式匹配的瑞士军刀2.1 re模块核心AP

SQL Server安装时候没有中文选项的解决方法

《SQLServer安装时候没有中文选项的解决方法》用户安装SQLServer时界面全英文,无中文选项,通过修改安装设置中的国家或地区为中文中国,重启安装程序后界面恢复中文,解决了问题,对SQLSe... 你是不是在安装SQL Server时候发现安装界面和别人不同,并且无论如何都没有中文选项?这个问题也

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (

Python实现PDF按页分割的技术指南

《Python实现PDF按页分割的技术指南》PDF文件处理是日常工作中的常见需求,特别是当我们需要将大型PDF文档拆分为多个部分时,下面我们就来看看如何使用Python创建一个灵活的PDF分割工具吧... 目录需求分析技术方案工具选择安装依赖完整代码实现使用说明基本用法示例命令输出示例技术亮点实际应用场景扩

Go语言编译环境设置教程

《Go语言编译环境设置教程》Go语言支持高并发(goroutine)、自动垃圾回收,编译为跨平台二进制文件,云原生兼容且社区活跃,开发便捷,内置测试与vet工具辅助检测错误,依赖模块化管理,提升开发效... 目录Go语言优势下载 Go  配置编译环境配置 GOPROXYIDE 设置(VS Code)一些基本

Python实现中文文本处理与分析程序的示例详解

《Python实现中文文本处理与分析程序的示例详解》在当今信息爆炸的时代,文本数据的处理与分析成为了数据科学领域的重要课题,本文将使用Python开发一款基于Python的中文文本处理与分析程序,希望... 目录一、程序概述二、主要功能解析2.1 文件操作2.2 基础分析2.3 高级分析2.4 可视化2.5

java使用protobuf-maven-plugin的插件编译proto文件详解

《java使用protobuf-maven-plugin的插件编译proto文件详解》:本文主要介绍java使用protobuf-maven-plugin的插件编译proto文件,具有很好的参考价... 目录protobuf文件作为数据传输和存储的协议主要介绍在Java使用maven编译proto文件的插件

Redis出现中文乱码的问题及解决

《Redis出现中文乱码的问题及解决》:本文主要介绍Redis出现中文乱码的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 问题的产生2China编程. 问题的解决redihttp://www.chinasem.cns数据进制问题的解决中文乱码问题解决总结

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

Qt如何实现文本编辑器光标高亮技术

《Qt如何实现文本编辑器光标高亮技术》这篇文章主要为大家详细介绍了Qt如何实现文本编辑器光标高亮技术,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录实现代码函数作用概述代码详解 + 注释使用 QTextEdit 的高亮技术(重点)总结用到的关键技术点应用场景举例示例优化建议