GCC编译步骤详解

    技术2022-05-19  25

    我们知道C/C++代码编译要经过4个步骤:预处理、编译、汇编、连接。 我们一般编译程序的时候大多通过编译器的一步操作就完成这4步操作,这反而让我们不太注意编译的具体过程。 我们这里详细看一下编译的每个步骤都发生了什么。 先写一个简单的helloworld.c helloworld.c------------------------ #include<stdio.h> int main(int argc, char* argv[]) {   printf("Hello World/n");   return 0; } ----------------------------------------- 如果简单的用gcc编译,一般看到的编译和执行结果是这样简单。 $ gcc helloworld.c -o helloworld $ ./helloworld Hello World 现在我们在编译的时候在gcc后面加上-v参数看一下编译的详细过程: $ gcc -v helloworld.c -o helloworld ---------------------------------------------------- Using built-in specs. Target: i486-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.4.3-4ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --program-suffix=-4.4 --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i486 --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu Thread model: posix gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) COLLECT_GCC_OPTIONS='-v' '-o' 'helloworld' '-mtune=generic' '-march=i486'  /usr/lib/gcc/i486-linux-gnu/4.4.3/cc1 -quiet -v helloworld.c -D_FORTIFY_SOURCE=2 -quiet -dumpbase helloworld.c -mtune=generic -march=i486 -auxbase helloworld -version -fstack-protector -o /tmp/cctE4Jk2.s GNU C (Ubuntu 4.4.3-4ubuntu5) version 4.4.3 (i486-linux-gnu)     compiled by GNU C version 4.4.3, GMP version 4.3.2, MPFR version 2.4.2-p1. GGC heuristics: --param ggc-min-expand=97 --param ggc-min-heapsize=126998 ignoring nonexistent directory "/usr/local/include/i486-linux-gnu" ignoring nonexistent directory "/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../i486-linux-gnu/include" ignoring nonexistent directory "/usr/include/i486-linux-gnu" #include "..." search starts here: #include <...> search starts here:  /usr/local/include  /usr/lib/gcc/i486-linux-gnu/4.4.3/include  /usr/lib/gcc/i486-linux-gnu/4.4.3/include-fixed  /usr/include End of search list. GNU C (Ubuntu 4.4.3-4ubuntu5) version 4.4.3 (i486-linux-gnu)     compiled by GNU C version 4.4.3, GMP version 4.3.2, MPFR version 2.4.2-p1. GGC heuristics: --param ggc-min-expand=97 --param ggc-min-heapsize=126998 Compiler executable checksum: 5998ce5f1765e99eea5269f4c1e38d44 COLLECT_GCC_OPTIONS='-v' '-o' 'helloworld' '-mtune=generic' '-march=i486'  as -V -Qy -o /tmp/ccc02j4Q.o /tmp/cctE4Jk2.s GNU assembler version 2.20.1 (i486-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.20.1-system.20100303 COMPILER_PATH=/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../:/lib/:/usr/lib/:/usr/lib/i486-linux-gnu/ COLLECT_GCC_OPTIONS='-v' '-o' 'helloworld' '-mtune=generic' '-march=i486'  /usr/lib/gcc/i486-linux-gnu/4.4.3/collect2 --build-id --eh-frame-hdr -m elf_i386 --hash-style=both -dynamic-linker /lib/ld-linux.so.2 -o helloworld -z relro /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crt1.o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crti.o /usr/lib/gcc/i486-linux-gnu/4.4.3/crtbegin.o -L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../.. -L/usr/lib/i486-linux-gnu /tmp/ccc02j4Q.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i486-linux-gnu/4.4.3/crtend.o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crtn.o ----------------------------------------------------- 从输出信息里可以看到里面实际执行的步骤有: 1.  /usr/lib/gcc/i486-linux-gnu/4.4.3/cc1 -quiet -v helloworld.c -D_FORTIFY_SOURCE=2 -quiet -dumpbase helloworld.c -mtune=generic -march=i486 -auxbase helloworld -version -fstack-protector -o /tmp/cctE4Jk2.s 2.  as -V -Qy -o /tmp/ccc02j4Q.o /tmp/cctE4Jk2.s 3.   /usr/lib/gcc/i486-linux-gnu/4.4.3/collect2 ............. 第1步是用cc1,进行预处理和编译 第2步是用as进行汇编 第3步是用collect2进行连接操作 其中第一步可以cc1实际进行了两步操作,预处理和连接,它实际上可以分成两步单独执行。 cpp -o helloworld.i helloworld.c cc1 hw.i -o /tmp/cctE4Jk2.s cpp的结果是对代码进行预处理,#define之类的宏在这里被预处理。 预处理的结果包含进来了那些#include进来的代码,这导致一个helloworld.i里面很长,可以打开看看。 类似这样的一段代码: ---------------------------------------------------------------------------------- 这是截取的代码最后一段: extern char *ctermid (char *__s) __attribute__ ((__nothrow__)); # 886 "/usr/include/stdio.h" 3 4 extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__)); extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__)) ; extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__)); # 916 "/usr/include/stdio.h" 3 4 # 2 "helloworld.c" 2 int main(int argc, char* argv[]) {   printf("Hello World/n");   return 0; } ---------------------------------------------------------------------------------- 第1步结果cc1的结果cctE4Jk2.s中是生成的汇编语言, inline内联函数在编译阶段被处理。 本例的汇编结果如下: ---------------------------------------------------------         .file   "helloworld.c"         .section        .rodata .LC0:         .string "Hello World"         .text .globl main         .type   main, @function main:         pushl  

    转载请注明原文地址: https://ibbs.8miu.com/read-2215453.html

    最新回复(0)