谁在CALL我 -- callstack的实现原理
转载时请注明出处和作者联系方式
作者联系方式:李先静 <xianjimli at hotmail dot com>
开发嵌入式软件通常是比较麻烦的事,一些常用的工具往往无法使用,在开发PC软件时简单的任务,此时变得很复杂。今天就遇到了这样一件事,折腾了几个小时,仅仅是为知道call stack。
我编译了一个程序放到PDA(ARM9+LINUX+UCLIBC)上面运行,出现了一个ASSERT,并显示了文件名和行号,原来是调用了一个没有实现的函数,我很想知道是谁调用了它,这看似简单的问题却让我很头疼,如果有gdb,那好办-用bt命令就可以搞定,如果用的libc,那也好办-用backtrace函数就可以搞定,问题是两者都没有。
想来想去只有自己写一个backtrace,要实现这个功能并不难,如果我们知道调用堆栈的格式,就可以很容易取出上层调用者的指令地址,有了这些上层调用者的指令地址,我们可以通过MAP文件找到指令地址对应的源文件名和行号。
下面简要介绍一下实现原理:
要获得调用者的地址,有必要介绍一下堆栈的格式:
+---------------------------+ (高地址)
+_参数1__________+
+---------------------------+
+_参数2__________+
+---------------------------+ 参数的顺序依赖于调用方式
+_参数.__________+
+---------------------------+
+_参数N__________+
+---------------------------+
+_eip____________+ 返回本次调用后,下一条指令的地址
+----------------------------+
+_ebp____________+ 这里保存的调用者的ebp
+----------------------------+
(ebp 指向这里:相当于调用者和被调用者的分界线)
+----------------------------+
+_临时变量1_______+
+----------------------------+
+_临时变量2_______+
+----------------------------+
+_临时变量.________+
+----------------------------+
+----------------------------+
+_临时变量N_______+
+----------------------------+(低地址)
由于优化、调用方式、编译器的不同,上述布局部可能有所不同,但一般来说,第一个局部变量前是调用者的ebp,ebp前是返回后下一条指令的地址。
知道了这个结构,要获得上层调用的者指令地址就容易了,我们可以用如下代码模拟glibc提供的backtrace的功能:
int backtrace (void **BUFFER, int SIZE)
{
int n = 0;
int *p = &n;
int i = 0;
int ebp = p[1];
int eip = p[2];
for(i = 0; i < SIZE; i++)
{
BUFFER[i] = (void*)eip;
p = (int*)ebp;
ebp = p[0];
eip = p[1];
}
return SIZE;
}
附:
通过addr2line可以找到地址对应的文件名和行号,不用手动去查MAP文件了。
谁在CALL我 -- callstack的实现原理相关推荐
- Native层HIDL服务的注册原理-Android10.0 HwBinder通信原理(六)
摘要:本节主要来讲解Android10.0 Native层HIDL服务的注册原理 阅读本文大约需要花费23分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Androi ...
- Android10.0 Binder通信原理(四)-Native-C\C++实例分析
摘要:本节主要来讲解Android10.0 Binder的Native层实例流程 阅读本文大约需要花费35分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Androi ...
- SendMessage、PostMessage原理
SendMessage.PostMessage原理 本文讲解SendMessage.PostMessage两个函数的实现原理,分为三个步骤进行讲解,分别适合初级.中级.高级程序员进行理解,三个步骤分别 ...
- SAP CRM One Order函数CRM_Object_FILL_OW的设计原理
标题:SAP CRM One Order函数CRM_FILL_OW的设计原理 There are totally 60 function modules in One order with namin ...
- SendMessage、PostMessage原理和源代码详解
本文讲解SendMessage.PostMessage两个函数的实现原理,分为三个步骤进行讲解,分别适合初级.中级.高级程序员进行理解,三个步骤分别为: 1.SendMessage.PostMessa ...
- Kotlin 协程,怎么开始的又是怎么结束的?原理讲解!
九心 | 作者 承香墨影 | 校对 https://juejin.cn/post/6862548590092140558 | 原文 Hi,大家好,这里是承香墨影! 上周我们聊到 Kotlin 协程的使 ...
- 一篇读懂:Android手机如何通过USB接口与外设通信(附原理分析及方案选型)
更多技术干货,欢迎扫码关注博主微信公众号:HowieXue,共同探讨软件知识经验,关注就有海量学习资料免费领哦: 目录 0背景 1.手机USB接口通信特点 1.1 使用方便 1.2 通用性强 1.3 ...
- ZT自老罗的博客 Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析...
Android系统的智能指针(轻量级指针.强指针和弱指针)的实现原理分析 分类: Android 2011-09-23 00:59 31568人阅读 评论(42) 收藏 举报 androidclass ...
- ATECC508A芯片开发笔记(八):ECDH算法配置方法、执行过程及实现原理
目录 AATECC508A芯片开发笔记(八):ECDH算法配置方法.过程原理及示例代码 1.ECDH介绍及原理 2.ECDH执行过程 3.508A某一slot执行Ecdh需要配置的参数 4.示例代码 ...
最新文章
- 新加坡计划通过区块链促进东盟金融包容性
- 设计模式学习----装饰器模式
- Redis 键(key) 命令
- IoU 判断矩形区域重叠
- SpringBoot配置Druid
- windows与linux中的路径书写,斜杠、反斜杠用法总结
- linux 文件夹 含义 表示(转)
- 3_4 IteratorMode 迭代器模式
- @Deprecated 注解 (@Documented 、@Retention、@Target)
- ssm如何在mapper插入实时的时间_第一个ssm整合
- ToolStripStatusRollingLabel——滚动显示状态栏标签
- 在web.config中添加配置信息
- 【算法基础】动态规划解题实例之野营问题
- 关于秩的等式与不等式总结
- 魅族魅蓝note3完美开启usb调试模式的经验
- Java进阶之路,技术要点
- 多目标遗传优化算法nsga2[python源码实现]
- STM32驱动TM1616程序加原理图
- 计算机导论 ——绪论
- Bentley MicroStation CE版的颜色变换(CONNECT Edition)
热门文章
- python seo分析器_python与SEO浅谈Python+ELK打造seo数据分析监控系统
- 计算机网络网站qige,海尔第三代七哥 Air Magic体感应用体验
- 华为DCIP Datacom认证分类
- 义嘉泰携手----炬芯蓝牙双模ATS3085 ATS3085C
- 响铃:智能小程序瞄准民生,发红包之外百度App的春节谋局
- 2019年,我被裁了!
- 东北大学20春计算机在线作业,东北大学19春《冶金工程计算机控制与仿真》在线作业123...
- HX711称重传感器的功能实现
- Java期末作业——王者荣耀的洛克王国版游戏
- rctimer二轴云台及云台控制板调试(Simple bgc 8位破解板)