为什么使用push/pop而不是sub和mov?

2023-12-02

当我使用不同的编译器时https://godbolt.org,我注意到编译器生成这样的代码是很常见的:

push    rax
push    rbx
push    rcx
call    rdx
pop     rcx
pop     rbx
pop     rax

我明白每个push or pop做了两件事:

  1. 将操作数移入/移出堆栈空间
  2. 递增/递减堆栈指针 (rsp)

因此,在上面的示例中,我假设 CPU 实际上执行 12 次操作(6 次移动、6 次添加/替换),不包括call。将添加/替换组合起来不是更有效吗?例如:

sub rsp, 24
mov [rsp-24], rax
mov [rsp-16], rbx
mov [rsp-8], rcx
call    rdx
mov rcx, [rsp-8]
mov rbx, [rsp-16]
mov rax, [rsp-24]
add rsp, 24

现在只有 8 个操作(6 个移动,2 个添加/替换),不包括call。为什么编译器不使用这种方法?


如果你编译-mtune=pentium3或早于-mtune=pentium-m, GCC will像你想象的那样进行代码生成,因为在那些旧的 CPU 上,push/pop 确实解码为堆栈指针上的单独 ALU 操作以及加载/存储。 (你必须使用-m32, or -march=nocona(64位P4 Prescott)因为那些旧的CPU也不支持x86-64)。为什么gcc使用movl而不是push来传递函数参数?

但 Pentium-M 在前端引入了一个“堆栈引擎”,消除了堆栈操作的堆栈调整部分,例如推送/调用/返回/弹出。它有效地以零延迟重命名堆栈指针。看Agner Fog 的微架构指南 and Sandybridge 微架构中的堆栈引擎是什么?

作为总体趋势,现有二进制文件中广泛使用的任何指令都会激励 CPU 设计人员提高其速度。例如,Pentium 4 试图让大家停止使用 INC/DEC;那不起作用;当前的 CPU 比以往更好地进行部分标志重命名。现代 x86 晶体管和功率预算可以支持这种复杂性,至少对于大核 CPU(不是 Atom / Silvermont)来说是这样。不幸的是,我认为对于诸如以下指令的错误依赖关系(在目的地上)没有任何希望sqrtss or cvtsi2ss, 尽管。


在指令中显式使用堆栈指针,例如add rsp, 8需要Intel CPU中的堆栈引擎插入同步微指令来更新寄存器的乱序后端值。如果内部偏移量太大,则相同。

In fact pop dummy_register is more效率比add rsp, 8 or add esp,4在现代 CPU 上,因此编译器通常会使用它来通过默认调整或使用-march=sandybridge例如。为什么这个函数将RAX压入堆栈作为第一个操作?

也可以看看什么 C/C++ 编译器可以使用 push pop 指令来创建局部变量,而不是只增加 esp 一次?回复:使用push初始化堆栈上的局部变量而不是sub rsp, n / mov。在某些情况下,这可能是一个胜利,特别是对于值较小的代码大小,但编译器不会这样做。


另外,不,GCC / clang 不会生成这样的代码exactly就像你所展示的那样。

如果他们需要在函数调用周围保存寄存器,他们通常会使用mov记忆。或者mov到他们保存在函数顶部的调用保留寄存器,并将在最后恢复。

除了传递堆栈参数之外,我从未见过 GCC 或 clang 在函数调用之前推送多个被调用破坏的寄存器。并且绝对不会在之后多次弹出以恢复到相同(或不同)寄存器中。函数内部的溢出/重新加载通常使用 mov。这避免了在循环内推送/弹出的可能性(除了将堆栈参数传递给call),并允许编译器进行分支,而不必担心推送与弹出的匹配。它还降低了堆栈展开元数据的复杂性,该元数据必须为移动 RSP 的每条指令都有一个条目。 (使用 RBP 作为传统帧指针时,指令数与元数据和代码大小之间的有趣权衡。)

某物like您的代码生成可以通过调用保留的寄存器+一些reg-reg在一个小函数中移动来看到,该函数只是调用另一个函数,然后返回一个__int128那是寄存器中的函数arg。因此,需要保存传入的 RSI:RDI,以便以 RDX:RAX 形式返回。

或者,如果在非内联函数调用后存储到全局或通过指针,编译器还需要保存函数参数直到调用之后。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么使用push/pop而不是sub和mov? 的相关文章

随机推荐

  • 通过字符串引用类名?

    我需要解析一些文本文件 为文本中遇到的各种实体创建对象 并将它们放入某种数据结构 例如列表 中以进行进一步处理 文本示例 laptop 17 dell weight 12 lb desktop 24 hp 我事先知道文本中可能存在哪些实体
  • 使用 Polybase 将数据并行加载到现有表中

    使用 CTAS 我们可以利用 Polybase 提供的并行性将数据加载到new以高度可扩展和高性能的方式创建表 有没有办法使用类似的方法将数据加载到existing桌子 桌子甚至可能是空的 创建外部表并使用INSERT INTO SELEC
  • 一个 StringToken 解析器,它提供 Google 搜索样式“您的意思是:”建议

    寻求一种方法 在字符串中采用空格分隔的标记 返回建议的单词 ie 谷歌搜索可以采取 拼音词翻译 并在结果页面顶部显示 您是说 拼音词翻译器 首选使用任何 C 语言或 Java 的解决方案 是否有任何现有的开放库可以执行此类功能 或者有没有办
  • 如何同时使用 Git 和 Dropbox? [关闭]

    Closed 这个问题需要细节或清晰度 目前不接受答案 Locked 这个问题及其答案是locked因为这个问题是题外话 但却具有历史意义 目前不接受新的答案或互动 是否可以使用Git and Dropbox一起 我认为 Dropbox 上
  • WinRT 8.1 手机 - ListView 重新排序

    我需要在使用 WinRT 创建的 Windows Phone 8 1 应用程序中创建可重新排序的 ListView XAML 如下 它绑定到代码隐藏中的 ObservableDictionary
  • 如何在 Android 中使用 Google Places API for Web 服务?

    如何使用此链接返回 json 格式的结果 我已经有一个服务器密钥 但它一直显示 此 IP 站点或移动应用程序无权使用此 API 密钥 集成 Google Places API 的官方方式是通过 Android 实现 你可以使用地点选择器这是
  • 使用 df2 的日期时间中 df1 的“小时”和“分钟”的条件合并 2 个数据帧

    我有一个数据框df sample像这样 id lt c A A A A A A A A A A A date lt c 2018 11 12 2018 11 12 2018 11 12 2018 11 12 2018 11 12 2018
  • 确定与 COM RPC 服务器通信的客户端进程的进程 ID

    在COM RPC模型中 如果服务器运行在单独的进程上 是否有可能知道与服务器通信的客户端进程的进程ID Use Case 我有一个进程外 RPC 服务器 它可以接收来自一个或多个客户端进程的请求 有时 服务器需要知道客户端进程使用以下命令将
  • 防止 input() 为字母字符以外的任何内容

    我试图为了自我认识而制作一个程序 我想问用户他们的名字是什么 并且我只希望用户能够使用字母表中的字母来回答 或者仅使用字符串 我不希望他们能够用数字 符号等来回答 def cc name input Hello what happens t
  • 为 C++ 标准库配置 clang-check

    我正在尝试运行 Ale 作为我的 linter 它又使用 clang check 来检查我的代码 clang check FeatureManager h Error while trying to load a compilation d
  • 使用自定义列表使用 ItemSource 之前,项目集合必须为空

    在我的班级里ResultEntity如果我做 resultMulti new List
  • 张量流:ValueError:用序列设置数组元素

    我正在使用来自的固定代码这个问题 我收到上述错误 谷歌搜索表明这可能是某种尺寸不匹配 尽管我的诊断没有显示任何 with tf Session as sess sess run init Fit all training data for
  • 将二维码传输到 MySql 数据库

    我一直在试图找出将扫描的 QR 文本文件放入 MySql 数据库的最简单方法 我希望应用程序做的是使用移动设备扫描二维码 然后将扫描的图像保存到文件中 然后将其添加到 MySql 驱动数据库中 有没有一个应用程序可以为我此类项目奠定基础 非
  • 攻击实验室中操作码末尾的 c3

    我正在开发攻击实验室的一个版本 对于阶段 4 和 5 在农场操作中 我有几个以 c3 结尾的操作 但后面还有一个单独的操作retq c3 指令如下 0000000000401a6e
  • XPath:: 获取以下同级

    我有以下 HTML 结构 我正在尝试构建一个强大的方法来提取第二个颜色摘要元素 因为 DOM 中会有许多这样的标签 table tbody tr tr tr tr tr td Color Digest td td AgArAQICGQMVB
  • 对于闪亮仪表板的特定选项卡完全禁用右侧边栏功能

    我下面有一个闪亮的仪表板 我想知道是否有一种方法可以在选择特定选项卡时默认隐藏左侧和右侧边栏 在这种情况下 选项卡 Front 我用它做了shinyJs 有没有办法也隐藏 gear 图标以及从根本上打开右侧边栏的能力 Front 更具体地说
  • 找到两个给定节点之间的路径?

    假设我有以下方式连接的节点 如何获得给定点之间存在的路径数量以及路径详细信息 1 2 node 1 and 2 are connected 2 3 2 5 4 2 5 11 11 12 6 7 5 6 3 6 6 8 8 10 8 9 找到
  • 在python中绘制热图

    我有两个列表 x y 代表二维坐标 例如x 1 4 0 5 2 5 10 33 0 04 and y 2 5 44 0 33 2 14 20 0 03 x i and y i 代表二维中的一个点 现在我还有一个表示每个 x y 点的 热 值
  • 雅虎财经网络服务消失了吗? API变了?暂时下降?

    相当长一段时间以来 我一直在使用以下 REST API 来查询雅虎财经的当前价格 它在多个 Stack Overflow 帖子中都有记录 例如雅虎财经网络服务以及其他地方雅虎财经 http finance yahoo com webserv
  • 为什么使用push/pop而不是sub和mov?

    当我使用不同的编译器时https godbolt org 我注意到编译器生成这样的代码是很常见的 push rax push rbx push rcx call rdx pop rcx pop rbx pop rax 我明白每个push o