分析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. Linux命令——ldd和ldconfig

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

  2. 静态链接 VS 动态链接

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

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

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

  4. ubuntu 安装 GCC

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

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

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

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

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

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

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

  8. 设计一个算法,採用BFS方式输出图G中从顶点u到v的最短路径(不带权的无向连通图G採用邻接表存储)

    思想:图G是不带权的无向连通图.一条边的长度计为1,因此,求带顶点u和顶点v的最短的路径即求顶点u和顶点v的边数最少的顶点序列.利用广度优先遍历算法,从u出发进行广度遍历,类似于从顶点u出发一层一层地 ...

  9. gcc的使用简介与命令行参数说明

    (一) gcc的基本用法(二) 警告提示功能选项(三) 库操作选项(四) 调试选项(五) 交叉编译选项 (一) gcc的基本用法使用gcc编译器时,必须给出一系列必要的调用参数和文件名称.不同参数的先 ...

随机推荐

  1. Java实现字符串反转的8种方法

    /** * */ package com.wsheng.aggregator.algorithm.string; import java.util.Stack; /** * 8 种字符串反转的方法, ...

  2. JQuery:JQuery的尺寸

    JQuery:尺寸 介绍:通过 jQuery,很容易处理元素和浏览器窗口的尺寸.jQuery 提供多个处理尺寸的重要方法:width().height().innerHeight().outerWid ...

  3. webpack我遇到的一些坑

    我的第一个用于实验webpack的项目是一个拥有多个版本的项目.什么叫多个版本?这个项目对3个语言版本+3个不同城市版本+(移动端  + PC端),也就是3*3*2,18个版本. 我的第一次想法肯定是 ...

  4. 多线程要点--CLR C#学习笔记

    1.windows永远不会调度一个进程,只调度线程. 2.线程和操作系统的关系:CLR(X)--AppDomain--线程池(包含工作者线程和I/O线程) 3.线程的关键组成部分 A.线程执行上下文 ...

  5. 配置Delphi工具菜单 转

    配置Delphi工具菜单 Delphi工具菜单是可配置的.缺省时,Delphi Tools工具菜单的菜单项为[Database Desktop].[Image Editor].[Package Col ...

  6. css3绘制几何图形

    用css3绘制你需要的几何图形 1.圆形 示例: 思路:给任何正方形元素设置一个足够大的 border-radius ,就可以把它变成一个圆形.代码如下: html: <div class=&q ...

  7. js动画学习(四)

    七.多属性封装函数 前面分别介绍了单独改变单一属性值得动画,从本节起开始介绍多属性封装函数,一个函数搞定多种属性值的改变. 首先介绍一个很重要的函数getStyle(),这个函数返回一个元素的当前属性 ...

  8. IOS开发创建开发证书及发布App应用(六)——打包应用

    6.打包应用 如下图,生成之后点击下面红框的按钮,按时间排序,然后点最新的一次生成 从右侧生成日志中找到如下图红框标识的部分,找到 -output ,把下面浅蓝色选中,这是app生成的文件夹路径 点击 ...

  9. salt+jenkins+gitlab+ecs构建公司部署平台

    1.网络架构图如下 2.采用这种方案的原因 1.现网机器都在各个省机房内网,或者堡垒机内部.无法直接从公司总部ssh到各个现网机器 2.现网机器可以访问到公网.因此可以从公网下载制作的tar包 3.每 ...

  10. 软工团队 - UML设计

    软工团队 - UML设计 分工 对于分工我们没有不是按"自己负责部分的核心模块做练习"(每个人对每个图的某一模块来依次做完四个UML)的原因,是在于画这些图并不是都能彻底分成各个& ...