函数消除
GCC 可以执行的另一种类型的死代码消除是删除整个未使用的符号(函数或变量),可以通过以下方式实现:
-fdata-sections -ffunction-sections -Wl,--gc-sections
如上所述: 如何使用 GCC 和 ld 删除未使用的 C/C++ 符号?
默认情况下, 这些标志在各个 GCC -O 级别(-O1、-O2 等)中未启用 .
另如图所示: GCC LTO 是否执行跨文件死代码消除? 如果某个函数由于 LTO 而被内联,那么它不会计入将编译单元放置在最终输出中。
让我们尝试一些函数内 DCE
让我们来测试一下 GCC 能做什么或不能做什么,这很有趣。测试 LLM 模型很无聊。
主程序
int main(int argc, char **argv) {
if (0) {
argc += 0x33;
}
return argc;
}
编译和反汇编:
gcc -O0 main.c
gdb -batch -ex 'disassemble/rs main' a.out
输出:
0x0000000000001129 <+0>: f3 0f 1e fa endbr64
0x000000000000112d <+4>: 55 push %rbp
0x000000000000112e <+5>: 48 89 e5 mov %rsp,%rbp
0x0000000000001131 <+8>: 89 7d fc mov %edi,-0x4(%rbp)
0x0000000000001134 <+11>: 48 89 75 f0 mov %rsi,-0x10(%rbp)
0x0000000000001138 <+15>: 8b 45 fc mov -0x4(%rbp),%eax
0x000000000000113b <+18>: 5d pop %rbp
0x000000000000113c <+19>: c3 ret
是的,它消失了。
其他一些:
在 中没有被移除 -O3
,它不知道 argc
必须为正:
int main(int argc, char **argv) {
if (argc >= 0) {
argc += 0x33;
}
return argc;
}
0x44 被删除 -O3
但没有被删除 -O4
,因此它可以执行 if/else 算术:
int main(int argc, char **argv) {
if (argc >= 0) {
argc += 0x33;
} else {
if (argc >= 0) {
argc += 0x44;
}
}
return argc;
}
删除了 0x33, -O3
以便可以执行范围和 +
:
int main(int argc, char **argv) {
if (argc < 10000) {
if (argc + 1 > 10000) {
argc += 0x33;
}
}
return argc;
}
0x33 未被删除,因此无法推断 sqrt
:
#include <math.h>
int main(int argc, char **argv) {
if (argc < 10000) {
if (sqrt(argc) > 100) {
argc += 0x33;
}
}
return argc;
}