【发布时间】:2015-09-18 22:22:30
【问题描述】:
我正在尝试从初级学习汇编的工作原理,因此我一直在玩 gcc 编译的-S 输出。我编写了一个简单的程序,它定义了两个字节并返回它们的总和。整个程序如下:
int main(void) {
char A = 5;
char B = 10;
return A + B;
}
当我在没有优化的情况下编译它时:
gcc -O0 -S -c test.c
我得到如下所示的 test.s:
.file "test.c"
.def ___main; .scl 2; .type 32; .endef
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $16, %esp
call ___main
movb $5, 15(%esp)
movb $10, 14(%esp)
movsbl 15(%esp), %edx
movsbl 14(%esp), %eax
addl %edx, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE0:
.ident "GCC: (GNU) 4.9.2"
现在,认识到这个程序可以很容易地简化为只返回一个常量 (15),我已经能够使用以下代码手动减少程序集以执行相同的功能:
.global _main
_main:
movl $15, %eax
ret
在我看来,这似乎是执行这项公认微不足道的任务的最少代码量(但我意识到这可能是非常错误的)。这种形式是我的 C 程序最“优化”的版本吗?
为什么 GCC 的初始输出如此冗长?从.cfi_startproc 到call __main 的行甚至可以做什么? call __main 是做什么的?我不知道这两个减法运算是干什么用的。
即使将 GCC 中的优化设置为 -O3 我也明白了:
.file "test.c"
.def ___main; .scl 2; .type 32; .endef
.section .text.unlikely,"x"
LCOLDB0:
.section .text.startup,"x"
LHOTB0:
.p2align 4,,15
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
call ___main
movl $15, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE0:
.section .text.unlikely,"x"
LCOLDE0:
.section .text.startup,"x"
LHOTE0:
.ident "GCC: (GNU) 4.9.2"
这似乎删除了一些操作,但仍然留下了所有通往call __main 的行,这似乎是不必要的。 所有.cfi_XXX 行是干什么用的?为什么要添加这么多标签? .section、.ident、.def .p2align等有什么作用?
我知道许多标签和符号都包含在调试中,但如果我没有启用 -g 进行编译,难道不应该删除或省略这些标签和符号吗?
更新
说清楚
在我看来,这可能是最少的代码(但我 意识到可能是完全错误的)来执行这个公认的微不足道的任务。 这种形式是我的 C 程序最“优化”的版本吗?
我并不是说我正在尝试或已经实现了该程序的优化版本。我意识到这个程序是无用的和微不足道的。我只是将它用作学习汇编和编译器工作原理的工具。
我添加这个位的核心是为了说明为什么我很困惑这个汇编代码的4行版本可以有效地达到与其他版本相同的效果。在我看来,GCC 添加了很多我无法辨别其目的的“东西”。
【问题讨论】:
-
调试。优化是调试器最大的敌人。所有这些冗余的、有据可查的行使调试汇编就像调试 C 一样容易。对于第二个问题,C 程序使用 C 运行时,它们需要遵守 ABI 并且可能使用操作系统特定的功能。
-
@WeatherVane 我的意图并不是说这个程序在任何方面都有意义或有用,我只是将它用作学习汇编和编译器工作原理的工具。
-
@Kin3TiX 抱歉,删除了我的粗话。
标签: c gcc assembly x86-64 gnu-assembler