栈帧

栈帧和指针可以说是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. Bootstrap字体图标Font-Awesome 使用教程

    转载自:https://blog.csdn.net/crper/article/details/46293295   以备记录使用.

  2. 【SSL1786】麻将游戏

    题目大意: 给出一个矩阵,查询其中两个点连通线段数 正文: 看这题好眼熟... 实质和这道题是一模一样的,只不过由一条询问升级到多条询问.

  3. Python入门之 函数

    Python入门之 函数 1.初识函数 1.1 什么是函数? <1> 将某个功能封装到一个空间中就是一个函数 <2> 减少重复代码 1.2 定义函数 def -- python ...

  4. 洛谷 - P1462 - 通往奥格瑞玛的道路 - 二分 - Dijkstra

    https://www.luogu.org/problem/P1462 感觉,要二分最大收费权的城市,把小于等于它的全部插进去,Dijkstra一下求出最小的血量.这样感觉太暴力了. 考虑只有1000 ...

  5. 细说SQL Server数据类型

    1.字符型 char 定长,查询速度快,最大8000字符(非unicode编码) ) '小明' 前四个字符存放‘小明’,后添6个空格补全 varchar 变长,最大8000字符(非unicode编码) ...

  6. 使用GET与POST方式获取html数据

    抓取网站数据解析的工作,其中,使用到GET和POST方法获取html数据. 使用GET方式: /** * 使用get方式获取html数据 * * @param strURL(需要访问的网站) * @r ...

  7. Vue 数据持久化

    方法一:使用 localStorage 存储数据 window.localStorage.setItem(key,value) 方法二:使用 vuex-persistedstate插件 vuex 存在 ...

  8. [七月挑选]使用idea创建spring boot 项目

    title: 使用idea创建spring boot 项目 参考lindaZ的IntelliJ IDEA 创建spring boot 的Hello World 项目 1.Open IDEA,choos ...

  9. Python numpy插入、读取至postgreSQL数据库中bytea类型字段

    安装psycopg2模块,此模块用于连接PostgreSQL数据库 ​pip install psycopg2 # -*- coding: utf-8 -*- import psycopg2 impo ...

  10. 34. Find First and Last Position of Element in Sorted Array (JAVA)

    Given an array of integers nums sorted in ascending order, find the starting and ending position of ...