x86_64架构栈帧以及帧指针FP

文章目录

  • 一、x86_64架构寄存器简介
  • 二、x86_64架构帧指针FP
  • 三、示例
  • 四、保存帧指针
  • 参考资料

一、x86_64架构寄存器简介

在x86架构中,有8个通用寄存器可用:eax、ebx、ecx、edx、ebp、esp、esi和edi。在x86_64(x64)扩展中,这些寄存器被扩展为64位,以’r’前缀代替’e’,并添加了另外8个寄存器:r8、r9、r10、r11、r12、r13、r14和r15。

x64架构中寄存器的数量增加了,这为优化寄存器分配提供了更多机会,并减少了对栈的依赖。这影响了应用程序二进制接口(ABI)的重要设计决策,ABI定义了函数如何被调用以及参数如何在程序的不同部分之间传递。

x64 ABI中的一个重要变化是更多地使用寄存器传递函数参数。调用约定指定最多可以通过寄存器(rdi、rsi、rdx、rcx、r8和r9)传递6个整数或指针参数,而不是将它们推入栈中。这减少了栈的使用,并改善了具有少量参数的函数调用的性能。

根据ABI规范,在函数中,前6个整数或指针参数将被传递到寄存器中。第一个参数被放置在rdi寄存器中,第二个参数放置在rsi寄存器中,第三个参数放置在rdx寄存器中,然后是rcx、r8和r9寄存器。只有第7个参数及以后的参数才会传递到栈上。

如下图所示函数P调用函数Q:
在这里插入图片描述

备注:第7个参数及以后的参数时保存在调用者的栈中,上述函数P调用函数Q过程中,如果函数Q需要大于6个的参数,那么函数P调用函数Q时将参数7-n保存在自己的栈帧中。

比如 函数 fun1 调用 函数 fun2:

fun2()
{

}

fun1()
{
	fun2(a,b,c,d,e,f,g,h);
}

函数 fun1 调用 函数 fun2时,通过寄存器最多传递6个整数(指针或者整数),但是fun2需要8个参数,那么函数 fun1 在调用函数 fun2之前在自己的栈帧中存储好多余的参数,也就是第7个参数及以后的参数。其中参数7位于位于栈顶。

函数 fun1 调用 函数 fun2的过程:将参数1-6复制到对应的寄存器(rdi、rsi、rdx、rcx、r8和r9),把参数7-8放在函数 fun1的栈顶,当参数到位后,程序就可以执行call指令将控制转移到函数 fun2了。如果函数 fun2也调用了大于6个参数的函数,那么也要把超出6个参数的部分保存在自己的栈帧中,

更多的寄存器可用性还影响了栈帧的使用。由于有更多的通用寄存器,可以更容易地将经常访问的变量保存在寄存器中,减少了将它们存储在栈上的需求。这可以提高代码执行效率,并可能导致更小的栈帧。

二、x86_64架构帧指针FP

在x86_64架构中,函数调用过程中需要的存储空间超出寄存器能够存放的大小时,就会在栈上分配空间,这个空间称为函数的栈帧(stack frame),函数调用创建一个栈帧(stack frame)来存储局部变量、函数参数、返回地址和其他与函数执行相关的信息。栈帧是在程序执行期间动态地分配和管理的。

并非每个函数调用都会创建栈帧。当函数调用参数少于6个且可以通过寄存器传递,以及所有局部变量都可以保存在寄存器中并且函数是叶子函数(叶子函数指该函数不会调用其他函数)时,就不需要创建栈帧。

大多数函数调用过程中栈帧都是定长的,在函数调用的开始就分配好了栈空间。

(1)帧指针(Frame Pointer):
在x86_64架构中,FP通常是指Frame Pointer,也称为帧指针。帧指针通常由RBP寄存器(Base Pointer)表示。
帧指针指向当前函数的栈帧的底部,即栈帧中局部变量和函数参数的起始位置。

使用帧指针的好处是,它提供了一种相对于固定参考点的偏移量访问局部变量和函数参数的方式。通过将帧指针与偏移量相结合,可以准确地访问栈帧中的特定变量或参数。

通过帧指针,可以访问局部变量、函数参数和返回地址等信息。

帧指针的值在函数执行过程中是稳定的,不会随着栈的动态变化而改变。这使得调试器和性能分析器能够使用帧指针来构建函数调用图和跟踪变量的访问情况。

(2)栈指针(Stack Pointer):
在x86_64架构中,栈指针通常由RSP寄存器(Stack Pointer)表示。
栈指针指向当前栈顶的位置,即最新压入栈的数据所在的内存地址。
使用push指令将数据存入栈中,使用pop指令将数据从栈中取出。

通过栈指针减小一个适当的量可以为没有指定初始值的数据在栈上分配空间,增加栈指针来释放栈空间。

(3)局部变量和函数参数:
每个函数调用都会在栈帧中分配一定的空间来存储局部变量和函数参数。
这些变量和参数的访问通常是相对于帧指针的偏移量来进行的。

(4)返回地址(Return Address):
在函数调用时,返回地址会被压入栈中,以便在函数执行完毕后返回到调用它的位置。

在跳转到被调用过程的第一条指令之前,CALL指令会将RIP寄存器中的地址推送到当前栈上。这个地址被称为返回指令指针(return-instruction pointer),它指向在从被调用过程返回后,调用过程应该从哪条指令继续执行。在从被调用过程返回时,RET指令会将返回指令指针从栈中弹出,并将其放回RIP寄存器中。然后,调用过程的执行会继续。

RIP寄存器:用于指示将要执行的下一条指令的地址。当处理器执行指令时,RIP寄存器会自动递增,指向下一条将要执行的指令的地址。在分支、跳转或调用指令执行时,RIP寄存器的值会被改变以跳转到新的指令地址。在过程调用中,CALL指令会将返回地址(下一条指令地址)推送到栈上,而RET指令会将栈上的返回地址弹出并存储回RIP寄存器,从而实现从子过程返回到调用过程。

(5)栈帧布局(Stack Frame Layout):
栈帧布局是指栈帧中各个元素的相对位置和顺序。
栈帧布局是由编译器在函数编译过程中决定的,通常根据函数的局部变量和参数的需求进行分配和组织。

备注:在x86_64架构下,gcc没有使用优化选项时,帧指针来访问栈帧的数据,栈指针来分配和释放栈帧的空间。

当gcc使用 -O 优化选项时会省略帧指针,即gcc的所有级别的优化(-O1, -O2, -O3等)都会打开-fomit-frame-pointer,该选项的功能是函数调用时不保存frame指针,请参考1.4节。

三、示例

long utilfunc(long a, long b, long c)
{
    long xx = a + 2;
    long yy = b + 3;
    long zz = c + 4;
    long sum = xx + yy + zz;
    return xx * yy * zz + sum;
}

long myfunc(long a, long b, long c, long d,
            long e, long f, long g, long h)
{
  long xx = a * b * c * d * e * f * g * h;
  long yy = a + b + c + d + e + f + g + h;
  long zz = utilfunc(xx, yy, xx % yy);
  return zz + 20;
}

func1
{
	myfunc(a,b,c,d,e,f,g,h);
}

(1)其中myfunc函数栈布局如下所示:

在这里插入图片描述
myfunc函数的栈帧就是 RBP到RSP,func1调用myfunc,将参数1-6(a、b、c、d、e、f)复制到对应的寄存器(rdi、rsi、rdx、rcx、r8和r9),把参数g、h放在函数 func1的栈顶,把返回地址压入到栈顶中,myfunc函数的栈帧保存局部变量xx、yy、zz。

返回地址和参数g、h都是放在函数 func1的栈帧中。

根据AMD64 ABI的正式定义:

%rsp指向的位置后面的128字节区域被认为是保留的,不应该被信号处理程序或中断处理程序修改。因此,函数可以使用这个区域作为临时数据存储区,这些数据在函数调用之间不需要保留。特别是,叶子函数可以将整个栈帧放在这个区域中,而不需要在函数的开头和结尾调整栈指针。这个区域被称为红区(red zone)。

简单来说,红区是一种优化策略。代码可以假设rsp下面的128字节不会被信号处理程序或中断处理程序异步破坏,因此可以将其用作临时数据的存储区,而无需显式地移动栈指针。这个优化的关键是最后一句话——使用红区存储数据时,可以节省减少rsp和恢复rsp的两条指令。

这意味着当函数使用红区来存储临时数据时,可以省略调整栈指针的指令,从而提高代码的执行效率。红区的使用使得对栈指针的调整仅发生在需要保留的数据超过128字节的情况下,而对于较小的临时数据,可以直接使用红区,无需额外操作。

需要注意的是,红区的使用是可选的,并且在使用时需要小心确保不会超出128字节的范围,以避免与异常处理相关的问题。

(2)其中utilfunc函数栈布局如下所示:
回想一下上面代码示例中的myfunc是如何调用另一个名为utilfunc的函数的。这样做是故意的,目的是使myfunc成为非叶子,从而防止编译器应用红区优化。看看utilfunc的代码,这确实是一个叶函数。让我们看看使用gcc编译时它的堆栈框架是什么样子的。
在这里插入图片描述
由于utilfunc只有3个参数,因此调用它不需要使用堆栈,因为所有参数都适合寄存器。此外,由于它是一个叶函数,gcc选择对其所有局部变量使用红色区域。因此,rsp不需要递减(稍后恢复)来为该数据分配空间。

四、保存帧指针

在函数执行过程中,基指针rbp(以及在x86上的前身ebp)作为指向栈帧开头的稳定"锚点",在手动汇编编码和调试中非常方便。然而,一段时间以前就注意到,编译器生成的代码实际上并不需要它(编译器可以轻松地从rsp跟踪偏移量),而DWARF调试格式提供了访问栈帧的手段(CFI),无需使用基指针。

因此,一些编译器开始省略基指针以进行积极的优化,从而缩短函数的前奏和尾声,并提供了一个额外的通用寄存器供使用(请记住,在具有有限通用寄存器集的x86上,这非常有用)。

gcc在x86上默认保留基指针,但允许使用-fomit-frame-pointer编译标志进行优化。关于是否建议使用此标志存在争议——如果您对此感兴趣,可以进行一些搜索。

无论如何,AMD64 ABI引入的另一个"新特性"是明确将基指针作为可选项,规定如下:

可以通过使用%rsp(栈指针)来索引栈帧,从而避免将%rbp用作栈帧指针的传统用法。这种技术在前奏和尾声中可以节省两条指令,并提供了一个额外的通用寄存器(%rbp)。

gcc遵循这个建议,并在进行优化编译时,默认情况下在x64上省略帧指针。它提供了一个选项通过使用-fno-omit-frame-pointer标志来保留帧指针。出于清晰起见,上面显示的栈帧是在没有省略帧指针的情况下生成的。

-fomit-frame-pointer:省略帧指针。
-fno-omit-frame-pointer:保留帧指针。

gcc在x86(x86_64)上默认保留基指针

x86_64架构,gcc优化选项 -O 默认使用-fomit-frame-pointer编译标志进行优化,省略帧指针。

      -fomit-frame-pointer
           Omit the frame pointer in functions that don't need one.  This avoids the instructions to save, set up and restore the frame pointer; on many targets it also makes
           an extra register available.

           On some targets this flag has no effect because the standard calling sequence always uses a frame pointer, so it cannot be omitted.

           Note that -fno-omit-frame-pointer doesn't guarantee the frame pointer is used in all functions.  Several targets always omit the frame pointer in leaf functions.

           Enabled by default at -O and higher.

-fomit-frame-pointer 是GCC编译器的一个编译选项。当启用该选项时,它告诉编译器在不需要基指针的函数中省略基指针。通过省略基指针,编译器避免了保存、设置和恢复基指针的指令,从而使生成的代码更小、更快。

省略基指针还提供了一个额外的通用寄存器可供使用,这对于具有有限通用寄存器数量的架构(如x86)非常有用。

然而,需要注意的是,该选项的效果可能因目标架构而异。在一些目标架构中,标准调用序列始终使用基指针,因此该选项可能没有效果,基指针仍然会被使用。

值得注意的是,即使不使用 -fno-omit-frame-pointer,也不能保证在所有函数中都使用基指针。一些目标架构,特别是在叶子函数(不调用其他函数的函数)中,仍然会省略基指针以进行优化。

默认情况下,在优化级别 -O 及更高级别时, -fomit-frame-pointer 选项会被启用,意味着在优化的代码中会省略基指针。

当gcc没有使用优化选项时,函数开头和结尾会有如下指令:

func
{
   push   %rbp
   mov    %rsp,%rbp
   sub    $0x50,%rsp
   ......
   ops %rbp
   ......
   pop    %rbp
   ret
}

首先,指令"push %rbp"将当前函数的基指针值压入栈中,保存起来。接下来,指令"mov %rsp, %rbp"将当前栈指针的值(rsp)复制到基指针(rbp)中,将其作为新的栈帧的基准。

接下来,指令"sub $0x50, %rsp"将栈指针向下移动,为函数的局部变量和临时存储空间分配一段空间。在这个例子中,它分配了80字节(0x50的十六进制值)的空间。

在这两条指令之后,可能会有其他指令用于函数的实际操作和计算。比如通过帧指针,可以访问局部变量、函数参数和返回地址等信息。

最后,指令"pop %rbp"将之前保存在栈中的基指针值弹出,并恢复原来的基指针值。然后,指令"ret"用于从函数中返回。

这段代码的作用是在函数执行前保存基指针,然后在函数执行完毕后恢复基指针,并返回到调用函数的位置。它还通过减少栈指针%rsp的值来为函数的局部变量和临时存储空间分配内存。这样可以确保函数在执行期间帧指针%rbp对局部变量和其他数据的正确访问,并在函数返回时释放相应的空间。

参考资料

https://accu.org/journals/overload/31/173/bendersky/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/457672.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于检索增强的 GPT-3.5 的文本到 SQL 框架,具有样本感知提示和动态修订链。

文章目录 一、论文关键信息二、基础概念三、主要内容1. Motivations2. Insights3. 解决方案的关键4. 实验 四、总结与讨论 🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 一、论文关键信息 论文标题:Retrieval-augmented GPT-3.5-based T…

港大提出图结构大语言模型:GraphGPT

1. 引言 图神经网络(Graph Neural Networks)已经成为分析和学习图结构数据的强大框架,推动了社交网络分析、推荐系统和生物网络分析等多个领域的进步。图神经网络的主要优势在于它们能够捕获图数据中固有的结构信息和依赖关系。利用消息传递…

Selenium 自动化 —— 入门和 Hello World 实例

Selenium 是什么 Selenium 是一个用于自动化网页浏览器操作的工具,它支持多种浏览器和多种操作系统。主要用于测试 web 应用程序的功能,也可用于执行一些基本的浏览器操作任务,例如自动化表单填写、网页导航等。 Selenium 是一个开源项目&a…

大米自动化生产线的运作原理与科技创新

在当今科技飞速发展的时代,自动化生产线已经成为各个行业提高效率、降低成本的重要工具。而在粮食产业中,大米的自动化生产线更是以其独特的魅力,引领着粮食加工业的转型升级。星派将带您深入了解大米自动化生产线的运作原理,以及…

Docker 安装部署MySQL教程

前言 Docker安装MySQL镜像以及启动容器,大致都是三步:查询镜像–>拉取镜像–>启动容器 1、查询镜像 docker search mysql2、拉取镜像 拉取镜像时选择stars值较高的 docker pull mysql:5.7 #这里指定拉取对应的版本Mysql5.7,没有指…

【新手】在idea中配置tomcat服务器,并部署一个项目

目录 第一步:新建java项目第二步:新建完成后,按照步骤选择添加框架支持第三步:点击添加配置第四步:在web文件包下创建一个新的jsp第五步:在新建的jsp里编写java或者html 前言:本章学习的是在ide…

Ubuntu虚拟机的IP总频繁变化,导致Xshell断开连接

文章目录 一、IP变化的原因二、解决方法:固定IP三、参考文章 一、IP变化的原因 1.DHCP协议 虚拟机系统(Ubuntu、CentOS、UOS等Linux系统)启动后,加入本地局域网网络时,会向本地网络申请租约一个IP地址,租约时长不定。我这里租约时…

谁将主导未来AI市场?Claude3、Gemini、Sora与GPT-4的技术比拼

【最新增加Claude3、Gemini、Sora、GPTs讲解及AI领域中的集中大模型的最新技术】 2023年随着OpenAI开发者大会的召开,最重磅更新当属GPTs,多模态API,未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义,不亚…

vscode 向下复制当前行(即visual studio 中的Ctrl + D)功能快捷键

参考:https://blog.csdn.net/haihui1996/article/details/87937912 打开vscode左下角键盘快捷键设置,找到copy line down,即可查看当前默认快捷键为“shift Alt ↓” 双击快捷键,输入自己想要的快捷组合,如CtrlD,然…

在 IntelliJ IDEA 中远程调试 Java 程序

1. 在idea中配置,如下图: 2. 配置启动脚本5005监听 启动脚本配置 nohup java -agentlib:jdwptransportdt_socket,servery,suspendn,address5005-Duser.timezoneGMT08 -Dserver_name${appname} $JAVA_OPT -jar ${jarname} --spring.cloud.nacos.discover…

uniapp遇到的问题

【uniapp】小程序中input输入框的placeholder-class不生效解决办法 解决:写在scope外面 uniapp设置底部导航 引用:https://www.jianshu.com/p/738dd51a0162 【微信小程序】moveable-view / moveable-area的使用 https://blog.csdn.net/qq_36901092/…

计讯物联水库泄洪监测预警系统,保障水库安全度汛

近日,受台风外围环流影响,多地受到特大暴雨侵袭。因此水库泄洪是势在必行。泄洪作为水库防洪的重要方法之一,水库可通过其库容拦蓄洪水,在水库容量超出或下游需求的时候则开始实行泄洪,达到减免洪水灾害的目的&#xf…

【Unity】程序创建Mesh(二)MeshRenderer、光照、Probes探针、UV信息、法线信息

文章目录 接上文MeshRenderer(网格渲染器)Materials(材质)Material和Mesh对应Lighting光照Lightmapping材质中的光照 光源类型阴影全局光照Probes(探针)Ray Tracing(光线追踪)Additi…

Hive企业级调优

本质就是一个hadoop的客户端,将HIve SQL转化成MapReduce程序 一、企业级调优 这部分主要用在实际工作中和面试中 1、主要分为计算资源调优 & 执行计划调优 计算资源调优就是yarn资源的配置,和mapreduce的资源配置,分给多少内存&#xff…

基于 RocketMQ Prometheus Exporter 打造定制化 DevOps 平台

tar -xzf prometheus-2.7.0-rc.1.linux-amd64.tar.gzcd prometheus-2.7.0-rc.1.linux-amd64/./prometheus --config.fileprometheus.yml --web.listen-address:5555 Prometheus 默认监听端口号为 9090,为了不与系统上的其它进程监听端口冲突,我们在启动…

docker 部署nacos

docker 部署nacos 1、配置数据库表 -- 导出 nacos 的数据库结构 DROP DATABASE IF EXISTS nacos; CREATE DATABASE IF NOT EXISTS nacos; USE nacos;-- 导出 表 nacos.config_info 结构 DROP TABLE IF EXISTS config_info; CREATE TABLE IF NOT EXISTS config_info (id bigi…

【Flutter 面试题】怎么理解Flutter异步编程的async和await?

【Flutter 面试题】怎么理解Flutter异步编程的async和await? 文章目录 写在前面口述回答补充说明完整代码示例运行结果详细说明 写在前面 🙋 关于我 ,小雨青年 👉 CSDN博客专家,GitChat专栏作者,阿里云社区…

GCNv2_SLAM-CPU详细安装教程(ubuntu18.04)

GCNv2_SLAM-CPU详细安装教程-ubuntu18.04 前言一、安装第三方库1.安装Pangolin2.安装OpenCV3.安装Eigen4.安装Pytorch(c) 二、安装以及运行GCNv2_SLAM1.安装编译GCNv2_SLAM2.单目模式运行演示案例 总结 前言 paper:https://arxiv.org/pdf/1902.11046.pdf githup::https://gith…

2、鸿蒙学习-申请调试证书和调试Profile文件

申请发布证书 发布证书由AGC颁发的、为HarmonyOS应用配置签名信息的数字证书,可保障软件代码完整性和发布者身份真实性。证书格式为.cer,包含公钥、证书指纹等信息。 说明 请确保您的开发者帐号已实名认证。每个帐号最多申请1个发布证书。 1、登录AppGa…

Stable Diffusion 模型下载:Juggernaut(主宰、真实、幻想)

本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八 下载地址 模型介绍 该模型是一个真实模型,并且具有幻想和创意色彩。 作者述:我选取了…