当前位置: 首页 > 知识库问答 >
问题:

从rsp开始布局堆栈变量比rbp开始布局的意义

邵耀
2023-03-14

这个问题是关于x86程序集的,但是我提供了一个C语言的例子,因为我试图检查GCC在做什么。

我不确定的是,我所观察到的是因为我更好地意识到并遵守的一些架构约束,还是纯粹是这个特定实现的工件,以及我所读代码的人的习惯的表现,我不应该赋予他们任何意义,例如,这需要在一个方向或另一个方向上完成,只要它是一致的,无论哪个方向都无关紧要。

或者,我现在只是在读写一些琐碎的代码,这将是双向的,因为我会在一段时间内得到一些更重要的东西?

我只想知道我应该如何在我自己的汇编代码中完成它。

00000000000005fa <leaf>:
 5fa:   55                      push   rbp
 5fb:   48 89 e5                mov    rbp,rsp
 5fe:   b8 01 00 00 00          mov    eax,0x1
 603:   5d                      pop    rbp
 604:   c3                      ret    

0000000000000605 <myfunc>:
 605:   55                      push   rbp
 606:   48 89 e5                mov    rbp,rsp
 609:   48 83 ec 10             sub    rsp,0x10
 60d:   b8 00 00 00 00          mov    eax,0x0
 612:   e8 e3 ff ff ff          call   5fa <leaf>
 617:   89 45 f4                mov    DWORD PTR [rbp-0xc],eax   ; // <--- This line
 61a:   c7 45 f8 02 00 00 00    mov    DWORD PTR [rbp-0x8],0x2   ; // <--  And this too
 621:   8b 55 f4                mov    edx,DWORD PTR [rbp-0xc]
 624:   8b 45 f8                mov    eax,DWORD PTR [rbp-0x8]
 627:   01 d0                   add    eax,edx
 629:   89 45 fc                mov    DWORD PTR [rbp-0x4],eax
 62c:   8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]
 62f:   c9                      leave  
 630:   c3                      ret 
int leaf() {
   return 1;
}

int myfunc() {
   int x = leaf(); // <--- This line
   int y = 2;      // <--  And this too
   int q = x + y;
   return q;
}

int main(int argc, char *argv[]) {
   return myfunc();
}

我是如何编译它的:

gcc -O0 main.c -o main.bin

我是如何拆解它的:

objdump -d -j .text -M intel main.bin

共有1个答案

阮轶
2023-03-14

对于必须存在的局部变量(因为您不能将它们优化到寄存器中),您想做什么就做什么,这样就没有什么区别了。

海合会的所作所为毫无意义;未使用的间隙在哪里(由于堆栈对齐而存在)并不重要。在本例中,它是[rsp]处的4个字节,也就是[rbp-0x10]
[rbp-4]处的4个字节用于q

此外,您没有告诉GCC优化,所以没有理由期望它的选择是最优的,或者是一个有用的学习指南。-O3使用volatile int局部变量会更有意义。(但由于没有什么重要的事情发生,实际上还是没有帮助。)

html" target="_blank">html" target="_blank">代码大小:尽可能多的寻址模式可以使用来自RBP的1小的(带符号的8位)位移(如果您相对于RSP寻址本地变量,则可以使用RSP,比如gcc-fomit-frame-pointer)。

当您只有几个标量局部变量时,这种情况很常见,它们远不到128字节。

可以一起操作的任何局部变量都是相邻的,最好不要跨越对齐边界,因此可以用一个qword或XMM存储区最有效地初始化它们两个/所有。

这只在超过16字节的边界上起作用;您知道,一个16字节对齐的块中的所有内容都在同一缓存行中。

一个缓存行中的下行访问模式可能会触发下一个缓存行的预取,但我不确定这种情况是否会发生在真正的CPU中。如果是这样,这可能是不这样做的一个原因,而是支持首先存储到堆栈帧的底部(在RSP或实际使用的最低红区地址)。

如果在另一个调用之前有未用于堆栈对齐的空间,通常最多只有8个字节。这比缓存行小得多,因此不会对局部变量的空间局部性产生任何重大影响。您知道相对于16字节边界的堆栈指针对齐方式,因此选择在堆栈框架的顶部或底部保留填充不会对是否接触新的缓存缓存行产生影响。

“变量”是一个高级概念,您可以任意实现。这不是C,没有要求它有一个地址,或者有相同的地址。(实际上,C编译器会将变量优化到寄存器中,如果地址没有被获取,或者内联后没有转义函数。)

这是一种离题,或者至少是一种迂腐的转移;通常情况下,当不能在寄存器中时,您只是对相同的东西使用相同的内存位置。

 类似资料:
  • 堆栈布局也是布局管理器的一种。它把一系列的窗口部件排列成类似堆栈的样子,但 每次只能有一个窗口部件是当前的可见窗口。 11.4.1 使用方法 QStackedLayout 类被用来创建堆栈布局的实例。使用堆栈布局创建出来的应用程序的 样子与使用 QTabWidget 创建的效果有些相像。也可以使用 QStackedWidget 类来创建一个 应用程序界面,和使用 QStackedLayout 效果

  • 堆叠布局需要一个二维的数据数组,并计算基准线;这个基准线会被传到上层,以便生成一个堆叠图。支持多个基线算法,以及启发式的排序算来可以提高感知灵敏度,就像拜伦(Byron)和瓦腾伯格(Wattenberg)在“Stacked Graphs—Geometry & Aesthetics”(http://www.leebyron.com/else/streamgraph/download.php?file

  • 本文向大家介绍从局部变量和全局变量开始全面解析Python中变量的作用域,包括了从局部变量和全局变量开始全面解析Python中变量的作用域的使用技巧和注意事项,需要的朋友参考一下 理解全局变量和局部变量 1.定义的函数内部的变量名如果是第一次出现, 且在=符号前,那么就可以认为是被定义为局部变量。在这种情况下,不论全局变量中是否用到该变量名,函数中使用的都是局部变量。例如: 输出结果是123。说明

  • 3. 变量的存储布局 首先看下面的例子: 例 19.2. 研究变量的存储布局 #include <stdio.h> const int A = 10; int a = 20; static int b = 30; int c; int main(void) { static int a = 40; char b[] = "Hello world"; register int c = 50

  • 本文向大家介绍从零开始在vue-cli4配置自适应vw布局的实现,包括了从零开始在vue-cli4配置自适应vw布局的实现的使用技巧和注意事项,需要的朋友参考一下 简介 viewportWidth也是vw布局从配置上来说比rem布局简洁了很多,bu需要配置安装lib,也不需要增加一个rem.js文件 简称拎包使用 安装包 或者 配置移动端 在vue.config.js中找到loaderOption

  • 我对python相当陌生,我想知道局部变量是如何工作的。让我们从一个简单方法的示例开始: 让我们假设local_dict像一种常量变量一样使用。这里有一个问题:它是在每次调用do_sth()时创建的,还是创建一次并保存在do_sth()内部的某个地方?