ARM下C语言栈帧机制

ARM下C语言栈帧机制原文 ARM 下 C 语言栈帧机制 简书 背景 最近在某个 RTOS 上遇到一个系统 BUG 几经折腾 终于将其斩于马下 结局美好 过程却很曲折 在分析定位问题的时候 顺便把 ARM 上 C 函数调用 stack frame 机制捋 https www jianshu com p 91c5dc0a8bb9

大家好,我是讯享网,很高兴认识大家。

原文:ARM下C语言栈帧机制 - 简书背景: 最近在某个RTOS上遇到一个系统BUG,几经折腾,终于将其斩于马下。结局美好,过程却很曲折,在分析定位问题的时候,顺便把ARM上C函数调用stack frame机制捋...https://www.jianshu.com/p/91c5dc0a8bb9

Loyen

0.0.10.21 22:56:43字数 1,039阅读 4,383

背景:

    最近在某个RTOS上遇到一个系统BUG,几经折腾,终于将其斩于马下。结局美好,过程却很曲折,在分析定位问题的时候,顺便把ARM上C函数调用stack frame机制捋了一遍,记录并分享一下。

概念:

栈:

1)从数据结构的角度来理解,栈是一种描述先进后出的数据结构;

2)从进程的内存空间角度来理解,栈是一种特殊的内存段,用于存放局部变量、函数参数、返回值等;

第一种角度,用来描述本身的特性,第二种角度,是将这种数据结构的特性用于实际的内存空间中。

栈帧:每个进程都会有自己的栈空间,而进程中的各个函数也会维护自己本身的一个栈的区域,这个区域就是栈帧。那么一个函数的栈帧的区域是如何来界定的呢?当然,我首先会普及ARM的几个特殊寄存器功能。

R11:frame pointer,FP寄存器

R12:IP寄存器,用于暂存SP

R13:stack pointer,SP寄存器

R14:link register,LR寄存器

R15:PC寄存器

而在ARM上,函数的栈帧是由SP寄存器和FP寄存器来界定的,相信你应该见过下边这张比较经典的图了:


讯享网

    上图描述的是main函数调用func1函数的栈帧情况,从图可知,当main函数调用func1函数时,func1函数会先将PC、LR、SP、FP四个寄存器压到栈上边,其中SP和FP的值分别指向main函数栈帧的两个边界,LR的值保存的是func1调用结束之后的返回值,PC值表示的是当前执行到的指令地址,放置的是进入func1后的指令地址。紧接着就会在栈上分配一片区域,用于放置局部变量等。

    如果func1中还调用了func2子函数,那么也会为func2创建一个栈帧,并且func2的SP和FP会指向func1栈帧的两个边界。这样当函数返回的时候,参数进行出栈,也能找到Caller函数,这个也就是backtrace的原理了。

示例:

    反汇编分析某段代码,如下图所示:

红色部分,表明进入到函数时先将几个特殊的寄存器压栈

黄色部分,sub sp, sp, #16,表明开辟一个4 x 32bit大小的栈区域

蓝色部分,将传入的参数压栈,在ARM ATPCS中规定,寄存器R0-R3用来传参

绿色部分,调用子函数

    那么,我们顺道看看子函数的栈帧区域吧:

    从图中可以看出,机制是一样的,当最终queue_push函数调用结束后,栈上的数据进行出栈,根据fp和ip,便能找到workflow_gather_input函数的栈帧了。

    当然,并不是所有函数调用都需要先push  {fp, ip, lr, pc},当子函数调用过程中,并不会去改变这些值的时候,就不需要压栈,说白了,压栈的目的就是为了在使用完的时候能恢复原来的状态。我会再次提供一个例子:

    strlen函数中没有子函数的调用,所以进入函数后,直接就在栈上分配4 * 32bit大小的区域了。

    栈里边能分析出每个参数的值,以及函数调用时的传参,这对分析与定位问题很有帮助。成熟的系统可能会提供一堆工具来dump stack,并去分析调用关系,但是在RTOS上,很多却并不完善,需要一定的低层知识去分析才能解决问题。

小讯
上一篇 2025-03-05 12:35
下一篇 2025-02-05 17:35

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/74459.html