每行之后似乎都有一个 .CFI 指令,并且这些指令的种类繁多,.cfi_startproc
、.cfi_endproc
等。more here。
.file "temp.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl $0, %eax
leave
ret
.cfi_endproc
.LFE0:
.size main, .-main
.globl func
.type func, @function
func:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
movl %esi, %eax
movb %al, -8(%rbp)
leave
ret
.cfi_endproc
.LFE1:
.size func, .-func
.ident "GCC: (Ubuntu 4.4.1-4ubuntu9) 4.4.1"
.section .note.GNU-stack,"",@progbits
我没有明白这些的目的。
要禁用这些,请使用 gcc 选项
-fno-asynchronous-unwind-tables
-fno-dwarf2-cfi-asm
也可能需要。
我感觉它代表 Call Frame Information 并且是管理调用帧的 GNU AS 扩展。从 DeveloperWorks:
在某些体系结构上,必须使用调用帧信息指令来管理异常处理。这些指令在程序集中用于指导异常处理。如果由于某种原因(例如代码库的可移植性),GCC 生成的异常处理信息不足,这些指令在 Linux on POWER 上可用。
看起来这些是在某些平台上根据异常处理的需要生成的。
如果您希望禁用这些,请参阅 David's answer。
:
可以看出)。请参阅stackoverflow.com/a/15285058/4294399
CFI 指令用于调试。它允许调试器展开堆栈。例如:如果过程 A 调用过程 B,过程 B 然后调用公共过程 C。过程 C 失败。您现在想知道谁实际呼叫了 C,然后您可能想知道谁呼叫了 B。
调试器可以通过使用堆栈指针 (%rsp) 并注册 %rbp 来展开此堆栈,但是它需要知道如何找到它们。这就是 CFI 指令的用武之地。
movq %rsp, %rbp
.cfi_def_cfa_register 6
所以这里的最后一行告诉它“调用帧地址”现在在寄存器 6 (%rbp)
-fomit-frame-pointer
编译的代码展开堆栈,作为 RBP 的替代方法(在 gcc 或 clang -O1
及更高版本中默认启用)。它被 C++ 异常处理以及调试器/分析器使用。在带有传统 RBP 帧指针的代码中,当前 RBP 值总是指向一个保存的 RBP 值,而该值指向前一个值,形成一个链表。在这种情况下,不需要 CFI。 (尽管在使用帧指针的函数中,CFI cfa_register 避免了每次 RSP 更改都需要更多元数据,就像您展示的那样。)
要禁用这些,g++ 需要 -fno-exceptions
以及前面提到的 -fno-asynchronous-unwind-tables
,前提是您不使用异常。
好吧,它只是代表控制流完整性。它们本质上是传递给调试器和其他工具的信息项,用于描述程序的预期流程。
endbr
)的 Intel CFE(控制流强制)。我不认为任何控制流完整性的东西都使用 .cfi_*
指令生成的堆栈展开元数据。
.eh_frame
展开信息。另见 What are CFI directives in Gnu Assembler (GAS) used for? / What do the CFI directives mean? (and some more questions)(遗憾的是 GAS 手册 section for them 没有扩展首字母缩写词)
不定期副业成功案例分享
-fno-dwarf2-cfi-asm