博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
GCC编译过程与链接过程
阅读量:563 次
发布时间:2019-03-09

本文共 5714 字,大约阅读时间需要 19 分钟。

编译过程

  • 预处理
    C/C++源文件中,以“#”开头的命令被称为预处理命令,如包含命令“#include"、宏定义命令“#define”、条件编译命令“#if"、 “#ifdef"等。预处理就是将要包含(include) 的文件插入原文件中、将宏定义展开、根据条件编译命令选择要使用的代码,最后将这些代码输出到一个 “.i”文件中等待进一步 处理。预处理将用到arm-linux-cpp工具。
  • 编译
    编译就是把C/C++代码(比如上述的“i”文件)“翻译”成汇编代码,所用到的工具为ccl
  • 汇编
    汇编就是将第二步输出的汇编代码翻译成符合–定格式的机器代码,在Linux系统上一般表现为ELF目标文件(OBJ文件),用到的工具为arm-linux-as。“反汇编”是指将机器代码转换为汇编代码,这在调试程序时常常用到。
  • 链接
    连接就是将上步生成的OBJ文件和系统库的OBJ文件、库文件连接起来,最终生成可
    以在特定平台运行的可执行文件,用到的工具为arm-linux-ld

gcc使用方法

  • gcc的使用方法:
    gcc [选项] 文件名
    gcc常用选项
    -v:查看gcc编译器的版本,显示gcc执行时的详细过程
    -o Place the output into
    指定输出文件名为file,这个名称不能跟源文件名同名
    -E Preprocess only; do not compile, assemble or link
    只预处理,不会编译、汇编、链接
    -S Compile only; do not assemble or link
    只编译,不会汇编、链接
    -c Compile and assemble, but do not link
    编译和汇编,不会链接
  • 编译过程:hello.c-(预处理)>hello.i-(编译)>hello.s-(汇编)>hello.o-(链接)>hello
    .o:object file(OBJ文件)
    1)输入文件的后缀名和选项共同决定gcc到底执行那些操作
    2)在编译过程中,除非这使用了-E、-S、-c(或者编译出错阻止了完整的编译过程)
    否则最后的步骤都是链接
  • 方式1:
gcc hello.c //输出一个a.out 然后./a.out来执行该应用程序gcc -o hello hello.c //输出hello,然后./hello来执行该应用程序
  • 方式2:
gcc -E -o hello.i hello.c  //预处理为hello.igcc -S -o hello.s hello.i  ///将hello.i编译为hello.sgcc -c -o hello.o hello.s  gcc -o hello hello.o
  • 方式3(常用)
gcc -c -o hello.o hello.cgcc -o hello hello.o
gcc会对.c文件默认进行预处理操作,-c再来指明了编译、汇编,从而得到.o文件再通过gcc -o hello hello.o将.o文件进行链接,得到可执行应用程序

链接过程

  • 链接就是将汇编生成的OBJ文件、系统库的OBJ文件、库文件链接起来,最终生成可以在特定平台运行的可执行程序
  • 加入-v选项来查看整个链接过程
gcc -v -o hello hello.o
Using built-in specs.COLLECT_GCC=gccCOLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapperTarget: x86_64-linux-gnuConfigured with: ../src/configure -v --with-pkgversion='Ubuntu 5.4.0-6ubuntu1~16.04.4' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnuThread model: posixgcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/5/:/usr/lib/gcc/x86_64-linux-gnu/5/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/5/:/usr/lib/gcc/x86_64-linux-gnu/LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/5/:/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/5/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/5/../../../:/lib/:/usr/lib/COLLECT_GCC_OPTIONS='-v' '-o' 'hello' '-mtune=generic' '-march=x86-64' /usr/lib/gcc/x86_64-linux-gnu/5/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/5/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper -plugin-opt=-fresolution=/tmp/ccbhavbV.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 --sysroot=/ --build-id  --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed  -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z relro  -o hello  /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o  /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o  /usr/lib/gcc/x86_64-linux-gnu/5/crtbegin.o  -L/usr/lib/gcc/x86_64-linux-gnu/5  -L/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu  -L/usr/lib/gcc/x86_64-linux-gnu/5/../../../../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/5/../../..   hello.o  -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed  /usr/lib/gcc/x86_64-linux-gnu/5/crtend.o  /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crtn.obook@www.100ask.org:/work/gcc_options/1th$
  • 其中crt1.o、crti.o、crtbegin.o、crtend.o、ortn.o是gcc加入的系统标准启动文件,对于一般应用程序,这些启动是必需的
  • 在链接过程中有个-lc选项,链接libc库文件,其中libc库文件中就实现了printf等函数
  • gcc -v -nostdlib -o hello hello.o会提示因为没有链接系统标准启动文件和标准库文件,而链接失败。
    这个-nostdlib选项常用于裸机/BootLoader、linux内核等程序,因为它们不需要启动文件、标准库文件。
    一般应用程序才需要系统标准启动文件和标准库文件。
    裸机/BootLoader、linux内核等程序不需要启动文件、标准库文件。
  • 查看hello.c链接的库 ldd hello 查看hello用到哪些动态库文件
guest-kpkiwy@book-virtual-machine:~/xiaoma$ ldd hello	linux-vdso.so.1 =>  (0x00007ffe0e5c8000)	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7dc9fab000)	/lib64/ld-linux-x86-64.so.2 (0x00007f7dca375000)
  • 其中.so为动态库
  • 动态链接使用动态链接库进行链接,生成的程序在执行的时候需要加载所需的动态库才能运行。动态链接生成的程序体积较小,但是必须依赖所需的动态库,否则无法执行。
  • 静态链接使用静态库进行链接,生成的程序包含程序运行所需要的全部库,可以直接运行, 不过静态链接生成的程序体积较大。
guest-kpkiwy@book-virtual-machine:~/xiaoma$ gcc -o hello_shared hello.cguest-kpkiwy@book-virtual-machine:~/xiaoma$ gcc -static -o hello_static hello.cguest-kpkiwy@book-virtual-machine:~/xiaoma$ ls -l hello*-rwxrwxr-x 1 guest-kpkiwy guest-kpkiwy   8600 12月 30 15:41 hello-rw-rw-r-- 1 guest-kpkiwy guest-kpkiwy     76 12月 30 15:40 hello.c-rwxrwxr-x 1 guest-kpkiwy guest-kpkiwy   8600 12月 30 15:45 hello_shared-rwxrwxr-x 1 guest-kpkiwy guest-kpkiwy 912720 12月 30 15:45 hello_static
  • 相比大小静态库程序体积大

转载地址:http://tpxpz.baihongyu.com/

你可能感兴趣的文章