栈帧

栈帧和指针可以说是C语言的精髓。栈帧是一种特殊的数据结构,在C语言函数调用时,栈帧用来保存当前函数的父一级函数的栈底指针,当前函数的局部变量以及被调用函数返回后下一条汇编指令的地址。如下图所示:

栈帧位于栈内存中,接下里我们用一个实例展示一下栈帧的入栈和退栈过程。

stackframe.c

#include <stdio.h>

int func(int m, int n)

{

  return m+n;

}

int main()

{

  int m = 8;

  int n = 6;

  func(m, n);

  return 0;

}

#gcc –g stackframe.c –o stackframe (编译)

#objdump –dS stackframe > stackframe.S (反汇编)

从133~139行我们可以看到main函数栈帧的形成过程(入栈操作):

1)    push %rbp 将上一级函数栈帧的栈底指针压栈

2)    mov %rsp, %rbp 将BP指针指向SP,因为上一级函数的栈顶指针是下一级函数的栈底指针,证明栈帧是依次向下增长的

3)    sub $0x10, %rsp SP栈顶指针向下位移16个字节,即创建main函数栈帧。这个地方为什么是16个字节呢?是因为上一级函数栈底指针和当前函数返回时下一条指令地址各占4个字节,m和n两个整形变量各占4个字节,加起来就是16个字节。

4)    movl $0x8, -0x4(%rbp) 将变量m压栈

5)    movl $0x6, -0x8(%rbp) 将变量n压栈

6)    mov -0x8(%rbp), %edx      将m变量值加载到edx寄存器

mov -0x4(%rbp), %eax     将n变量值加载到eax寄存器

mov %edx, %esi

mov %eax, %edi

7)callq 4004c4 <func> 调用callq指令跳转到func函数段,同时压栈EIP+4,即返回func函数时下一条可执行指令的地址

从func函数的反汇编代码可以看到,0x4004c4地址就是func函数开始处,和前面的callq对应。在进入func函数段之后,就是func函数压栈的动作,基本顺序和前面的main函数压栈过程一致。这个地方需要注意的是,首先是mov %edi, -0x4(rbp),从前面的汇编代码可以看到%edi保存的是n变量的值,其次才执行mov %esi, -0x8(rbp)压栈m变量值,证明函数参数的传递顺序是从右往左。另外,这个操作过程演示了实参传递的过程,那么形参传递和指针传递又是怎么样的呢?有兴趣可以试一下。

前面的描述详细介绍了函数栈帧的形成过程,也就是函数调用的底层实现。之所以要重点介绍这一部分内容,是因为在Linux系统出现死机或者异常重启情况时,我们通常会获取死机时的backtrace信息,即函数调用顺序和函数入参,这样我们就可以精准地定位到导致死机的代码段进一步分析。而backtrace就是通过对函数栈帧进行逆推得到的。

前面介绍的是Intel X86架构栈帧的实现原理,和ARM平台上的栈帧实现略有差异,ARM平台栈帧会依次压栈PC指针寄存器值,LR返回指针寄存器值,SP栈顶指针寄存器值,FP栈底指针寄存器值,函数入参,局部变量,即将调用的函数的参数。从本质上讲,栈帧是为了记录函数调用过程,不同平台会压栈不同的数据,但是基本上都是大同小异的。

之所以要重点介绍栈帧这一部分内容,是因为代码调试的最有效方法是获取系统崩溃时的系统运行上下文,包括寄存器组值、函数调用栈,这样我们就能缩小定位范围,详细地知道函数的入参,执行到哪一条指令出的问题。这种backtrace的思路贯穿Linux内核调试、Native层应用调试(用户空间C/C++可执行文件、静态库、动态库)、Java层调试,因此衍生出了ramdump, coredump, Exception.printStack()等技术,其目的就是为了获取函数调用栈信息。

Linux内核调试方法总结之栈帧的更多相关文章

  1. Linux内核调试方法总结

    Linux内核调试方法总结 一  调试前的准备 二  内核中的bug 三  内核调试配置选项 1  内核配置 2  调试原子操作 四  引发bug并打印信息 1  BUG()和BUG_ON() 2   ...

  2. Linux内核调试方法总结【转】

    转自:http://my.oschina.net/fgq611/blog/113249 内核开发比用户空间开发更难的一个因素就是内核调试艰难.内核错误往往会导致系统宕机,很难保留出错时的现场.调试内核 ...

  3. 【转】Linux内核调试方法总结

    目录[-] 一  调试前的准备 二  内核中的bug 三  内核调试配置选项 1  内核配置 2  调试原子操作 四  引发bug并打印信息 1  BUG()和BUG_ON() 2  dump_sta ...

  4. Linux内核调试方法总结之反汇编

    Linux反汇编调试方法 Linux内核模块或者应用程序经常因为各种各样的原因而崩溃,一般情况下都会打印函数调用栈信息,那么,这种情况下,我们怎么去定位问题呢?本文档介绍了一种反汇编的方法辅助定位此类 ...

  5. Linux内核调试方法总结之序言

    本系列主要介绍Linux内核死机.异常重启类稳定性问题的调试方法. 在Linux系统中,一切皆为文件,而系统运行的载体,是一类特殊的文件,即进程.因此,我尝试从进程的角度分析Linux内核的死机.异常 ...

  6. Linux内核调试方法【转】

    转自:http://www.cnblogs.com/shineshqw/articles/2359114.html kdb:只能在汇编代码级进行调试: 优点是不需要两台机器进行调试. gdb:在调试模 ...

  7. Linux内核调试方法总结之调试宏

    本文介绍的内核调试宏属于静态调试方法,通过调试宏主动触发oops从而打印出函数调用栈信息. 1) BUG_ON 查看bug处堆栈内容,主动制造oops Linux中BUG_ON,WARN_ON用于调试 ...

  8. 转载:Linux内核调试方法

    转载文章请注明作者和二维码及全文信息. 转自:http://blog.csdn.net/swingwang/article/details/72331196 不会编程的程序员,不是好的架构师,编程和内 ...

  9. Linux内核调试方法总结之coredump

    什么是core dump? 分析core dump是Linux应用程序调试的一种有效方式,像内核调试抓取ram dump一样,core dump主要是获取应用程序崩溃时的现场信息,如程序运行时的内存. ...

随机推荐

  1. P1536村村通

    这是一个并查集的题,被洛谷评为提高—. 拿到这个题便看出了这是一个裸的并查集,于是就写了一个模板,结果发现连输入都输不进去,一看竟然是多组数据,,然后看到N==0结束,于是便加了一层while.之后提 ...

  2. 网络流 ISAP算法

    网络流问题: 我自己理解,在流网络中,在不违背容量限制的条件下,解决各种从源点到汇点的问题. ISAP算法概念: 据说不会有卡ISAP时间的题目---时间复杂度O(E^2*V) 首先原理都是基于不断寻 ...

  3. 剑指offer-旋转数组的最小数字-数组-python

    题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转 ...

  4. Spring的底层实现机制

    Spring的底层实现机制是通过Demo4j+java反射机制实现的. 使用demo4j来解析xml,使用反射机制实例化bean.

  5. Python 操作sqlite数据库及保存查询numpy类型数据(一)

    # -*- coding: utf-8 -*- ''' Created on 2019年3月6日 @author: Administrator ''' import sqlite3 import nu ...

  6. linux常用的小命令

    查看linux版本 uname -a 图上可知,linux内核版本为2.6.32 查看cpu核数 cat /proc/cpuinfo |grep "cores"| uniq 系统中 ...

  7. Django视图中使用本地缓存

    Django服务器视图使用缓存可以大大减小服务器的压力,对数据实时性要求不高的场景使用缓存非常适合. 使用Django本地缓存 1. 在settings.py配置CACHES CACHES = { ' ...

  8. shell脚本监控Tomcat并重启发送短信

    #!/bin/sh TomcatID=$(ps -ef |grep tomcat |grep -w 'tomcat'|grep -v 'grep'|awk '{print $2}') StartTom ...

  9. VS插件CodeRush for Visual Studio发布v18.2.9|附下载

    CodeRush能帮助你以极高的效率创建和维护源代码.Consume-first 申明,强大的模板,智能的选择工具,智能代码分析和创新的导航以及一个无与伦比的重构集,在它们的帮助下能够大大的提高你效率 ...

  10. B1011. A+B 和 C

    题目描述 给定区间[-2^63, 2^63]内的三个整数A.B 和 C,请判断A+B是否大于C 输入格式 第一行给出正整数T(≤10),即测试用例的个数.随后给出T组测试用例,每组占一行,顺序给出A. ...