ARM下C语言栈帧机制

作者: Loyen | 来源:发表于2018-10-21 22:56 被阅读8次

背景:

    最近在某个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上,很多却并不完善,需要一定的低层知识去分析才能解决问题。

相关文章

  • ARM下C语言栈帧机制

    背景: 最近在某个RTOS上遇到一个系统BUG,几经折腾,终于将其斩于马下。结局美好,过程却很曲折,在分析定位问题...

  • 缓冲区溢出:栈溢出、格式化字符串和堆溢出

    一、栈溢出 1、定义 栈溢出:在C语言中,栈溢出是由于C语言系列没有内置检查机制来确保复制到缓冲区的数据不得大于缓...

  • C/C++代码复用与包管理

    由于工作原因,常常会在各种编程语言技术栈下切换。每次切回到C/C++技术栈下,都会为C/C++语言缺乏一个好用的包...

  • canary骚操作一览

    canary是栈溢出的防护机制,一般是位于ebp的上方,用于检测栈帧是否有溢出状态,用图形表示: 因为一个栈帧往往...

  • 0x7e相关转义

    PPP数据成帧转义,C语言实现 PPP数据成帧转义,JAVA语言实现 串口数据成帧转义,C语言实现 串口数据成帧转...

  • 5. linux下的栈帧分析

    @toc 1.linux下的栈帧分析2. 栈帧 1. 栈帧 每一次函数的调用,都会在调用栈上维护一个独立的栈帧(s...

  • 干货 | ARMv8架构下程序运行时栈帧布局

    结合ARM相关文档和在飞腾机器上使用gdb调试实际程序来研究ARM的指令和运行时栈帧布局。主要参考了三篇文档。 1...

  • C++语言实现顺序栈

    C++语言实现顺序栈 在写C语言实现顺序栈的时候,我已经向大家介绍了>栈的特点以及介绍了栈的相关操作,并利用C语言...

  • 使用 ScopeGuard 让代码更加安全可靠

    ScopeGuard用于实现Go语言中defer的功能。其主要思想和ScopeLock类似,即利用C++栈展开机制...

  • golang内存逃逸

    一篇很好的博客: Go 语言机制之栈与指针 Go 语言机制之逃逸分析 Go 语言机制之内存剖析 Go 语言机制之数...

网友评论

    本文标题:ARM下C语言栈帧机制

    本文链接:https://www.haomeiwen.com/subject/nygizftx.html