分析gcc -v的详细信息的意义

首先我们需要清楚一点,我们并不能完全弄清楚gcc -v的所有信息,因为毕竟我们并不是GCC编译器集合的实现者,对于这些信息,他们才是最清楚的。由于我们不能将所有的信息都搞清楚,所以我们只分析关键信息。虽然我们不能将所有信息都全部弄清楚,但是分析里面的关键信息还是非常有意义的,我们可以通过这些信息弄清楚很多事情,比如:

①通过这些信息,我就知道gcc其实最终还是调用ccp/cc1/as/collect2(或ld)等程序来实现编译的四个过程的。

②知道c的启动代码是怎么来的

③知道为什么在程序中调用printf、scanf、malloc等函数时,我们不需要主动链接这些函数的动态库,但是依然能够使用这些函数

gcc -v详细信息分析

源代码

#include <stdio.h>
#include <stdlib.h> #define NUM 100 int main()
{
#if 0
printf("Test condition macro\n");
#endif printf("Hello World\n");
return ;
}

gcc test.c -o test -v

[root@localhost ~]# gcc test.c -o test -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8./lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.8. (Red Hat 4.8.-) (GCC)
COLLECT_GCC_OPTIONS='-o' 'test' '-v' '-mtune=generic' '-march=x86-64'
/usr/libexec/gcc/x86_64-redhat-linux/4.8./cc1 -quiet -v test.c -quiet -dumpbase test.c -mtune=generic -march=x86- -auxbase test -version -o /tmp/cceAJij2.s
GNU C (GCC) version 4.8. (Red Hat 4.8.-) (x86_64-redhat-linux)
compiled by GNU C version 4.8. (Red Hat 4.8.-), GMP version 6.0., MPFR version 3.1., MPC version 1.0.
GGC heuristics: --param ggc-min-expand= --param ggc-min-heapsize=
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-redhat-linux/4.8./include
/usr/local/include
/usr/include
End of search list.
GNU C (GCC) version 4.8. (Red Hat 4.8.-) (x86_64-redhat-linux)
compiled by GNU C version 4.8. (Red Hat 4.8.-), GMP version 6.0., MPFR version 3.1., MPC version 1.0.
GGC heuristics: --param ggc-min-expand= --param ggc-min-heapsize=
Compiler executable checksum: 949efbe3007c23535d2d04d4c10b1f32
COLLECT_GCC_OPTIONS='-o' 'test' '-v' '-mtune=generic' '-march=x86-64'
as -v -- -o /tmp/ccL4wd1V.o /tmp/cceAJij2.s
GNU assembler version 2.27 (x86_64-redhat-linux) using BFD version version 2.27-.base.el7
COMPILER_PATH=/usr/libexec/gcc/x86_64-redhat-linux/4.8./:/usr/libexec/gcc/x86_64-redhat-linux/4.8./:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/4.8./:/usr/lib/gcc/x86_64-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.8./:/usr/lib/gcc/x86_64-redhat-linux/4.8./../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/lib/gcc/x86_64-redhat-linux/4.8./../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-o' 'test' '-v' '-mtune=generic' '-march=x86-64'
/usr/libexec/gcc/x86_64-redhat-linux/4.8./collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-.so. -o test /usr/lib/gcc/x86_64-redhat-linux/4.8./../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.8./../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.8./crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8. -L/usr/lib/gcc/x86_64-redhat-linux/4.8./../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8./../../.. /tmp/ccL4wd1V.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.8./crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.8./../../../../lib64/crtn.o
[root@localhost ~]#

Using built-in specs.               //编译链接详细信息
COLLECT_GCC=gcc                  //编译时所调用的总调度程序

Target: x86_64-linux-gnu           //gcc编译得到的可执行文件的运行环境,cpu:64位x86, OS:linux, gnu:gcc的开发组织

Configured with: ../configure --prefix=/usr         //gcc配置信息

gcc配置信息

什么是gcc配置信息

gcc也是一个程序,也是被别人开发出来的,应该是c/c++语言写的。编写gcc这个编译器程序的人,在编译gcc时所给的信息就是配置信息,这些信息会决定编译gcc哪些代码,不编译哪些代码,最终得到针对某个环境(OS/CPU)的gcc可执行程序。

gcc程序如何面对众多环境的

gnu开发的gcc可以面对很多的环境,比如windows x86环境,Linux x86环境,Linux arm环境。编写gcc的人,为了让程序能够应对各种环境(OS、cpu),gcc程序里面会包含应对各个环境的代码,如果你想得到针对某个环境gcc可执行程序,就必须只编译针对该环境的代码,其它代码不编译。

如何选择只编译gcc程序针对某个环境的代码

通过条件编译来选择,就可以在预编译阶段决定你要保留哪些代码,放弃哪些代码,编译时只编译你保留的代码。

比如

gcc.c

#define X86_LINUX

#ifdef X86_LINUX
针对x86、Linux环境的代码。
#endif #ifdef ARM_LINUX
针对arm、Linux环境的代码。
#endif #ifdef X86_WINDOWS
针对X86、windows环境的代码。
#endif

通过条件编译所需的宏,就能让条件编译保留和编译只针对某个环境的代码。但是由于c条件编译使用的宏实在是太多了,所以我们不可能自己一个一个的定义这些宏,所以就需要通过配置信息自动生成需要的宏。

配置信息保存在哪里呢?

配置信息保存在配置文件中,我们配置信息时,其实就是修改配置文件中的内容。运行配置文件时,根据配置信息的要求,会自动生成需要的宏定义,并把这些宏定义保存到相应的.h(头文件)中。再将.h给c/c++程序,预处理时,条件编译根据.h中定义的宏定义,就能决定保留和编译哪些代码。编译时就只编译保留的代码,最后就得到了针对某个环境的gcc可执行程序,不过这些配置信息会保留gcc中,gcc -v时会显示出来。

Configured with: ../configure  

这句话仅仅只是向我们表明,gcc的配置信息其实是来源于这个文件,这个配置文件并不在我的电脑上,而是在gcc开发者的电脑上,编译gcc时gcc开发者会去设置这个配置文件。

--prefix=/usr  

路径固定前缀,也就是说gcc所使用到的路径都是/usr打头的,换句话说gcc所用到的文件,都在这个/usr目录下。

--with-bugurl=http://bugzilla.redhat.com/bugzilla  

gcc bug报告说明书:如果你发现了gcc的bug,需要按照README.Bugs说明书的要求来提交gcc的bug

--enable-languages  

gcc编译器集合所支持的语言,不过想要编译java等其它语言,需要下载相应的插件

--libdir=/usr/lib  

GCC编译器集合“自带库”所在目录

--enable-java-awt=gtk   

使用gcc编译带界面的java程序,图形界面底层调用的是ubuntu的gtk基础图形库。gcc可以编译java,但是java程序运行需要相应的运行环境(最起码要有个java虚拟机jvm)以下信息描述的就是java的运行环境

--with-java-home=/usr/lib/jvm/java-1.5.-gcj--amd64/jre
--enable-java-home
--with-jvm-root-dir=/usr/lib/jvm/java-1.5.-gcj--amd64
--with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.-gcj--amd64
--with-arch-directory=amd64
--with-ecj-jar=/usr/share/java/eclipse-ecj.jar
--enable-objc-gc

gcc基本选项:

-march=x86-64:intel 64位 x86 cpu  

-mtune=generic:

编译得到的机器指令,属于通用指令集(同款的不同型号的cpu都支持的指令集)。如果需要指定某型号cpu的特殊指令集时,就不能写成generic,而要写特殊指令集名称COLLECT_GCC_OPTIONS='-o' 'helloworld' '-v' '-mtune=generic' '-march=x86-64'

crt1.o、crti.o、crtbegin.o:

用于生成程序的“启动代码”,这三个.o是由GCC编译器集合提供的(由GCC开发者编写的),crt就是c/c++ run time的意思,翻译为中文就是“运行时环境”。

启动代码的作用:搭建c/c++的运行环境

crt1.o:汇编写的。

①里面的_start是整个程序的开始(入口)

②main函数是由crt1.o调用

③c/c++函数运行所需要的栈,是由crt1.o建立的

crti.o:在调用main之前,实现c的一些初始化工作,比如全局变量初始化

crtbegin.o:在调用main之前,实现c++的一些初始化,比如调用全局构造函数,创建全局对象

crtend.o、crtn.o:

用于生成扫尾代码,程序运行结束时,做一些扫尾工作,这两个.o也是由gcc开发者编写的,为了方便描述,我们往往将扫尾代码认为是启动代码的一部分。

crtend.o:扫尾做什么?比如调用c++析构函数,释放全局对象的空间

crtn.o:扫尾做什么?比如,接收main函数的返回值并处理

①如果程序是裸机运行的,返回值到扫尾代码这里就结束了,裸机时返回值的意义不大

②如果程序是基于OS运行的,扫尾代码会将返回值交给OS

头文件包含

包含""所指定的头文件:到程序员自己指定的路径下去搜索

#include "..." search starts here:

包含<>所指定的头文件:到系统指定的路径下去找

#include <...> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/5/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/5/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.

汇编

由于as的路径已经被加入到了环境变量中,因此调用as时,并不需要指定as的路径。生成xxx.s汇编文件是一个临时文件,/tmp目录专门用于存放Linux系统所生成的临时文件,一旦编译得到了可执行文件,这个xxx.s将会别删除

链接

collect2为链接器,由于collect2的路径没有加入环境变量,因此需要我们自己指明collect2所在的路径。

/usr/lib/gcc/x86_64-linux-gnu/5/collect2

collect2的选项和参数
...

给程序指定动态链接器:程序运行起来后,用于加载动态库
-dynamic-linker /lib64/ld-linux-x86-64.so.2

最终生成的可执行文件

 

剖析gcc -v输出的更多相关文章

  1. IP 层收发报文简要剖析6--ip报文输出3 ip_push_pending_frames

    L4层的协议会把数据通过ip_append_data或ip_append_page把数据线放在缓冲区,然后再显示调用ip_push_pending_frames传送数据. 把数据放在缓冲区有两个优点, ...

  2. Linux命令——ldd和ldconfig

    转自:Linux系统中“动态库”和“静态库”那点事儿 前言 在调试lua脚本的时候,报错. 我已经再lua脚本中更改了cpath package.cpath = package.cpath .. &q ...

  3. 静态链接 VS 动态链接

    什么是链接? 链接其实就是连接的意思,将所有相关的东西连接起来. 简单理解静态连接和动态链接: 静态链接:编译时完成链接 动态链接:程序运行起来后,根据需求再去链接,这就是动态链接 静态链接 什么是静 ...

  4. 预处理、编译、汇编、链接、启动代码、相关command

    被忽略的过程 对于C这种编译性语言,我们平时编译时,不管是通过IDE图形界面,还是通过命令行,总感觉编译一下就完成了,然后就得到了针对某OS和某CPU的二进制可执行文件(机器指令的文件).但是实际上在 ...

  5. ubuntu 安装 GCC

    网上查了好多方式,试了一下,最简单可行的是: sudo apt-get install  build-essential 等待执行完,输入 gcc -v 输出: Using built-in spec ...

  6. DPM检测模型 VoC-release 5 linux 下编译运行

    (转载请注明作者和出处 楼燚(yì)航的blog :http://www.cnblogs.com/louyihang-loves-baiyan/ 未经允许请勿用于商业用途) DPM目前使非神经网络方法 ...

  7. 内网服务器离线编译安装mysql5.7并调优

    目录 内网服务器离线编译安装mysql5.7并调优 前言 关于MySQL 一.MySQL安装篇 部署环境 前期准备工具 挂载系统ISO镜像,配置yum源 二.MySQL调优篇 1.对MySQL进行安全 ...

  8. 开发C语言的3款神器,VS2019、VScode和IntelliJ Clion

    一.Visual Studio 2019环境安装配置+代码调试 环境安装配置 首先我们要在Visual Studio官方网站去下载安装包 进入官网后会发现有三种版本可供下载,分别是社区版.专业版和企业 ...

  9. 控制台程序的中文输出乱码问题(export LC_CTYPE=zh_CN.GBK,或者修改/etc/sysconfig/i18n为zh_CN.GBK。使用setlocale(LC_CTYPE, "");会使用默认办法。编译器会将源码做转换成Unicode格式,或者指定gcc的输入文件的编码参数-finput-charset=GBK。Linux下应该用wprintf(L"%ls/n",wstr))

    今天发现用securecrt登陆时,gcc编译出错时会出现乱码,但直接在主机的窗口界面下用Shell编译却没有乱码.查看了一下当时的错误描述,发现它的引号是中文引号,导致在SecureCRT中显示出错 ...

随机推荐

  1. 【计算机视觉】OpenCV篇(5) - 仿射变换与透视变换

    参考: 图像处理的仿射变换与透视变换(https://www.imooc.com/article/27535) http://ex2tron.wang/opencv-python-extra-warp ...

  2. elasticsearch in语句和not in语句

    sql语句示例: select * from table where t_id in (1,2,3,4) php代码示例: $search_query = [ "bool" =&g ...

  3. 【Leetcode_easy】1047. Remove All Adjacent Duplicates In String

    problem 1047. Remove All Adjacent Duplicates In String 参考 1. Leetcode_easy_1047. Remove All Adjacent ...

  4. 【VS开发】【OpenGL开发】OpenGL---Windows下配置与第一个OpenGL程序

    面记录一下Windows下配置OpenGL与我的第一个OpenGL程序. 第一步:选择一个编译环境    现在Windows系统的主流编译环境有Visual Studio,Broland C++ Bu ...

  5. vue-cli3 + ts 定义全局方法

    一.定义全局方法不生效  虽然在main.ts当中定义了全局方法,但是在使用的时候根本找不到,也是无语了. 二.解决方法 我在网上找了很多方法,其中很多大神都是这样做的:  但是,我这样写了还是不生效 ...

  6. AES加密、解密(linux、window加密解密效果一致,支持中文)

    转自: http://sunfish.iteye.com/blog/2169158 import java.io.UnsupportedEncodingException; import java.s ...

  7. LeetCode 172. 阶乘后的零(Factorial Trailing Zeroes)

    172. 阶乘后的零 172. Factorial Trailing Zeroes 题目描述 给定一个整数 n,返回 n! 结果尾数中零的数量. LeetCode172. Factorial Trai ...

  8. 037 Android Glide图片加载开源框架使用

    1.Glide简单介绍 Glide是一款由Bump Technologies开发的图片加载框架,使得我们可以在Android平台上以极度简单的方式加载和展示图片.Glide是一个快速高效的Androi ...

  9. 2019ICPC南昌现场赛总结

    非常可惜的一场比赛,多了60分钟罚时与银牌无缘.今年6场ICPC网络赛里面打的最差的就是南昌站,冥冥之中自有天意吧,最后被安排去了南昌. 开场被队友叫去先看的L,说是足球,发现就是简单模拟,就直接上机 ...

  10. POJ 3233-Matrix Power Series( S = A + A^2 + A^3 + … + A^k 矩阵快速幂取模)

    Matrix Power Series Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 20309   Accepted:  ...