gcc 是一个很庞大的项目,包含了很多模块和组件,我是第一次阅读这么大的项目,所以我决定跟着 GCC for New Contributors — GCC Contributors Guide 0.1 documentation 先来了解一个大概
我使用的 gcc 版本如下
1 gcc.exe (MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders, r5) 15.2.0
wsl 中下载了两个
1 2 gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0 gcc-15 (Ubuntu 15.2.0-14ubuntu1~24~ppa1) 15.2.0
一般后面的程序运行我都会使用 wsl 上的 gcc-15 进行编译
二进制和程序 简单的 c 程序:
1 2 3 4 5 6 #include <stdio.h> int main () { printf ("hello world\n" ); return 0 ; }
使用 gcc 编译时
1 2 3 4 5 gcc hello.c -o hello ls hello hello.c ./hello hello world
看起来很简单,但是其实发生了很多操作,gcc 的 C 编译器将 ,c 文件编译到汇编器中,生成 .cc1 的二进制文件,然后汇编器将 .cc1 文件编译成 .s 的汇编文件,最后链接器将 .s 文件链接成可执行文件 hello(ELF文件)
这个二过程可以通过 -v 参数来查看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 Using built-in specs. COLLECT_GCC=gcc-15 COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-linux-gnu/15/lto-wrapper OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 15.2.0-14ubuntu1~24~ppa1' --with-bugurl=file:///usr/share/doc/gcc-15/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2,rust,cobol,algol68 --prefix=/usr --with-gcc-major-version-only --program-suffix=-15 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-15-9rFPkZ/gcc-15-15.2.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-15-9rFPkZ/gcc-15-15.2.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2 Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 15.2.0 (Ubuntu 15.2.0-14ubuntu1~24~ppa1) COLLECT_GCC_OPTIONS='-o' 'hello' '-v' '-mtune=generic' '-march=x86-64' /usr/libexec/gcc/x86_64-linux-gnu/15/cc1 -quiet -v -imultiarch x86_64-linux-gnu hello.c -quiet -dumpbase hello.c -dumpbase-ext .c -mtune=generic -march=x86-64 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/ccazwD5q.s GNU C23 (Ubuntu 15.2.0-14ubuntu1~24~ppa1) version 15.2.0 (x86_64-linux-gnu) compiled by GNU C version 15.2.0, GMP version 6.3.0, MPFR version 4.2.1, MPC version 1.3.1, isl version isl-0.26-GMP GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu" ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/15/include-fixed/x86_64-linux-gnu" ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/15/include-fixed" ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/15/../../../../x86_64-linux-gnu/include" /usr/lib/gcc/x86_64-linux-gnu/15/include /usr/local/include /usr/include/x86_64-linux-gnu /usr/include End of search list. Compiler executable checksum: 9f19bc9cfc443ddd3de419fa42b46591 COLLECT_GCC_OPTIONS='-o' 'hello' '-v' '-mtune=generic' '-march=x86-64' /usr/bin/x86_64-linux-gnu-as -v --64 -o /tmp/ccBZEtx5.o /tmp/ccazwD5q.s GNU assembler version 2.42 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.42 COMPILER_PATH=/usr/libexec/gcc/x86_64-linux-gnu/15/:/usr/libexec/gcc/x86_64-linux-gnu/15/:/usr/libexec/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/15/:/usr/lib/gcc/x86_64-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/15/:/usr/lib/gcc/x86_64-linux-gnu/15/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/15/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/15/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-o' 'hello' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'hello.' /usr/libexec/gcc/x86_64-linux-gnu/15/collect2 -plugin /usr/libexec/gcc/x86_64-linux-gnu/15/liblto_plugin.so -plugin-opt=/usr/libexec/gcc/x86_64-linux-gnu/15/lto-wrapper -plugin-opt=-fresolution=/tmp/cceF2KPL.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o hello /usr/lib/gcc/x86_64-linux-gnu/15/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/15/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/15/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/15 -L/usr/lib/gcc/x86_64-linux-gnu/15/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/15/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/15/../../.. -L/lib -L/usr/lib /tmp/ccBZEtx5.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/15/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/15/../../../x86_64-linux-gnu/crtn.o COLLECT_GCC_OPTIONS='-o' 'hello' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'hello.'
一步一步拆解这个输出
1 2 3 4 5 6 7 8 9 10 11 Using built-in specs. COLLECT_GCC=gcc-15 COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-linux-gnu/15/lto-wrapper OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 15.2.0-14ubuntu1~24~ppa1' --with-bugurl=file:///usr/share/doc/gcc-15/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2,rust,cobol,algol68 --prefix=/usr --with-gcc-major-version-only --program-suffix=-15 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-15-9rFPkZ/gcc-15-15.2.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-15-9rFPkZ/gcc-15-15.2.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2 Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 15.2.0 (Ubuntu 15.2.0-14ubuntu1~24~ppa1) COLLECT_GCC_OPTIONS='-o' 'hello' '-v' '-mtune=generic' '-march=x86-64'
这一部分是 gcc 编译器的配置信息和版本信息,这一大串其实包含了下面的信息
gcc 的版本是 15.2.0 系统和架构是 x86_64-linux-gnu 支持的语言有 c,ada,c++,go,d,fortran,objc,obj-c++,m2,rust,cobol,algol68 支持的线程模型是 posix 链接时优化 然后调用 cc1
1 /usr/libexec/gcc/x86_64-linux-gnu/15/cc1 -quiet -v -imultiarch x86_64-linux-gnu hello.c -quiet -dumpbase hello.c -dumpbase-ext .c -mtune=generic -march=x86-64 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/ccazwD5q.s
这个其实是一个命令,GCC 编译器内部组件 cc1 的命令行,cc1 是 GCC 的 C 语言编译器的前端,拆开来看这个命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 /usr/libexec/gcc/x86_64-linux-gnu/15/cc1 \ -quiet \ -v \ -imultiarch x86_64-linux-gnu hello.c \ -quiet \ -dumpbase hello.c \ -dumpbase-ext .c \ -mtune=generic \ -march=x86-64 \ -version \ -fasynchronous-unwind-tables \ -fstack-protector-strong \ -Wformat \ -Wformat-security \ -fstack-clash-protection \ -fcf-protection \ -o /tmp/ccazwD5q.s
来拆解一下:
/usr/libexec/gcc/x86_64-linux-gnu/15/cc1:这是 cc1,它不在系统的标准 PATH 路径中,而是被 gcc 驱动程序调用,用于将 C 代码编译为汇编代码
-quite :这个选项被提供了两次。它的作用是抑制编译器在处理过程中输出常规的调试信息到 stderr。如果没有该选项,cc1 会输出更多的内部处理信息
-v 启用详细输出模式,cc1 会向 stderr 输出大量信息,例如搜索路径、版本信息以及编译过程中的具体步骤
-imultiarch x86_64-linux-gnu:这个选项告诉 cc1 在编译过程中使用特定的多架构搜索路径,适用于 x86_64-linux-gnu 架构。这对于支持多架构的系统非常重要
hello.c 这个是输入文件,cc1 将编译这个 C 源文件
-dumpbase hello.c 告诉 cc1 在创建任何转储文件时,应该使用 hello.c 作为文件名的基础。默认情况下它不会创建任何转储文件
-dumpbase-ext .c 指定了转储文件的扩展名为 .c,其实意思是指定从 -dumpbase 设置的基础名称中移除的文件扩展名
-mtune=generic 特定于 x86 架构的调优选项,告诉编译器生成适合广泛 x86 处理器的代码,而不是针对特定处理器进行优化
-march=x86-64 指定目标架构为 x86-64,这会启用该架构特有的指令集和功能
-version 使 cc1 在标准错误输出(stderr)中打印详细的版本信息和配置说明
-fasynchronous-unwind-tables 启用异步展开表的生成,这对于支持异常处理和栈展开非常重要
-fstack-protector-strong 启用启用堆栈保护机制以防止缓冲区溢出攻击,比普通的 -fstack-protector 更严格,插入了更多的保护代码
-Wformat 和 -Wformat-security 这两个选项启用格式字符串相关的警告,前者启用对 printf、scanf 等格式字符串函数的参数类型检查,确保格式说明符与传入的参数类型匹配;后者增加对可能不安全的格式字符串使用的警告
-fstack-clash-protection 启用堆栈冲突保护机制,防止攻击者通过大量分配堆栈空间来触发堆栈溢出
-fcf-protection 启用控制流保护机制,防止攻击者通过修改返回地址或函数指针来改变程序的控制流,一种硬件辅助的安全特性
-o /tmp/ccazwD5q.s 指定输出文件为 /tmp/ccazwD5q.s,这是 cc1 生成的汇编代码文件,是一个临时文件,gcc 会在完成后续步骤(汇编和链接)后删除
可以在 Invoking GCC (Using the GNU Compiler Collection (GCC)) 中查看所有的选项,或者在命令行中使用 man gcc 来查看 gcc 的手册页,其中也包含了这些选项的说明
gcc 使用 -v 将 cc1 的输出直接发送到 stderr,所以我们可以看到 cc1 的版本信息和配置说明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 GNU C23 (Ubuntu 15.2.0-14ubuntu1~24~ppa1) version 15.2.0 (x86_64-linux-gnu) compiled by GNU C version 15.2.0, GMP version 6.3.0, MPFR version 4.2.1, MPC version 1.3.1, isl version isl-0.26-GMP GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu" ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/15/include-fixed/x86_64-linux-gnu" ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/15/include-fixed" ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/15/../../../../x86_64-linux-gnu/include" /usr/lib/gcc/x86_64-linux-gnu/15/include /usr/local/include /usr/include/x86_64-linux-gnu /usr/include End of search list. Compiler executable checksum: 9f19bc9cfc443ddd3de419fa42b46591
然后是对汇编器 as 的调用
1 /usr/bin/x86_64-linux-gnu-as -v --64 -o /tmp/ccBZEtx5.o /tmp/ccazwD5q.s
这只是说明输入 .s 文件,输出 .o 文件,并且启用详细输出
然后是链接器
1 2 3 4 5 COMPILER_PATH=/usr/libexec/gcc/x86_64-linux-gnu/15/:/usr/libexec/gcc/x86_64-linux-gnu/15/:/usr/libexec/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/15/:/usr/lib/gcc/x86_64-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/15/:/usr/lib/gcc/x86_64-linux-gnu/15/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/15/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/15/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-o' 'hello' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'hello.' /usr/libexec/gcc/x86_64-linux-gnu/15/collect2 -plugin /usr/libexec/gcc/x86_64-linux-gnu/15/liblto_plugin.so -plugin-opt=/usr/libexec/gcc/x86_64-linux-gnu/15/lto-wrapper -plugin-opt=-fresolution=/tmp/cceF2KPL.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o hello /usr/lib/gcc/x86_64-linux-gnu/15/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/15/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/15/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/15 -L/usr/lib/gcc/x86_64-linux-gnu/15/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/15/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/15/../../.. -L/lib -L/usr/lib /tmp/ccBZEtx5.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/15/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/15/../../../x86_64-linux-gnu/crtn.o COLLECT_GCC_OPTIONS='-o' 'hello' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'hello.'
在这种情况下,gcc 调用了 collect2 来链接生成最终的可执行文件 hello,collect2 是一个 GCC 的链接器驱动程序,它负责调用系统的链接器(如 ld)来完成链接过程,同时处理一些 GCC 特有的选项和功能,例如 LTO 插件和库的链接
这玩意比 cc1 还长,就不拆解命令是什么意思了,总之就是链接器的调用,链接器会将之前生成的 .o 文件和一些库文件链接成最终的可执行文件 hello
查看生成的汇编 我们可以使用 -S 选项来让 gcc 直接输出汇编代码,而不是生成可执行文件
1 2 3 gcc-15 -S hello.c ls hello hello.c hello.s
这里的步骤是这样的
1 2 cc1 hello.c -----> hello.s
查看一下汇编
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 .file "hello.c" .text .section .rodata .LC0: .string "hello world" .text .globl main .type main, @function main: .LFB0: .cfi_startproc endbr64 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 leaq .LC0(%rip), %rax movq %rax, %rdi call puts@PLT movl $0, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Ubuntu 15.2.0-14ubuntu1~24~ppa1) 15.2.0" .section .note.GNU-stack,"",@progbits .section .note.gnu.property,"a" .align 8 .long 1f - 0f .long 4f - 1f .long 5 0: .string "GNU" 1: .align 8 .long 0xc0000002 .long 3f - 2f 2: .long 0x3 3: .align 8 4:
可以看到,顶部有一些汇编指令和数据段的定义,.file 指令指定了源文件的名称,.text 指令表示接下来的代码段,.section .rodata 定义了一个只读数据段,其中包含了字符串 “hello world”,.globl main 声明了 main 函数是全局可见的,.type main, @function 指定了 main 是一个函数
main 函数的汇编代码从 main: 标签开始,首先是一些函数前置代码,例如保存栈帧和设置基指针,然后是加载字符串地址到寄存器并调用 puts 函数,最后是返回 0 并结束函数
最后还有一些元信息,例如 .ident 指令包含了编译器的版本信息,.section .note.GNU-stack 和 .section .note.gnu.property 定义了一些特殊的段,这些段通常用于指定栈的属性和其他元数据
可以使用 -fverbose-asm 选项来让 gcc 生成更详细的汇编注释,这样可以更容易理解每条指令的作用
1 gcc-15 -S hello.c -fverbose-asm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 .file "hello.c" # GNU C23 (Ubuntu 15.2.0-14ubuntu1~24~ppa1) version 15.2.0 (x86_64-linux-gnu) # compiled by GNU C version 15.2.0, GMP version 6.3.0, MPFR version 4.2.1, MPC version 1.3.1, isl version isl-0.26-GMP # GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 # options passed: -mtune=generic -march=x86-64 -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection -fcf-protection .text .section .rodata .LC0: .string "hello world" .text .globl main .type main, @function main: .LFB0: .cfi_startproc endbr64 pushq %rbp # .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp #, .cfi_def_cfa_register 6 # hello.c:4: printf ("hello world\n"); leaq .LC0(%rip), %rax #, tmp100 movq %rax, %rdi # tmp100, call puts@PLT # # hello.c:5: return 0; movl $0, %eax #, _3 # hello.c:6: } popq %rbp # .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Ubuntu 15.2.0-14ubuntu1~24~ppa1) 15.2.0" .section .note.GNU-stack,"",@progbits .section .note.gnu.property,"a" .align 8 .long 1f - 0f .long 4f - 1f .long 5 0: .string "GNU" 1: .align 8 .long 0xc0000002 .long 3f - 2f 2: .long 0x3 3: .align 8 4:
这下就可以关注 main() 的部分了
1 2 3 4 5 6 7 8 9 10 # hello.c:4: printf ("hello world\n"); leaq .LC0(%rip), %rax #, tmp100 movq %rax, %rdi # tmp100, call puts@PLT # # hello.c:5: return 0; movl $0, %eax #, _3 # hello.c:6: } popq %rbp # .cfi_def_cfa 7, 8 ret
cc1 gcc 是一个针对不同编程语言的编译器集合,支持 10 中源语言和 55 种 CPU 架构,由于不想编写 550 个编译器,所以会把 gcc 结构化为三个部分:
源语言的前端:负责解析源代码,进行语义分析和优化,生成中间表示(IR),例如 cc1 就是 C 语言的前端 特定目标的后端:负责将中间表示转换为特定目标架构的机器代码,例如 x86 后端 介于两者的中间端:负责在前端和后端之间进行优化和转换,例如 GIMPLE 和 RTL 因此,为 x86_64 构建的 cc1 包含了 C 前端、共享的优化代码和 x86_64 后端的代码
1 2 3 4 5 6 7 8 +-----+ +-| cc1 |--------------------------------------------------+ | +-----+ | | | | C 前端 优化器 x86_64 后端 | C 源代码 ====+==============> IR =============> IR ===================+==> x86_64 汇编 | | +----------------------------------------------------------+