当前位置: 首页 > news >正文

ARM64架构栈帧回溯

文章目录

  • 前言
  • 一、栈帧简介
  • 二、demo演示

前言

请参考:ARM64架构栈帧以及帧指针FP

一、栈帧简介

假设下列函数调用:

funb()
{func()
}funa()
{funb()
}main()
{funa()
}

main函数,funa函数,funb函数都不是叶子函数,其栈布局如下所示:
在这里插入图片描述
LR 和FP寄存器保存在每个函数栈帧的栈顶:
FP = SP + 0
LR = SP + 8
根据这两个寄存器就可以反推出所有函数的调用栈。

FP栈帧指针(X29)指向保存在栈上的上一个栈帧的帧指针。在它之后存储了保存的LR(X30)。链中的最后一个帧指针应设置为0。

知道FP寄存器就能得到每个函数的栈帧基地址。而知道每个函数的栈帧基地址的条件下,可通过当前函数栈帧保存的LR获得当前函数的Entry地址和函数名。
通过FP还可以知道上一级的FP(栈帧基地址)。

在ARM64体系结构中,函数调用栈以单链表形式组织,其中每个栈帧都包含两个地址,用于构建这个链表。这种链表通常被称为调用链或链式栈。

在链式栈中,每个栈帧都有两个64位宽的地址:
(1)低地址(栈顶)存放了指向上一个栈帧的基地址,通常使用FP(Frame Pointer)寄存器来保存。类似于链表中的prev指针,它指向上一个栈帧的基地址,以便在函数返回时回到调用者的上下文。

(2)高地址存放了LR(Link Register)寄存器的值,它保存了当前函数的返回地址。LR寄存器中的值指向了调用当前函数的下一条指令的地址。当函数执行完毕时,该地址将被用于恢复程序控制流,并返回到调用者的位置。

通过这种方式,每个栈帧都可以通过链表中的prev指针链接在一起,形成一个完整的函数调用链。当函数返回时,可以使用prev指针获取上一个栈帧的基地址,并利用LR寄存器中的返回地址将控制流传递给调用者。

ARM64栈回溯:
在AAPC64中,栈指针(SP)指向当前栈帧的顶部,其中包含了上一级函数的LR和FP寄存器现场。通过查看SP所指向的地址,可以找到保存的上一级函数的LR和FP寄存器值。

对于LR寄存器,根据(LR-4)可以找到上一级函数所在的地址,减去4是因为ARM64指令集中的跳转指令(例如BL)会将要跳转到的地址加上4。因此,在栈上保存的LR值实际上是要跳转到的下一条指令的地址,而不是当前指令的地址。所以,为了找到上一级函数所在的地址,需要减去4。

上一级函数的FP寄存器实际上等于上一级函数使用的栈顶地址。通过保存上一级FP寄存器现场的位置,可以在栈上找到上一级函数的栈帧。同样,该栈帧中也会保存更上一级函数的LR和FP寄存器现场,以此类推,形成函数调用链。

通过链式保存的方式,可以回溯整个函数的调用流程,从当前函数一直追溯到最外层的调用者。这种方式使得在函数返回时可以按照相反的顺序恢复各个函数的现场,并正确返回到调用者的位置。

二、demo演示

C语言示例:

int fund(int g, int h)
{return g + h;
}int func(int e, int f)
{int ret = e + f;ret = fund(e, ret);return ret;
}int funb(int c, int d)
{int ret = c + d;ret = func(c, ret);return ret;}int funa(int a, int b)
{int ret = a + b ;ret = funb(a, ret);return ret;
}int main(void)
{int i = 1, j = 2;int ret = funa(i,j);return 0;
}
(gdb) b main
(gdb) b funa
(gdb) b funb
(gdb) b func
(gdb) r

(1)
main:

(gdb) disassemble
Dump of assembler code for function main:......0x0000005555555810 <+32>:    bl      0x55555557b4 <funa>0x0000005555555814 <+36>:    str     w0, [sp, #28]......
x29            0x7ffffff400
x30            0x7ff7e5c110

(2)
funa:

(gdb) c
(gdb) disassemble
Dump of assembler code for function funa:......0x00000055555557dc <+40>:    bl      0x5555555778 <funb>0x00000055555557e0 <+44>:    str     w0, [sp, #44]......
(gdb) info registers
x29            0x7ffffff3d0
x30            0x5555555814

可以看到x30寄存器的值就是main函数 bl funa 下一条指令的地址。

根据x29寄存器得到funa栈帧基地址:

0x7ffffff3d0

读取该地址的值(x29寄存器FP存放了指向上一个栈帧的基地址):

(gdb) x/1xg 0x7ffffff3d0
0x7ffffff3d0:   0x0000007ffffff400

那么可以得到main函数的栈帧基地址:0x0000007ffffff400
这个值就等于执行main函数时,x29寄存器的值。

将main函数的栈帧基地址+8然后读取获取main的返回地址:
这里 + 8 的原因:LR = FP + 8

0x0000007ffffff400 + 8 = 0x0000007ffffff408
(gdb) x/1xg 0x0000007ffffff408
0x7ffffff408:   0x0000007ff7e5c110

main的返回地址:0x0000007ff7e5c110

将main的返回地址 - 4 就可以获取 BL main这条函数跳转指令的地址:
这里 - 4 的原因:执行BL指令时,将下一条指令的地址(即返回地址)写入X30寄存器中,这里我们已经获取到了返回地址,那么 -4 就获取到了 BL 指令的地址。

0x0000007ff7e5c110 - 4 = 0x0000007ff7e5c10c

那么其上一条调用main的指令地址就是0x0000007ff7e5c10c:

(gdb) x/i 0x0000007ff7e5c10c0x7ff7e5c10c <__libc_start_main+228>:        blr     x3
(gdb) x/2i 0x0000007ff7e5c10c0x7ff7e5c10c <__libc_start_main+228>:        blr     x30x7ff7e5c110 <__libc_start_main+232>:        bl      0x7ff7e71a40 <exit>

可以看到是__libc_start_main函数调用 main 函数。

(3)
funb:

(gdb) disassemble
Dump of assembler code for function funb:......0x00000055555557a0 <+40>:    bl      0x555555573c <func>0x00000055555557a4 <+44>:    str     w0, [sp, #44]......
(gdb) info registers
x29            0x7ffffff3a0
x30            0x55555557e0

可以看到x30寄存器的值就是 funa bl funb下一条指令的地址。

根据x29寄存器得到funb栈帧基地址:

0x7ffffff3a0

读取该地址的值(x29寄存器FP存放了指向上一个栈帧funa的基地址):

(gdb) x/1xg 0x7ffffff3a0
0x7ffffff3a0:   0x0000007ffffff3d0

这个值就等于执行funa函数时,x29寄存器的值。

将funa函数的栈帧基地址+8然后读取获取funa的返回地址:

0x0000007ffffff3d0 + 8 = 0x0000007ffffff3d8
(gdb) x/1xg 0x0000007ffffff3d8
0x7ffffff3d8:   0x0000005555555814

funa的返回地址:0x0000005555555814

将funa的返回地址 - 4 就可以获取 main BL funa这条函数跳转指令的地址:

0x0000005555555814- 4 = 0x0000005555555810

那么其上一条调用funa的指令地址就是0x0000005555555810:

(gdb) x/i 0x00000055555558100x5555555810 <main+32>:      bl      0x55555557b4 <funa>
(gdb) x/2i 0x00000055555558100x5555555810 <main+32>:      bl      0x55555557b4 <funa>0x5555555814 <main+36>:      str     w0, [sp, #28]

可以看到是main函数调用 funa 函数。

(4)
func:

(gdb) disassemble
Dump of assembler code for function func:......0x0000005555555764 <+40>:    bl      0x555555571c <fund>0x0000005555555768 <+44>:    str     w0, [sp, #44]......
(gdb) info registers
x29            0x7ffffff370
x30            0x55555557a4

可以看到x30寄存器的值就是 funb bl func下一条指令的地址。

根据x29寄存器得到func栈帧基地址:

0x7ffffff370

读取该地址的值(x29寄存器FP存放了指向上一个栈帧funb的基地址):

(gdb) x/1xg 0x7ffffff370
0x7ffffff370:   0x0000007ffffff3a0

这个值就等于执行funb函数时,x29寄存器的值。

将funb函数的栈帧基地址+8然后读取获取funb的返回地址:

0x0000007ffffff3a0 + 8 = 0x0000007ffffff3a8
(gdb) x/1xg 0x0000007ffffff3a8
0x7ffffff3a8:   0x00000055555557e0

funb的返回地址:0x00000055555557e0

将funb的返回地址 - 4 就可以获取 funaBL funb这条函数跳转指令的地址:

0x00000055555557e0 - 4 = 0x00000055555557dc

那么其上一条调用funb的指令地址就是0x00000055555557dc:

(gdb) x/i 0x00000055555557dc0x55555557dc <funa+40>:      bl      0x5555555778 <funb>
(gdb) x/2i 0x00000055555557dc0x55555557dc <funa+40>:      bl      0x5555555778 <funb>0x55555557e0 <funa+44>:      str     w0, [sp, #44]

可以看到是funa函数调用 funb 函数。

相关文章:

ARM64架构栈帧回溯

文章目录 前言一、栈帧简介二、demo演示 前言 请参考&#xff1a;ARM64架构栈帧以及帧指针FP 一、栈帧简介 假设下列函数调用&#xff1a; funb() {func() }funa() {funb() }main() {funa() }main函数&#xff0c;funa函数&#xff0c;funb函数都不是叶子函数&#xff0c;其…...

LangChain:大型语言模型(LLMs)-- 基础知识

1、LangChain的调用大型语言模型模块的介绍 LangChain是一个强大的框架&#xff0c;旨在通过调用大型语言模型&#xff08;LLM&#xff09;来开发各种语言驱动的应用程序。在LangChain中&#xff0c;LLM不仅仅是一个简单的模型调用&#xff0c;而是一个复杂链条中的关键部分。…...

总分410+专业130+国防科技大学831信号与系统考研经验国防科大电子信息与通信工程,真题,大纲,参考书。

好几个学弟催着&#xff0c;总结一下我自己的复习经历&#xff0c;希望大家复习少走弯路&#xff0c;投入的复习正比换回分数。我专业课831信号与系统130&#xff08;感觉比估分要低&#xff0c;后面找Jenny老师讨论了自己拿不准的地方也没有错误&#xff0c;心里最近也这经常回…...

chatgpt Team 4.0共享合租账号的新方式

为了更好地满足工作需求&#xff0c;我订阅了GPT PLUS会员&#xff0c;但我发现&#xff0c;4.0每三小时问答40次经常吃灰&#xff0c;而且每月近200元的费用让我感到有点肉痛。 于是&#xff0c;我开始寻找有没有什么替代品。在逛某论坛的时候&#xff0c;发现了一个共享Team…...

类和对象二

一、运算符重载 为了使自定义类型可以使用加减等运算符&#xff0c;CPP提供了一个功能叫运算符重载。 关键字&#xff1a;operator操作符 运算符重载最好定义在类对象里&#xff0c;这也可以避免访问不到私有成员的问题。 代码演示&#xff1a; 在类里定义之后&#xff0c;…...

GD32 HID键盘矩阵键盘发送数据时,一直发送数据问题处理

这个问题找了两三天,开始并不认为是示例程序的问题,只是感觉是自己代码问题。 这个解决流程大概是: 先调好矩阵键盘=> 调用发送函数。 就是因为调用时,一直发送数据,我也在按键抬起做了操作,始终不行。 最后,发现时示例代码中有个 空闲中断 引起的。 udev->reg…...

小程序地理位置权限申请+uniapp调用uni.getLocation

文章目录 一、小程序地理位置权限申请二、uniapp调用uni.getLocation 一、小程序地理位置权限申请 需要确保小程序类目已经填写 点击左侧导航栏找到最后的“设置”——“基本设置”——“前往填写” 在开发管理——接口设置——地理位置中可以看到&#xff1a; 即可点击想要申…...

后台权限控制及动态路由

需求 后台系统需要能实现不同的用户权限可以看到不同的功能。 用户只能使用他的权限所允许使用的功能。 功能设计 之前在我的SpringSecurity的课程中就介绍过RBAC权限模型。没有学习过的可以去看下 RBAC权限模型 。这里我们就是在RBAC权限模型的基础上去实现这个功能。 表分…...

云计算:Linux 部署 OVS 集群(控制端)实现OpenFlow

目录 一、实验 1.环境 2.Linux 部署 OVS 集群&#xff08;控制端&#xff09; 3.控制端对接服务端OVS网元 4.服务端OVS添加流表 5.服务端删除OVS 二、问题 1. ODL如何查找已安装插件 2.查看流表显示不全 3.如何删除OVS流表 一、实验 1.环境 (1) 主机 表1 宿主机 主…...

使用/api/put保存数据到OpenTSDB,报204错误

错误信息 HttpResponseProxy{HTTP/1.1 204 No Content [Content-Type: application/json; charsetUTF-8, Content-Length: 0]} 错误原因 在OpenTSDB中&#xff0c;使用/api/put保执行写入操作&#xff0c;得到204响应&#xff0c;表示已经成功写入数据库。...

Open3D kmeans聚类(马氏距离,Python版本)

文章目录 一、简介二、算法步骤三、代码实现四、实现效果参考资料一、简介 在诸多的聚类方法中,K-Means聚类方法是属于“基于原型的聚类”(也称为原型聚类)的方法,此类方法均是假设聚类结构能通过一组原型刻画,在现实聚类中极为常用。通常情况下,该类算法会先对原型进行初始…...

python抠图程序

import cv2 import numpy as np def color_threshold(image, lower, upper): hsv_image cv2.cvtColor(image, cv2.COLOR_BGR2HSV) mask cv2.inRange(hsv_image, lower, upper) result cv2.bitwise_and(image, image, maskmask) return result # 读取图片…...

Android13 CameraServer启动流程

代码入口 frameworks/av/camera/cameraserver 里面包含了四个文件 我们先来看看Android.bp的内容 package {// See: http://go/android-license-faq// A large-scale-change added default_applicable_licenses to import// all of the license_kinds from "frameworks_a…...

如何升级node.js版本

升级Node.js可以通过多种方式来完成&#xff0c;以下是四种常见的方法&#xff1a; 方法一&#xff1a;使用Node.js官方安装程序 访问Node.js的官方网站&#xff0c;下载对应你操作系统的最新版本安装程序。通常&#xff0c;你可以 https://nodejs.org/en/download 找到你需…...

Excel---一个工作簿中的多个sheet合并成一个PDF

0 Preface/Foreword 1 操作方法 1.1 方法一 文件》 导出 》创建PDF/XPS 》 选项 》发布内容 》“整个工作簿” 1.2 方法二 文件》 打印》 打印机选项中&#xff0c;选择一种PDF阅读器 》设置选项中&#xff0c;选择打印整个工作簿。...

结合文本的目标检测:Open-GroundingDino训练自己的数据集

1、简单介绍 Open-GroundingDino是GroundingDino的第三方实现训练流程的代码&#xff0c;因为官方GroundingDino没有提供训练代码&#xff0c;只提供了demo推理代码。 关于GroundingDino的介绍可以看论文&#xff1a;https://arxiv.org/pdf/2303.05499.pdf GroundingDino的G…...

分布式锁-redission锁的MutiLock原理

5.5 分布式锁-redission锁的MutiLock原理 为了提高redis的可用性&#xff0c;我们会搭建集群或者主从&#xff0c;现在以主从为例 此时我们去写命令&#xff0c;写在主机上&#xff0c; 主机会将数据同步给从机&#xff0c;但是假设在主机还没有来得及把数据写入到从机去的时…...

MySQL索引、B+树相关知识汇总

MySQL索引、B树相关知识汇总 一、有一个查询需求&#xff0c;MySQL中有两个表&#xff0c;一个表1000W数据&#xff0c;另一个表只有几千数据&#xff0c;要做一个关联查询&#xff0c;如何优化&#xff1f;1、为关联字段建立索引二、小表驱动大表 二、b树和b树的区别1、更高的…...

相机模型浅析

相机模型 文章目录 相机模型四个坐标系针孔相机模型世界坐标系到相机坐标系相机坐标系到图像坐标系图像坐标到像素坐标 四个坐标系 ①世界坐标系&#xff1a;是客观三维世界的绝对坐标系&#xff0c;也称客观坐标系。因为数码相机安放在三维空间中&#xff0c;我们需要世界坐标…...

国芯科技(C*Core)双芯片汽车安全气囊解决方案

汽车安全气囊是20世纪汽车上的十大发明之一&#xff0c;是目前汽车的法定标准配置&#xff0c;成为汽车驾乘人员生命安全的保护神。随着人们对汽车安全性要求的进一步提高&#xff0c;已形成前排驾驶员气囊、前排副驾驶员气囊、前排侧气囊、后排侧气囊、膝部气囊、安全气帘等等…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...