gcc - gcc如何生成可以使用ENTER指令设置堆栈帧的程序集
问题描述
我用 gcc 生成这样的汇编代码, gcc 可以生成具有 ENTER 用于堆栈帧的代码吗?
.file "temp.c"
.text
.globl main
.type main, @function
main:
pushq %rbp
movq %rsp, %rbp
movl $0, -12(%rbp)
movl $0, -8(%rbp)
movl $0, -4(%rbp)
movl $0, %eax
popq %rbp
ret
.size main, .-main
.ident "GCC: (Ubuntu 7.4.0-1ubuntu1~18.04) 7.4.0"
.section .note.GNU-stack,"",@progbits
这是原始代码:
#include <stdio.h>
int main(){
int a;
int b;
int c;
a = 0;
b = 0;
c = 0;
}
解决方案
GCC 永远不会发射enter
,因为与 2 或 3 条单指令的正常帧指针设置相比,它的速度非常慢。
(如果它完全生成一个帧指针;gcc -O1
并且更高的启用-fomit-frame-pointer
。除了优化大小时,因为x(%rsp)
寻址模式使用额外的字节而不是x(%rbp)
模式。)
# equivalent to enter $24, $0 (4 bytes)
push %rbp # 1 byte
mov %rsp, %rbp # 3 bytes
sub $24, %rsp # 4 bytes only for a non-zero immediate
具体来说,在 Skylake 上enter
是 12 微指令,每 8 个周期的吞吐量为enter a, 0
(Agner Fog 的指令表)一个。对于非零嵌套级别,它非常慢,例如87 cycles + 7 * nesting level
.
在 Ryzen 上,enter
是 12 微指令,每 16 周期吞吐量一个。
leave
不过很好:在 Intel CPU 上只有 3 微指令。(这仍然比mov %rbp, %rsp
/多一个pop %rbp
。3 微指令不包括堆栈同步微指令;即使堆栈引擎之前同步,它也是 3。leave
)
使用的唯一原因enter
是以牺牲速度为代价优化代码大小。但即使gcc -Os
对代码大小也没有足够的关心,所以没有选择。
甚至clang -Oz
(将使用push $1
/pop %rax
来节省 2 个字节 vs. mov $1, %eax
)不使用enter
. (Godbolt 编译器资源管理器)
但enter 0,0
甚至不保存代码大小,所以它只是很糟糕。
我按照手册说程序开始输入 ENTER
这是一个(过时且不推荐)选项。
如果您想编写自己的编译器来生成慢速代码,请继续。
推荐阅读
- android-studio - 在 Android Studio 的外部库中禁用方法的警告 lint
- html - HTML:两行文本居中垂直对齐
- python-3.x - 无法在 Pandas 中塑造数据
- android - Android如何知道它必须将允许的vpn应用程序引导到tun0
- assembly - lui MIPS的故障
- java - 使用 JPA 创建和查询表 - 如何返回多行?
- javascript - bootstrap 4 通过 javascript 崩溃
- sqlite - SQLite 连接字符串不起作用。在“||”附近给出:语法错误
- php - I get parse error code within my php code
- sql - 加快将 XML 文件插入 SQL Server 表的速度