-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
arm 栈帧/栈回溯/栈帧回溯 相关 #981
Comments
ARM下C语言栈帧机制【转】背景:最近在某个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中还调用了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上,很多却并不完善,需要一定的低层知识去分析才能解决问题。 |
arm平台的调用栈回溯(backtrace)title: arm平台的调用栈回溯(backtrace)
|
总结
The text was updated successfully, but these errors were encountered: