gcc、g++中生成ASM代码需要什么

Alo*_*lok 1 c++ assembly gcc g++

为了缩小我的问题范围,让我描述一下我的假设和我所做的实验......

我的假设:用汇编语言编写的代码将比 C/C++ 对应的代码运行得快得多,并且可执行文件的大小也比 C/C++ 代码生成的代码小得多。

实验:我将以下程序写入bin2dec.c

#include <stdio.h>

int main()
{
    long int binary, decimal, reminder, exp;
    int i, j;

    for(i=0; i<10000; i++)
    {
        for(j=0; j<1000; j++)
        {
            binary = 11000101;

            exp = 1;
            decimal = 0;

            while(binary != 0)
            {
                reminder = binary % 10;
                binary = binary / 10;
                decimal = decimal + reminder * exp;
                exp *= 2;
            }   
        }
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

然后为其生成ASM代码gcc -S bin2dec.c -o bin2dec.s

之后我编译了两个文件,如下所示

gcc bin2dec.c -o bin2dec_c
gcc bin2dec.s -o bin2dec_s
Run Code Online (Sandbox Code Playgroud)

测试1:找出两个文件的一些内部细节

[guest@localhost ASM]$ size bin2dec_c bin2dec_s
   text    data     bss     dec     hex filename
    951     252       4    1207     4b7 bin2dec_c
    951     252       4    1207     4b7 bin2dec_s
Run Code Online (Sandbox Code Playgroud)

结果:两者完全相同...

测试2:执行文件并计算所花费的时间

[guest@localhost ASM]$ time ./bin2dec_c
real    0m1.724s
user    0m1.675s
sys     0m0.002s

[guest@localhost ASM]$ time ./bin2dec_s
real    0m1.721s
user    0m1.676s
sys     0m0.001s
Run Code Online (Sandbox Code Playgroud)

结果:两者相同。有时,从 ASM 生成的可执行文件运行速度较慢:-(

那么问题来了,我的假设是否错误呢?如果不是,我犯了什么错误,使得可执行文件 bin2dec_c 和 bin2dec_s 以相同的速度运行?有没有更好的方法从 C/C++ 程序获取 ASM 代码,或者我应该在 ASM 中从头开始重写所有逻辑,以获得速度和程序大小的优势?

Bas*_*tch 5

这是一个古老的传统(在 20 世纪 70 年代的早期 Unix 系统上,机器很小,生成一些汇编文件更简单),并且一些编译器可以直接生成目标文件或机器代码;可能是Clang/LLVMTinyCC的最新版本(仅适用于 C:编译时间快,但可执行速度非常慢!)也许是 IBM 的一些专有 XLC 编译器,GCC 社区中的一些人正在考虑这一点(特别是GCCJIT) 。

然而,对于编译器开发人员来说,生成汇编程序文件通常更容易。由于大多数编译器工作发生在优化过程中(正在转换编译器中的一些内部表示),因此启动汇编器损失几毫秒并不是很重要。

使用GCC,使用gcc -timegcc -ftime-report(当然还有常用的优化标志,例如-O2)进行编译,以了解编译器将时间花在哪里。它从来不在汇编器中......

有时您可能会发现查看生成的汇编程序文件很有用。编译foo.ccC++11 文件,g++ -O2 -Wall -S -fverbose-asm -std=c++11 foo.cc然后查看(使用某些编辑器或分页器)生成的foo.s汇编程序文件。

您甚至可以使用GCCg++ -fdump-tree-all -O2进行编译并获取数百个编译器转储文件,解释编译器对您的代码进行了哪些转换。

顺便说一句,当今的(超标量、流水线)处理器(台式机、笔记本电脑、平板电脑、服务器中的处理器)非常复杂,实际上编译器可以比人类程序员更好地优化。因此,实际上,优化编译器根据一些实际大小的 C 代码(例如几百行的 C 源文件)生成的汇编代码通常比经过实验的汇编程序人类程序员在几周内编写的代码(不到一千行)要快。装配线)。换句话说,您的假设(人类用汇编程序编写的代码比人类用 C 语言编写并由良好的优化编译器编译的代码更快/更好)在实践中错误的

(顺便说一句,优化编译器可以将bin2dec.c没有可观察到的副作用(例如没有输入和输出)的程序转换为空程序,GCC 5.2可以通过 !! 来实现这一点gcc -O2!)

另请阅读有关停止问题赖斯定理的内容。优化编译器或静态程序分析器可以实现的目标存在固有的限制。

  • 能够生成汇编代码对于理解生成的代码和调试可能的编译器错误非常重要。不需要付出额外的努力来直接生成机器代码而不需要经过汇编,这可能是一些编译器供应商避免的麻烦。 (5认同)
  • @DavidSchwartz:更重要的是,您可以使用 gcc/clang 的“-fverbose-asm”等编译器选项,其中编译器将根据其决定生成该 asm 的方式向 asm 添加注释。(例如哪个源变量名称正在加载到寄存器中)。仅编译为机器代码然后反汇编是不容易做到的。 (2认同)